markdown_preview: Add ScrollToTop and ScrollToBottom actions (#50460)

Add `gg`/`G` (vim), `cmd-up`/`cmd-down` (macOS), and
`ctrl-home`/`ctrl-end` (Linux/Windows) keybindings to scroll to the top
and bottom of the markdown preview.

The markdown preview already has page scroll (`ctrl-d`/`ctrl-u`), line
scroll (`ctrl-e`/`ctrl-y`), and item scroll (`alt-up`/`alt-down`) but
was missing top/bottom navigation. This adds two new actions —
`ScrollToTop` and `ScrollToBottom` — using the existing
`ListState::scroll_to()` infrastructure, following the same pattern as
the other scroll actions.

- [x] Done a self-review taking into account security and performance
aspects

Release Notes:

- Added scroll-to-top and scroll-to-bottom keybindings for markdown
preview (`gg`/`G` in vim mode, `cmd-up`/`cmd-down` on macOS,
`ctrl-home`/`ctrl-end` on Linux/Windows)
This commit is contained in:
andrew j authored and GitHub committed 2026-03-17 11:55:48 +02:00
1 parent 5eb4d334f2
commit 4e9ffa3ee1
6 files changed
+40 -2

No files matched your search

+2
View File
@@ -1234,6 +1234,8 @@
"down": "markdown::ScrollDown",
"alt-up": "markdown::ScrollUpByItem",
"alt-down": "markdown::ScrollDownByItem",
"ctrl-home": "markdown::ScrollToTop",
"ctrl-end": "markdown::ScrollToBottom",
},
},
{
+2
View File
@@ -1340,6 +1340,8 @@
"down": "markdown::ScrollDown",
"alt-up": "markdown::ScrollUpByItem",
"alt-down": "markdown::ScrollDownByItem",
"cmd-up": "markdown::ScrollToTop",
"cmd-down": "markdown::ScrollToBottom",
},
},
{
+2
View File
@@ -1263,6 +1263,8 @@
"down": "markdown::ScrollDown",
"alt-up": "markdown::ScrollUpByItem",
"alt-down": "markdown::ScrollDownByItem",
"ctrl-home": "markdown::ScrollToTop",
"ctrl-end": "markdown::ScrollToBottom",
},
},
{
+2
View File
@@ -1100,6 +1100,8 @@
"ctrl-d": "markdown::ScrollPageDown",
"ctrl-y": "markdown::ScrollUp",
"ctrl-e": "markdown::ScrollDown",
"g g": "markdown::ScrollToTop",
"shift-g": "markdown::ScrollToBottom",
},
},
{
@@ -26,6 +26,10 @@ actions!(
ScrollUpByItem,
/// Scrolls down by one markdown element in the markdown preview
ScrollDownByItem,
/// Scrolls to the top of the markdown preview.
ScrollToTop,
/// Scrolls to the bottom of the markdown preview.
ScrollToBottom,
/// Opens a following markdown preview that syncs with the editor.
OpenFollowingPreview
]
@@ -8,7 +8,7 @@ use editor::scroll::Autoscroll;
use editor::{Editor, EditorEvent, MultiBufferOffset, SelectionEffects};
use gpui::{
App, ClickEvent, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
IntoElement, IsZero, ListState, ParentElement, Render, RetainAllImageCache, Styled,
IntoElement, IsZero, ListOffset, ListState, ParentElement, Render, RetainAllImageCache, Styled,
Subscription, Task, WeakEntity, Window, list,
};
use language::LanguageRegistry;
@@ -26,7 +26,7 @@ use crate::{
markdown_parser::parse_markdown,
markdown_renderer::{RenderContext, render_markdown_block},
};
use crate::{ScrollDown, ScrollDownByItem, ScrollUp, ScrollUpByItem};
use crate::{ScrollDown, ScrollDownByItem, ScrollToBottom, ScrollToTop, ScrollUp, ScrollUpByItem};
const REPARSE_DEBOUNCE: Duration = Duration::from_millis(200);
@@ -511,6 +511,30 @@ impl MarkdownPreviewView {
}
cx.notify();
}
fn scroll_to_top(&mut self, _: &ScrollToTop, _window: &mut Window, cx: &mut Context<Self>) {
self.list_state.scroll_to(ListOffset {
item_ix: 0,
offset_in_item: px(0.),
});
cx.notify();
}
fn scroll_to_bottom(
&mut self,
_: &ScrollToBottom,
_window: &mut Window,
cx: &mut Context<Self>,
) {
let count = self.list_state.item_count();
if count > 0 {
self.list_state.scroll_to(ListOffset {
item_ix: count - 1,
offset_in_item: px(0.),
});
}
cx.notify();
}
}
impl Focusable for MarkdownPreviewView {
@@ -562,6 +586,8 @@ impl Render for MarkdownPreviewView {
.on_action(cx.listener(MarkdownPreviewView::scroll_down))
.on_action(cx.listener(MarkdownPreviewView::scroll_up_by_item))
.on_action(cx.listener(MarkdownPreviewView::scroll_down_by_item))
.on_action(cx.listener(MarkdownPreviewView::scroll_to_top))
.on_action(cx.listener(MarkdownPreviewView::scroll_to_bottom))
.size_full()
.bg(cx.theme().colors().editor_background)
.p_4()