actions.rs

  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}