feat: add floating and docked searchable file picker

This commit is contained in:
Valdemar Lorenzen
2026-10-08 14:25:54 +02:00
parent 5a67bf64a3
commit c60e625555
12 changed files with 1820 additions and 34 deletions
+92
View File
@@ -36,6 +36,12 @@ impl EditorSession {
if let Err(error) = editor.set_leader(&config.leader) {
notices.push(format!("leader {:?}: {error}", config.leader));
}
if let Err(error) = editor.set_file_explorer_side(&config.file_explorer_side) {
notices.push(format!(
"file explorer side {:?}: {error}",
config.file_explorer_side
));
}
let mut plugins = BTreeMap::new();
for path in config.plugins {
match RubyPlugin::start(&path) {
@@ -158,6 +164,80 @@ Vamp.command("healthy") { |editor, args| editor.replace "healthy #{args}" }
}
}
#[test]
fn configured_picker_presentations_preserve_editing_and_docked_focus() {
let fixture = Fixture::new();
fixture.file("buffer.txt", "alpha");
let mut session = fixture.open(
r#"
Vamp.configure do |config|
config.file_explorer_side = "left"
config.bind "ctrl+o", config.core.file_picker
config.bind "ctrl+e", config.core.file_explorer
end
"#,
);
assert_eq!(
session.editor().file_explorer_side(),
crate::files::DockSide::Left
);
session.handle(Input::Ctrl('e'));
assert_eq!(
session.editor().file_picker().unwrap().presentation,
crate::files::FilePresentation::Docked
);
for ch in "dir e\u{301}".chars() {
session.handle(Input::Char(ch));
}
session.handle(Input::Backspace);
assert_eq!(session.editor().file_picker().unwrap().query, "dir ");
session.handle(Input::Escape);
assert!(!session.editor().file_picker().unwrap().focused);
session.handle(Input::Char('i'));
for ch in " a b ".chars() {
session.handle(Input::Char(ch));
}
session.handle(Input::Escape);
assert_eq!(session.editor().lines(), &[" a b alpha"]);
session.handle(Input::Ctrl('o'));
assert_eq!(
session.editor().file_picker().unwrap().presentation,
crate::files::FilePresentation::Floating
);
assert_eq!(session.editor().file_picker().unwrap().query, "dir ");
session.handle(Input::Escape);
assert!(session.editor().file_picker().is_none());
session.handle(Input::Char('u'));
assert_eq!(session.editor().lines(), &["alpha"]);
}
#[test]
fn invalid_explorer_side_preserves_default_and_valid_bindings() {
let fixture = Fixture::new();
fixture.file("buffer.txt", "abc");
let mut session = fixture.open(
r#"
Vamp.configure do |config|
config.file_explorer_side = "diagonal"
config.bind "n", config.core.right
end
"#,
);
assert_eq!(
session.editor().file_explorer_side(),
crate::files::DockSide::Right
);
session.handle(Input::Char('n'));
assert_eq!(
session.editor().cursor(),
crate::editor::Cursor { row: 0, column: 1 }
);
session.handle(Input::Char('i'));
session.handle(Input::Char('!'));
session.handle(Input::Escape);
assert_eq!(session.editor().lines(), &["a!bc"]);
}
#[test]
fn no_config_uses_space_leader_for_palette_and_write() {
let fixture = Fixture::new();
@@ -962,6 +1042,18 @@ end
("config.leader = 7", "leader key must be a String"),
("config.leader = nil", "leader key must be a String"),
(r#"config.leader = """#, "leader key must not be empty"),
(
"config.file_explorer_side = 7",
"file explorer side must be a String",
),
(
"config.file_explorer_side = nil",
"file explorer side must be a String",
),
(
r#"config.file_explorer_side = """#,
"file explorer side must not be empty",
),
(r#"config.bind "n", "core.insert""#, "TypeError"),
(r#"config.bind "n", nil, mode: "insert""#, "TypeError"),
(r#"config.bind "n", config.modes.insert"#, "TypeError"),