editor_utils.rs

 1use editor::{display_map::DisplaySnapshot, Bias, DisplayPoint, Editor};
 2use gpui::ViewContext;
 3use language::{Selection, SelectionGoal};
 4
 5pub trait VimEditorExt {
 6    fn clip_selections(self: &mut Self, cx: &mut ViewContext<Self>);
 7    fn clipped_move_selections(
 8        self: &mut Self,
 9        cx: &mut ViewContext<Self>,
10        move_selection: impl Fn(&DisplaySnapshot, &mut Selection<DisplayPoint>),
11    );
12    fn clipped_move_selection_heads(
13        &mut self,
14        cx: &mut ViewContext<Self>,
15        update_head: impl Fn(
16            &DisplaySnapshot,
17            DisplayPoint,
18            SelectionGoal,
19        ) -> (DisplayPoint, SelectionGoal),
20    );
21    fn clipped_move_cursors(
22        self: &mut Self,
23        cx: &mut ViewContext<Self>,
24        update_cursor_position: impl Fn(
25            &DisplaySnapshot,
26            DisplayPoint,
27            SelectionGoal,
28        ) -> (DisplayPoint, SelectionGoal),
29    );
30}
31
32pub fn clip_display_point(map: &DisplaySnapshot, mut display_point: DisplayPoint) -> DisplayPoint {
33    let next_char = map.chars_at(display_point).next();
34    if next_char == Some('\n') || next_char == None {
35        *display_point.column_mut() = display_point.column().saturating_sub(1);
36        display_point = map.clip_point(display_point, Bias::Left);
37    }
38    display_point
39}
40
41impl VimEditorExt for Editor {
42    fn clip_selections(self: &mut Self, cx: &mut ViewContext<Self>) {
43        self.move_selections(cx, |map, selection| {
44            if selection.is_empty() {
45                let adjusted_cursor = clip_display_point(map, selection.start);
46                selection.collapse_to(adjusted_cursor, selection.goal);
47            } else {
48                let adjusted_head = clip_display_point(map, selection.head());
49                selection.set_head(adjusted_head, selection.goal);
50            }
51        })
52    }
53
54    fn clipped_move_selections(
55        self: &mut Self,
56        cx: &mut ViewContext<Self>,
57        move_selection: impl Fn(&DisplaySnapshot, &mut Selection<DisplayPoint>),
58    ) {
59        self.move_selections(cx, |map, selection| {
60            move_selection(map, selection);
61            let adjusted_head = clip_display_point(map, selection.head());
62            selection.set_head(adjusted_head, selection.goal);
63        })
64    }
65
66    fn clipped_move_selection_heads(
67        &mut self,
68        cx: &mut ViewContext<Self>,
69        update_head: impl Fn(
70            &DisplaySnapshot,
71            DisplayPoint,
72            SelectionGoal,
73        ) -> (DisplayPoint, SelectionGoal),
74    ) {
75        self.clipped_move_selections(cx, |map, selection| {
76            let (new_head, new_goal) = update_head(map, selection.head(), selection.goal);
77            let adjusted_head = clip_display_point(map, new_head);
78            selection.set_head(adjusted_head, new_goal);
79        });
80    }
81
82    fn clipped_move_cursors(
83        self: &mut Self,
84        cx: &mut ViewContext<Self>,
85        update_cursor_position: impl Fn(
86            &DisplaySnapshot,
87            DisplayPoint,
88            SelectionGoal,
89        ) -> (DisplayPoint, SelectionGoal),
90    ) {
91        self.move_selections(cx, |map, selection| {
92            let (cursor, new_goal) = update_cursor_position(map, selection.head(), selection.goal);
93            let adjusted_cursor = clip_display_point(map, cursor);
94            selection.collapse_to(adjusted_cursor, new_goal);
95        });
96    }
97}