Detailed changes
@@ -12,7 +12,7 @@ pub fn init(cx: &mut AppContext) {
fn normal_before(_: &mut Workspace, action: &NormalBefore, cx: &mut ViewContext<Workspace>) {
let should_repeat = Vim::update(cx, |vim, cx| {
- let count = vim.take_count().unwrap_or(1);
+ let count = vim.take_count(cx).unwrap_or(1);
vim.stop_recording_immediately(action.boxed_clone());
if count <= 1 || vim.workspace_state.replaying {
vim.update_active_editor(cx, |editor, cx| {
@@ -229,7 +229,7 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
Vim::update(cx, |vim, cx| vim.pop_operator(cx));
}
- let count = Vim::update(cx, |vim, _| vim.take_count());
+ let count = Vim::update(cx, |vim, cx| vim.take_count(cx));
let operator = Vim::read(cx).active_operator();
match Vim::read(cx).state().mode {
Mode::Normal => normal_motion(motion, operator, count, cx),
@@ -68,21 +68,21 @@ pub fn init(cx: &mut AppContext) {
cx.add_action(|_: &mut Workspace, _: &DeleteLeft, cx| {
Vim::update(cx, |vim, cx| {
vim.record_current_action(cx);
- let times = vim.take_count();
+ let times = vim.take_count(cx);
delete_motion(vim, Motion::Left, times, cx);
})
});
cx.add_action(|_: &mut Workspace, _: &DeleteRight, cx| {
Vim::update(cx, |vim, cx| {
vim.record_current_action(cx);
- let times = vim.take_count();
+ let times = vim.take_count(cx);
delete_motion(vim, Motion::Right, times, cx);
})
});
cx.add_action(|_: &mut Workspace, _: &ChangeToEndOfLine, cx| {
Vim::update(cx, |vim, cx| {
vim.start_recording(cx);
- let times = vim.take_count();
+ let times = vim.take_count(cx);
change_motion(
vim,
Motion::EndOfLine {
@@ -96,7 +96,7 @@ pub fn init(cx: &mut AppContext) {
cx.add_action(|_: &mut Workspace, _: &DeleteToEndOfLine, cx| {
Vim::update(cx, |vim, cx| {
vim.record_current_action(cx);
- let times = vim.take_count();
+ let times = vim.take_count(cx);
delete_motion(
vim,
Motion::EndOfLine {
@@ -110,7 +110,7 @@ pub fn init(cx: &mut AppContext) {
cx.add_action(|_: &mut Workspace, _: &JoinLines, cx| {
Vim::update(cx, |vim, cx| {
vim.record_current_action(cx);
- let mut times = vim.take_count().unwrap_or(1);
+ let mut times = vim.take_count(cx).unwrap_or(1);
if vim.state().mode.is_visual() {
times = 1;
} else if times > 1 {
@@ -8,7 +8,7 @@ use crate::{normal::ChangeCase, state::Mode, Vim};
pub fn change_case(_: &mut Workspace, _: &ChangeCase, cx: &mut ViewContext<Workspace>) {
Vim::update(cx, |vim, cx| {
vim.record_current_action(cx);
- let count = vim.take_count().unwrap_or(1) as u32;
+ let count = vim.take_count(cx).unwrap_or(1) as u32;
vim.update_active_editor(cx, |editor, cx| {
let mut ranges = Vec::new();
let mut cursor_positions = Vec::new();
@@ -60,7 +60,7 @@ pub(crate) fn repeat(cx: &mut WindowContext, from_insert_mode: bool) {
let Some(editor) = vim.active_editor.clone() else {
return None;
};
- let count = vim.take_count();
+ let count = vim.take_count(cx);
let selection = vim.workspace_state.recorded_selection.clone();
match selection {
@@ -253,7 +253,7 @@ mod test {
deterministic.run_until_parked();
cx.simulate_shared_keystrokes(["."]).await;
deterministic.run_until_parked();
- cx.set_shared_state("THE QUICK ˇbrown fox").await;
+ cx.assert_shared_state("THE QUICK ˇbrown fox").await;
}
#[gpui::test]
@@ -48,7 +48,7 @@ pub fn init(cx: &mut AppContext) {
fn scroll(cx: &mut ViewContext<Workspace>, by: fn(c: Option<f32>) -> ScrollAmount) {
Vim::update(cx, |vim, cx| {
- let amount = by(vim.take_count().map(|c| c as f32));
+ let amount = by(vim.take_count(cx).map(|c| c as f32));
vim.update_active_editor(cx, |editor, cx| scroll_editor(editor, &amount, cx));
})
}
@@ -52,7 +52,7 @@ fn search(workspace: &mut Workspace, action: &Search, cx: &mut ViewContext<Works
Direction::Next
};
Vim::update(cx, |vim, cx| {
- let count = vim.take_count().unwrap_or(1);
+ let count = vim.take_count(cx).unwrap_or(1);
pane.update(cx, |pane, cx| {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
search_bar.update(cx, |search_bar, cx| {
@@ -119,7 +119,7 @@ pub fn move_to_internal(
) {
Vim::update(cx, |vim, cx| {
let pane = workspace.active_pane().clone();
- let count = vim.take_count().unwrap_or(1);
+ let count = vim.take_count(cx).unwrap_or(1);
pane.update(cx, |pane, cx| {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
let search = search_bar.update(cx, |search_bar, cx| {
@@ -11,7 +11,7 @@ pub(crate) fn init(cx: &mut AppContext) {
cx.add_action(|_: &mut Workspace, _: &Substitute, cx| {
Vim::update(cx, |vim, cx| {
vim.start_recording(cx);
- let count = vim.take_count();
+ let count = vim.take_count(cx);
substitute(vim, count, vim.state().mode == Mode::VisualLine, cx);
})
});
@@ -22,7 +22,7 @@ pub(crate) fn init(cx: &mut AppContext) {
if matches!(vim.state().mode, Mode::VisualBlock | Mode::Visual) {
vim.switch_mode(Mode::VisualLine, false, cx)
}
- let count = vim.take_count();
+ let count = vim.take_count(cx);
substitute(vim, count, true, cx)
})
});
@@ -186,6 +186,7 @@ impl EditorState {
if self.active_operator().is_none() && self.pre_count.is_some()
|| self.active_operator().is_some() && self.post_count.is_some()
{
+ dbg!("VimCount");
context.add_identifier("VimCount");
}
@@ -587,9 +587,34 @@ async fn test_clear_counts(cx: &mut gpui::TestAppContext) {
cx.simulate_shared_keystrokes(["4", "escape", "3", "d", "l"])
.await;
- cx.set_shared_state(indoc! {"
+ cx.assert_shared_state(indoc! {"
The quick brown
fox juˇ over
the lazy dog"})
.await;
}
+
+#[gpui::test]
+async fn test_zero(cx: &mut gpui::TestAppContext) {
+ 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(["0"]).await;
+ cx.assert_shared_state(indoc! {"
+ ˇThe quick brown
+ fox jumps over
+ the lazy dog"})
+ .await;
+
+ cx.simulate_shared_keystrokes(["1", "0", "l"]).await;
+ cx.assert_shared_state(indoc! {"
+ The quick ˇbrown
+ fox jumps over
+ the lazy dog"})
+ .await;
+}
@@ -68,6 +68,8 @@ pub struct NeovimBackedTestContext<'a> {
last_set_state: Option<String>,
recent_keystrokes: Vec<String>,
+
+ is_dirty: bool,
}
impl<'a> NeovimBackedTestContext<'a> {
@@ -81,6 +83,7 @@ impl<'a> NeovimBackedTestContext<'a> {
last_set_state: None,
recent_keystrokes: Default::default(),
+ is_dirty: false,
}
}
@@ -128,6 +131,7 @@ impl<'a> NeovimBackedTestContext<'a> {
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;
context_handle
}
@@ -153,6 +157,7 @@ impl<'a> NeovimBackedTestContext<'a> {
}
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 editor = self.editor_state();
@@ -258,6 +263,7 @@ impl<'a> NeovimBackedTestContext<'a> {
}
pub async fn assert_state_matches(&mut self) {
+ self.is_dirty = false;
let neovim = self.neovim_state().await;
let editor = self.editor_state();
let initial_state = self
@@ -383,6 +389,14 @@ impl<'a> DerefMut for NeovimBackedTestContext<'a> {
}
}
+impl<'a> Drop for NeovimBackedTestContext<'a> {
+ 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 gpui::TestAppContext;
@@ -73,7 +73,7 @@ pub fn init(cx: &mut AppContext) {
},
);
cx.add_action(|_: &mut Workspace, n: &Number, cx: _| {
- Vim::update(cx, |vim, _| vim.push_count_digit(n.0));
+ Vim::update(cx, |vim, cx| vim.push_count_digit(n.0, cx));
});
cx.add_action(|_: &mut Workspace, _: &Tab, cx| {
@@ -228,13 +228,7 @@ impl Vim {
let editor = self.active_editor.clone()?.upgrade(cx)?;
Some(editor.update(cx, update))
}
- // ~, shift-j, x, shift-x, p
- // shift-c, shift-d, shift-i, i, a, o, shift-o, s
- // c, d
- // r
- // TODO: shift-j?
- //
pub fn start_recording(&mut self, cx: &mut WindowContext) {
if !self.workspace_state.replaying {
self.workspace_state.recording = true;
@@ -309,7 +303,7 @@ impl Vim {
state.operator_stack.clear();
});
if mode != Mode::Insert {
- self.take_count();
+ self.take_count(cx);
}
cx.emit_global(VimEvent::ModeChanged { mode });
@@ -363,7 +357,7 @@ impl Vim {
});
}
- fn push_count_digit(&mut self, number: usize) {
+ fn push_count_digit(&mut self, number: usize, cx: &mut WindowContext) {
if self.active_operator().is_some() {
self.update_state(|state| {
state.post_count = Some(state.post_count.unwrap_or(0) * 10 + number)
@@ -373,9 +367,11 @@ impl Vim {
state.pre_count = Some(state.pre_count.unwrap_or(0) * 10 + number)
})
}
+ // update the keymap so that 0 works
+ self.sync_vim_settings(cx)
}
- fn take_count(&mut self) -> Option<usize> {
+ fn take_count(&mut self, cx: &mut WindowContext) -> Option<usize> {
if self.workspace_state.replaying {
return self.workspace_state.recorded_count;
}
@@ -390,6 +386,7 @@ impl Vim {
if self.workspace_state.recording {
self.workspace_state.recorded_count = count;
}
+ self.sync_vim_settings(cx);
count
}
@@ -415,7 +412,7 @@ impl Vim {
popped_operator
}
fn clear_operator(&mut self, cx: &mut WindowContext) {
- self.take_count();
+ self.take_count(cx);
self.update_state(|state| state.operator_stack.clear());
self.sync_vim_settings(cx);
}
@@ -4,4 +4,4 @@
{"Key":"3"}
{"Key":"d"}
{"Key":"l"}
-{"Put":{"state":"The quick brown\nfox juˇ over\nthe lazy dog"}}
+{"Get":{"state":"The quick brown\nfox juˇ over\nthe lazy dog","mode":"Normal"}}
@@ -35,4 +35,4 @@
{"Key":"."}
{"Put":{"state":"THE QUIˇck brown fox"}}
{"Key":"."}
-{"Put":{"state":"THE QUICK ˇbrown fox"}}
+{"Get":{"state":"THE QUICK ˇbrown fox","mode":"Normal"}}
@@ -0,0 +1,7 @@
+{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}}
+{"Key":"0"}
+{"Get":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}}
+{"Key":"1"}
+{"Key":"0"}
+{"Key":"l"}
+{"Get":{"state":"The quick ˇbrown\nfox jumps over\nthe lazy dog","mode":"Normal"}}