rustfmt, no behaviour change

rustfmt and clippy were installed all along; I had wrongly recorded them as
missing and never ran either. This is the mechanical half -- files rustfmt
reformatted and nothing else touched, committed separately so the real fixes
in the next commit are readable.
This commit is contained in:
2026-08-10 09:23:08 +07:00
parent 272ec0c5d2
commit a9400d0550
7 changed files with 191 additions and 54 deletions
+33 -8
View File
@@ -92,7 +92,12 @@ fn parse_modifiers(raw: &str, span: Span) -> Result<Vec<&'static str>, BindError
)); ));
} }
found.sort_by_key(|m| MODIFIER_ORDER.iter().position(|o| o == m).unwrap_or(usize::MAX)); found.sort_by_key(|m| {
MODIFIER_ORDER
.iter()
.position(|o| o == m)
.unwrap_or(usize::MAX)
});
Ok(found) Ok(found)
} }
@@ -179,7 +184,10 @@ fn workspace_index(arg: &str, span: Span, dispatcher: &str) -> Result<u8, BindEr
arg.trim().parse::<u8>().map_err(|_| { arg.trim().parse::<u8>().map_err(|_| {
err( err(
span, span,
format!("`{dispatcher}` needs a workspace number, got `{}`", arg.trim()), format!(
"`{dispatcher}` needs a workspace number, got `{}`",
arg.trim()
),
Some("COSMIC addresses workspaces 1-255 by index"), Some("COSMIC addresses workspaces 1-255 by index"),
) )
}) })
@@ -342,19 +350,33 @@ mod tests {
// COSMIC's defaults bind bare Super to the launcher this way. // COSMIC's defaults bind bare Super to the launcher this way.
let b = bind("SUPER, , exec, rofi -show drun"); let b = bind("SUPER, , exec, rofi -show drun");
assert_eq!(b.key, None); assert_eq!(b.key, None);
assert_eq!(render(&[b]), "{\n (modifiers: [Super]): Spawn(\"rofi -show drun\"),\n}\n"); assert_eq!(
render(&[b]),
"{\n (modifiers: [Super]): Spawn(\"rofi -show drun\"),\n}\n"
);
} }
#[test] #[test]
fn keys_normalise_to_xkb_spelling() { fn keys_normalise_to_xkb_spelling() {
assert_eq!(bind("SUPER, Q, killactive").key.as_deref(), Some("q")); assert_eq!(bind("SUPER, Q, killactive").key.as_deref(), Some("q"));
assert_eq!(bind("SUPER, Return, killactive").key.as_deref(), Some("Return")); assert_eq!(
assert_eq!(bind("SUPER, enter, killactive").key.as_deref(), Some("Return")); bind("SUPER, Return, killactive").key.as_deref(),
Some("Return")
);
assert_eq!(
bind("SUPER, enter, killactive").key.as_deref(),
Some("Return")
);
assert_eq!(bind("SUPER, f5, killactive").key.as_deref(), Some("F5")); assert_eq!(bind("SUPER, f5, killactive").key.as_deref(), Some("F5"));
assert_eq!(bind("SUPER, slash, killactive").key.as_deref(), Some("slash")); assert_eq!(
bind("SUPER, slash, killactive").key.as_deref(),
Some("slash")
);
// Unknown names pass through so exact keysyms stay usable. // Unknown names pass through so exact keysyms stay usable.
assert_eq!( assert_eq!(
bind("SUPER, XF86AudioRaiseVolume, killactive").key.as_deref(), bind("SUPER, XF86AudioRaiseVolume, killactive")
.key
.as_deref(),
Some("XF86AudioRaiseVolume") Some("XF86AudioRaiseVolume")
); );
} }
@@ -381,7 +403,10 @@ mod tests {
assert_eq!(bind("SUPER, Q, killactive").action, "Close"); assert_eq!(bind("SUPER, Q, killactive").action, "Close");
assert_eq!(bind("SUPER, F, fullscreen").action, "Fullscreen"); assert_eq!(bind("SUPER, F, fullscreen").action, "Fullscreen");
assert_eq!(bind("SUPER, left, movefocus, l").action, "Focus(Left)"); assert_eq!(bind("SUPER, left, movefocus, l").action, "Focus(Left)");
assert_eq!(bind("SUPER SHIFT, left, movewindow, l").action, "Move(Left)"); assert_eq!(
bind("SUPER SHIFT, left, movewindow, l").action,
"Move(Left)"
);
assert_eq!(bind("SUPER, 1, workspace, 1").action, "Workspace(1)"); assert_eq!(bind("SUPER, 1, workspace, 1").action, "Workspace(1)");
assert_eq!( assert_eq!(
bind("SUPER SHIFT, 1, movetoworkspace, 1").action, bind("SUPER SHIFT, 1, movetoworkspace, 1").action,
+58 -19
View File
@@ -72,9 +72,15 @@ impl CornerRadii {
pub enum EmitError { pub enum EmitError {
Io(io::Error), Io(io::Error),
/// A projected target whose composite shape this emitter cannot rebuild. /// A projected target whose composite shape this emitter cannot rebuild.
UnsupportedComposite { key: String, detail: String }, UnsupportedComposite {
key: String,
detail: String,
},
/// An existing file could not be parsed, so read-modify-write is unsafe. /// An existing file could not be parsed, so read-modify-write is unsafe.
Unreadable { path: PathBuf, detail: String }, Unreadable {
path: PathBuf,
detail: String,
},
NoConfigDirectory, NoConfigDirectory,
} }
@@ -293,10 +299,12 @@ fn composite(
// default (0, 8) — theme.rs:939. // default (0, 8) — theme.rs:939.
"gaps" => { "gaps" => {
let (mut outer, mut inner) = match previous { let (mut outer, mut inner) = match previous {
Some(text) => ron::from_str::<(u32, u32)>(text).map_err(|e| EmitError::Unreadable { Some(text) => {
path: path.to_path_buf(), ron::from_str::<(u32, u32)>(text).map_err(|e| EmitError::Unreadable {
detail: e.to_string(), path: path.to_path_buf(),
})?, detail: e.to_string(),
})?
}
None => (0, 8), None => (0, 8),
}; };
@@ -398,7 +406,10 @@ mod tests {
let e = Emitter::with_root(tmp.path()); let e = Emitter::with_root(tmp.path());
e.apply(&planned).unwrap(); e.apply(&planned).unwrap();
assert_eq!(read(tmp.path(), "com.system76.CosmicComp", "autotile"), "true"); assert_eq!(
read(tmp.path(), "com.system76.CosmicComp", "autotile"),
"true"
);
} }
#[test] #[test]
@@ -411,7 +422,10 @@ mod tests {
let root = tmp.path(); let root = tmp.path();
assert_eq!(read(root, "com.system76.CosmicComp", "autotile"), "true"); assert_eq!(read(root, "com.system76.CosmicComp", "autotile"), "true");
assert_eq!(read(root, "com.system76.CosmicComp", "edge_snap_threshold"), "12"); assert_eq!(
read(root, "com.system76.CosmicComp", "edge_snap_threshold"),
"12"
);
assert_eq!( assert_eq!(
read(root, "com.system76.CosmicTk", "icon_theme"), read(root, "com.system76.CosmicTk", "icon_theme"),
"\"Tela-circle-dracula\"" "\"Tela-circle-dracula\""
@@ -423,7 +437,8 @@ mod tests {
#[test] #[test]
fn both_gaps_reach_disk_in_one_tuple() { fn both_gaps_reach_disk_in_one_tuple() {
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let planned = plan_for("general {\n gaps_in = 3\n gaps_out = 8\n}\n", tmp.path()).unwrap(); let planned =
plan_for("general {\n gaps_in = 3\n gaps_out = 8\n}\n", tmp.path()).unwrap();
Emitter::with_root(tmp.path()).apply(&planned).unwrap(); Emitter::with_root(tmp.path()).apply(&planned).unwrap();
// (outer, inner) — theme.rs:895 // (outer, inner) — theme.rs:895
@@ -480,10 +495,16 @@ mod tests {
let b = "com.system76.CosmicTheme.Dark.Builder"; let b = "com.system76.CosmicTheme.Dark.Builder";
// Option<Srgb>: three components, no alpha. // Option<Srgb>: three components, no alpha.
assert_eq!(read(tmp.path(), b, "accent"), "Some((red: 1.0, green: 0.0, blue: 0.0))"); assert_eq!(
read(tmp.path(), b, "accent"),
"Some((red: 1.0, green: 0.0, blue: 0.0))"
);
// Option<Srgba>: four. // Option<Srgba>: four.
let bg = read(tmp.path(), b, "bg_color"); let bg = read(tmp.path(), b, "bg_color");
assert!(bg.starts_with("Some((red: 0.0, green: 1.0, blue: 0.0, alpha: "), "{bg}"); assert!(
bg.starts_with("Some((red: 0.0, green: 1.0, blue: 0.0, alpha: "),
"{bg}"
);
} }
#[test] #[test]
@@ -492,7 +513,11 @@ mod tests {
let planned = plan_for("decoration {\n rounding = 10\n}\n", tmp.path()).unwrap(); let planned = plan_for("decoration {\n rounding = 10\n}\n", tmp.path()).unwrap();
Emitter::with_root(tmp.path()).apply(&planned).unwrap(); Emitter::with_root(tmp.path()).apply(&planned).unwrap();
let text = read(tmp.path(), "com.system76.CosmicTheme.Dark.Builder", "corner_radii"); let text = read(
tmp.path(),
"com.system76.CosmicTheme.Dark.Builder",
"corner_radii",
);
let radii: CornerRadii = ron::from_str(&text).expect("round-trips as CornerRadii"); let radii: CornerRadii = ron::from_str(&text).expect("round-trips as CornerRadii");
assert_eq!(radii.radius_m, [10.0; 4]); assert_eq!(radii.radius_m, [10.0; 4]);
} }
@@ -504,7 +529,11 @@ mod tests {
let planned = plan_for("decoration {\n rounding = 10\n}\n", tmp.path()).unwrap(); let planned = plan_for("decoration {\n rounding = 10\n}\n", tmp.path()).unwrap();
Emitter::with_root(tmp.path()).apply(&planned).unwrap(); Emitter::with_root(tmp.path()).apply(&planned).unwrap();
let text = read(tmp.path(), "com.system76.CosmicTheme.Dark.Builder", "corner_radii"); let text = read(
tmp.path(),
"com.system76.CosmicTheme.Dark.Builder",
"corner_radii",
);
let radii: CornerRadii = ron::from_str(&text).unwrap(); let radii: CornerRadii = ron::from_str(&text).unwrap();
let d = CornerRadii::default(); let d = CornerRadii::default();
assert_eq!(radii.radius_0, d.radius_0); assert_eq!(radii.radius_0, d.radius_0);
@@ -544,10 +573,13 @@ mod tests {
}; };
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let e = Emitter::with_root(tmp.path()); let e = Emitter::with_root(tmp.path());
let res = e.plan(&Resolved { writes: vec![write] }); let res = e.plan(&Resolved {
assert!( writes: vec![write],
matches!(res.unwrap_err()[0], EmitError::UnsupportedComposite { .. }), });
); assert!(matches!(
res.unwrap_err()[0],
EmitError::UnsupportedComposite { .. }
),);
} }
#[test] #[test]
@@ -561,7 +593,11 @@ mod tests {
fs::write(dir.join("gaps"), "not ron at all").unwrap(); fs::write(dir.join("gaps"), "not ron at all").unwrap();
let errs = plan_for("general {\n gaps_in = 3\n}\n", tmp.path()).unwrap_err(); let errs = plan_for("general {\n gaps_in = 3\n}\n", tmp.path()).unwrap_err();
assert!(matches!(errs[0], EmitError::Unreadable { .. }), "{:?}", errs[0]); assert!(
matches!(errs[0], EmitError::Unreadable { .. }),
"{:?}",
errs[0]
);
} }
/// Planning must not touch disk — that is what makes emission transactional. /// Planning must not touch disk — that is what makes emission transactional.
@@ -613,7 +649,10 @@ mod tests {
.map(|e| e.file_name().to_string_lossy().to_string()) .map(|e| e.file_name().to_string_lossy().to_string())
.filter(|n| n.starts_with(".atomicwrite")) .filter(|n| n.starts_with(".atomicwrite"))
.collect(); .collect();
assert!(leftovers.is_empty(), "temp files left behind: {leftovers:?}"); assert!(
leftovers.is_empty(),
"temp files left behind: {leftovers:?}"
);
} }
#[test] #[test]
+38 -13
View File
@@ -70,7 +70,8 @@ fn strip_hyde_header(src: &str) -> &str {
let Some(first) = lines.next() else { let Some(first) = lines.next() else {
return src; return src;
}; };
let is_destination_header = !first.contains('=') && (first.contains("|>") || first.contains('|')); let is_destination_header =
!first.contains('=') && (first.contains("|>") || first.contains('|'));
if is_destination_header { if is_destination_header {
// Preserve line numbering by keeping the newline count intact: callers // Preserve line numbering by keeping the newline count intact: callers
// report spans against the stripped text, so re-add a blank line. // report spans against the stripped text, so re-add a blank line.
@@ -105,7 +106,12 @@ fn is_gradient(value: &str) -> bool {
/// Flatten to dotted keys, keeping variables separate — HyDE carries /// Flatten to dotted keys, keeping variables separate — HyDE carries
/// `$GTK_THEME` / `$ICON_THEME` as variables rather than config keys. /// `$GTK_THEME` / `$ICON_THEME` as variables rather than config keys.
fn walk(items: &[Item], prefix: &str, out: &mut Vec<(String, String, Span)>, vars: &mut Vec<(String, String, Span)>) { fn walk(
items: &[Item],
prefix: &str,
out: &mut Vec<(String, String, Span)>,
vars: &mut Vec<(String, String, Span)>,
) {
for item in items { for item in items {
match item { match item {
Item::Section { name, items } => { Item::Section { name, items } => {
@@ -150,7 +156,11 @@ pub fn import_hypr_theme(src: &str, theme_name: &str) -> Result<Import, ParseErr
match name.as_str() { match name.as_str() {
"ICON_THEME" => theme.push(("icon_theme".into(), value.clone())), "ICON_THEME" => theme.push(("icon_theme".into(), value.clone())),
"COLOR_SCHEME" => { "COLOR_SCHEME" => {
let mode = if value.contains("light") { "light" } else { "dark" }; let mode = if value.contains("light") {
"light"
} else {
"dark"
};
theme.push(("mode".into(), mode.into())); theme.push(("mode".into(), mode.into()));
} }
"GTK_THEME" => notes.push(Note { "GTK_THEME" => notes.push(Note {
@@ -208,14 +218,16 @@ pub fn import_hypr_theme(src: &str, theme_name: &str) -> Result<Import, ParseErr
"general.layout" => notes.push(note(Reason::NoEquivalent( "general.layout" => notes.push(note(Reason::NoEquivalent(
"cosmic-comp uses a BSP tiler; dwindle/master are not available", "cosmic-comp uses a BSP tiler; dwindle/master are not available",
))), ))),
"general.resize_on_border" => notes.push(note(Reason::NoEquivalent( "general.resize_on_border" => {
"no equivalent setting", notes.push(note(Reason::NoEquivalent("no equivalent setting")))
))), }
k if k.starts_with("decoration.blur") => notes.push(note( k if k.starts_with("decoration.blur") => {
Reason::NeedsCompositorPatch("COSMIC blur is client-requested via \ notes.push(note(Reason::NeedsCompositorPatch(
ext-background-effect; rule-driven blur is spec Phase 2"), "COSMIC blur is client-requested via \
)), ext-background-effect; rule-driven blur is spec Phase 2",
)))
}
k if k.starts_with("decoration.shadow") => notes.push(note( k if k.starts_with("decoration.shadow") => notes.push(note(
Reason::NeedsCompositorPatch("shadow.frag exists but is not configurable yet"), Reason::NeedsCompositorPatch("shadow.frag exists but is not configurable yet"),
)), )),
@@ -300,7 +312,12 @@ pub fn render_report(import: &Import) -> String {
if !lossy.is_empty() { if !lossy.is_empty() {
out.push_str("Translated with loss:\n"); out.push_str("Translated with loss:\n");
for n in &lossy { for n in &lossy {
out.push_str(&format!(" {} = {}\n {}\n", n.key, n.value, n.reason.describe())); out.push_str(&format!(
" {} = {}\n {}\n",
n.key,
n.value,
n.reason.describe()
));
} }
} }
if !dropped.is_empty() { if !dropped.is_empty() {
@@ -309,7 +326,12 @@ pub fn render_report(import: &Import) -> String {
} }
out.push_str("Not translated:\n"); out.push_str("Not translated:\n");
for n in &dropped { for n in &dropped {
out.push_str(&format!(" {} = {}\n {}\n", n.key, n.value, n.reason.describe())); out.push_str(&format!(
" {} = {}\n {}\n",
n.key,
n.value,
n.reason.describe()
));
} }
} }
out out
@@ -431,7 +453,10 @@ layerrule = blur,waybar
"group.col.border_active", "group.col.border_active",
"layerrule", "layerrule",
] { ] {
assert!(keys.contains(&expected), "`{expected}` missing from {keys:?}"); assert!(
keys.contains(&expected),
"`{expected}` missing from {keys:?}"
);
} }
} }
+15 -3
View File
@@ -25,7 +25,10 @@ pub use resolve::{resolve, Diagnostic, Resolved, Value, Write, WriteKind};
/// Render a diagnostic against source text, cargo-style. /// Render a diagnostic against source text, cargo-style.
pub fn render_diagnostic(source: &str, span: Span, message: &str, help: Option<&str>) -> String { pub fn render_diagnostic(source: &str, span: Span, message: &str, help: Option<&str>) -> String {
let line = source.lines().nth(span.line.saturating_sub(1)).unwrap_or(""); let line = source
.lines()
.nth(span.line.saturating_sub(1))
.unwrap_or("");
let gutter = span.line.to_string().len(); let gutter = span.line.to_string().len();
let pad = " ".repeat(gutter); let pad = " ".repeat(gutter);
let caret = " ".repeat(span.col.saturating_sub(1)) + &"^".repeat(span.len.max(1)); let caret = " ".repeat(span.col.saturating_sub(1)) + &"^".repeat(span.len.max(1));
@@ -72,7 +75,11 @@ theme {
// gaps fold per builder; accent fans out to both; autotile is direct. // gaps fold per builder; accent fans out to both; autotile is direct.
let gaps: Vec<_> = r.writes.iter().filter(|w| w.target.key == "gaps").collect(); let gaps: Vec<_> = r.writes.iter().filter(|w| w.target.key == "gaps").collect();
assert_eq!(gaps.len(), 2); assert_eq!(gaps.len(), 2);
let accent: Vec<_> = r.writes.iter().filter(|w| w.target.key == "accent").collect(); let accent: Vec<_> = r
.writes
.iter()
.filter(|w| w.target.key == "accent")
.collect();
assert_eq!(accent.len(), 2); assert_eq!(accent.len(), 2);
} }
@@ -81,7 +88,12 @@ theme {
let src = "general {\n gaps_inn = 8\n}\n"; let src = "general {\n gaps_inn = 8\n}\n";
let ast = parse(src).unwrap(); let ast = parse(src).unwrap();
let diags = resolve(&ast).unwrap_err(); let diags = resolve(&ast).unwrap_err();
let out = render_diagnostic(src, diags[0].span, &diags[0].message, diags[0].help.as_deref()); let out = render_diagnostic(
src,
diags[0].span,
&diags[0].message,
diags[0].help.as_deref(),
);
assert!(out.contains("unknown key"), "{out}"); assert!(out.contains("unknown key"), "{out}");
assert!(out.contains("cosmic.conf:2:5"), "{out}"); assert!(out.contains("cosmic.conf:2:5"), "{out}");
+9 -2
View File
@@ -300,7 +300,10 @@ mod tests {
_ => None, _ => None,
}) })
.collect(); .collect();
assert_eq!(binds, vec!["SUPER, Return, spawn, kitty", "SUPER, Q, close"]); assert_eq!(
binds,
vec!["SUPER, Return, spawn, kitty", "SUPER, Q, close"]
);
} }
#[test] #[test]
@@ -332,7 +335,11 @@ mod tests {
#[test] #[test]
fn rejects_line_without_equals() { fn rejects_line_without_equals() {
let err = parse("this is not valid\n").unwrap_err(); let err = parse("this is not valid\n").unwrap_err();
assert!(err.message.contains("expected `key = value`"), "{}", err.message); assert!(
err.message.contains("expected `key = value`"),
"{}",
err.message
);
assert_eq!(err.span.line, 1); assert_eq!(err.span.line, 1);
} }
} }
+30 -7
View File
@@ -114,8 +114,16 @@ macro_rules! both_themes {
macro_rules! both_themes_direct { macro_rules! both_themes_direct {
($key:literal) => { ($key:literal) => {
&[ &[
Target::Direct { component: DARK_BUILDER, version: 1, key: $key }, Target::Direct {
Target::Direct { component: LIGHT_BUILDER, version: 1, key: $key }, component: DARK_BUILDER,
version: 1,
key: $key,
},
Target::Direct {
component: LIGHT_BUILDER,
version: 1,
key: $key,
},
] ]
}; };
} }
@@ -126,14 +134,20 @@ pub const REGISTRY: &[Entry] = &[
conf: "general.gaps_in", conf: "general.gaps_in",
targets: both_themes!("gaps", &[GAPS_INNER_IDX]), targets: both_themes!("gaps", &[GAPS_INNER_IDX]),
ty: Ty::U32, ty: Ty::U32,
validate: Some(Range { min: 0.0, max: 128.0 }), validate: Some(Range {
min: 0.0,
max: 128.0,
}),
doc: "Gap between adjacent tiled windows, in px", doc: "Gap between adjacent tiled windows, in px",
}, },
Entry { Entry {
conf: "general.gaps_out", conf: "general.gaps_out",
targets: both_themes!("gaps", &[GAPS_OUTER_IDX]), targets: both_themes!("gaps", &[GAPS_OUTER_IDX]),
ty: Ty::U32, ty: Ty::U32,
validate: Some(Range { min: 0.0, max: 256.0 }), validate: Some(Range {
min: 0.0,
max: 256.0,
}),
doc: "Gap between tiled windows and the screen edge, in px", doc: "Gap between tiled windows and the screen edge, in px",
}, },
Entry { Entry {
@@ -177,7 +191,10 @@ pub const REGISTRY: &[Entry] = &[
key: "focus_follows_cursor_delay", key: "focus_follows_cursor_delay",
}], }],
ty: Ty::U32, ty: Ty::U32,
validate: Some(Range { min: 0.0, max: 5000.0 }), validate: Some(Range {
min: 0.0,
max: 5000.0,
}),
doc: "Delay in ms before focus follows the cursor", doc: "Delay in ms before focus follows the cursor",
}, },
Entry { Entry {
@@ -199,7 +216,10 @@ pub const REGISTRY: &[Entry] = &[
key: "edge_snap_threshold", key: "edge_snap_threshold",
}], }],
ty: Ty::U32, ty: Ty::U32,
validate: Some(Range { min: 0.0, max: 256.0 }), validate: Some(Range {
min: 0.0,
max: 256.0,
}),
doc: "Distance in px at which windows snap to output edges", doc: "Distance in px at which windows snap to output edges",
}, },
// ---- decoration ------------------------------------------------------ // ---- decoration ------------------------------------------------------
@@ -207,7 +227,10 @@ pub const REGISTRY: &[Entry] = &[
conf: "decoration.rounding", conf: "decoration.rounding",
targets: both_themes!("corner_radii", &["radius_m"]), targets: both_themes!("corner_radii", &["radius_m"]),
ty: Ty::F32, ty: Ty::F32,
validate: Some(Range { min: 0.0, max: 64.0 }), validate: Some(Range {
min: 0.0,
max: 64.0,
}),
doc: "Window corner radius in px (maps to the theme's radius_m)", doc: "Window corner radius in px (maps to the theme's radius_m)",
}, },
// ---- theme ----------------------------------------------------------- // ---- theme -----------------------------------------------------------
+8 -2
View File
@@ -65,13 +65,19 @@ fn write_raw_link(header: &mut tar::Header, target: &str) {
} }
/// A theme directory just complete enough for `plan` to consider the archive. /// A theme directory just complete enough for `plan` to consider the archive.
fn theme_with_archive(entries: &[(&str, tar::EntryType, &[u8], Option<&str>)]) -> (TempDir, PathBuf, PathBuf) { fn theme_with_archive(
entries: &[(&str, tar::EntryType, &[u8], Option<&str>)],
) -> (TempDir, PathBuf, PathBuf) {
let tmp = TempDir::new().unwrap(); let tmp = TempDir::new().unwrap();
let theme_dir = tmp.path().join("Configs/.config/hyde/themes/Evil"); let theme_dir = tmp.path().join("Configs/.config/hyde/themes/Evil");
let source_dir = tmp.path().join("Source"); let source_dir = tmp.path().join("Source");
fs::create_dir_all(&theme_dir).unwrap(); fs::create_dir_all(&theme_dir).unwrap();
fs::create_dir_all(&source_dir).unwrap(); fs::create_dir_all(&source_dir).unwrap();
fs::write(theme_dir.join("hypr.theme"), "general {\n gaps_in = 3\n}\n").unwrap(); fs::write(
theme_dir.join("hypr.theme"),
"general {\n gaps_in = 3\n}\n",
)
.unwrap();
hostile_tarball(&source_dir.join("Gtk_Evil.tar.gz"), entries); hostile_tarball(&source_dir.join("Gtk_Evil.tar.gz"), entries);
(tmp, theme_dir, source_dir) (tmp, theme_dir, source_dir)