1use gpui::{
2 actions, geometry::vector::Vector2F, impl_internal_actions, Axis, MutableAppContext,
3 ViewContext,
4};
5use language::Bias;
6
7use crate::{Editor, EditorMode};
8
9use super::{autoscroll::Autoscroll, scroll_amount::ScrollAmount, ScrollAnchor};
10
11actions!(
12 editor,
13 [
14 LineDown,
15 LineUp,
16 HalfPageDown,
17 HalfPageUp,
18 PageDown,
19 PageUp,
20 NextScreen,
21 ScrollCursorTop,
22 ScrollCursorCenter,
23 ScrollCursorBottom,
24 ]
25);
26
27#[derive(Clone, PartialEq)]
28pub struct Scroll {
29 pub scroll_position: Vector2F,
30 pub axis: Option<Axis>,
31}
32
33impl_internal_actions!(editor, [Scroll]);
34
35pub fn init(cx: &mut MutableAppContext) {
36 cx.add_action(Editor::next_screen);
37 cx.add_action(Editor::scroll);
38 cx.add_action(Editor::scroll_cursor_top);
39 cx.add_action(Editor::scroll_cursor_center);
40 cx.add_action(Editor::scroll_cursor_bottom);
41 cx.add_action(|this: &mut Editor, _: &LineDown, cx| {
42 this.scroll_screen(&ScrollAmount::LineDown, cx)
43 });
44 cx.add_action(|this: &mut Editor, _: &LineUp, cx| {
45 this.scroll_screen(&ScrollAmount::LineUp, cx)
46 });
47 cx.add_action(|this: &mut Editor, _: &HalfPageDown, cx| {
48 this.scroll_screen(&ScrollAmount::HalfPageDown, cx)
49 });
50 cx.add_action(|this: &mut Editor, _: &HalfPageUp, cx| {
51 this.scroll_screen(&ScrollAmount::HalfPageUp, cx)
52 });
53 cx.add_action(|this: &mut Editor, _: &PageDown, cx| {
54 this.scroll_screen(&ScrollAmount::PageDown, cx)
55 });
56 cx.add_action(|this: &mut Editor, _: &PageUp, cx| {
57 this.scroll_screen(&ScrollAmount::PageUp, cx)
58 });
59}
60
61impl Editor {
62 pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) -> Option<()> {
63 if self.take_rename(true, cx).is_some() {
64 return None;
65 }
66
67 if self.mouse_context_menu.read(cx).visible() {
68 return None;
69 }
70
71 if matches!(self.mode, EditorMode::SingleLine) {
72 cx.propagate_action();
73 return None;
74 }
75 self.request_autoscroll(Autoscroll::Next, cx);
76 Some(())
77 }
78
79 fn scroll(&mut self, action: &Scroll, cx: &mut ViewContext<Self>) {
80 self.scroll_manager.update_ongoing_scroll(action.axis);
81 self.set_scroll_position(action.scroll_position, cx);
82 }
83
84 fn scroll_cursor_top(editor: &mut Editor, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
85 let snapshot = editor.snapshot(cx).display_snapshot;
86 let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
87
88 let mut new_screen_top = editor.selections.newest_display(cx).head();
89 *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
90 *new_screen_top.column_mut() = 0;
91 let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
92 let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
93
94 editor.set_scroll_anchor(
95 ScrollAnchor {
96 top_anchor: new_anchor,
97 offset: Default::default(),
98 },
99 cx,
100 )
101 }
102
103 fn scroll_cursor_center(
104 editor: &mut Editor,
105 _: &ScrollCursorCenter,
106 cx: &mut ViewContext<Editor>,
107 ) {
108 let snapshot = editor.snapshot(cx).display_snapshot;
109 let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
110 visible_rows as u32
111 } else {
112 return;
113 };
114
115 let mut new_screen_top = editor.selections.newest_display(cx).head();
116 *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
117 *new_screen_top.column_mut() = 0;
118 let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
119 let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
120
121 editor.set_scroll_anchor(
122 ScrollAnchor {
123 top_anchor: new_anchor,
124 offset: Default::default(),
125 },
126 cx,
127 )
128 }
129
130 fn scroll_cursor_bottom(
131 editor: &mut Editor,
132 _: &ScrollCursorBottom,
133 cx: &mut ViewContext<Editor>,
134 ) {
135 let snapshot = editor.snapshot(cx).display_snapshot;
136 let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
137 let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
138 visible_rows as u32
139 } else {
140 return;
141 };
142
143 let mut new_screen_top = editor.selections.newest_display(cx).head();
144 *new_screen_top.row_mut() = new_screen_top
145 .row()
146 .saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
147 *new_screen_top.column_mut() = 0;
148 let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
149 let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
150
151 editor.set_scroll_anchor(
152 ScrollAnchor {
153 top_anchor: new_anchor,
154 offset: Default::default(),
155 },
156 cx,
157 )
158 }
159}