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