feat: show current-line git blame by default

This commit is contained in:
Valdemar Lorenzen
2026-10-13 12:21:03 +02:00
parent 5382307fcc
commit 7a3c27c30e
12 changed files with 1231 additions and 7 deletions
+70 -3
View File
@@ -38,6 +38,7 @@ pub struct Config {
pub file_picker_view: String,
pub file_explorer_view: String,
pub clipboard_mode: String,
pub git_blame: bool,
pub top_bar: ChromeLine,
pub bottom_bar: ChromeLine,
pub popup: PopupConfig,
@@ -80,6 +81,7 @@ impl Default for Config {
file_picker_view: "tree".into(),
file_explorer_view: "tree".into(),
clipboard_mode: "system".into(),
git_blame: true,
top_bar: ChromeLine::top(),
bottom_bar: ChromeLine::bottom(),
popup: PopupConfig::default(),
@@ -109,6 +111,7 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
file_picker_view,
file_explorer_view,
clipboard_mode,
git_blame,
top_bar,
bottom_bar,
popup,
@@ -139,6 +142,7 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
config.file_picker_view = file_picker_view;
config.file_explorer_view = file_explorer_view;
config.clipboard_mode = clipboard_mode;
config.git_blame = git_blame;
config.top_bar = top_bar;
config.bottom_bar = bottom_bar;
config.popup = popup;
@@ -453,6 +457,7 @@ struct ConfigFrame {
file_picker_view: String,
file_explorer_view: String,
clipboard_mode: String,
git_blame: bool,
#[serde(deserialize_with = "crate::chrome::top")]
top_bar: ChromeLine,
#[serde(deserialize_with = "crate::chrome::bottom")]
@@ -854,6 +859,8 @@ fn read_frame(reader: &mut impl BufRead) -> Result<Vec<u8>, String> {
#[cfg(test)]
mod tests {
use crate::{editor::Input, session::EditorSession};
use super::*;
use std::sync::atomic::{AtomicU64, Ordering};
@@ -1204,14 +1211,73 @@ 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","top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical"}"#,
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","top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical"}"#,
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","top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical"}"#,
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,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical"}"#,
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,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical"}"#,
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,"top_bar":{},"bottom_bar":{},"popup":{"command":{},"search":{}},"labels":{},"diff_context_lines":10,"diff_expand_lines":15,"diff_view_mode":"split","diff_split_orientation":"vertical"}"#,
] {
assert!(serde_json::from_str::<Response>(frame).is_err(), "{frame}");
}
}
#[test]
fn git_blame_boolean_config_typed_toggle_palette_and_wire_validation() {
let fixture = Fixture::new();
let config = fixture.file("config.rb", "Vamp.configure { |_config| }");
assert!(load_config(&config).unwrap().git_blame);
let config = fixture.file("config.rb", r#"
Vamp.configure do |config|
config.git_blame = false
config.bind "G", config.core.git_blame.toggle
raise "mutable blame action" unless config.core.git_blame.frozen? && config.core.git_blame.toggle.frozen?
end
"#);
let mut session = EditorSession::open(None, vec![], Some(&config)).unwrap();
assert!(!session.editor().git_blame());
session.handle(Input::Char('G'));
assert!(session.editor().git_blame());
session.execute("git_blame.toggle extra");
assert!(session.editor().git_blame());
session.execute("git_blame.toggle");
assert!(!session.editor().git_blame());
session.handle(Input::Ctrl('p'));
for ch in "git blame".chars() {
session.handle(Input::Char(ch));
}
assert_eq!(session.editor().palette().unwrap().entries.len(), 1);
session.handle(Input::Enter);
assert!(session.editor().git_blame());
for value in ["nil", "0", r#""false""#, "[]", "{}"] {
let config = fixture.file(
"config.rb",
&format!("Vamp.configure {{ |config| config.git_blame = {value} }}"),
);
assert!(
load_config(&config)
.unwrap_err()
.contains("git_blame must be true or false")
);
}
let mut frame = serde_json::json!({
"type": "config", "version": 1, "plugins": [], "lsp": {}, "bindings": [],
"leader": "space", "file_explorer_side": "right", "file_picker_view": "tree",
"file_explorer_view": "tree", "clipboard_mode": "system", "git_blame": true,
"top_bar": {}, "bottom_bar": {}, "popup": {"command": {}, "search": {}},
"labels": {}, "diff_context_lines": 10, "diff_expand_lines": 15,
"diff_view_mode": "split", "diff_split_orientation": "vertical"
});
assert!(serde_json::from_value::<Response>(frame.clone()).is_ok());
for value in [
serde_json::Value::Null,
serde_json::json!(0),
serde_json::json!("false"),
] {
frame["git_blame"] = value;
assert!(serde_json::from_value::<Response>(frame.clone()).is_err());
}
frame.as_object_mut().unwrap().remove("git_blame");
assert!(serde_json::from_value::<Response>(frame).is_err());
}
#[test]
fn chrome_configuration_normalizes_ruby_values_and_retains_unspecified_defaults() {
let fixture = Fixture::new();
@@ -1842,6 +1908,7 @@ end"#,
"version": 1, "type": "config", "plugins": [], "lsp": {},
"bindings": [], "leader": "space", "file_explorer_side": "right",
"file_picker_view": "tree", "file_explorer_view": "tree",
"git_blame": true,
"top_bar": {}, "bottom_bar": {}, "labels": {},
"popup": {"command": {}, "search": {}},
"clipboard_mode": "system", "diff_context_lines": 10, "diff_expand_lines": 15,