C14.8 r1: the outline scrolls in its pane

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-12 05:53:35 -04:00
1 parent 53ce8eec0b
commit 1539c3a018
6 files changed
+67 -9

No files matched your search

+2 -2
View File
@@ -40,7 +40,7 @@ pub struct Desk {
pub going: Option<(PathBuf, usize)>,
/// The path each tab last put in the recent list.
pub remembered: HashMap<u64, PathBuf>,
side: Entity<crate::side::Side>,
pub(crate) side: Entity<crate::side::Side>,
pub watcher: Option<notify::RecommendedWatcher>,
/// The folders the watcher covers.
pub watched: Vec<PathBuf>,
@@ -449,4 +449,4 @@ fn large_banner(
}
#[cfg(test)]
mod tests;
pub(crate) mod tests;
+2 -2
View File
@@ -7,7 +7,7 @@ use super::{Desk, open_in};
use crate::view::Mode;
/// ElyMark over a fresh data folder, as `main` opens it.
fn start(cx: &mut TestAppContext, data: &Path) -> (Entity<Desk>, &'static mut VisualTestContext) {
pub(crate) fn start(cx: &mut TestAppContext, data: &Path) -> (Entity<Desk>, &'static mut VisualTestContext) {
// The file watcher runs on a real thread.
cx.executor().allow_parking();
cx.update(ely_gpui_component::init_for_tests);
@@ -33,7 +33,7 @@ fn start(cx: &mut TestAppContext, data: &Path) -> (Entity<Desk>, &'static mut Vi
(desk, cx)
}
fn open(desk: &Entity<Desk>, path: &Path, cx: &mut VisualTestContext) {
pub(crate) fn open(desk: &Entity<Desk>, path: &Path, cx: &mut VisualTestContext) {
desk.update(cx, |desk, cx| desk.open_path(path.to_path_buf(), cx));
cx.run_until_parked();
}
+12 -4
View File
@@ -6,6 +6,7 @@ use ely_gpui_component::{
buttons::{Button, SegmentedControl},
feedback::EmptyState,
forms::{InputEvent, SearchInput, TextInput},
layout::ScrollArea,
lists::{FileTree, ListItem, Outline, SelectableList},
primitives::IconName,
theme::ControlSize,
@@ -13,7 +14,8 @@ use ely_gpui_component::{
use ely_office::prelude::*;
use ely_ui::{commands, i18n::text};
use gpui::{
AnyElement, AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render,
AnyElement, AppContext as _, Context, Entity, InteractiveElement as _, IntoElement,
ParentElement as _, Render,
SharedString, Styled as _, WeakEntity, Window, div,
};
@@ -248,15 +250,18 @@ impl Side {
outline.item(at.to_string(), heading.title.clone(), heading.level)
},
);
outline
.on_select(move |key, window, cx| {
let outline = outline.on_select(move |key, window, cx| {
let Some(heading) = key.parse::<usize>().ok().and_then(|at| headings.get(at)) else {
return log::error!("mark: the outline chose no heading");
};
// The heading in view, the caret on it.
let line = heading.line;
view.update(cx, |view, cx| view.reveal(line, window, cx));
})
});
ScrollArea::new("mark-outline-scroll")
.vertical()
.size_full()
.child(div().debug_selector(|| "mark-outline".into()).child(outline))
.into_any_element()
}
@@ -374,3 +379,6 @@ impl Render for Side {
.into_any_element()
}
}
#[cfg(test)]
mod tests;
+47
View File
@@ -0,0 +1,47 @@
use gpui::{ScrollDelta, ScrollWheelEvent, TestAppContext, point, px};
use super::Pane;
use crate::desk::tests::{open, start};
#[gpui::test]
fn a_long_outline_scrolls_to_its_last_heading(cx: &mut TestAppContext) {
let (data, files) = (
tempfile::tempdir().expect("data"),
tempfile::tempdir().expect("files"),
);
let path = files.path().join("long.md");
let text: String = (0..100).map(|n| format!("# Heading {n}\n\n")).collect();
std::fs::write(&path, text).expect("a file");
let (desk, cx) = start(cx, data.path());
open(&desk, &path, cx);
let side = desk.read_with(cx, |desk, _| desk.side.clone());
side.update(cx, |side, cx| {
side.pane = Pane::Outline;
cx.notify();
});
cx.run_until_parked();
let before = cx
.debug_bounds("mark-outline")
.expect("the outline is drawn");
let window = cx.update(|window, _| window.viewport_size());
assert!(
before.bottom() > window.height,
"the outline is longer than the window"
);
let at = point(before.left() + px(20.0), px(300.0));
for _ in 0..20 {
cx.simulate_event(ScrollWheelEvent {
position: at,
delta: ScrollDelta::Pixels(point(px(0.0), px(-1000.0))),
..Default::default()
});
cx.run_until_parked();
}
let after = cx
.debug_bounds("mark-outline")
.expect("the outline is drawn");
assert!(
after.bottom() <= window.height,
"the last heading is in view: {after:?}"
);
}