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