Add bread init: Hyprland compositor layer-rule integration

Installs the layerrule blur/ignore_alpha/animation integration that
breadbar's translucency depends on into a user's hyprland.lua, with a
consent-gated single marked block, timestamped backup, dry-run/--yes,
and --undo. Generates a self-contained ~/.config/hypr/bread.lua that
reads layerrules.json (bread-theme layerrules) and emits hl.layer_rule
calls, appearance fields only. Falls back to printing a snippet
(translated to hyprlang .conf syntax when relevant) rather than
writing when the config isn't a Lua hyprland.lua bread recognizes, and
refuses to install when an existing breadbar layer rule (e.g. BOS's
own dotfiles) is already found under ~/.config/hypr.

bread doctor now reports compositor integration status via a pure
filesystem check, independent of the daemon; it never installs
anything itself.

Wired as a top-level Commands::Init (not a HooksCommand variant) since
it needs diff/consent/backup/undo machinery the hooks family has no
use for.
This commit is contained in:
Breadway 2026-08-26 19:31:18 +08:00
parent 72afe790fd
commit 1fce1979c3
2 changed files with 1316 additions and 0 deletions

1281
bread-cli/src/init.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
mod init;
mod hooks_git; mod hooks_git;
mod hooks_shell; mod hooks_shell;
mod modules_mgmt; mod modules_mgmt;
@ -99,6 +100,22 @@ enum Commands {
#[arg(long)] #[arg(long)]
json: bool, json: bool,
}, },
/// Install bread's Hyprland compositor layer-rule integration
/// (breadbar/breadbox blur, ignore_alpha, animation) into
/// ~/.config/hypr/hyprland.lua, with consent, a backup, and full undo.
/// See bread-cli/src/init.rs for the design rationale.
Init {
/// Print the proposed diff and change nothing
#[arg(long)]
dry_run: bool,
/// Skip the confirmation prompt (for scripted/image builds)
#[arg(long)]
yes: bool,
/// Remove the previously installed marked block instead of
/// installing it
#[arg(long)]
undo: bool,
},
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
@ -224,6 +241,9 @@ async fn main() -> Result<()> {
print_doctor(&socket).await?; print_doctor(&socket).await?;
} }
} }
Commands::Init { dry_run, yes, undo } => {
init::run(dry_run, yes, undo)?;
}
} }
Ok(()) Ok(())
@ -691,6 +711,7 @@ async fn print_doctor(socket: &Path) -> Result<()> {
println!(); println!();
println!(" start the daemon: systemctl --user start breadd"); println!(" start the daemon: systemctl --user start breadd");
println!(" view logs: journalctl --user -u breadd -f"); println!(" view logs: journalctl --user -u breadd -f");
print_compositor_doctor_section();
return Ok(()); return Ok(());
} }
@ -775,6 +796,20 @@ fn render_doctor(health: &Value) {
} }
} }
} }
print_compositor_doctor_section();
}
/// Compositor integration status — pure filesystem check, independent of
/// the daemon, so it prints the same whether breadd is up or not. Reports
/// only; `bread doctor` never installs anything (that's `bread init`'s
/// job).
fn print_compositor_doctor_section() {
println!();
println!("compositor");
for line in init::doctor_report(&init::hypr_dir()) {
println!("{line}");
}
} }
fn config_directory() -> PathBuf { fn config_directory() -> PathBuf {