search.rs

  1use gpui::{impl_actions, ViewContext};
  2use search::{BufferSearchBar, SearchOptions};
  3use serde_derive::Deserialize;
  4use workspace::{searchable::Direction, Workspace};
  5
  6use crate::Vim;
  7
  8#[derive(Clone, Deserialize, PartialEq)]
  9#[serde(rename_all = "camelCase")]
 10pub(crate) struct MoveToNext {
 11    #[serde(default)]
 12    partial_word: bool,
 13}
 14
 15#[derive(Clone, Deserialize, PartialEq)]
 16#[serde(rename_all = "camelCase")]
 17pub(crate) struct MoveToPrev {
 18    #[serde(default)]
 19    partial_word: bool,
 20}
 21
 22impl_actions!(vim, [MoveToNext, MoveToPrev]);
 23
 24pub(crate) fn move_to_next(
 25    workspace: &mut Workspace,
 26    action: &MoveToNext,
 27    cx: &mut ViewContext<Workspace>,
 28) {
 29    move_to_internal(workspace, Direction::Next, !action.partial_word, cx)
 30}
 31
 32pub(crate) fn move_to_prev(
 33    workspace: &mut Workspace,
 34    action: &MoveToPrev,
 35    cx: &mut ViewContext<Workspace>,
 36) {
 37    move_to_internal(workspace, Direction::Prev, !action.partial_word, cx)
 38}
 39
 40fn move_to_internal(
 41    workspace: &mut Workspace,
 42    direction: Direction,
 43    whole_word: bool,
 44    cx: &mut ViewContext<Workspace>,
 45) {
 46    Vim::update(cx, |vim, cx| {
 47        let pane = workspace.active_pane().clone();
 48        pane.update(cx, |pane, cx| {
 49            if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
 50                search_bar.update(cx, |search_bar, cx| {
 51                    let mut options = SearchOptions::CASE_SENSITIVE;
 52                    options.set(SearchOptions::WHOLE_WORD, whole_word);
 53                    search_bar.select_word_under_cursor(direction, options, cx);
 54                });
 55            }
 56        });
 57        vim.clear_operator(cx);
 58    });
 59}
 60
 61#[cfg(test)]
 62mod test {
 63    use search::BufferSearchBar;
 64
 65    use crate::{state::Mode, test::VimTestContext};
 66
 67    #[gpui::test]
 68    async fn test_move_to_next(cx: &mut gpui::TestAppContext) {
 69        let mut cx = VimTestContext::new(cx, true).await;
 70        let search_bar = cx.workspace(|workspace, cx| {
 71            workspace
 72                .active_pane()
 73                .read(cx)
 74                .toolbar()
 75                .read(cx)
 76                .item_of_type::<BufferSearchBar>()
 77                .expect("Buffer search bar should be deployed")
 78        });
 79        cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal);
 80
 81        cx.simulate_keystrokes(["*"]);
 82        search_bar.next_notification(&cx).await;
 83        cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal);
 84
 85        cx.simulate_keystrokes(["*"]);
 86        search_bar.next_notification(&cx).await;
 87        cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal);
 88
 89        cx.simulate_keystrokes(["#"]);
 90        search_bar.next_notification(&cx).await;
 91        cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal);
 92
 93        cx.simulate_keystrokes(["#"]);
 94        search_bar.next_notification(&cx).await;
 95        cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal);
 96
 97        cx.simulate_keystrokes(["g", "*"]);
 98        search_bar.next_notification(&cx).await;
 99        cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal);
100
101        cx.simulate_keystrokes(["n"]);
102        cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal);
103
104        cx.simulate_keystrokes(["g", "#"]);
105        search_bar.next_notification(&cx).await;
106        cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal);
107    }
108}