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    Vim,
 15};
 16
 17pub fn create_mark(vim: &mut Vim, text: Arc<str>, tail: bool, cx: &mut WindowContext) {
 18    let Some(anchors) = vim.update_active_editor(cx, |_, editor, _| {
 19        editor
 20            .selections
 21            .disjoint_anchors()
 22            .iter()
 23            .map(|s| if tail { s.tail() } else { s.head() })
 24            .collect::<Vec<_>>()
 25    }) else {
 26        return;
 27    };
 28    vim.update_state(|state| state.marks.insert(text.to_string(), anchors));
 29    vim.clear_operator(cx);
 30}
 31
 32pub fn create_mark_after(vim: &mut Vim, text: Arc<str>, cx: &mut WindowContext) {
 33    let Some(anchors) = vim.update_active_editor(cx, |_, editor, cx| {
 34        let (map, selections) = editor.selections.all_display(cx);
 35        selections
 36            .into_iter()
 37            .map(|selection| {
 38                let point = movement::saturating_right(&map, selection.tail());
 39                map.buffer_snapshot
 40                    .anchor_before(point.to_offset(&map, Bias::Left))
 41            })
 42            .collect::<Vec<_>>()
 43    }) else {
 44        return;
 45    };
 46
 47    vim.update_state(|state| state.marks.insert(text.to_string(), anchors));
 48    vim.clear_operator(cx);
 49}
 50
 51pub fn create_mark_before(vim: &mut Vim, text: Arc<str>, cx: &mut WindowContext) {
 52    let Some(anchors) = vim.update_active_editor(cx, |_, editor, cx| {
 53        let (map, selections) = editor.selections.all_display(cx);
 54        selections
 55            .into_iter()
 56            .map(|selection| {
 57                let point = movement::saturating_left(&map, selection.head());
 58                map.buffer_snapshot
 59                    .anchor_before(point.to_offset(&map, Bias::Left))
 60            })
 61            .collect::<Vec<_>>()
 62    }) else {
 63        return;
 64    };
 65
 66    vim.update_state(|state| state.marks.insert(text.to_string(), anchors));
 67    vim.clear_operator(cx);
 68}
 69
 70pub fn jump(text: Arc<str>, line: bool, cx: &mut WindowContext) {
 71    let anchors = match &*text {
 72        "{" | "}" => Vim::update(cx, |vim, cx| {
 73            vim.update_active_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        }),
 89        _ => Vim::read(cx).state().marks.get(&*text).cloned(),
 90    };
 91
 92    Vim::update(cx, |vim, cx| {
 93        vim.pop_operator(cx);
 94    });
 95
 96    let Some(anchors) = anchors else { return };
 97
 98    let is_active_operator = Vim::read(cx).state().active_operator().is_some();
 99    if is_active_operator {
100        if let Some(anchor) = anchors.last() {
101            motion::motion(
102                Motion::Jump {
103                    anchor: *anchor,
104                    line,
105                },
106                cx,
107            )
108        }
109        return;
110    } else {
111        Vim::update(cx, |vim, cx| {
112            vim.update_active_editor(cx, |_, editor, cx| {
113                let map = editor.snapshot(cx);
114                let mut ranges: Vec<Range<Anchor>> = Vec::new();
115                for mut anchor in anchors {
116                    if line {
117                        let mut point = anchor.to_display_point(&map.display_snapshot);
118                        point = motion::first_non_whitespace(&map.display_snapshot, false, point);
119                        anchor = map
120                            .display_snapshot
121                            .buffer_snapshot
122                            .anchor_before(point.to_point(&map.display_snapshot));
123                    }
124                    if ranges.last() != Some(&(anchor..anchor)) {
125                        ranges.push(anchor..anchor);
126                    }
127                }
128                editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
129                    s.select_anchor_ranges(ranges)
130                })
131            });
132        })
133    }
134}
135
136pub fn jump_motion(
137    map: &DisplaySnapshot,
138    anchor: Anchor,
139    line: bool,
140) -> (DisplayPoint, SelectionGoal) {
141    let mut point = anchor.to_display_point(map);
142    if line {
143        point = motion::first_non_whitespace(map, false, point)
144    }
145
146    (point, SelectionGoal::None)
147}