vim test redux (#11709)
This cleans up the neovim-backed vim tests: - removed exempted tests (we'll rely on bug reports to find missing edge cases) - moved all assertions into non-async fn's so that failures are reporting on the right file/line - removed the NeovimBackedBindingTestContext - renamed a few things to make them clearer - reduced the number of permutations tested in some cases to reduce slowest test from 60s to 5s Release Notes: - N/A
This commit is contained in:
parent
48cba328f2
commit
f550f23b97
38 changed files with 2311 additions and 6505 deletions
|
@ -1,92 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::state::Mode;
|
||||
|
||||
use super::{ExemptionFeatures, NeovimBackedTestContext, SUPPORTED_FEATURES};
|
||||
|
||||
pub struct NeovimBackedBindingTestContext<const COUNT: usize> {
|
||||
cx: NeovimBackedTestContext,
|
||||
keystrokes_under_test: [&'static str; COUNT],
|
||||
}
|
||||
|
||||
impl<const COUNT: usize> NeovimBackedBindingTestContext<COUNT> {
|
||||
pub fn new(keystrokes_under_test: [&'static str; COUNT], cx: NeovimBackedTestContext) -> Self {
|
||||
Self {
|
||||
cx,
|
||||
keystrokes_under_test,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(self) -> NeovimBackedTestContext {
|
||||
self.cx
|
||||
}
|
||||
|
||||
pub fn binding<const NEW_COUNT: usize>(
|
||||
self,
|
||||
keystrokes: [&'static str; NEW_COUNT],
|
||||
) -> NeovimBackedBindingTestContext<NEW_COUNT> {
|
||||
self.consume().binding(keystrokes)
|
||||
}
|
||||
|
||||
pub async fn assert(&mut self, marked_positions: &str) {
|
||||
self.cx
|
||||
.assert_binding_matches(self.keystrokes_under_test, marked_positions)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn assert_exempted(&mut self, marked_positions: &str, feature: ExemptionFeatures) {
|
||||
if SUPPORTED_FEATURES.contains(&feature) {
|
||||
self.cx
|
||||
.assert_binding_matches(self.keystrokes_under_test, marked_positions)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_manual(
|
||||
&mut self,
|
||||
initial_state: &str,
|
||||
mode_before: Mode,
|
||||
state_after: &str,
|
||||
mode_after: Mode,
|
||||
) {
|
||||
self.cx.assert_binding(
|
||||
self.keystrokes_under_test,
|
||||
initial_state,
|
||||
mode_before,
|
||||
state_after,
|
||||
mode_after,
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn assert_all(&mut self, marked_positions: &str) {
|
||||
self.cx
|
||||
.assert_binding_matches_all(self.keystrokes_under_test, marked_positions)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn assert_all_exempted(
|
||||
&mut self,
|
||||
marked_positions: &str,
|
||||
feature: ExemptionFeatures,
|
||||
) {
|
||||
if SUPPORTED_FEATURES.contains(&feature) {
|
||||
self.cx
|
||||
.assert_binding_matches_all(self.keystrokes_under_test, marked_positions)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const COUNT: usize> Deref for NeovimBackedBindingTestContext<COUNT> {
|
||||
type Target = NeovimBackedTestContext;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cx
|
||||
}
|
||||
}
|
||||
|
||||
impl<const COUNT: usize> DerefMut for NeovimBackedBindingTestContext<COUNT> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.cx
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
use editor::test::editor_test_context::ContextHandle;
|
||||
use gpui::{px, size, BorrowAppContext, Context};
|
||||
use indoc::indoc;
|
||||
use settings::SettingsStore;
|
||||
|
@ -7,57 +6,132 @@ use std::{
|
|||
panic, thread,
|
||||
};
|
||||
|
||||
use collections::{HashMap, HashSet};
|
||||
use language::language_settings::{AllLanguageSettings, SoftWrap};
|
||||
use util::test::marked_text_offsets;
|
||||
|
||||
use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext};
|
||||
use super::{neovim_connection::NeovimConnection, VimTestContext};
|
||||
use crate::state::Mode;
|
||||
|
||||
pub const SUPPORTED_FEATURES: &[ExemptionFeatures] = &[];
|
||||
|
||||
/// Enum representing features we have tests for but which don't work, yet. Used
|
||||
/// to add exemptions and automatically
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum ExemptionFeatures {
|
||||
// MOTIONS
|
||||
// When an operator completes at the end of the file, an extra newline is left
|
||||
OperatorLastNewlineRemains,
|
||||
|
||||
// OBJECTS
|
||||
// Resulting position after the operation is slightly incorrect for unintuitive reasons.
|
||||
IncorrectLandingPosition,
|
||||
// Operator around the text object at the end of the line doesn't remove whitespace.
|
||||
AroundObjectLeavesWhitespaceAtEndOfLine,
|
||||
// Sentence object on empty lines
|
||||
SentenceOnEmptyLines,
|
||||
// Whitespace isn't included with text objects at the start of the line
|
||||
SentenceAtStartOfLineWithWhitespace,
|
||||
// Whitespace around sentences is slightly incorrect when starting between sentences
|
||||
AroundSentenceStartingBetweenIncludesWrongWhitespace,
|
||||
// Non empty selection with text objects in visual mode
|
||||
NonEmptyVisualTextObjects,
|
||||
// Sentence Doesn't backtrack when its at the end of the file
|
||||
SentenceAfterPunctuationAtEndOfFile,
|
||||
}
|
||||
|
||||
impl ExemptionFeatures {
|
||||
pub fn supported(&self) -> bool {
|
||||
SUPPORTED_FEATURES.contains(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NeovimBackedTestContext {
|
||||
cx: VimTestContext,
|
||||
// Lookup for exempted assertions. Keyed by the insertion text, and with a value indicating which
|
||||
// bindings are exempted. If None, all bindings are ignored for that insertion text.
|
||||
exemptions: HashMap<String, Option<HashSet<String>>>,
|
||||
pub(crate) neovim: NeovimConnection,
|
||||
|
||||
last_set_state: Option<String>,
|
||||
recent_keystrokes: Vec<String>,
|
||||
}
|
||||
|
||||
is_dirty: bool,
|
||||
#[derive(Default)]
|
||||
pub struct SharedState {
|
||||
neovim: String,
|
||||
editor: String,
|
||||
initial: String,
|
||||
neovim_mode: Mode,
|
||||
editor_mode: Mode,
|
||||
recent_keystrokes: String,
|
||||
}
|
||||
|
||||
impl SharedState {
|
||||
#[track_caller]
|
||||
pub fn assert_matches(&self) {
|
||||
if self.neovim != self.editor || self.neovim_mode != self.editor_mode {
|
||||
panic!(
|
||||
indoc! {"Test failed (zed does not match nvim behaviour)
|
||||
# initial state:
|
||||
{}
|
||||
# keystrokes:
|
||||
{}
|
||||
# neovim ({}):
|
||||
{}
|
||||
# zed ({}):
|
||||
{}"},
|
||||
self.initial,
|
||||
self.recent_keystrokes,
|
||||
self.neovim_mode,
|
||||
self.neovim,
|
||||
self.editor_mode,
|
||||
self.editor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn assert_eq(&mut self, marked_text: &str) {
|
||||
let marked_text = marked_text.replace('•', " ");
|
||||
if self.neovim == marked_text
|
||||
&& self.neovim == self.editor
|
||||
&& self.neovim_mode == self.editor_mode
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let message = if self.neovim != marked_text {
|
||||
"Test is incorrect (currently expected != neovim_state)"
|
||||
} else {
|
||||
"Editor does not match nvim behaviour"
|
||||
};
|
||||
panic!(
|
||||
indoc! {"{}
|
||||
# initial state:
|
||||
{}
|
||||
# keystrokes:
|
||||
{}
|
||||
# currently expected:
|
||||
{}
|
||||
# neovim ({}):
|
||||
{}
|
||||
# zed ({}):
|
||||
{}"},
|
||||
message,
|
||||
self.initial,
|
||||
self.recent_keystrokes,
|
||||
marked_text.replace(" \n", "•\n"),
|
||||
self.neovim_mode,
|
||||
self.neovim.replace(" \n", "•\n"),
|
||||
self.editor_mode,
|
||||
self.editor.replace(" \n", "•\n"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SharedClipboard {
|
||||
neovim: String,
|
||||
editor: String,
|
||||
state: SharedState,
|
||||
}
|
||||
|
||||
impl SharedClipboard {
|
||||
#[track_caller]
|
||||
pub fn assert_eq(&self, expected: &str) {
|
||||
if expected == self.neovim && self.neovim == self.editor {
|
||||
return;
|
||||
}
|
||||
|
||||
let message = if expected == self.neovim {
|
||||
"Test is incorrect (currently expected != neovim_state)"
|
||||
} else {
|
||||
"Editor does not match nvim behaviour"
|
||||
};
|
||||
|
||||
panic!(
|
||||
indoc! {"{}
|
||||
# initial state:
|
||||
{}
|
||||
# keystrokes:
|
||||
{}
|
||||
# currently expected:
|
||||
{}
|
||||
# neovim clipboard:
|
||||
{}
|
||||
# zed clipboard:
|
||||
{}"},
|
||||
message,
|
||||
self.state.initial,
|
||||
self.state.recent_keystrokes,
|
||||
expected,
|
||||
self.neovim,
|
||||
self.editor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl NeovimBackedTestContext {
|
||||
|
@ -78,49 +152,13 @@ impl NeovimBackedTestContext {
|
|||
.to_string();
|
||||
Self {
|
||||
cx: VimTestContext::new(cx, true).await,
|
||||
exemptions: Default::default(),
|
||||
neovim: NeovimConnection::new(test_name).await,
|
||||
|
||||
last_set_state: None,
|
||||
recent_keystrokes: Default::default(),
|
||||
is_dirty: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_initial_state_exemptions(
|
||||
&mut self,
|
||||
marked_positions: &str,
|
||||
missing_feature: ExemptionFeatures, // Feature required to support this exempted test case
|
||||
) {
|
||||
if !missing_feature.supported() {
|
||||
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
|
||||
|
||||
for cursor_offset in cursor_offsets.iter() {
|
||||
let mut marked_text = unmarked_text.clone();
|
||||
marked_text.insert(*cursor_offset, 'ˇ');
|
||||
|
||||
// None represents all key bindings being exempted for that initial state
|
||||
self.exemptions.insert(marked_text, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn simulate_shared_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
|
||||
self.neovim.send_keystroke(keystroke_text).await;
|
||||
self.simulate_keystroke(keystroke_text)
|
||||
}
|
||||
|
||||
pub async fn simulate_shared_keystrokes<const COUNT: usize>(
|
||||
&mut self,
|
||||
keystroke_texts: [&str; COUNT],
|
||||
) {
|
||||
for keystroke_text in keystroke_texts.into_iter() {
|
||||
self.recent_keystrokes.push(keystroke_text.to_string());
|
||||
self.neovim.send_keystroke(keystroke_text).await;
|
||||
}
|
||||
self.simulate_keystrokes(keystroke_texts);
|
||||
}
|
||||
|
||||
pub async fn set_shared_state(&mut self, marked_text: &str) {
|
||||
let mode = if marked_text.contains('»') {
|
||||
Mode::Visual
|
||||
|
@ -131,7 +169,21 @@ impl NeovimBackedTestContext {
|
|||
self.last_set_state = Some(marked_text.to_string());
|
||||
self.recent_keystrokes = Vec::new();
|
||||
self.neovim.set_state(marked_text).await;
|
||||
self.is_dirty = true;
|
||||
}
|
||||
|
||||
pub async fn simulate_shared_keystrokes(&mut self, keystroke_texts: &str) {
|
||||
for keystroke_text in keystroke_texts.split(' ') {
|
||||
self.recent_keystrokes.push(keystroke_text.to_string());
|
||||
self.neovim.send_keystroke(keystroke_text).await;
|
||||
}
|
||||
self.simulate_keystrokes(keystroke_texts);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub async fn simulate(&mut self, keystrokes: &str, initial_state: &str) -> SharedState {
|
||||
self.set_shared_state(initial_state).await;
|
||||
self.simulate_shared_keystrokes(keystrokes).await;
|
||||
self.shared_state().await
|
||||
}
|
||||
|
||||
pub async fn set_shared_wrap(&mut self, columns: u32) {
|
||||
|
@ -186,241 +238,51 @@ impl NeovimBackedTestContext {
|
|||
self.neovim.set_option(option).await;
|
||||
}
|
||||
|
||||
pub async fn assert_shared_state(&mut self, marked_text: &str) {
|
||||
self.is_dirty = false;
|
||||
let marked_text = marked_text.replace('•', " ");
|
||||
let neovim = self.neovim_state().await;
|
||||
let neovim_mode = self.neovim_mode().await;
|
||||
let editor = self.editor_state();
|
||||
let editor_mode = self.mode();
|
||||
if neovim == marked_text && neovim == editor && neovim_mode == editor_mode {
|
||||
return;
|
||||
}
|
||||
let initial_state = self
|
||||
.last_set_state
|
||||
.as_ref()
|
||||
.unwrap_or(&"N/A".to_string())
|
||||
.clone();
|
||||
|
||||
let message = if neovim != marked_text {
|
||||
"Test is incorrect (currently expected != neovim_state)"
|
||||
} else {
|
||||
"Editor does not match nvim behaviour"
|
||||
};
|
||||
panic!(
|
||||
indoc! {"{}
|
||||
# initial state:
|
||||
{}
|
||||
# keystrokes:
|
||||
{}
|
||||
# currently expected:
|
||||
{}
|
||||
# neovim ({}):
|
||||
{}
|
||||
# zed ({}):
|
||||
{}"},
|
||||
message,
|
||||
initial_state,
|
||||
self.recent_keystrokes.join(" "),
|
||||
marked_text.replace(" \n", "•\n"),
|
||||
neovim_mode,
|
||||
neovim.replace(" \n", "•\n"),
|
||||
editor_mode,
|
||||
editor.replace(" \n", "•\n"),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn assert_shared_clipboard(&mut self, text: &str) {
|
||||
let neovim = self.neovim.read_register('"').await;
|
||||
let editor = self.read_from_clipboard().unwrap().text().clone();
|
||||
|
||||
if text == neovim && text == editor {
|
||||
return;
|
||||
}
|
||||
|
||||
let message = if neovim != text {
|
||||
"Test is incorrect (currently expected != neovim)"
|
||||
} else {
|
||||
"Editor does not match nvim behaviour"
|
||||
};
|
||||
|
||||
let initial_state = self
|
||||
.last_set_state
|
||||
.as_ref()
|
||||
.unwrap_or(&"N/A".to_string())
|
||||
.clone();
|
||||
|
||||
panic!(
|
||||
indoc! {"{}
|
||||
# initial state:
|
||||
{}
|
||||
# keystrokes:
|
||||
{}
|
||||
# currently expected:
|
||||
{}
|
||||
# neovim clipboard:
|
||||
{}
|
||||
# zed clipboard:
|
||||
{}"},
|
||||
message,
|
||||
initial_state,
|
||||
self.recent_keystrokes.join(" "),
|
||||
text,
|
||||
neovim,
|
||||
editor
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn neovim_state(&mut self) -> String {
|
||||
self.neovim.marked_text().await
|
||||
}
|
||||
|
||||
pub async fn neovim_mode(&mut self) -> Mode {
|
||||
self.neovim.mode().await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn assert_shared_mode(&mut self, mode: Mode) {
|
||||
let neovim = self.neovim_mode().await;
|
||||
let editor = self.cx.mode();
|
||||
|
||||
if neovim != mode || editor != mode {
|
||||
panic!(
|
||||
indoc! {"Test failed (zed does not match nvim behaviour)
|
||||
# desired mode:
|
||||
{:?}
|
||||
# neovim mode:
|
||||
{:?}
|
||||
# zed mode:
|
||||
{:?}"},
|
||||
mode, neovim, editor,
|
||||
)
|
||||
#[must_use]
|
||||
pub async fn shared_clipboard(&mut self) -> SharedClipboard {
|
||||
SharedClipboard {
|
||||
state: self.shared_state().await,
|
||||
neovim: self.neovim.read_register('"').await,
|
||||
editor: self.read_from_clipboard().unwrap().text().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn assert_state_matches(&mut self) {
|
||||
self.is_dirty = false;
|
||||
let neovim = self.neovim_state().await;
|
||||
let neovim_mode = self.neovim_mode().await;
|
||||
let editor = self.editor_state();
|
||||
let editor_mode = self.mode();
|
||||
let initial_state = self
|
||||
.last_set_state
|
||||
.as_ref()
|
||||
.unwrap_or(&"N/A".to_string())
|
||||
.clone();
|
||||
|
||||
if neovim != editor || neovim_mode != editor_mode {
|
||||
panic!(
|
||||
indoc! {"Test failed (zed does not match nvim behaviour)
|
||||
# initial state:
|
||||
{}
|
||||
# keystrokes:
|
||||
{}
|
||||
# neovim ({}):
|
||||
{}
|
||||
# zed ({}):
|
||||
{}"},
|
||||
initial_state,
|
||||
self.recent_keystrokes.join(" "),
|
||||
neovim_mode,
|
||||
neovim,
|
||||
editor_mode,
|
||||
editor,
|
||||
)
|
||||
#[must_use]
|
||||
pub async fn shared_state(&mut self) -> SharedState {
|
||||
let (mode, marked_text) = self.neovim.state().await;
|
||||
SharedState {
|
||||
neovim: marked_text,
|
||||
neovim_mode: mode,
|
||||
editor: self.editor_state(),
|
||||
editor_mode: self.mode(),
|
||||
initial: self
|
||||
.last_set_state
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or("N/A".to_string()),
|
||||
recent_keystrokes: self.recent_keystrokes.join(" "),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn assert_binding_matches<const COUNT: usize>(
|
||||
#[must_use]
|
||||
pub async fn simulate_at_each_offset(
|
||||
&mut self,
|
||||
keystrokes: [&str; COUNT],
|
||||
initial_state: &str,
|
||||
) {
|
||||
if let Some(possible_exempted_keystrokes) = self.exemptions.get(initial_state) {
|
||||
match possible_exempted_keystrokes {
|
||||
Some(exempted_keystrokes) => {
|
||||
if exempted_keystrokes.contains(&format!("{keystrokes:?}")) {
|
||||
// This keystroke was exempted for this insertion text
|
||||
return;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// All keystrokes for this insertion text are exempted
|
||||
return;
|
||||
}
|
||||
keystrokes: &str,
|
||||
marked_positions: &str,
|
||||
) -> SharedState {
|
||||
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
|
||||
|
||||
for cursor_offset in cursor_offsets.iter() {
|
||||
let mut marked_text = unmarked_text.clone();
|
||||
marked_text.insert(*cursor_offset, 'ˇ');
|
||||
|
||||
let state = self.simulate(keystrokes, &marked_text).await;
|
||||
if state.neovim != state.editor || state.neovim_mode != state.editor_mode {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
let _state_context = self.set_shared_state(initial_state).await;
|
||||
let _keystroke_context = self.simulate_shared_keystrokes(keystrokes).await;
|
||||
self.assert_state_matches().await;
|
||||
}
|
||||
|
||||
pub async fn assert_binding_matches_all<const COUNT: usize>(
|
||||
&mut self,
|
||||
keystrokes: [&str; COUNT],
|
||||
marked_positions: &str,
|
||||
) {
|
||||
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
|
||||
|
||||
for cursor_offset in cursor_offsets.iter() {
|
||||
let mut marked_text = unmarked_text.clone();
|
||||
marked_text.insert(*cursor_offset, 'ˇ');
|
||||
|
||||
self.assert_binding_matches(keystrokes, &marked_text).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn each_marked_position(&self, marked_positions: &str) -> Vec<String> {
|
||||
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
|
||||
let mut ret = Vec::with_capacity(cursor_offsets.len());
|
||||
|
||||
for cursor_offset in cursor_offsets.iter() {
|
||||
let mut marked_text = unmarked_text.clone();
|
||||
marked_text.insert(*cursor_offset, 'ˇ');
|
||||
ret.push(marked_text)
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
pub async fn assert_neovim_compatible<const COUNT: usize>(
|
||||
&mut self,
|
||||
marked_positions: &str,
|
||||
keystrokes: [&str; COUNT],
|
||||
) {
|
||||
self.set_shared_state(&marked_positions).await;
|
||||
self.simulate_shared_keystrokes(keystrokes).await;
|
||||
self.assert_state_matches().await;
|
||||
}
|
||||
|
||||
pub async fn assert_matches_neovim<const COUNT: usize>(
|
||||
&mut self,
|
||||
marked_positions: &str,
|
||||
keystrokes: [&str; COUNT],
|
||||
result: &str,
|
||||
) {
|
||||
self.set_shared_state(marked_positions).await;
|
||||
self.simulate_shared_keystrokes(keystrokes).await;
|
||||
self.assert_shared_state(result).await;
|
||||
}
|
||||
|
||||
pub async fn assert_binding_matches_all_exempted<const COUNT: usize>(
|
||||
&mut self,
|
||||
keystrokes: [&str; COUNT],
|
||||
marked_positions: &str,
|
||||
feature: ExemptionFeatures,
|
||||
) {
|
||||
if SUPPORTED_FEATURES.contains(&feature) {
|
||||
self.assert_binding_matches_all(keystrokes, marked_positions)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binding<const COUNT: usize>(
|
||||
self,
|
||||
keystrokes: [&'static str; COUNT],
|
||||
) -> NeovimBackedBindingTestContext<COUNT> {
|
||||
NeovimBackedBindingTestContext::new(keystrokes, self)
|
||||
SharedState::default()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,17 +300,6 @@ impl DerefMut for NeovimBackedTestContext {
|
|||
}
|
||||
}
|
||||
|
||||
// a common mistake in tests is to call set_shared_state when
|
||||
// you mean asswert_shared_state. This notices that and lets
|
||||
// you know.
|
||||
impl Drop for NeovimBackedTestContext {
|
||||
fn drop(&mut self) {
|
||||
if self.is_dirty {
|
||||
panic!("Test context was dropped after set_shared_state before assert_shared_state")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::test::NeovimBackedTestContext;
|
||||
|
@ -457,8 +308,8 @@ mod test {
|
|||
#[gpui::test]
|
||||
async fn neovim_backed_test_context_works(cx: &mut TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
cx.assert_state_matches().await;
|
||||
cx.shared_state().await.assert_matches();
|
||||
cx.set_shared_state("This is a tesˇt").await;
|
||||
cx.assert_state_matches().await;
|
||||
cx.shared_state().await.assert_matches();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ static NEOVIM_LOCK: ReentrantMutex<()> = ReentrantMutex::new(());
|
|||
pub enum NeovimData {
|
||||
Put { state: String },
|
||||
Key(String),
|
||||
Get { state: String, mode: Option<Mode> },
|
||||
Get { state: String, mode: Mode },
|
||||
ReadRegister { name: char, value: String },
|
||||
Exec { command: String },
|
||||
SetOption { value: String },
|
||||
|
@ -218,7 +218,7 @@ impl NeovimConnection {
|
|||
}
|
||||
|
||||
if let Some(NeovimData::Get { mode, state }) = self.data.back() {
|
||||
if *mode == Some(Mode::Normal) && *state == marked_text {
|
||||
if *mode == Mode::Normal && *state == marked_text {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ impl NeovimConnection {
|
|||
#[cfg(not(feature = "neovim"))]
|
||||
pub async fn set_state(&mut self, marked_text: &str) {
|
||||
if let Some(NeovimData::Get { mode, state: text }) = self.data.front() {
|
||||
if *mode == Some(Mode::Normal) && *text == marked_text {
|
||||
if *mode == Mode::Normal && *text == marked_text {
|
||||
return;
|
||||
}
|
||||
self.data.pop_front();
|
||||
|
@ -334,7 +334,7 @@ impl NeovimConnection {
|
|||
}
|
||||
|
||||
#[cfg(feature = "neovim")]
|
||||
pub async fn state(&mut self) -> (Option<Mode>, String) {
|
||||
pub async fn state(&mut self) -> (Mode, String) {
|
||||
let nvim_buffer = self
|
||||
.nvim
|
||||
.get_current_buf()
|
||||
|
@ -369,12 +369,13 @@ impl NeovimConnection {
|
|||
.expect("Could not find mode value");
|
||||
|
||||
let mode = match nvim_mode_text.as_ref() {
|
||||
"i" => Some(Mode::Insert),
|
||||
"n" => Some(Mode::Normal),
|
||||
"v" => Some(Mode::Visual),
|
||||
"V" => Some(Mode::VisualLine),
|
||||
"\x16" => Some(Mode::VisualBlock),
|
||||
_ => None,
|
||||
"i" => Mode::Insert,
|
||||
"n" => Mode::Normal,
|
||||
"v" => Mode::Visual,
|
||||
"V" => Mode::VisualLine,
|
||||
"R" => Mode::Replace,
|
||||
"\x16" => Mode::VisualBlock,
|
||||
_ => panic!("unexpected vim mode: {nvim_mode_text}"),
|
||||
};
|
||||
|
||||
let mut selections = Vec::new();
|
||||
|
@ -382,7 +383,7 @@ impl NeovimConnection {
|
|||
// Zed uses the index of the positions between the characters, so we need
|
||||
// to add one to the end in visual mode.
|
||||
match mode {
|
||||
Some(Mode::VisualBlock) if selection_row != cursor_row => {
|
||||
Mode::VisualBlock if selection_row != cursor_row => {
|
||||
// in zed we fake a block selection by using multiple cursors (one per line)
|
||||
// this code emulates that.
|
||||
// to deal with casees where the selection is not perfectly rectangular we extract
|
||||
|
@ -415,7 +416,7 @@ impl NeovimConnection {
|
|||
}
|
||||
}
|
||||
}
|
||||
Some(Mode::Visual) | Some(Mode::VisualLine) | Some(Mode::VisualBlock) => {
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
|
||||
if (selection_row, selection_col) > (cursor_row, cursor_col) {
|
||||
let selection_line_length =
|
||||
self.read_position("echo strlen(getline(line('v')))").await;
|
||||
|
@ -439,7 +440,7 @@ impl NeovimConnection {
|
|||
Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col),
|
||||
)
|
||||
}
|
||||
Some(Mode::Insert) | Some(Mode::Normal) | Some(Mode::Replace) | None => selections
|
||||
Mode::Insert | Mode::Normal | Mode::Replace => selections
|
||||
.push(Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col)),
|
||||
}
|
||||
|
||||
|
@ -457,7 +458,7 @@ impl NeovimConnection {
|
|||
}
|
||||
|
||||
#[cfg(not(feature = "neovim"))]
|
||||
pub async fn state(&mut self) -> (Option<Mode>, String) {
|
||||
pub async fn state(&mut self) -> (Mode, String) {
|
||||
if let Some(NeovimData::Get { state: raw, mode }) = self.data.front() {
|
||||
(*mode, raw.to_string())
|
||||
} else {
|
||||
|
@ -465,14 +466,6 @@ impl NeovimConnection {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn mode(&mut self) -> Option<Mode> {
|
||||
self.state().await.0
|
||||
}
|
||||
|
||||
pub async fn marked_text(&mut self) -> String {
|
||||
self.state().await.1
|
||||
}
|
||||
|
||||
fn test_data_path(test_case_id: &str) -> PathBuf {
|
||||
let mut data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
data_path.push("test_data");
|
||||
|
|
|
@ -145,9 +145,9 @@ impl VimTestContext {
|
|||
assert_eq!(self.mode(), mode, "{}", self.assertion_context());
|
||||
}
|
||||
|
||||
pub fn assert_binding<const COUNT: usize>(
|
||||
pub fn assert_binding(
|
||||
&mut self,
|
||||
keystrokes: [&str; COUNT],
|
||||
keystrokes: &str,
|
||||
initial_state: &str,
|
||||
initial_mode: Mode,
|
||||
state_after: &str,
|
||||
|
@ -160,9 +160,9 @@ impl VimTestContext {
|
|||
assert_eq!(self.active_operator(), None, "{}", self.assertion_context());
|
||||
}
|
||||
|
||||
pub fn assert_binding_normal<const COUNT: usize>(
|
||||
pub fn assert_binding_normal(
|
||||
&mut self,
|
||||
keystrokes: [&str; COUNT],
|
||||
keystrokes: &str,
|
||||
initial_state: &str,
|
||||
state_after: &str,
|
||||
) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue