mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:01:33 +00:00
vim: Fix linewise copy of last line with no trailing newline (#2885)
Along the way, delete the VimBindingTestContext by updating the visual tests to no-longer need it. Release Notes: - vim: Fix `y` when on the last line of a file with no trailing newline.
This commit is contained in:
commit
3b6794fe36
7 changed files with 118 additions and 187 deletions
|
@ -1,7 +1,6 @@
|
|||
mod neovim_backed_binding_test_context;
|
||||
mod neovim_backed_test_context;
|
||||
mod neovim_connection;
|
||||
mod vim_binding_test_context;
|
||||
mod vim_test_context;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
@ -10,7 +9,6 @@ use command_palette::CommandPalette;
|
|||
use editor::DisplayPoint;
|
||||
pub use neovim_backed_binding_test_context::*;
|
||||
pub use neovim_backed_test_context::*;
|
||||
pub use vim_binding_test_context::*;
|
||||
pub use vim_test_context::*;
|
||||
|
||||
use indoc::indoc;
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::*;
|
||||
|
||||
use super::VimTestContext;
|
||||
|
||||
pub struct VimBindingTestContext<'a, const COUNT: usize> {
|
||||
cx: VimTestContext<'a>,
|
||||
keystrokes_under_test: [&'static str; COUNT],
|
||||
mode_before: Mode,
|
||||
mode_after: Mode,
|
||||
}
|
||||
|
||||
impl<'a, const COUNT: usize> VimBindingTestContext<'a, COUNT> {
|
||||
pub fn new(
|
||||
keystrokes_under_test: [&'static str; COUNT],
|
||||
mode_before: Mode,
|
||||
mode_after: Mode,
|
||||
cx: VimTestContext<'a>,
|
||||
) -> Self {
|
||||
Self {
|
||||
cx,
|
||||
keystrokes_under_test,
|
||||
mode_before,
|
||||
mode_after,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binding<const NEW_COUNT: usize>(
|
||||
self,
|
||||
keystrokes_under_test: [&'static str; NEW_COUNT],
|
||||
) -> VimBindingTestContext<'a, NEW_COUNT> {
|
||||
VimBindingTestContext {
|
||||
keystrokes_under_test,
|
||||
cx: self.cx,
|
||||
mode_before: self.mode_before,
|
||||
mode_after: self.mode_after,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert(&mut self, initial_state: &str, state_after: &str) {
|
||||
self.cx.assert_binding(
|
||||
self.keystrokes_under_test,
|
||||
initial_state,
|
||||
self.mode_before,
|
||||
state_after,
|
||||
self.mode_after,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const COUNT: usize> Deref for VimBindingTestContext<'a, COUNT> {
|
||||
type Target = VimTestContext<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const COUNT: usize> DerefMut for VimBindingTestContext<'a, COUNT> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.cx
|
||||
}
|
||||
}
|
|
@ -8,8 +8,6 @@ use search::{BufferSearchBar, ProjectSearchBar};
|
|||
|
||||
use crate::{state::Operator, *};
|
||||
|
||||
use super::VimBindingTestContext;
|
||||
|
||||
pub struct VimTestContext<'a> {
|
||||
cx: EditorLspTestContext<'a>,
|
||||
}
|
||||
|
@ -126,14 +124,6 @@ impl<'a> VimTestContext<'a> {
|
|||
assert_eq!(self.mode(), mode_after, "{}", self.assertion_context());
|
||||
assert_eq!(self.active_operator(), None, "{}", self.assertion_context());
|
||||
}
|
||||
|
||||
pub fn binding<const COUNT: usize>(
|
||||
mut self,
|
||||
keystrokes: [&'static str; COUNT],
|
||||
) -> VimBindingTestContext<'a, COUNT> {
|
||||
let mode = self.mode();
|
||||
VimBindingTestContext::new(keystrokes, mode, mode, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for VimTestContext<'a> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use editor::{ClipboardSelection, Editor};
|
||||
use gpui::{AppContext, ClipboardItem};
|
||||
use language::Point;
|
||||
|
||||
pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut AppContext) {
|
||||
let selections = editor.selections.all_adjusted(cx);
|
||||
|
@ -9,7 +10,7 @@ pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut App
|
|||
{
|
||||
let mut is_first = true;
|
||||
for selection in selections.iter() {
|
||||
let start = selection.start;
|
||||
let mut start = selection.start;
|
||||
let end = selection.end;
|
||||
if is_first {
|
||||
is_first = false;
|
||||
|
@ -17,9 +18,25 @@ pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut App
|
|||
text.push_str("\n");
|
||||
}
|
||||
let initial_len = text.len();
|
||||
|
||||
// if the file does not end with \n, and our line-mode selection ends on
|
||||
// that line, we will have expanded the start of the selection to ensure it
|
||||
// contains a newline (so that delete works as expected). We undo that change
|
||||
// here.
|
||||
let is_last_line = linewise
|
||||
&& end.row == buffer.max_buffer_row()
|
||||
&& buffer.max_point().column > 0
|
||||
&& start == Point::new(start.row, buffer.line_len(start.row));
|
||||
|
||||
if is_last_line {
|
||||
start = Point::new(buffer.max_buffer_row(), 0);
|
||||
}
|
||||
for chunk in buffer.text_for_range(start..end) {
|
||||
text.push_str(chunk);
|
||||
}
|
||||
if is_last_line {
|
||||
text.push_str("\n");
|
||||
}
|
||||
clipboard_selections.push(ClipboardSelection {
|
||||
len: text.len() - initial_len,
|
||||
is_entire_line: linewise,
|
||||
|
|
|
@ -563,38 +563,41 @@ mod test {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_visual_line_delete(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx)
|
||||
.await
|
||||
.binding(["shift-v", "x"]);
|
||||
cx.assert(indoc! {"
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
The quˇick brown
|
||||
fox jumps over
|
||||
the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["shift-v", "x"]).await;
|
||||
cx.assert_state_matches().await;
|
||||
|
||||
// Test pasting code copied on delete
|
||||
cx.simulate_shared_keystroke("p").await;
|
||||
cx.assert_state_matches().await;
|
||||
|
||||
cx.assert_all(indoc! {"
|
||||
cx.set_shared_state(indoc! {"
|
||||
The quick brown
|
||||
fox juˇmps over
|
||||
the laˇzy dog"})
|
||||
.await;
|
||||
let mut cx = cx.binding(["shift-v", "j", "x"]);
|
||||
cx.assert(indoc! {"
|
||||
The quˇick brown
|
||||
fox jumps over
|
||||
the lazy dog"})
|
||||
.await;
|
||||
// Test pasting code copied on delete
|
||||
cx.simulate_shared_keystroke("p").await;
|
||||
cx.assert_state_matches().await;
|
||||
|
||||
cx.assert_all(indoc! {"
|
||||
The quick brown
|
||||
fox juˇmps over
|
||||
the laˇzy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["shift-v", "x"]).await;
|
||||
cx.assert_state_matches().await;
|
||||
cx.assert_shared_clipboard("the lazy dog\n").await;
|
||||
|
||||
for marked_text in cx.each_marked_position(indoc! {"
|
||||
The quˇick brown
|
||||
fox jumps over
|
||||
the lazy dog"})
|
||||
{
|
||||
cx.set_shared_state(&marked_text).await;
|
||||
cx.simulate_shared_keystrokes(["shift-v", "j", "x"]).await;
|
||||
cx.assert_state_matches().await;
|
||||
// Test pasting code copied on delete
|
||||
cx.simulate_shared_keystroke("p").await;
|
||||
cx.assert_state_matches().await;
|
||||
}
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
The ˇlong line
|
||||
|
@ -608,86 +611,57 @@ mod test {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_visual_yank(cx: &mut gpui::TestAppContext) {
|
||||
let cx = VimTestContext::new(cx, true).await;
|
||||
let mut cx = cx.binding(["v", "w", "y"]);
|
||||
cx.assert("The quick ˇbrown", "The quick ˇbrown");
|
||||
cx.assert_clipboard_content(Some("brown"));
|
||||
let mut cx = cx.binding(["v", "w", "j", "y"]);
|
||||
cx.assert(
|
||||
indoc! {"
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
||||
cx.set_shared_state("The quick ˇbrown").await;
|
||||
cx.simulate_shared_keystrokes(["v", "w", "y"]).await;
|
||||
cx.assert_shared_state("The quick ˇbrown").await;
|
||||
cx.assert_shared_clipboard("brown").await;
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
The ˇquick brown
|
||||
fox jumps over
|
||||
the lazy dog"},
|
||||
indoc! {"
|
||||
The ˇquick brown
|
||||
fox jumps over
|
||||
the lazy dog"},
|
||||
);
|
||||
cx.assert_clipboard_content(Some(indoc! {"
|
||||
quick brown
|
||||
fox jumps o"}));
|
||||
cx.assert(
|
||||
indoc! {"
|
||||
The quick brown
|
||||
fox jumps over
|
||||
the ˇlazy dog"},
|
||||
indoc! {"
|
||||
The quick brown
|
||||
fox jumps over
|
||||
the ˇlazy dog"},
|
||||
);
|
||||
cx.assert_clipboard_content(Some("lazy d"));
|
||||
cx.assert(
|
||||
indoc! {"
|
||||
The quick brown
|
||||
fox jumps ˇover
|
||||
the lazy dog"},
|
||||
indoc! {"
|
||||
The quick brown
|
||||
fox jumps ˇover
|
||||
the lazy dog"},
|
||||
);
|
||||
cx.assert_clipboard_content(Some(indoc! {"
|
||||
over
|
||||
t"}));
|
||||
the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["v", "w", "j", "y"]).await;
|
||||
cx.assert_shared_state(indoc! {"
|
||||
The ˇquick brown
|
||||
fox jumps over
|
||||
the lazy dog"})
|
||||
.await;
|
||||
cx.assert_shared_clipboard(indoc! {"
|
||||
quick brown
|
||||
fox jumps o"})
|
||||
.await;
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
The quick brown
|
||||
fox jumps over
|
||||
the ˇlazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["v", "w", "j", "y"]).await;
|
||||
cx.assert_shared_state(indoc! {"
|
||||
The quick brown
|
||||
fox jumps over
|
||||
the ˇlazy dog"})
|
||||
.await;
|
||||
cx.assert_shared_clipboard("lazy d").await;
|
||||
cx.simulate_shared_keystrokes(["shift-v", "y"]).await;
|
||||
cx.assert_shared_clipboard("the lazy dog\n").await;
|
||||
|
||||
let mut cx = cx.binding(["v", "b", "k", "y"]);
|
||||
cx.assert(
|
||||
indoc! {"
|
||||
The ˇquick brown
|
||||
fox jumps over
|
||||
the lazy dog"},
|
||||
indoc! {"
|
||||
ˇThe quick brown
|
||||
fox jumps over
|
||||
the lazy dog"},
|
||||
);
|
||||
cx.set_shared_state(indoc! {"
|
||||
The ˇquick brown
|
||||
fox jumps over
|
||||
the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes(["v", "b", "k", "y"]).await;
|
||||
cx.assert_shared_state(indoc! {"
|
||||
ˇThe quick brown
|
||||
fox jumps over
|
||||
the lazy dog"})
|
||||
.await;
|
||||
cx.assert_clipboard_content(Some("The q"));
|
||||
cx.assert(
|
||||
indoc! {"
|
||||
The quick brown
|
||||
fox jumps over
|
||||
the ˇlazy dog"},
|
||||
indoc! {"
|
||||
The quick brown
|
||||
ˇfox jumps over
|
||||
the lazy dog"},
|
||||
);
|
||||
cx.assert_clipboard_content(Some(indoc! {"
|
||||
fox jumps over
|
||||
the l"}));
|
||||
cx.assert(
|
||||
indoc! {"
|
||||
The quick brown
|
||||
fox jumps ˇover
|
||||
the lazy dog"},
|
||||
indoc! {"
|
||||
The ˇquick brown
|
||||
fox jumps over
|
||||
the lazy dog"},
|
||||
);
|
||||
cx.assert_clipboard_content(Some(indoc! {"
|
||||
quick brown
|
||||
fox jumps o"}));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
{"Get":{"state":"fox juˇmps over\nthe lazy dog","mode":"Normal"}}
|
||||
{"Key":"p"}
|
||||
{"Get":{"state":"fox jumps over\nˇThe quick brown\nthe lazy dog","mode":"Normal"}}
|
||||
{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"x"}
|
||||
{"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}}
|
||||
{"Put":{"state":"The quick brown\nfox jumps over\nthe laˇzy dog"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"x"}
|
||||
{"Get":{"state":"The quick brown\nfox juˇmps over","mode":"Normal"}}
|
||||
{"ReadRegister":{"name":"\"","value":"the lazy dog\n"}}
|
||||
{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"j"}
|
||||
|
@ -19,16 +16,6 @@
|
|||
{"Get":{"state":"the laˇzy dog","mode":"Normal"}}
|
||||
{"Key":"p"}
|
||||
{"Get":{"state":"the lazy dog\nˇThe quick brown\nfox jumps over","mode":"Normal"}}
|
||||
{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"j"}
|
||||
{"Key":"x"}
|
||||
{"Get":{"state":"The quˇick brown","mode":"Normal"}}
|
||||
{"Put":{"state":"The quick brown\nfox jumps over\nthe laˇzy dog"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"j"}
|
||||
{"Key":"x"}
|
||||
{"Get":{"state":"The quick brown\nfox juˇmps over","mode":"Normal"}}
|
||||
{"Put":{"state":"The ˇlong line\nshould not\ncrash\n"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"$"}
|
||||
|
|
29
crates/vim/test_data/test_visual_yank.json
Normal file
29
crates/vim/test_data/test_visual_yank.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{"Put":{"state":"The quick ˇbrown"}}
|
||||
{"Key":"v"}
|
||||
{"Key":"w"}
|
||||
{"Key":"y"}
|
||||
{"Get":{"state":"The quick ˇbrown","mode":"Normal"}}
|
||||
{"ReadRegister":{"name":"\"","value":"brown"}}
|
||||
{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}}
|
||||
{"Key":"v"}
|
||||
{"Key":"w"}
|
||||
{"Key":"j"}
|
||||
{"Key":"y"}
|
||||
{"Get":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}}
|
||||
{"ReadRegister":{"name":"\"","value":"quick brown\nfox jumps o"}}
|
||||
{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}}
|
||||
{"Key":"v"}
|
||||
{"Key":"w"}
|
||||
{"Key":"j"}
|
||||
{"Key":"y"}
|
||||
{"Get":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog","mode":"Normal"}}
|
||||
{"ReadRegister":{"name":"\"","value":"lazy d"}}
|
||||
{"Key":"shift-v"}
|
||||
{"Key":"y"}
|
||||
{"ReadRegister":{"name":"\"","value":"the lazy dog\n"}}
|
||||
{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}}
|
||||
{"Key":"v"}
|
||||
{"Key":"b"}
|
||||
{"Key":"k"}
|
||||
{"Key":"y"}
|
||||
{"Get":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}}
|
Loading…
Reference in a new issue