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