Compare commits

..

No commits in common. "main" and "v0.2.6" have entirely different histories.
main ... v0.2.6

9 changed files with 19 additions and 52 deletions

3
.gitignore vendored
View file

@ -40,6 +40,3 @@ logs/
.claude/ .claude/
# Local hygiene notes (not for commit) # Local hygiene notes (not for commit)
# graphify knowledge-graph output (local tool cache, not for commit)
graphify-out/

View file

@ -4,6 +4,6 @@ breadsearch indexes your files so you can find things instantly, without
digging through folders. digging through folders.
- Open it from BOS Settings, or run it directly. - Open it from BOS Settings, or run it directly.
- Describe what you are looking for in plain language — breadsearch ranks files by meaning, not by letters in a filename. Results update as you type. - Type a few letters of a filename — results update as you type.
- [Run]breadsearch|Open File Search[/Run] - [Run]breadsearch|Open File Search[/Run]

View file

@ -15,8 +15,7 @@ nothing here is mandatory either, click around if you'd rather.
- [Show Keybind]super + space[/Show Keybind] opens the launcher (breadbox) - [Show Keybind]super + space[/Show Keybind] opens the launcher (breadbox)
- [Show Keybind]super + e[/Show Keybind] opens files (nautilus) - [Show Keybind]super + e[/Show Keybind] opens files (nautilus)
- [Show Keybind]super + b[/Show Keybind] opens the browser - [Show Keybind]super + b[/Show Keybind] opens the browser
- [Show Keybind]super + u[/Show Keybind] opens notes (breadpad) - [Show Keybind]super + u[/Show Keybind] opens notes
- [Show Keybind]super + ,[/Show Keybind] opens BOS Settings
- [Show Keybind]super + l[/Show Keybind] locks the screen - [Show Keybind]super + l[/Show Keybind] locks the screen
## Screenshots ## Screenshots

View file

