mark.rs

  1use std::{ops::Range, sync::Arc};
  2
  3use editor::{
  4    display_map::{DisplaySnapshot, ToDisplayPoint},
  5    movement,
  6    scroll::Autoscroll,
  7    Anchor, Bias, DisplayPoint,
  8};
  9use gpui::WindowContext;
 10use language::SelectionGoal;
 11
 12use crate::{
 13    motion::{self, Motion},
 14    state::Mode,
 15    Vim,
 16};
 17
 18pub fn create_mark(vim: &mut Vim, text: Arc<str>, tail: bool, cx: &mut WindowContext) {
 19    let Some(anchors) = vim.update_active_editor(cx, |_, editor, _| {
 20        editor
 21            .selections
 22            .disjoint_anchors()
 23            .iter()
 24            .map(|s| if tail { s.tail() } else { s.head() })
 25            .collect::<Vec<_>>()
 26    }) else {
 27        return;
 28    };
 29    vim.update_state(|state| state.marks.insert(text.to_string(), anchors));
 30    vim.clear_operator(cx);
 31}
 32
 33pub fn create_visual_marks(vim: &mut Vim, mode: Mode, cx: &mut WindowContext) {
 34    let mut starts = vec![];
 35    let mut ends = vec![];
 36    let mut reversed = vec![];
 37
 38    vim.update_active_editor(cx, |_, editor, cx| {
 39        let (map, selections) = editor.selections.all_display(cx);
 40        for selection in selections {
 41            let end = movement::saturating_left(&map, selection.end);
 42            ends.push(
 43                map.buffer_snapshot
 44                    .anchor_before(end.to_offset(&map, Bias::Left)),
 45            );
 46            starts.push(
 47                map.buffer_snapshot
 48                    .anchor_after(selection.start.to_offset(&map, Bias::Right)),
 49            );
 50            reversed.push(selection.reversed)
 51        }
 52    });
 53
 54    vim.update_state(|state| {
 55        state.marks.insert("<".to_string(), starts);
 56        state.marks.insert(">".to_string(), ends);
 57        state.stored_visual_mode.replace((mode, reversed));
 58    });
 59    vim.clear_operator(cx);
 60}
 61
 62pub fn jump(text: Arc<str>, line: bool, cx: &mut WindowContext) {
 63    let anchors = Vim::update(cx, |vim, cx| {
 64        vim.pop_operator(cx);
 65
 66        match &*text {
 67            "{" | "}" => vim.update_active_editor(cx, |_, editor, cx| {
 68                let (map, selections) = editor.selections.all_display(cx);
 69                selections
 70                    .into_iter()
 71                    .map(|selection| {
 72                        let point = if &*text == "{" {
 73                            movement::start_of_paragraph(&map, selection.head(), 1)
 74                        } else {
 75                            movement::end_of_paragraph(&map, selection.head(), 1)
 76                        };
 77                        map.buffer_snapshot
 78                            .anchor_before(point.to_offset(&map, Bias::Left))
 79                    })
 80                    .collect::<Vec<Anchor>>()
 81            }),
 82            "." => vim.state().change_list.last().cloned(),
 83            _ => vim.state().marks.get(&*text).cloned(),
 84        }
 85    });
 86
 87    let Some(anchors) = anchors else { return };
 88
 89    let is_active_operator = Vim::read(cx).state().active_operator().is_some();
 90    if is_active_operator {
 91        if let Some(anchor) = anchors.last() {
 92            motion::motion(
 93                Motion::Jump {
 94                    anchor: *anchor,
 95                    line,
 96                },
 97                cx,
 98            )
 99        }
100        return;
101    } else {
102        Vim::update(cx, |vim, cx| {
103            vim.update_active_editor(cx, |_, editor, cx| {
104                let map = editor.snapshot(cx);
105                let mut ranges: Vec<Range<Anchor>> = Vec::new();
106                for mut anchor in anchors {
107                    if line {
108                        let mut point = anchor.to_display_point(&map.display_snapshot);
109                        point = motion::first_non_whitespace(&map.display_snapshot, false, point);
110                        anchor = map
111                            .display_snapshot
112                            .buffer_snapshot
113                            .anchor_before(point.to_point(&map.display_snapshot));
114                    }
115                    if ranges.last() != Some(&(anchor..anchor)) {
116                        ranges.push(anchor..anchor);
117                    }
118                }
119                editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
120                    s.select_anchor_ranges(ranges)
121                })
122            });
123        })
124    }
125}
126
127pub fn jump_motion(
128    map: &DisplaySnapshot,
129    anchor: Anchor,
130    line: bool,
131) -> (DisplayPoint, SelectionGoal) {
132    let mut point = anchor.to_display_point(map);
133    if line {
134        point = motion::first_non_whitespace(map, false, point)
135    }
136
137    (point, SelectionGoal::None)
138}