feat: default editing to shared system clipboard
This commit is contained in:
+179
-2
@@ -54,6 +54,12 @@ impl EditorSession {
|
||||
config.file_explorer_view
|
||||
));
|
||||
}
|
||||
if let Err(error) = editor.set_clipboard_mode(&config.clipboard_mode) {
|
||||
notices.push(format!(
|
||||
"clipboard mode {:?}: {error}",
|
||||
config.clipboard_mode
|
||||
));
|
||||
}
|
||||
let mut plugins = BTreeMap::new();
|
||||
for path in config.plugins {
|
||||
match RubyPlugin::start(&path) {
|
||||
@@ -151,12 +157,38 @@ mod tests {
|
||||
|
||||
fn open(&self, config: &str) -> EditorSession {
|
||||
let config = self.file("config.rb", config);
|
||||
EditorSession::open(
|
||||
let mut session = EditorSession::open(
|
||||
Some(self.0.join("buffer.txt")),
|
||||
vec!["text".into()],
|
||||
Some(&config),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
// Legacy editing scenarios exercise the internal register, never the user's desktop.
|
||||
session.editor.set_clipboard_mode("separate").unwrap();
|
||||
session
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn system_session(&self, config: &str) -> EditorSession {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let config = self.file("config.rb", config);
|
||||
let mut session = EditorSession::open(
|
||||
Some(self.0.join("buffer.txt")),
|
||||
vec!["text".into()],
|
||||
Some(&config),
|
||||
)
|
||||
.unwrap();
|
||||
self.file("system.txt", "");
|
||||
let reader = self.file("clip-read", "#!/bin/sh\n[ -e \"${0%/*}/read.fail\" ] && exit 13\nexec /bin/cat \"${0%/*}/system.txt\"\n");
|
||||
let writer = self.file("clip-write", "#!/bin/sh\n[ -e \"${0%/*}/write.fail\" ] && exit 13\nexec /bin/cat > \"${0%/*}/system.txt\"\n");
|
||||
fs::set_permissions(&reader, fs::Permissions::from_mode(0o700)).unwrap();
|
||||
fs::set_permissions(&writer, fs::Permissions::from_mode(0o700)).unwrap();
|
||||
session
|
||||
.editor
|
||||
.set_system_clipboard(crate::clipboard::SystemClipboard::with_commands(
|
||||
reader, writer,
|
||||
));
|
||||
session
|
||||
}
|
||||
|
||||
fn healthy(&self) {
|
||||
@@ -176,6 +208,138 @@ Vamp.command("healthy") { |editor, args| editor.replace "healthy #{args}" }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn invalid_clipboard_policy_retains_system_default_and_valid_bindings() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.file("buffer.txt", "abc");
|
||||
let mut session = fixture.system_session(
|
||||
r#"
|
||||
Vamp.configure do |config|
|
||||
config.clipboard_mode = "combined"
|
||||
config.bind "n", config.core.right
|
||||
end
|
||||
"#,
|
||||
);
|
||||
assert_eq!(
|
||||
session.editor().clipboard_mode(),
|
||||
crate::clipboard::ClipboardMode::System
|
||||
);
|
||||
session.handle(Input::Char('n'));
|
||||
session.handle(Input::Char('v'));
|
||||
session.handle(Input::Char('y'));
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("system.txt")).unwrap(),
|
||||
"b"
|
||||
);
|
||||
assert_eq!(session.editor().lines(), &["abc"]);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn default_system_clipboard_tracks_external_text_and_preserves_cut_failures() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.file("buffer.txt", "alpha beta");
|
||||
let mut session = fixture.system_session("");
|
||||
assert_eq!(
|
||||
session.editor().clipboard_mode(),
|
||||
crate::clipboard::ClipboardMode::System
|
||||
);
|
||||
fixture.file("system.txt", "external");
|
||||
session.handle(Input::Char('P'));
|
||||
assert_eq!(session.editor().lines(), &["externalalpha beta"]);
|
||||
session.handle(Input::Char('u'));
|
||||
for ch in "vey".chars() {
|
||||
session.handle(Input::Char(ch));
|
||||
}
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("system.txt")).unwrap(),
|
||||
"alpha"
|
||||
);
|
||||
fixture.file("system.txt", "outside");
|
||||
session.handle(Input::Home);
|
||||
session.handle(Input::Char('P'));
|
||||
assert_eq!(session.editor().lines(), &["outsidealpha beta"]);
|
||||
fixture.file("system.txt", "fresh");
|
||||
session.handle(Input::Home);
|
||||
session.handle(Input::Char('.'));
|
||||
assert_eq!(session.editor().lines(), &["outsideoutsidealpha beta"]);
|
||||
session.handle(Input::Char('u'));
|
||||
session.handle(Input::Char('u'));
|
||||
assert_eq!(session.editor().lines(), &["alpha beta"]);
|
||||
session.handle(Input::Home);
|
||||
session.handle(Input::Char('v'));
|
||||
session.handle(Input::Char('e'));
|
||||
let selection = session.editor().selections();
|
||||
fixture.file("write.fail", "");
|
||||
session.handle(Input::Char('c'));
|
||||
assert_eq!(session.editor().mode(), crate::editor::Mode::Visual);
|
||||
assert_eq!(session.editor().selections(), selection);
|
||||
assert_eq!(session.editor().lines(), &["alpha beta"]);
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("system.txt")).unwrap(),
|
||||
"fresh"
|
||||
);
|
||||
fs::remove_file(fixture.0.join("write.fail")).unwrap();
|
||||
session.handle(Input::Escape);
|
||||
session.handle(Input::Home);
|
||||
fixture.file("system.txt", "\u{1b}");
|
||||
session.handle(Input::Char('P'));
|
||||
assert_eq!(session.editor().lines(), &["alpha beta"]);
|
||||
assert_eq!(session.editor().cursor(), crate::editor::Cursor::default());
|
||||
assert_eq!(session.editor().mode(), crate::editor::Mode::Normal);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn separate_clipboards_keep_internal_and_explicit_system_routes_independent() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.file("buffer.txt", "alpha beta");
|
||||
let mut session = fixture.system_session(
|
||||
r#"
|
||||
Vamp.configure do |config|
|
||||
config.clipboard_mode = "separate"
|
||||
config.bind "ctrl+s", config.core.copy_system, mode: config.modes.visual
|
||||
config.bind "ctrl+g", config.core.paste_system_before
|
||||
end
|
||||
"#,
|
||||
);
|
||||
fixture.file("system.txt", "outside");
|
||||
for ch in "vey".chars() {
|
||||
session.handle(Input::Char(ch));
|
||||
}
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("system.txt")).unwrap(),
|
||||
"outside"
|
||||
);
|
||||
for ch in "wve".chars() {
|
||||
session.handle(Input::Char(ch));
|
||||
}
|
||||
session.handle(Input::Ctrl('s'));
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("system.txt")).unwrap(),
|
||||
"beta"
|
||||
);
|
||||
session.handle(Input::Home);
|
||||
session.handle(Input::Char('P'));
|
||||
assert_eq!(session.editor().lines(), &["alphaalpha beta"]);
|
||||
session.handle(Input::Char('u'));
|
||||
session.handle(Input::Home);
|
||||
session.handle(Input::Ctrl('g'));
|
||||
assert_eq!(session.editor().lines(), &["betaalpha beta"]);
|
||||
session.handle(Input::Char('u'));
|
||||
session.handle(Input::Home);
|
||||
session.handle(Input::Char('v'));
|
||||
session.handle(Input::Char('e'));
|
||||
fixture.file("write.fail", "");
|
||||
session.handle(Input::Char('d'));
|
||||
assert_eq!(session.editor().lines(), &[" beta"]);
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("system.txt")).unwrap(),
|
||||
"beta"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selection_bindings_remap_palette_navigation_without_changing_editing_bindings() {
|
||||
let fixture = Fixture::new();
|
||||
@@ -1011,6 +1175,7 @@ end
|
||||
let fixture = Fixture::new();
|
||||
let buffer = fixture.file("buffer.txt", "old elephant zebra");
|
||||
let mut session = EditorSession::open(Some(buffer), vec!["text".into()], None).unwrap();
|
||||
session.editor.set_clipboard_mode("separate").unwrap();
|
||||
for key in ['v', 'e', 'c'] {
|
||||
session.handle(Input::Char(key));
|
||||
}
|
||||
@@ -1604,6 +1769,18 @@ end
|
||||
r#"config.file_explorer_view = """#,
|
||||
"file explorer view must not be empty",
|
||||
),
|
||||
(
|
||||
"config.clipboard_mode = 7",
|
||||
"clipboard mode must be a String",
|
||||
),
|
||||
(
|
||||
"config.clipboard_mode = nil",
|
||||
"clipboard mode must be a String",
|
||||
),
|
||||
(
|
||||
r#"config.clipboard_mode = """#,
|
||||
"clipboard mode 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"),
|
||||
|
||||
Reference in New Issue
Block a user