@ -12,23 +12,14 @@ pub enum Difficulty {
#[derive(serde::Deserialize, Clone, Default)] #[derive(serde::Deserialize, Clone, Default)]
pub struct GuideMeta { pub struct GuideMeta {
pub title: String, pub title: String,
/// Not read by any UI yet — reserved for a future difficulty badge.
/// Real content already sets it, so kept rather than dropped.
#[allow(dead_code)]
#[serde(default)] #[serde(default)]
pub difficulty: Difficulty, pub difficulty: Difficulty,
#[serde(default)] #[serde(default)]
pub tags: Vec<String>, pub tags: Vec<String>,
/// Guide dir-names in the same or another category. Unresolvable entries /// Guide dir-names in the same or another category. Unresolvable entries
/// are silently dropped when rendering "related guides" — never a crash. /// are silently dropped when rendering "related guides" — never a crash.
/// Not read by any UI yet — the "related guides" render path doesn't
/// exist. Real content already sets it, so kept rather than dropped.
#[allow(dead_code)]
#[serde(default)] #[serde(default)]
pub related: Vec<String>, pub related: Vec<String>,
/// Not read by any UI yet — reserved for a future "N min read" hint.
/// Real content already sets it, so kept rather than dropped.
#[allow(dead_code)]
#[serde(default)] #[serde(default)]
pub estimated_minutes: u32, pub estimated_minutes: u32,
/// Overrides the parent directory name as the guide's category, if set. /// Overrides the parent directory name as the guide's category, if set.

View file

@ -29,10 +29,6 @@ pub enum Success {
#[derive(serde::Deserialize, Clone)] #[derive(serde::Deserialize, Clone)]
pub struct Step { pub struct Step {
/// Not read by any Rust code yet — steps are matched by index, not id.
/// Real tour content already sets it (content authors use it to keep
/// track of steps), so kept rather than dropped.
#[allow(dead_code)]
pub id: String, pub id: String,
pub title: String, pub title: String,
pub body: String, pub body: String,

View file

@ -15,11 +15,6 @@ pub struct SymptomOption {
pub struct Fix { pub struct Fix {
pub description: String, pub description: String,
pub command: String, pub command: String,
/// Not read by `ui::troubleshoot_wizard` yet — the "Run fix" button
/// currently executes unconditionally regardless of this flag. Real
/// symptom content already sets it, so kept rather than dropped; the
/// wizard should gate on it before this is treated as safe.
#[allow(dead_code)]
#[serde(default)] #[serde(default)]
pub requires_confirm: bool, pub requires_confirm: bool,
} }

View file

@ -28,6 +28,10 @@ pub struct Client {
pub struct Monitor { pub struct Monitor {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
pub focused: bool, pub focused: bool,
} }

View file

@ -110,7 +110,7 @@ pub fn self_heal() {
pub fn on_tour_event(id: &str) { pub fn on_tour_event(id: &str) {
let hit = STATE.with(|cell| { let hit = STATE.with(|cell| {
let mut borrow = cell.borrow_mut(); let mut borrow = cell.borrow_mut();
let state = borrow.as_mut()?; let Some(state) = borrow.as_mut() else { return None };
// Only a *visibly* confirmed step blocks a re-fire. `confirmed` gets // Only a *visibly* confirmed step blocks a re-fire. `confirmed` gets
// set below, before `render_step` runs, so that render actually // set below, before `render_step` runs, so that render actually
// paints the "done" state instead of the stale pre-confirmation one // paints the "done" state instead of the stale pre-confirmation one

View file

@ -30,33 +30,13 @@ thread_local! {
/// over D-Bus to this primary instance by a second `breadhelp` launch — so /// over D-Bus to this primary instance by a second `breadhelp` launch — so
/// it must build the window at most once and reuse it thereafter. /// it must build the window at most once and reuse it thereafter.
pub fn present(app: &Application, action: Action) { pub fn present(app: &Application, action: Action) {
// Crash-recover keybinds even if this invocation never builds a window
// (silent every-login autostart).
tour::self_heal();
// Once onboarding is done, autostart only needs a warm process so
// Super+/ is instant. GTK/theme/font load is most of that cost and is
// paid by staying resident (~14 MiB PSS, no window). Building tabs
// adds ~2 MiB of dead weight for a session that may never open help.
let is_bare_silent_autostart = action.autostart
&& action.screenshot.is_none()
&& !action.force_onboard
&& action.tour_event.is_none()
&& action.suggest.is_none()
&& State::load().onboarding_completed();
if is_bare_silent_autostart {
// No window means nothing holds GApplication open. Forget the hold
// guard so the primary instance lives for the session; logout is
// what ends it. Without this, the next Super+/ would cold-start.
std::mem::forget(app.hold());
return;
}
HANDLE.with(|cell| { HANDLE.with(|cell| {
let mut just_built = false;
{ {
let mut cell_ref = cell.borrow_mut(); let mut cell_ref = cell.borrow_mut();
if cell_ref.is_none() { if cell_ref.is_none() {
*cell_ref = Some(build(app)); *cell_ref = Some(build(app));
just_built = true;
} }
} }
let cell_ref = cell.borrow(); let cell_ref = cell.borrow();
@ -82,14 +62,19 @@ pub fn present(app: &Application, action: Action) {
if let Some(s) = crate::services::breadd::resolve(id) { if let Some(s) = crate::services::breadd::resolve(id) {
handle.home.set_suggestion(Some(&s.text)); handle.home.set_suggestion(Some(&s.text));
} }
// Background daemon event — never steal focus. A `--suggest` // Only focus the window the first time this process builds it
// can now be the first invocation of the session because // (i.e. breadhelp wasn't already running) — a background daemon
// silent autostart no longer builds a window. // event shouldn't steal focus from whatever the user is doing.
if just_built {
show_window(&handle.window, action.autostart);
}
return; return;
} }
// Bare silent autostart (onboarding done) already returned above. // Every-login autostart builds the window (so the app is ready to
// Autostart that reaches here is a genuine first run. // respond to SUPER+/ instantly) but only shows UI on a genuine
// first run — never on later logins. First run is now the in-window
// day-zero wizard; the live tour starts when that finishes.
let onboarded = State::load().onboarding_completed(); let onboarded = State::load().onboarding_completed();
if action.autostart && onboarded { if action.autostart && onboarded {
return; return;