mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 05:12:06 +03:00
vim: ? to search backwards, and /<enter> to repeat search
This commit is contained in:
parent
d70f415e8e
commit
6cf13c62d1
@ -197,10 +197,11 @@
|
||||
"p": "vim::Paste",
|
||||
"u": "editor::Undo",
|
||||
"ctrl-r": "editor::Redo",
|
||||
"/": [
|
||||
"buffer_search::Deploy",
|
||||
"/": "vim::Search",
|
||||
"?": [
|
||||
"vim::Search",
|
||||
{
|
||||
"focus": true
|
||||
"backwards": true,
|
||||
}
|
||||
],
|
||||
"ctrl-f": "vim::PageDown",
|
||||
@ -356,7 +357,8 @@
|
||||
{
|
||||
"context": "BufferSearchBar",
|
||||
"bindings": {
|
||||
"enter": "buffer_search::FocusEditor"
|
||||
"enter": "buffer_search::FocusEditor",
|
||||
"escape": "buffer_search::Dismiss"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -28,7 +28,6 @@ use self::{
|
||||
case::change_case,
|
||||
change::{change_motion, change_object},
|
||||
delete::{delete_motion, delete_object},
|
||||
search::{move_to_next, move_to_prev},
|
||||
substitute::substitute,
|
||||
yank::{yank_motion, yank_object},
|
||||
};
|
||||
@ -59,8 +58,7 @@ pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(insert_line_above);
|
||||
cx.add_action(insert_line_below);
|
||||
cx.add_action(change_case);
|
||||
cx.add_action(move_to_next);
|
||||
cx.add_action(move_to_prev);
|
||||
search::init(cx);
|
||||
cx.add_action(|_: &mut Workspace, _: &Substitute, cx| {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
let times = vim.pop_number_operator(cx);
|
||||
|
@ -1,4 +1,4 @@
|
||||
use gpui::{impl_actions, ViewContext};
|
||||
use gpui::{impl_actions, AppContext, ViewContext};
|
||||
use search::{BufferSearchBar, SearchOptions};
|
||||
use serde_derive::Deserialize;
|
||||
use workspace::{searchable::Direction, Workspace};
|
||||
@ -19,25 +19,47 @@ pub(crate) struct MoveToPrev {
|
||||
partial_word: bool,
|
||||
}
|
||||
|
||||
impl_actions!(vim, [MoveToNext, MoveToPrev]);
|
||||
#[derive(Clone, Deserialize, PartialEq)]
|
||||
pub(crate) struct Search {
|
||||
#[serde(default)]
|
||||
backwards: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn move_to_next(
|
||||
workspace: &mut Workspace,
|
||||
action: &MoveToNext,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
impl_actions!(vim, [MoveToNext, MoveToPrev, Search]);
|
||||
|
||||
pub(crate) fn init(cx: &mut AppContext) {
|
||||
cx.add_action(move_to_next);
|
||||
cx.add_action(move_to_prev);
|
||||
cx.add_action(search);
|
||||
}
|
||||
|
||||
fn move_to_next(workspace: &mut Workspace, action: &MoveToNext, cx: &mut ViewContext<Workspace>) {
|
||||
move_to_internal(workspace, Direction::Next, !action.partial_word, cx)
|
||||
}
|
||||
|
||||
pub(crate) fn move_to_prev(
|
||||
workspace: &mut Workspace,
|
||||
action: &MoveToPrev,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
fn move_to_prev(workspace: &mut Workspace, action: &MoveToPrev, cx: &mut ViewContext<Workspace>) {
|
||||
move_to_internal(workspace, Direction::Prev, !action.partial_word, cx)
|
||||
}
|
||||
|
||||
fn move_to_internal(
|
||||
fn search(workspace: &mut Workspace, action: &Search, cx: &mut ViewContext<Workspace>) {
|
||||
let pane = workspace.active_pane().clone();
|
||||
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| {
|
||||
let options = SearchOptions::CASE_SENSITIVE | SearchOptions::REGEX;
|
||||
let direction = if action.backwards {
|
||||
Direction::Prev
|
||||
} else {
|
||||
Direction::Next
|
||||
};
|
||||
search_bar.select_match(direction, cx);
|
||||
search_bar.show_with_options(true, false, options, cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn move_to_internal(
|
||||
workspace: &mut Workspace,
|
||||
direction: Direction,
|
||||
whole_word: bool,
|
||||
@ -60,6 +82,7 @@ fn move_to_internal(
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use editor::DisplayPoint;
|
||||
use search::BufferSearchBar;
|
||||
|
||||
use crate::{state::Mode, test::VimTestContext};
|
||||
@ -105,4 +128,65 @@ mod test {
|
||||
search_bar.next_notification(&cx).await;
|
||||
cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_search(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes(["/", "c", "c"]);
|
||||
|
||||
let search_bar = cx.workspace(|workspace, cx| {
|
||||
workspace
|
||||
.active_pane()
|
||||
.read(cx)
|
||||
.toolbar()
|
||||
.read(cx)
|
||||
.item_of_type::<BufferSearchBar>()
|
||||
.expect("Buffer search bar should be deployed")
|
||||
});
|
||||
|
||||
search_bar.read_with(cx.cx, |bar, cx| {
|
||||
assert_eq!(bar.query_editor.read(cx).text(cx), "cc");
|
||||
});
|
||||
|
||||
// wait for the query editor change event to fire.
|
||||
search_bar.next_notification(&cx).await;
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
let highlights = editor.all_background_highlights(cx);
|
||||
assert_eq!(3, highlights.len());
|
||||
assert_eq!(
|
||||
DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2),
|
||||
highlights[0].0
|
||||
)
|
||||
});
|
||||
|
||||
cx.simulate_keystrokes(["enter"]);
|
||||
|
||||
// n to go to next/N to go to previous
|
||||
cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes(["n"]);
|
||||
cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes(["shift-n"]);
|
||||
|
||||
// ?<enter> to go to previous
|
||||
cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes(["?", "enter"]);
|
||||
cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes(["?", "enter"]);
|
||||
|
||||
// /<enter> to go to next
|
||||
cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes(["/", "enter"]);
|
||||
cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal);
|
||||
|
||||
// ?{search}<enter> to search backwards
|
||||
cx.simulate_keystrokes(["?", "b", "enter"]);
|
||||
|
||||
// wait for the query editor change event to fire.
|
||||
search_bar.next_notification(&cx).await;
|
||||
|
||||
cx.assert_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ async fn test_buffer_search(cx: &mut gpui::TestAppContext) {
|
||||
});
|
||||
|
||||
search_bar.read_with(cx.cx, |bar, cx| {
|
||||
assert_eq!(bar.query_editor.read(cx).text(cx), "jumps");
|
||||
assert_eq!(bar.query_editor.read(cx).text(cx), "");
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,7 @@ impl<'a> VimTestContext<'a> {
|
||||
self.cx.set_state(text)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn assert_state(&mut self, text: &str, mode: Mode) {
|
||||
self.assert_editor_state(text);
|
||||
assert_eq!(self.mode(), mode, "{}", self.assertion_context());
|
||||
|
Loading…
Reference in New Issue
Block a user