feat: configure interchangeable top and bottom bars
This commit is contained in:
+82
-60
@@ -38,8 +38,8 @@ pub struct Config {
|
||||
pub file_picker_view: String,
|
||||
pub file_explorer_view: String,
|
||||
pub clipboard_mode: String,
|
||||
pub tabline: ChromeLine,
|
||||
pub statusline: ChromeLine,
|
||||
pub top_bar: ChromeLine,
|
||||
pub bottom_bar: ChromeLine,
|
||||
pub labels: BTreeMap<String, String>,
|
||||
pub diff_context_lines: usize,
|
||||
pub diff_expand_lines: usize,
|
||||
@@ -77,8 +77,8 @@ impl Default for Config {
|
||||
file_picker_view: "tree".into(),
|
||||
file_explorer_view: "tree".into(),
|
||||
clipboard_mode: "system".into(),
|
||||
tabline: ChromeLine::tabline(),
|
||||
statusline: ChromeLine::statusline(),
|
||||
top_bar: ChromeLine::top(),
|
||||
bottom_bar: ChromeLine::bottom(),
|
||||
labels: BTreeMap::new(),
|
||||
diff_context_lines: 10,
|
||||
diff_expand_lines: 15,
|
||||
@@ -102,8 +102,8 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
|
||||
file_picker_view,
|
||||
file_explorer_view,
|
||||
clipboard_mode,
|
||||
tabline,
|
||||
statusline,
|
||||
top_bar,
|
||||
bottom_bar,
|
||||
labels,
|
||||
diff_context_lines,
|
||||
diff_expand_lines,
|
||||
@@ -129,8 +129,8 @@ 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.tabline = tabline;
|
||||
config.statusline = statusline;
|
||||
config.top_bar = top_bar;
|
||||
config.bottom_bar = bottom_bar;
|
||||
config.labels = labels;
|
||||
config.diff_context_lines = diff_context_lines;
|
||||
config.diff_expand_lines = diff_expand_lines;
|
||||
@@ -450,10 +450,10 @@ enum Response {
|
||||
file_picker_view: String,
|
||||
file_explorer_view: String,
|
||||
clipboard_mode: String,
|
||||
#[serde(deserialize_with = "crate::chrome::tabline")]
|
||||
tabline: ChromeLine,
|
||||
#[serde(deserialize_with = "crate::chrome::statusline")]
|
||||
statusline: ChromeLine,
|
||||
#[serde(deserialize_with = "crate::chrome::top")]
|
||||
top_bar: ChromeLine,
|
||||
#[serde(deserialize_with = "crate::chrome::bottom")]
|
||||
bottom_bar: ChromeLine,
|
||||
#[serde(deserialize_with = "crate::chrome::labels")]
|
||||
labels: BTreeMap<String, String>,
|
||||
#[serde(deserialize_with = "diff_context_lines")]
|
||||
@@ -1181,9 +1181,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","tabline":{},"statusline":{},"labels":{},"diff_context_lines":10,"diff_expand_lines":15}"#,
|
||||
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","tabline":{},"statusline":{},"labels":{},"diff_context_lines":10,"diff_expand_lines":15}"#,
|
||||
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","tabline":{},"statusline":{},"labels":{},"diff_context_lines":10,"diff_expand_lines":15}"#,
|
||||
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":{},"labels":{},"diff_context_lines":10,"diff_expand_lines":15}"#,
|
||||
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":{},"labels":{},"diff_context_lines":10,"diff_expand_lines":15}"#,
|
||||
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":{},"labels":{},"diff_context_lines":10,"diff_expand_lines":15}"#,
|
||||
] {
|
||||
assert!(serde_json::from_str::<Response>(frame).is_err(), "{frame}");
|
||||
}
|
||||
@@ -1196,69 +1196,91 @@ end
|
||||
"config.rb",
|
||||
r#"
|
||||
Vamp.configure do |config|
|
||||
config.tabline = {left: [:tabs], center: ["workspace"], right: [:battery],
|
||||
config.bar.top = {left: [:tabs], center: ["workspace"], right: [:battery],
|
||||
tabs: {title: "T{index}:{path}{modified}", padding: 0, first_leading_edge: ""},
|
||||
battery: {leading_edge: "界", trailing_edge: ""}}
|
||||
config.statusline = {"left" => [], center: [:workspace]}
|
||||
config.bar.bottom = {"left" => [], center: [:workspace]}
|
||||
config.labels = {battery: "bat 38%", "workspace" => "界 e\u0301 👩🚀\t\n\e"}
|
||||
end
|
||||
"#,
|
||||
);
|
||||
let loaded = load_config(&path).unwrap();
|
||||
assert_eq!(loaded.tabline.left, ["tabs"]);
|
||||
assert_eq!(loaded.tabline.center, ["workspace"]);
|
||||
assert_eq!(loaded.tabline.right, ["battery"]);
|
||||
assert_eq!(loaded.top_bar.left, ["tabs"]);
|
||||
assert_eq!(loaded.top_bar.center, ["workspace"]);
|
||||
assert_eq!(loaded.top_bar.right, ["battery"]);
|
||||
assert_eq!(
|
||||
loaded.tabline.segment("tabs").title,
|
||||
loaded.top_bar.segment("tabs").title,
|
||||
"T{index}:{path}{modified}"
|
||||
);
|
||||
assert_eq!(loaded.tabline.segment("tabs").padding, 0);
|
||||
assert_eq!(loaded.tabline.segment("tabs").trailing_edge, "▓▒░");
|
||||
assert_eq!(loaded.tabline.segment("battery").leading_edge, "界");
|
||||
assert_eq!(loaded.top_bar.segment("tabs").padding, 0);
|
||||
assert_eq!(loaded.top_bar.segment("tabs").trailing_edge, "▓▒░");
|
||||
assert_eq!(loaded.top_bar.segment("battery").leading_edge, "界");
|
||||
assert_eq!(
|
||||
loaded.tabline.segment("workspace"),
|
||||
loaded.top_bar.segment("workspace"),
|
||||
&crate::chrome::SegmentConfig::default()
|
||||
);
|
||||
assert!(loaded.statusline.left.is_empty());
|
||||
assert_eq!(loaded.statusline.right, ["position"]);
|
||||
assert!(loaded.bottom_bar.left.is_empty());
|
||||
assert_eq!(loaded.bottom_bar.right, ["position"]);
|
||||
assert_eq!(loaded.labels["battery"], "bat 38%");
|
||||
assert_eq!(loaded.labels["workspace"], "界 e\u{301} 👩🚀\t\n\u{1b}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bar_namespace_is_stable_and_accepts_swapped_builtins() {
|
||||
let fixture = Fixture::new();
|
||||
let path = fixture.file(
|
||||
"config.rb",
|
||||
r#"
|
||||
Vamp.configure do |config|
|
||||
bar = config.bar
|
||||
raise "bar namespace must be stable" unless bar.equal?(config.bar)
|
||||
bar.top = {left: [:mode, :language], right: [], mode: {padding: 0}}
|
||||
config.bar.bottom = {left: [:tabs], right: [], tabs: {title: "{name}{modified}"}}
|
||||
end
|
||||
"#,
|
||||
);
|
||||
let loaded = load_config(&path).unwrap();
|
||||
assert_eq!(loaded.top_bar.left, ["mode", "language"]);
|
||||
assert_eq!(loaded.top_bar.segment("mode").padding, 0);
|
||||
assert_eq!(loaded.top_bar.segment("language").padding, 1);
|
||||
assert_eq!(loaded.bottom_bar.left, ["tabs"]);
|
||||
assert_eq!(loaded.bottom_bar.segment("tabs").title, "{name}{modified}");
|
||||
|
||||
for setter in ["bar", "tabline", "statusline"] {
|
||||
let path = fixture.file(
|
||||
"config.rb",
|
||||
&format!("Vamp.configure {{ |config| config.{setter} = {{}} }}"),
|
||||
);
|
||||
let error = load_config(&path).unwrap_err();
|
||||
assert!(error.contains("undefined method"), "{setter}: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chrome_configuration_rejects_invalid_types_names_and_templates() {
|
||||
let fixture = Fixture::new();
|
||||
for (setting, value, expected) in [
|
||||
("tabline", "[]", "must be a Hash"),
|
||||
("tabline", "{left: :tabs}", "must be an Array"),
|
||||
("tabline", "{left: [7]}", "must be a String"),
|
||||
("tabline", "{left: [:bad_name!]}", "must match"),
|
||||
("bar.top", "[]", "must be a Hash"),
|
||||
("bar.bottom", "[]", "must be a Hash"),
|
||||
("bar.top", "{left: :tabs}", "must be an Array"),
|
||||
("bar.top", "{left: [7]}", "must be a String"),
|
||||
("bar.top", "{left: [:bad_name!]}", "must match"),
|
||||
(
|
||||
"tabline",
|
||||
"{left: [:mode]}",
|
||||
"only available in the statusline",
|
||||
),
|
||||
(
|
||||
"statusline",
|
||||
"{right: [:tabs]}",
|
||||
"only available in the tabline",
|
||||
),
|
||||
(
|
||||
"tabline",
|
||||
"bar.bottom",
|
||||
"{tabs: {title: '{unknown}'}}",
|
||||
"unknown title placeholder",
|
||||
),
|
||||
("tabline", r#"{tabs: {leading_edge: "\n"}}"#, "single-line"),
|
||||
("tabline", "{tabs: {padding: 65}}", "between 0 and 64"),
|
||||
("tabline", "{tabs: {padding: '1'}}", "must be an Integer"),
|
||||
("tabline", "{tabs: {title: nil}}", "must be a String"),
|
||||
("bar.top", r#"{mode: {leading_edge: "\n"}}"#, "single-line"),
|
||||
("bar.top", "{language: {padding: 65}}", "between 0 and 64"),
|
||||
("bar.bottom", "{tabs: {padding: '1'}}", "must be an Integer"),
|
||||
("bar.top", "{mode: {title: nil}}", "must be a String"),
|
||||
(
|
||||
"tabline",
|
||||
"bar.bottom",
|
||||
"{tabs: {color: 'red'}}",
|
||||
"unknown chrome style option",
|
||||
),
|
||||
(
|
||||
"tabline",
|
||||
"bar.top",
|
||||
"{left: [], 'left' => []}",
|
||||
"duplicate chrome key",
|
||||
),
|
||||
@@ -1310,7 +1332,7 @@ end
|
||||
"version": 1, "type": "config", "plugins": [], "lsp": {},
|
||||
"bindings": [], "leader": "space", "file_explorer_side": "right",
|
||||
"file_picker_view": "tree", "file_explorer_view": "tree",
|
||||
"tabline": {}, "statusline": {}, "labels": {},
|
||||
"top_bar": {}, "bottom_bar": {}, "labels": {},
|
||||
"clipboard_mode": "system", "diff_context_lines": 0, "diff_expand_lines": 7
|
||||
});
|
||||
for setting in ["diff_context_lines", "diff_expand_lines"] {
|
||||
@@ -1723,7 +1745,7 @@ end"#,
|
||||
"version": 1, "type": "config", "plugins": [], "lsp": {},
|
||||
"bindings": [], "leader": "space", "file_explorer_side": "right",
|
||||
"file_picker_view": "tree", "file_explorer_view": "tree",
|
||||
"tabline": {}, "statusline": {}, "labels": {},
|
||||
"top_bar": {}, "bottom_bar": {}, "labels": {},
|
||||
"clipboard_mode": "system", "diff_context_lines": 10, "diff_expand_lines": 15
|
||||
});
|
||||
let Response::Config { lsp, .. } =
|
||||
@@ -1806,18 +1828,18 @@ end"#,
|
||||
for mutation in [
|
||||
"return '['",
|
||||
"frame.delete('lsp')",
|
||||
"frame.delete('tabline')",
|
||||
"frame.delete('statusline')",
|
||||
"frame.delete('top_bar')",
|
||||
"frame.delete('bottom_bar')",
|
||||
"frame.delete('labels')",
|
||||
"frame['tabline'] = 7",
|
||||
"frame['statusline'] = []",
|
||||
"frame['top_bar'] = 7",
|
||||
"frame['bottom_bar'] = []",
|
||||
"frame['labels'] = {'battery' => 7}",
|
||||
"frame['tabline'] = {'tabs' => {'title' => '{unknown}'}}",
|
||||
"frame['tabline'] = {'tabs' => {'leading_edge' => \"\\n\"}}",
|
||||
"frame['tabline'] = {'left' => nil}",
|
||||
"frame['tabline'] = {'left' => ['bad-name']}",
|
||||
"frame['tabline'] = {'tabs' => {'padding' => '1'}}",
|
||||
"frame['tabline'] = {'tabs' => {'color' => 'red'}}",
|
||||
"frame['bottom_bar'] = {'tabs' => {'title' => '{unknown}'}}",
|
||||
"frame['top_bar'] = {'mode' => {'leading_edge' => \"\\n\"}}",
|
||||
"frame['top_bar'] = {'left' => nil}",
|
||||
"frame['bottom_bar'] = {'left' => ['bad-name']}",
|
||||
"frame['bottom_bar'] = {'tabs' => {'padding' => '1'}}",
|
||||
"frame['top_bar'] = {'language' => {'color' => 'red'}}",
|
||||
"frame['labels'] = {'bad-name' => ''}",
|
||||
"frame['leader'] = 7",
|
||||
"frame['unexpected'] = true",
|
||||
|
||||
Reference in New Issue
Block a user