Resolve upstream merge conflicts
This commit is contained in:
commit
2e8a132a65
531 changed files with 34692 additions and 13324 deletions
|
@ -6,7 +6,7 @@ use editor::{
|
|||
actions::{SortLinesCaseInsensitive, SortLinesCaseSensitive},
|
||||
display_map::ToDisplayPoint,
|
||||
};
|
||||
use gpui::{Action, App, AppContext as _, Context, Global, Window, actions};
|
||||
use gpui::{Action, App, AppContext as _, Context, Global, Keystroke, Window, actions};
|
||||
use itertools::Itertools;
|
||||
use language::Point;
|
||||
use multi_buffer::MultiBufferRow;
|
||||
|
@ -202,6 +202,7 @@ actions!(
|
|||
ArgumentRequired
|
||||
]
|
||||
);
|
||||
|
||||
/// Opens the specified file for editing.
|
||||
#[derive(Clone, PartialEq, Action)]
|
||||
#[action(namespace = vim, no_json, no_register)]
|
||||
|
@ -209,6 +210,13 @@ struct VimEdit {
|
|||
pub filename: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Action)]
|
||||
#[action(namespace = vim, no_json, no_register)]
|
||||
struct VimNorm {
|
||||
pub range: Option<CommandRange>,
|
||||
pub command: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WrappedAction(Box<dyn Action>);
|
||||
|
||||
|
@ -447,6 +455,81 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
});
|
||||
});
|
||||
|
||||
Vim::action(editor, cx, |vim, action: &VimNorm, window, cx| {
|
||||
let keystrokes = action
|
||||
.command
|
||||
.chars()
|
||||
.map(|c| Keystroke::parse(&c.to_string()).unwrap())
|
||||
.collect();
|
||||
vim.switch_mode(Mode::Normal, true, window, cx);
|
||||
let initial_selections = vim.update_editor(window, cx, |_, editor, _, _| {
|
||||
editor.selections.disjoint_anchors()
|
||||
});
|
||||
if let Some(range) = &action.range {
|
||||
let result = vim.update_editor(window, cx, |vim, editor, window, cx| {
|
||||
let range = range.buffer_range(vim, editor, window, cx)?;
|
||||
editor.change_selections(
|
||||
SelectionEffects::no_scroll().nav_history(false),
|
||||
window,
|
||||
cx,
|
||||
|s| {
|
||||
s.select_ranges(
|
||||
(range.start.0..=range.end.0)
|
||||
.map(|line| Point::new(line, 0)..Point::new(line, 0)),
|
||||
);
|
||||
},
|
||||
);
|
||||
anyhow::Ok(())
|
||||
});
|
||||
if let Some(Err(err)) = result {
|
||||
log::error!("Error selecting range: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let Some(workspace) = vim.workspace(window) else {
|
||||
return;
|
||||
};
|
||||
let task = workspace.update(cx, |workspace, cx| {
|
||||
workspace.send_keystrokes_impl(keystrokes, window, cx)
|
||||
});
|
||||
let had_range = action.range.is_some();
|
||||
|
||||
cx.spawn_in(window, async move |vim, cx| {
|
||||
task.await;
|
||||
vim.update_in(cx, |vim, window, cx| {
|
||||
vim.update_editor(window, cx, |_, editor, window, cx| {
|
||||
if had_range {
|
||||
editor.change_selections(SelectionEffects::default(), window, cx, |s| {
|
||||
s.select_anchor_ranges([s.newest_anchor().range()]);
|
||||
})
|
||||
}
|
||||
});
|
||||
if matches!(vim.mode, Mode::Insert | Mode::Replace) {
|
||||
vim.normal_before(&Default::default(), window, cx);
|
||||
} else {
|
||||
vim.switch_mode(Mode::Normal, true, window, cx);
|
||||
}
|
||||
vim.update_editor(window, cx, |_, editor, _, cx| {
|
||||
if let Some(first_sel) = initial_selections {
|
||||
if let Some(tx_id) = editor
|
||||
.buffer()
|
||||
.update(cx, |multi, cx| multi.last_transaction_id(cx))
|
||||
{
|
||||
let last_sel = editor.selections.disjoint_anchors();
|
||||
editor.modify_transaction_selection_history(tx_id, |old| {
|
||||
old.0 = first_sel;
|
||||
old.1 = Some(last_sel);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
|
||||
Vim::action(editor, cx, |vim, _: &CountCommand, window, cx| {
|
||||
let Some(workspace) = vim.workspace(window) else {
|
||||
return;
|
||||
|
@ -675,14 +758,15 @@ impl VimCommand {
|
|||
} else {
|
||||
return None;
|
||||
};
|
||||
if !args.is_empty() {
|
||||
|
||||
let action = if args.is_empty() {
|
||||
action
|
||||
} else {
|
||||
// if command does not accept args and we have args then we should do no action
|
||||
if let Some(args_fn) = &self.args {
|
||||
args_fn.deref()(action, args)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if let Some(range) = range {
|
||||
self.args.as_ref()?(action, args)?
|
||||
};
|
||||
|
||||
if let Some(range) = range {
|
||||
self.range.as_ref().and_then(|f| f(action, range))
|
||||
} else {
|
||||
Some(action)
|
||||
|
@ -1061,6 +1145,27 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
|
|||
save_intent: Some(SaveIntent::Skip),
|
||||
close_pinned: true,
|
||||
}),
|
||||
VimCommand::new(
|
||||
("norm", "al"),
|
||||
VimNorm {
|
||||
command: "".into(),
|
||||
range: None,
|
||||
},
|
||||
)
|
||||
.args(|_, args| {
|
||||
Some(
|
||||
VimNorm {
|
||||
command: args,
|
||||
range: None,
|
||||
}
|
||||
.boxed_clone(),
|
||||
)
|
||||
})
|
||||
.range(|action, range| {
|
||||
let mut action: VimNorm = action.as_any().downcast_ref::<VimNorm>().unwrap().clone();
|
||||
action.range.replace(range.clone());
|
||||
Some(Box::new(action))
|
||||
}),
|
||||
VimCommand::new(("bn", "ext"), workspace::ActivateNextItem).count(),
|
||||
VimCommand::new(("bN", "ext"), workspace::ActivatePreviousItem).count(),
|
||||
VimCommand::new(("bp", "revious"), workspace::ActivatePreviousItem).count(),
|
||||
|
@ -1085,12 +1190,12 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
|
|||
),
|
||||
VimCommand::new(
|
||||
("tabo", "nly"),
|
||||
workspace::CloseInactiveItems {
|
||||
workspace::CloseOtherItems {
|
||||
save_intent: Some(SaveIntent::Close),
|
||||
close_pinned: false,
|
||||
},
|
||||
)
|
||||
.bang(workspace::CloseInactiveItems {
|
||||
.bang(workspace::CloseOtherItems {
|
||||
save_intent: Some(SaveIntent::Skip),
|
||||
close_pinned: false,
|
||||
}),
|
||||
|
@ -1106,13 +1211,28 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
|
|||
VimCommand::str(("cl", "ist"), "diagnostics::Deploy"),
|
||||
VimCommand::new(("cc", ""), editor::actions::Hover),
|
||||
VimCommand::new(("ll", ""), editor::actions::Hover),
|
||||
VimCommand::new(("cn", "ext"), editor::actions::GoToDiagnostic).range(wrap_count),
|
||||
VimCommand::new(("cp", "revious"), editor::actions::GoToPreviousDiagnostic)
|
||||
VimCommand::new(("cn", "ext"), editor::actions::GoToDiagnostic::default())
|
||||
.range(wrap_count),
|
||||
VimCommand::new(("cN", "ext"), editor::actions::GoToPreviousDiagnostic).range(wrap_count),
|
||||
VimCommand::new(("lp", "revious"), editor::actions::GoToPreviousDiagnostic)
|
||||
.range(wrap_count),
|
||||
VimCommand::new(("lN", "ext"), editor::actions::GoToPreviousDiagnostic).range(wrap_count),
|
||||
VimCommand::new(
|
||||
("cp", "revious"),
|
||||
editor::actions::GoToPreviousDiagnostic::default(),
|
||||
)
|
||||
.range(wrap_count),
|
||||
VimCommand::new(
|
||||
("cN", "ext"),
|
||||
editor::actions::GoToPreviousDiagnostic::default(),
|
||||
)
|
||||
.range(wrap_count),
|
||||
VimCommand::new(
|
||||
("lp", "revious"),
|
||||
editor::actions::GoToPreviousDiagnostic::default(),
|
||||
)
|
||||
.range(wrap_count),
|
||||
VimCommand::new(
|
||||
("lN", "ext"),
|
||||
editor::actions::GoToPreviousDiagnostic::default(),
|
||||
)
|
||||
.range(wrap_count),
|
||||
VimCommand::new(("j", "oin"), JoinLines).range(select_range),
|
||||
VimCommand::new(("fo", "ld"), editor::actions::FoldSelectedRanges).range(act_on_range),
|
||||
VimCommand::new(("foldo", "pen"), editor::actions::UnfoldLines)
|
||||
|
@ -2283,4 +2403,78 @@ mod test {
|
|||
});
|
||||
assert!(mark.is_none())
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_normal_command(cx: &mut TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
The quick
|
||||
brown« fox
|
||||
jumpsˇ» over
|
||||
the lazy dog
|
||||
"})
|
||||
.await;
|
||||
|
||||
cx.simulate_shared_keystrokes(": n o r m space w C w o r d")
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("enter").await;
|
||||
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
The quick
|
||||
brown word
|
||||
jumps worˇd
|
||||
the lazy dog
|
||||
"});
|
||||
|
||||
cx.simulate_shared_keystrokes(": n o r m space _ w c i w t e s t")
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("enter").await;
|
||||
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
The quick
|
||||
brown word
|
||||
jumps tesˇt
|
||||
the lazy dog
|
||||
"});
|
||||
|
||||
cx.simulate_shared_keystrokes("_ l v l : n o r m space s l a")
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("enter").await;
|
||||
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
The quick
|
||||
brown word
|
||||
lˇaumps test
|
||||
the lazy dog
|
||||
"});
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
ˇThe quick
|
||||
brown fox
|
||||
jumps over
|
||||
the lazy dog
|
||||
"})
|
||||
.await;
|
||||
|
||||
cx.simulate_shared_keystrokes("c i w M y escape").await;
|
||||
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
Mˇy quick
|
||||
brown fox
|
||||
jumps over
|
||||
the lazy dog
|
||||
"});
|
||||
|
||||
cx.simulate_shared_keystrokes(": n o r m space u").await;
|
||||
cx.simulate_shared_keystrokes("enter").await;
|
||||
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
ˇThe quick
|
||||
brown fox
|
||||
jumps over
|
||||
the lazy dog
|
||||
"});
|
||||
// Once ctrl-v to input character literals is added there should be a test for redo
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,34 @@ mod boundary;
|
|||
mod object;
|
||||
mod select;
|
||||
|
||||
use editor::{DisplayPoint, Editor, movement};
|
||||
use editor::{DisplayPoint, Editor, SelectionEffects, ToOffset, ToPoint, movement};
|
||||
use gpui::{Action, actions};
|
||||
use gpui::{Context, Window};
|
||||
use language::{CharClassifier, CharKind};
|
||||
use text::SelectionGoal;
|
||||
use text::{Bias, SelectionGoal};
|
||||
|
||||
use crate::{Vim, motion::Motion, state::Mode};
|
||||
use crate::{
|
||||
Vim,
|
||||
motion::{Motion, right},
|
||||
state::Mode,
|
||||
};
|
||||
|
||||
actions!(
|
||||
vim,
|
||||
[
|
||||
/// Switches to normal mode after the cursor (Helix-style).
|
||||
HelixNormalAfter
|
||||
HelixNormalAfter,
|
||||
/// Inserts at the beginning of the selection.
|
||||
HelixInsert,
|
||||
/// Appends at the end of the selection.
|
||||
HelixAppend,
|
||||
]
|
||||
);
|
||||
|
||||
pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
||||
Vim::action(editor, cx, Vim::helix_normal_after);
|
||||
Vim::action(editor, cx, Vim::helix_insert);
|
||||
Vim::action(editor, cx, Vim::helix_append);
|
||||
}
|
||||
|
||||
impl Vim {
|
||||
|
@ -303,6 +313,112 @@ impl Vim {
|
|||
_ => self.helix_move_and_collapse(motion, times, window, cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn helix_insert(&mut self, _: &HelixInsert, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.start_recording(cx);
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|_map, selection| {
|
||||
// In helix normal mode, move cursor to start of selection and collapse
|
||||
if !selection.is_empty() {
|
||||
selection.collapse_to(selection.start, SelectionGoal::None);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
self.switch_mode(Mode::Insert, false, window, cx);
|
||||
}
|
||||
|
||||
fn helix_append(&mut self, _: &HelixAppend, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.start_recording(cx);
|
||||
self.switch_mode(Mode::Insert, false, window, cx);
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let point = if selection.is_empty() {
|
||||
right(map, selection.head(), 1)
|
||||
} else {
|
||||
selection.end
|
||||
};
|
||||
selection.collapse_to(point, SelectionGoal::None);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn helix_replace(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.transact(window, cx, |editor, window, cx| {
|
||||
let (map, selections) = editor.selections.all_display(cx);
|
||||
|
||||
// Store selection info for positioning after edit
|
||||
let selection_info: Vec<_> = selections
|
||||
.iter()
|
||||
.map(|selection| {
|
||||
let range = selection.range();
|
||||
let start_offset = range.start.to_offset(&map, Bias::Left);
|
||||
let end_offset = range.end.to_offset(&map, Bias::Left);
|
||||
let was_empty = range.is_empty();
|
||||
let was_reversed = selection.reversed;
|
||||
(
|
||||
map.buffer_snapshot.anchor_at(start_offset, Bias::Left),
|
||||
end_offset - start_offset,
|
||||
was_empty,
|
||||
was_reversed,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut edits = Vec::new();
|
||||
for selection in &selections {
|
||||
let mut range = selection.range();
|
||||
|
||||
// For empty selections, extend to replace one character
|
||||
if range.is_empty() {
|
||||
range.end = movement::saturating_right(&map, range.start);
|
||||
}
|
||||
|
||||
let byte_range = range.start.to_offset(&map, Bias::Left)
|
||||
..range.end.to_offset(&map, Bias::Left);
|
||||
|
||||
if !byte_range.is_empty() {
|
||||
let replacement_text = text.repeat(byte_range.len());
|
||||
edits.push((byte_range, replacement_text));
|
||||
}
|
||||
}
|
||||
|
||||
editor.edit(edits, cx);
|
||||
|
||||
// Restore selections based on original info
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
let ranges: Vec<_> = selection_info
|
||||
.into_iter()
|
||||
.map(|(start_anchor, original_len, was_empty, was_reversed)| {
|
||||
let start_point = start_anchor.to_point(&snapshot);
|
||||
if was_empty {
|
||||
// For cursor-only, collapse to start
|
||||
start_point..start_point
|
||||
} else {
|
||||
// For selections, span the replaced text
|
||||
let replacement_len = text.len() * original_len;
|
||||
let end_offset = start_anchor.to_offset(&snapshot) + replacement_len;
|
||||
let end_point = snapshot.offset_to_point(end_offset);
|
||||
if was_reversed {
|
||||
end_point..start_point
|
||||
} else {
|
||||
start_point..end_point
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.select_ranges(ranges);
|
||||
});
|
||||
});
|
||||
});
|
||||
self.switch_mode(Mode::HelixNormal, true, window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -501,4 +617,94 @@ mod test {
|
|||
|
||||
cx.assert_state("«ˇaa»\n", Mode::HelixNormal);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_insert_selected(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
cx.set_state(
|
||||
indoc! {"
|
||||
«The ˇ»quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.simulate_keystrokes("i");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
ˇThe quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::Insert,
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_append(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
// test from the end of the selection
|
||||
cx.set_state(
|
||||
indoc! {"
|
||||
«Theˇ» quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.simulate_keystrokes("a");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
Theˇ quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::Insert,
|
||||
);
|
||||
|
||||
// test from the beginning of the selection
|
||||
cx.set_state(
|
||||
indoc! {"
|
||||
«ˇThe» quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.simulate_keystrokes("a");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
Theˇ quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::Insert,
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_replace(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
// No selection (single character)
|
||||
cx.set_state("ˇaa", Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("r x");
|
||||
|
||||
cx.assert_state("ˇxa", Mode::HelixNormal);
|
||||
|
||||
// Cursor at the beginning
|
||||
cx.set_state("«ˇaa»", Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("r x");
|
||||
|
||||
cx.assert_state("«ˇxx»", Mode::HelixNormal);
|
||||
|
||||
// Cursor at the end
|
||||
cx.set_state("«aaˇ»", Mode::HelixNormal);
|
||||
|
||||
cx.simulate_keystrokes("r x");
|
||||
|
||||
cx.assert_state("«xxˇ»", Mode::HelixNormal);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
}
|
||||
|
||||
impl Vim {
|
||||
fn normal_before(
|
||||
pub(crate) fn normal_before(
|
||||
&mut self,
|
||||
action: &NormalBefore,
|
||||
window: &mut Window,
|
||||
|
|
|
@ -64,6 +64,8 @@ actions!(
|
|||
DeleteRight,
|
||||
/// Deletes using Helix-style behavior.
|
||||
HelixDelete,
|
||||
/// Collapse the current selection
|
||||
HelixCollapseSelection,
|
||||
/// Changes from cursor to end of line.
|
||||
ChangeToEndOfLine,
|
||||
/// Deletes from cursor to end of line.
|
||||
|
@ -143,6 +145,20 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
vim.switch_mode(Mode::HelixNormal, true, window, cx);
|
||||
});
|
||||
|
||||
Vim::action(editor, cx, |vim, _: &HelixCollapseSelection, window, cx| {
|
||||
vim.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let mut point = selection.head();
|
||||
if !selection.reversed && !selection.is_empty() {
|
||||
point = movement::left(map, selection.head());
|
||||
}
|
||||
selection.collapse_to(point, selection.goal)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Vim::action(editor, cx, |vim, _: &ChangeToEndOfLine, window, cx| {
|
||||
vim.start_recording(cx);
|
||||
let times = Vim::take_count(cx);
|
||||
|
|
|
@ -230,7 +230,11 @@ fn scroll_editor(
|
|||
// column position, or the right-most column in the current
|
||||
// line, seeing as the cursor might be in a short line, in which
|
||||
// case we don't want to go past its last column.
|
||||
let max_row_column = map.line_len(new_row);
|
||||
let max_row_column = if new_row <= map.max_point().row() {
|
||||
map.line_len(new_row)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let max_column = match min_column + visible_column_count as u32 {
|
||||
max_column if max_column >= max_row_column => max_row_column,
|
||||
max_column => max_column,
|
||||
|
|
|
@ -1006,8 +1006,6 @@ async fn test_rename(cx: &mut gpui::TestAppContext) {
|
|||
cx.assert_state("const afterˇ = 2; console.log(after)", Mode::Normal)
|
||||
}
|
||||
|
||||
// TODO: this test is flaky on our linux CI machines
|
||||
#[cfg(target_os = "macos")]
|
||||
#[gpui::test]
|
||||
async fn test_remap(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
@ -1048,8 +1046,6 @@ async fn test_remap(cx: &mut gpui::TestAppContext) {
|
|||
cx.simulate_keystrokes("g x");
|
||||
cx.assert_state("1234fooˇ56789", Mode::Normal);
|
||||
|
||||
cx.executor().allow_parking();
|
||||
|
||||
// test command
|
||||
cx.update(|_, cx| {
|
||||
cx.bind_keys([KeyBinding::new(
|
||||
|
|
|
@ -1680,6 +1680,7 @@ impl Vim {
|
|||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
|
||||
self.visual_replace(text, window, cx)
|
||||
}
|
||||
Mode::HelixNormal => self.helix_replace(&text, window, cx),
|
||||
_ => self.clear_operator(window, cx),
|
||||
},
|
||||
Some(Operator::Digraph { first_char }) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue