Vectrum
Sign In

Jump to the revealing row when a searched row is hidden

Searching for a row that only shows with another setting, such as the
days before auto-settle or the branch prefix, now lands on the setting
that reveals it instead of the top of the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JjohannSocommitted 1 parent 29cc77ecommit511a677

Showing 3 changed files with 37 additions and 5 deletions.

+1−0src/ui/settings/keybindings.rsView File
@@ -87,6 +87,7 @@ pub(super) fn search_items() -> impl Iterator<Item = Item> {
8787 terms: id,
8888 fold: None,
8989 secondary: true,
90+ fallback: None,
9091 })
9192 }
9293
+11−0src/ui/settings/mod.rsView File
@@ -132,6 +132,8 @@ pub struct SettingsView {
132132 active_result: usize,
133133 scroll: ScrollHandle,
134134 jumps: usize,
135+ /// Where the running jump goes if its row isn't shown.
136+ jump_fallback: Option<&'static str>,
135137 /// Folded sections the user opened.
136138 open_folds: HashSet<&'static str>,
137139 add_project_dir: Entity<InputState>,
@@ -212,6 +214,7 @@ impl SettingsView {
212214 active_result: 0,
213215 scroll: ScrollHandle::new(),
214216 jumps: 0,
217+ jump_fallback: None,
215218 open_folds: HashSet::new(),
216219 add_project_dir,
217220 branch_prefix,
@@ -312,6 +315,7 @@ impl SettingsView {
312315 self.jumps += 1;
313316 cx.set_global(Target { id: item.id, generation: self.jumps, bounds: Rc::new(Cell::new(None)) });
314317 self.focus_handle.focus(window, cx);
318+ self.jump_fallback = item.fallback;
315319 self.scroll_to_target(0, window, cx);
316320 // Let the pulse play out, then forget the target so it doesn't
317321 // pulse again when its page is opened later.
@@ -336,6 +340,13 @@ impl SettingsView {
336340 if attempt < 6 {
337341 let _ = view.update(cx, |view, cx| view.scroll_to_target(attempt + 1, window, cx));
338342 window.refresh();
343+ } else if let Some(fallback) = view.update(cx, |view, _| view.jump_fallback.take()).ok().flatten()
344+ && let Some(generation) = cx.try_global::<Target>().map(|target| target.generation)
345+ {
346+ // The row isn't shown; aim for the one that reveals it.
347+ cx.set_global(Target { id: fallback, generation, bounds: Rc::new(Cell::new(None)) });
348+ let _ = view.update(cx, |view, cx| view.scroll_to_target(0, window, cx));
349+ window.refresh();
339350 }
340351 return;
341352 };
+25−5src/ui/settings/search.rsView File
@@ -16,14 +16,22 @@ pub struct Item {
1616 pub fold: Option<&'static str>,
1717 /// Sorts after every other match, like keybinding commands.
1818 pub secondary: bool,
19+ /// Where to jump instead when the row isn't shown, such as a row only
20+ /// one choice of another reveals.
21+ pub fallback: Option<&'static str>,
1922 }
2023
2124 const fn item(id: &'static str, title: &'static str, page: Page, terms: &'static str) -> Item {
22- Item { id, title, page, terms, fold: None, secondary: false }
25+ Item { id, title, page, terms, fold: None, secondary: false, fallback: None }
26+ }
27+
28+ /// A row that's only shown sometimes; the jump falls back to `fallback`.
29+ const fn revealed(id: &'static str, title: &'static str, page: Page, terms: &'static str, fallback: &'static str) -> Item {
30+ Item { id, title, page, terms, fold: None, secondary: false, fallback: Some(fallback) }
2331 }
2432
2533 const fn folded(id: &'static str, title: &'static str, page: Page, terms: &'static str, fold: &'static str) -> Item {
26- Item { id, title, page, terms, fold: Some(fold), secondary: false }
34+ Item { id, title, page, terms, fold: Some(fold), secondary: false, fallback: None }
2735 }
2836
2937 /// Searchable settings, in result order.
@@ -50,7 +58,13 @@ pub const ITEMS: &[Item] = &[
5058 item("working-shelf", "Working section (beta)", Page::General, "hide fold running monitoring threads inbox sidebar shelf"),
5159 item("auto-settle-inactive-threads", "Auto-settle inactive threads", Page::General, "sidebar inactivity days no activity automatically"),
5260 item("auto-settle-merged-threads", "Auto-settle merged threads", Page::General, "pull request merge closed automatically sidebar"),
53- item("days-before-auto-settle", "Days of inactivity before auto-settle", Page::General, "thread timeout activity sidebar"),
61+ revealed(
62+ "days-before-auto-settle",
63+ "Days of inactivity before auto-settle",
64+ Page::General,
65+ "thread timeout activity sidebar",
66+ "auto-settle-inactive-threads",
67+ ),
5468 item("thread-notifications", "Thread notifications", Page::General, "notification sound alert completion input approval desktop"),
5569 item("in-app-notifications", "In-app notifications", Page::General, "notification toast popup completion input approval failure"),
5670 item("time-format", "Time format", Page::General, "timestamp clock locale system os 12 hour 24 hour"),
@@ -102,8 +116,14 @@ pub const ITEMS: &[Item] = &[
102116 item("open-in", "Open in", Page::Integrations, "editor zed vs code cursor vscodium sublime kate file manager"),
103117 item("source-control", "Source control", Page::SourceControl, "version control git github hosting integrations credentials gh"),
104118 item("worktree-branch-naming", "Worktree branch naming", Page::SourceControl, "static semantic prefix custom prompt instructions feat fix refactor chore"),
105- item("branch-prefix", "Branch prefix", Page::SourceControl, "worktree branch name prefix vectrum"),
106- item("branch-naming-instructions", "Branch naming instructions", Page::SourceControl, "worktree branch custom prompt model"),
119+ revealed("branch-prefix", "Branch prefix", Page::SourceControl, "worktree branch name prefix vectrum", "worktree-branch-naming"),
120+ revealed(
121+ "branch-naming-instructions",
122+ "Branch naming instructions",
123+ Page::SourceControl,
124+ "worktree branch custom prompt model",
125+ "worktree-branch-naming",
126+ ),
107127 item(
108128 "connections-environment",
109129 "This machine",