vim: Fix edge-case in } when trailing newline is absent

Added .assert_shared_state() to NeovimBackedTestContext – although it's
not strictly necessary to show the expected behaviour in the test file
(as we can just compare to neovim's JSON recording), it makes it much
easier to understand what we're testing.
This commit is contained in:
Conrad Irwin 2023-06-29 23:24:51 -06:00
parent 9ee2707d43
commit abb58c41db
4 changed files with 94 additions and 48 deletions

View file

@ -210,6 +210,10 @@ impl<'a> EditorTestContext<'a> {
self.assert_selections(expected_selections, marked_text.to_string()) self.assert_selections(expected_selections, marked_text.to_string())
} }
pub fn editor_state(&mut self) -> String {
generate_marked_text(self.buffer_text().as_str(), &self.editor_selections(), true)
}
#[track_caller] #[track_caller]
pub fn assert_editor_background_highlights<Tag: 'static>(&mut self, marked_text: &str) { pub fn assert_editor_background_highlights<Tag: 'static>(&mut self, marked_text: &str) {
let expected_ranges = self.ranges(marked_text); let expected_ranges = self.ranges(marked_text);
@ -248,14 +252,8 @@ impl<'a> EditorTestContext<'a> {
self.assert_selections(expected_selections, expected_marked_text) self.assert_selections(expected_selections, expected_marked_text)
} }
#[track_caller] fn editor_selections(&self) -> Vec<Range<usize>> {
fn assert_selections( self.editor
&mut self,
expected_selections: Vec<Range<usize>>,
expected_marked_text: String,
) {
let actual_selections = self
.editor
.read_with(self.cx, |editor, cx| editor.selections.all::<usize>(cx)) .read_with(self.cx, |editor, cx| editor.selections.all::<usize>(cx))
.into_iter() .into_iter()
.map(|s| { .map(|s| {
@ -265,12 +263,22 @@ impl<'a> EditorTestContext<'a> {
s.start..s.end s.start..s.end
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>()
}
#[track_caller]
fn assert_selections(
&mut self,
expected_selections: Vec<Range<usize>>,
expected_marked_text: String,
) {
let actual_selections = self.editor_selections();
let actual_marked_text = let actual_marked_text =
generate_marked_text(&self.buffer_text(), &actual_selections, true); generate_marked_text(&self.buffer_text(), &actual_selections, true);
if expected_selections != actual_selections { if expected_selections != actual_selections {
panic!( panic!(
indoc! {" indoc! {"
{}Editor has unexpected selections. {}Editor has unexpected selections.
Expected selections: Expected selections:

View file

@ -255,7 +255,7 @@ impl Motion {
SelectionGoal::None, SelectionGoal::None,
), ),
EndOfParagraph => ( EndOfParagraph => (
movement::end_of_paragraph(map, point, times), map.clip_at_line_end(movement::end_of_paragraph(map, point, times)),
SelectionGoal::None, SelectionGoal::None,
), ),
CurrentLine => (end_of_line(map, point), SelectionGoal::None), CurrentLine => (end_of_line(map, point), SelectionGoal::None),
@ -618,12 +618,12 @@ fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) ->
mod test { mod test {
use crate::{state::Mode, test::VimTestContext}; use crate::test::NeovimBackedTestContext;
use indoc::indoc; use indoc::indoc;
#[gpui::test] #[gpui::test]
async fn test_start_end_of_paragraph(cx: &mut gpui::TestAppContext) { async fn test_start_end_of_paragraph(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = NeovimBackedTestContext::new(cx).await;
let initial_state = indoc! {r"ˇabc let initial_state = indoc! {r"ˇabc
def def
@ -637,10 +637,9 @@ mod test {
final"}; final"};
// goes down once // goes down once
cx.set_state(initial_state, Mode::Normal); cx.set_shared_state(initial_state).await;
cx.simulate_keystrokes(["}"]); cx.simulate_shared_keystrokes(["}"]).await;
cx.assert_state( cx.assert_shared_state(indoc! {r"abc
indoc! {r"abc
def def
ˇ ˇ
paragraph paragraph
@ -649,18 +648,16 @@ mod test {
third and third and
final"}, final"})
Mode::Normal, .await;
);
// goes up once // goes up once
cx.simulate_keystrokes(["{"]); cx.simulate_shared_keystrokes(["{"]).await;
cx.assert_state(initial_state, Mode::Normal); cx.assert_shared_state(initial_state).await;
// goes down twice // goes down twice
cx.simulate_keystrokes(["2", "}"]); cx.simulate_shared_keystrokes(["2", "}"]).await;
cx.assert_state( cx.assert_shared_state(indoc! {r"abc
indoc! {r"abc
def def
paragraph paragraph
@ -669,14 +666,12 @@ mod test {
third and third and
final"}, final"})
Mode::Normal, .await;
);
// goes down over multiple blanks // goes down over multiple blanks
cx.simulate_keystrokes(["}"]); cx.simulate_shared_keystrokes(["}"]).await;
cx.assert_state( cx.assert_shared_state(indoc! {r"abc
indoc! {r"abc
def def
paragraph paragraph
@ -685,14 +680,12 @@ mod test {
third and third and
finalˇ"}, finaˇl"})
Mode::Normal, .await;
);
// goes up twice // goes up twice
cx.simulate_keystrokes(["2", "{"]); cx.simulate_shared_keystrokes(["2", "{"]).await;
cx.assert_state( cx.assert_shared_state(indoc! {r"abc
indoc! {r"abc
def def
ˇ ˇ
paragraph paragraph
@ -701,8 +694,7 @@ mod test {
third and third and
final"}, final"})
Mode::Normal, .await
)
} }
} }

View file

@ -1,9 +1,10 @@
use std::ops::{Deref, DerefMut}; use indoc::indoc;
use std::ops::{Deref, DerefMut, Range};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use gpui::ContextHandle; use gpui::ContextHandle;
use language::OffsetRangeExt; use language::OffsetRangeExt;
use util::test::marked_text_offsets; use util::test::{generate_marked_text, marked_text_offsets};
use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext}; use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext};
use crate::state::Mode; use crate::state::Mode;
@ -112,6 +113,43 @@ impl<'a> NeovimBackedTestContext<'a> {
context_handle context_handle
} }
pub async fn assert_shared_state(&mut self, marked_text: &str) {
let neovim = self.neovim_state().await;
if neovim != marked_text {
panic!(
indoc! {"Test is incorrect (currently expected != neovim state)
# currently expected:
{}
# neovim state:
{}
# zed state:
{}"},
marked_text,
neovim,
self.editor_state(),
)
}
self.assert_editor_state(marked_text)
}
pub async fn neovim_state(&mut self) -> String {
generate_marked_text(
self.neovim.text().await.as_str(),
&vec![self.neovim_selection().await],
true,
)
}
async fn neovim_selection(&mut self) -> Range<usize> {
let mut neovim_selection = self.neovim.selection().await;
// Zed selections adjust themselves to make the end point visually make sense
if neovim_selection.start > neovim_selection.end {
neovim_selection.start.column += 1;
}
neovim_selection.to_offset(&self.buffer_snapshot())
}
pub async fn assert_state_matches(&mut self) { pub async fn assert_state_matches(&mut self) {
assert_eq!( assert_eq!(
self.neovim.text().await, self.neovim.text().await,
@ -120,13 +158,8 @@ impl<'a> NeovimBackedTestContext<'a> {
self.assertion_context() self.assertion_context()
); );
let mut neovim_selection = self.neovim.selection().await; let selections = vec![self.neovim_selection().await];
// Zed selections adjust themselves to make the end point visually make sense self.assert_editor_selections(selections);
if neovim_selection.start > neovim_selection.end {
neovim_selection.start.column += 1;
}
let neovim_selection = neovim_selection.to_offset(&self.buffer_snapshot());
self.assert_editor_selections(vec![neovim_selection]);
if let Some(neovim_mode) = self.neovim.mode().await { if let Some(neovim_mode) = self.neovim.mode().await {
assert_eq!(neovim_mode, self.mode(), "{}", self.assertion_context(),); assert_eq!(neovim_mode, self.mode(), "{}", self.assertion_context(),);

View file

@ -0,0 +1,13 @@
{"Put":{"state":"ˇabc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinal"}}
{"Key":"}"}
{"Get":{"state":"abc\ndef\nˇ\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}}
{"Key":"{"}
{"Get":{"state":"ˇabc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}}
{"Key":"2"}
{"Key":"}"}
{"Get":{"state":"abc\ndef\n\nparagraph\nthe second\nˇ\n\n\nthird and\nfinal","mode":"Normal"}}
{"Key":"}"}
{"Get":{"state":"abc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinaˇl","mode":"Normal"}}
{"Key":"2"}
{"Key":"{"}
{"Get":{"state":"abc\ndef\nˇ\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}}