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}