feat: add opt-in trailing whitespace highlighting

This commit is contained in:
2026-10-13 22:42:30 +02:00
parent b58fb085a3
commit e2f33519d1
8 changed files with 179 additions and 4 deletions
+28 -3
View File
@@ -45,6 +45,7 @@ pub struct Config {
pub popup: PopupConfig,
pub labels: BTreeMap<String, String>,
pub scroll_distance: Option<usize>,
pub highlight_trailing_whitespace: bool,
pub diff_context_lines: usize,
pub diff_expand_lines: usize,
pub diff_view_mode: crate::diff::ViewMode,
@@ -91,6 +92,7 @@ impl Default for Config {
popup: PopupConfig::default(),
labels: BTreeMap::new(),
scroll_distance: Some(0),
highlight_trailing_whitespace: false,
diff_context_lines: 10,
diff_expand_lines: 15,
diff_view_mode: crate::diff::ViewMode::Split,
@@ -124,6 +126,7 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
popup,
labels,
scroll_distance,
highlight_trailing_whitespace,
diff_context_lines,
diff_expand_lines,
diff_view_mode,
@@ -158,6 +161,7 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
config.popup = popup;
config.labels = labels;
config.scroll_distance = scroll_distance;
config.highlight_trailing_whitespace = highlight_trailing_whitespace;
config.diff_context_lines = diff_context_lines;
config.diff_expand_lines = diff_expand_lines;
config.diff_view_mode = diff_view_mode;
@@ -491,6 +495,7 @@ struct ConfigFrame {
labels: BTreeMap<String, String>,
#[serde(deserialize_with = "scroll_distance")]
scroll_distance: Option<usize>,
highlight_trailing_whitespace: bool,
#[serde(deserialize_with = "diff_context_lines")]
diff_context_lines: usize,
#[serde(deserialize_with = "diff_expand_lines")]
@@ -1234,9 +1239,9 @@ end
assert!(load_config(&path).unwrap_err().contains(error), "{value}");
}
for frame in [
r#"{"type":"config","version":1,"plugins":[],"lsp":{},"bindings":[],"file_explorer_side":"right","file_picker_view":"list","file_explorer_view":"tree","clipboard_mode":"system","git_blame":true,"git_gutter":"bar","scroll_distance":0,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical","diff_follow_working_copy":true}"#,
r#"{"type":"config","version":1,"plugins":[],"lsp":{},"bindings":[],"leader":null,"file_explorer_side":"right","file_picker_view":"list","file_explorer_view":"tree","clipboard_mode":"system","git_blame":true,"git_gutter":"bar","scroll_distance":0,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical","diff_follow_working_copy":true}"#,
r#"{"type":"config","version":1,"plugins":[],"lsp":{},"bindings":[],"leader":7,"file_explorer_side":"right","file_picker_view":"list","file_explorer_view":"tree","clipboard_mode":"system","git_blame":true,"git_gutter":"bar","scroll_distance":0,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical","diff_follow_working_copy":true}"#,
r#"{"type":"config","version":1,"plugins":[],"lsp":{},"bindings":[],"file_explorer_side":"right","file_picker_view":"list","file_explorer_view":"tree","clipboard_mode":"system","git_blame":true,"git_gutter":"bar","scroll_distance":0,"highlight_trailing_whitespace":false,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical","diff_follow_working_copy":true}"#,
r#"{"type":"config","version":1,"plugins":[],"lsp":{},"bindings":[],"leader":null,"file_explorer_side":"right","file_picker_view":"list","file_explorer_view":"tree","clipboard_mode":"system","git_blame":true,"git_gutter":"bar","scroll_distance":0,"highlight_trailing_whitespace":false,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical","diff_follow_working_copy":true}"#,
r#"{"type":"config","version":1,"plugins":[],"lsp":{},"bindings":[],"leader":7,"file_explorer_side":"right","file_picker_view":"list","file_explorer_view":"tree","clipboard_mode":"system","git_blame":true,"git_gutter":"bar","scroll_distance":0,"highlight_trailing_whitespace":false,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical","diff_follow_working_copy":true}"#,
] {
assert!(serde_json::from_str::<Response>(frame).is_err(), "{frame}");
}
@@ -1313,6 +1318,7 @@ end
"file_explorer_view": "tree", "clipboard_mode": "system", "git_blame": true,
"git_gutter": "bar",
"scroll_distance": 0,
"highlight_trailing_whitespace": false,
"top_bar": {}, "bottom_bar": {}, "popup": {"command": {}, "search": {}},
"labels": {}, "diff_context_lines": 10, "diff_expand_lines": 15,
"diff_view_mode": "split", "diff_split_orientation": "vertical",
@@ -1331,6 +1337,22 @@ end
assert!(serde_json::from_value::<Response>(frame).is_err());
}
#[test]
fn trailing_whitespace_configuration_rejects_non_booleans() {
let fixture = Fixture::new();
for value in ["nil", "0", "\"true\"", "[]", "{}"] {
let path = fixture.file(
"config.rb",
&format!("Vamp.configure {{ |c| c.highlight_trailing_whitespace = {value} }}"),
);
assert!(
load_config(&path)
.unwrap_err()
.contains("highlight_trailing_whitespace must be true or false")
);
}
}
#[test]
fn working_diff_tracking_rejects_non_boolean_configuration() {
let fixture = Fixture::new();
@@ -1564,6 +1586,7 @@ end
"file_picker_view": "tree", "file_explorer_view": "tree",
"top_bar": {}, "bottom_bar": {}, "labels": {},
"scroll_distance": 0,
"highlight_trailing_whitespace": false,
"popup": {"command": {}, "search": {}},
"clipboard_mode": "system", "diff_context_lines": 0, "diff_expand_lines": 7,
"diff_view_mode": "split", "diff_split_orientation": "vertical",
@@ -1612,6 +1635,7 @@ end
"bindings": [], "leader": "space", "file_explorer_side": "right",
"file_picker_view": "tree", "file_explorer_view": "tree",
"clipboard_mode": "system", "git_blame": true, "git_gutter": "bar",
"highlight_trailing_whitespace": false,
"top_bar": {}, "bottom_bar": {}, "labels": {},
"popup": {"command": {}, "search": {}},
"diff_context_lines": 10, "diff_expand_lines": 15,
@@ -2040,6 +2064,7 @@ end"#,
"git_blame": true,
"git_gutter": "bar",
"scroll_distance": 0,
"highlight_trailing_whitespace": false,
"top_bar": {}, "bottom_bar": {}, "labels": {},
"popup": {"command": {}, "search": {}},
"clipboard_mode": "system", "diff_context_lines": 10, "diff_expand_lines": 15,