1use super::Axis;
2use crate::{
3 Autoscroll, Editor, EditorMode, NextScreen, NextScrollCursorCenterTopBottom,
4 SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT, ScrollCursorBottom, ScrollCursorCenter,
5 ScrollCursorCenterTopBottom, ScrollCursorTop, display_map::DisplayRow, scroll::ScrollOffset,
6};
7use gpui::{Context, Point, Window};
8
9impl Editor {
10 pub fn next_screen(&mut self, _: &NextScreen, window: &mut Window, cx: &mut Context<Editor>) {
11 if self.take_rename(true, window, cx).is_some() {
12 return;
13 }
14
15 if self.mouse_context_menu.is_some() {
16 return;
17 }
18
19 if matches!(self.mode, EditorMode::SingleLine) {
20 cx.propagate();
21 return;
22 }
23 self.request_autoscroll(Autoscroll::Next, cx);
24 }
25
26 pub fn scroll(
27 &mut self,
28 scroll_position: Point<ScrollOffset>,
29 axis: Option<Axis>,
30 window: &mut Window,
31 cx: &mut Context<Self>,
32 ) {
33 self.scroll_manager.update_ongoing_scroll(axis);
34 self.set_scroll_position(scroll_position, window, cx);
35 }
36
37 pub fn scroll_cursor_center_top_bottom(
38 &mut self,
39 _: &ScrollCursorCenterTopBottom,
40 window: &mut Window,
41 cx: &mut Context<Self>,
42 ) {
43 match self.next_scroll_position {
44 NextScrollCursorCenterTopBottom::Center => {
45 self.scroll_cursor_center(&Default::default(), window, cx);
46 }
47 NextScrollCursorCenterTopBottom::Top => {
48 self.scroll_cursor_top(&Default::default(), window, cx);
49 }
50 NextScrollCursorCenterTopBottom::Bottom => {
51 self.scroll_cursor_bottom(&Default::default(), window, cx);
52 }
53 }
54
55 self.next_scroll_position = self.next_scroll_position.next();
56 self._scroll_cursor_center_top_bottom_task = cx.spawn(async move |editor, cx| {
57 cx.background_executor()
58 .timer(SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT)
59 .await;
60 editor
61 .update(cx, |editor, _| {
62 editor.next_scroll_position = NextScrollCursorCenterTopBottom::default();
63 })
64 .ok();
65 });
66 }
67
68 pub fn scroll_cursor_top(
69 &mut self,
70 _: &ScrollCursorTop,
71 window: &mut Window,
72 cx: &mut Context<Editor>,
73 ) {
74 let display_snapshot = self.display_snapshot(cx);
75 let scroll_margin_rows = self.vertical_scroll_margin() as u32;
76 let selection_head = self.selections.newest_display(&display_snapshot).head();
77
78 let sticky_headers_len =
79 self.visible_sticky_header_count_for_point(&display_snapshot, selection_head, cx)
80 as u32;
81
82 let new_screen_top = selection_head.row().0;
83 let header_offset = display_snapshot
84 .buffer_snapshot()
85 .show_headers()
86 .then(|| display_snapshot.buffer_header_height())
87 .unwrap_or(0);
88
89 // If the number of sticky headers exceeds the vertical_scroll_margin,
90 // we need to adjust the scroll top a bit further
91 let adjustment = scroll_margin_rows.max(sticky_headers_len) + header_offset;
92 let new_screen_top = new_screen_top.saturating_sub(adjustment);
93 self.set_scroll_top_row(DisplayRow(new_screen_top), window, cx);
94 }
95
96 pub fn scroll_cursor_center(
97 &mut self,
98 _: &ScrollCursorCenter,
99 window: &mut Window,
100 cx: &mut Context<Editor>,
101 ) {
102 let Some(visible_rows) = self.visible_line_count().map(|count| count as u32) else {
103 return;
104 };
105 let new_screen_top = self
106 .selections
107 .newest_display(&self.display_snapshot(cx))
108 .head()
109 .row()
110 .0;
111 let new_screen_top = new_screen_top.saturating_sub(visible_rows / 2);
112 self.set_scroll_top_row(DisplayRow(new_screen_top), window, cx);
113 }
114
115 pub fn scroll_cursor_bottom(
116 &mut self,
117 _: &ScrollCursorBottom,
118 window: &mut Window,
119 cx: &mut Context<Editor>,
120 ) {
121 let scroll_margin_rows = self.vertical_scroll_margin() as u32;
122 let Some(visible_rows) = self.visible_line_count().map(|count| count as u32) else {
123 return;
124 };
125 let new_screen_top = self
126 .selections
127 .newest_display(&self.display_snapshot(cx))
128 .head()
129 .row()
130 .0;
131 let new_screen_top =
132 new_screen_top.saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
133 self.set_scroll_top_row(DisplayRow(new_screen_top), window, cx);
134 }
135}