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