Skip to content

Commit effd641

Browse files
joskeclaude
andcommitted
preferences dialog with persistent settings
Add a preferences dialog (gear icon / Ctrl+,) with live-apply for: - Font selection (via FontDialogButton) - Color scheme (sourceview5 schemes dropdown) - Line numbers, current line highlight, word wrap, tab width - User-editable directory filter list (in a framed group) Settings persist to ~/.config/meld-rs/settings.toml via serde/toml. Uses a shared thread-local CssProvider for font CSS so updates replace rather than stack. Fixes gutter arrow positioning with word wrap by using per-line line_yrange instead of arithmetic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5cd46e3 commit effd641

5 files changed

Lines changed: 572 additions & 49 deletions

File tree

Cargo.lock

Lines changed: 67 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ chrono = "0.4"
1212
notify = "8"
1313
clap = { version = "4", features = ["derive"] }
1414
sourceview5 = { version = "0.11.0", features = ["gtk_v4_14"] }
15+
serde = { version = "1", features = ["derive"] }
16+
toml = "0.8"

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use gio::prelude::ApplicationExtManual;
55
use gtk4::{Application, glib};
66

77
mod myers;
8+
mod settings;
89
mod ui;
910

1011
#[derive(Parser)]

src/settings.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use serde::{Deserialize, Serialize};
2+
use std::path::PathBuf;
3+
4+
#[derive(Debug, Clone, Serialize, Deserialize)]
5+
#[serde(default)]
6+
pub struct Settings {
7+
pub font: String,
8+
pub style_scheme: String,
9+
pub show_line_numbers: bool,
10+
pub wrap_mode: String,
11+
pub tab_width: u32,
12+
pub highlight_current_line: bool,
13+
pub dir_filters: Vec<String>,
14+
}
15+
16+
impl Default for Settings {
17+
fn default() -> Self {
18+
Self {
19+
font: "Monospace 11".to_string(),
20+
style_scheme: "Adwaita".to_string(),
21+
show_line_numbers: true,
22+
wrap_mode: "none".to_string(),
23+
tab_width: 4,
24+
highlight_current_line: true,
25+
dir_filters: vec![
26+
".git".into(),
27+
".svn".into(),
28+
".hg".into(),
29+
".bzr".into(),
30+
"_darcs".into(),
31+
".CVS".into(),
32+
"__pycache__".into(),
33+
"node_modules".into(),
34+
".DS_Store".into(),
35+
],
36+
}
37+
}
38+
}
39+
40+
impl Settings {
41+
pub fn config_path() -> PathBuf {
42+
let mut p = if let Some(config) = std::env::var_os("XDG_CONFIG_HOME") {
43+
PathBuf::from(config)
44+
} else if let Some(home) = std::env::var_os("HOME") {
45+
PathBuf::from(home).join(".config")
46+
} else {
47+
PathBuf::from(".")
48+
};
49+
p.push("meld-rs");
50+
p.push("settings.toml");
51+
p
52+
}
53+
54+
pub fn load() -> Self {
55+
let path = Self::config_path();
56+
match std::fs::read_to_string(&path) {
57+
Ok(contents) => toml::from_str(&contents).unwrap_or_default(),
58+
Err(_) => Self::default(),
59+
}
60+
}
61+
62+
pub fn save(&self) {
63+
let path = Self::config_path();
64+
if let Some(parent) = path.parent() {
65+
let _ = std::fs::create_dir_all(parent);
66+
}
67+
if let Ok(contents) = toml::to_string_pretty(self) {
68+
let _ = std::fs::write(&path, contents);
69+
}
70+
}
71+
72+
pub fn wrap_mode_gtk(&self) -> gtk4::WrapMode {
73+
match self.wrap_mode.as_str() {
74+
"word" => gtk4::WrapMode::Word,
75+
"char" => gtk4::WrapMode::Char,
76+
_ => gtk4::WrapMode::None,
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)