diff --git a/config/cosmic.conf b/config/cosmic.conf index 4eb81d8..11ccd2c 100644 --- a/config/cosmic.conf +++ b/config/cosmic.conf @@ -4,6 +4,20 @@ # every key here overwrites whatever COSMIC's own settings UI last stored, so # edit this rather than the GUI for anything it covers. +# --- Theme -------------------------------------------------------------- +# +# `cosmic-conf import-theme /hypr.theme --out ~/.config/hyprcosmic/theme.conf` +# turns a HyDE theme into conf keys. Sourcing it rather than pasting it in +# keeps the two apart: re-importing overwrites theme.conf and cannot touch the +# keybindings below, and anything you want to override can simply be repeated +# later in this file, since the last assignment to a key wins. +# +# Commented out because a `source` pointing at a file that does not exist is a +# hard error, and no theme is imported yet. Uncomment it once you have run the +# command above -- import-theme will remind you. +# +# source = ~/.config/hyprcosmic/theme.conf + $mainMod = SUPER # --- Launcher ----------------------------------------------------------- diff --git a/cosmic-conf/src/main.rs b/cosmic-conf/src/main.rs index 597e551..dcbd263 100644 --- a/cosmic-conf/src/main.rs +++ b/cosmic-conf/src/main.rs @@ -181,6 +181,9 @@ fn run_import(args: &[String]) -> Result { std::fs::write(&p, &imported.conf) .map_err(|e| format!("error: cannot write {}: {e}\n", p.display()))?; out.push_str(&format!("Wrote {}\n", p.display())); + if let Some(hint) = unsourced_hint(&p) { + out.push_str(&hint); + } } None => out.push_str(&imported.conf), } @@ -203,6 +206,44 @@ fn run_import(args: &[String]) -> Result { Ok(out) } +/// Warn when the file just written is not reachable from its sibling +/// cosmic.conf, and say what to add. +/// +/// A theme lives in its own file so that re-importing cannot clobber the +/// keybindings around it, but that only works if something sources it. +/// Writing an inert file and reporting success is the worst of both: the tool +/// looks like it worked and the desktop does not change. +/// +/// The match is textual and deliberately loose -- it is looking for evidence +/// that the user already knows about the file, not parsing the config. A false +/// negative costs one redundant hint; a false positive would hide a real +/// problem, so the substring searched for is the filename itself. +fn unsourced_hint(written: &Path) -> Option { + let dir = written.parent()?; + let name = written.file_name()?.to_string_lossy().to_string(); + let main = dir.join("cosmic.conf"); + + // Nothing to say when the theme *is* the config, or there is no config yet + // to add a line to: `apply` will be pointed at this file directly. + if main == written || !main.exists() { + return None; + } + + let text = std::fs::read_to_string(&main).ok()?; + if text + .lines() + .any(|l| l.trim_start().starts_with("source") && l.contains(&name)) + { + return None; + } + + Some(format!( + "\nNothing sources it yet, so `apply` will ignore it. Add this to {}:\n\n source = {}\n", + main.display(), + written.display(), + )) +} + /// The half of a theme that is not config: wallpapers, GTK/icon tarballs, and /// the `.theme` files belonging to waybar, rofi and kitty. ///