Skip to content

ENG-2273 Scroll to and highlight the matched line when previewing a tagged result - #1490

Merged
trangdoan982 merged 4 commits into
mainfrom
eng-2273-scroll-to-and-highlight-the-matched-line-when-previewing-a
Sep 30, 2026
Merged

trangdoan982 merged 4 commits into
mainfrom
eng-2273-scroll-to-and-highlight-the-matched-line-when-previewing-a

Conversation

@trangdoan982

@trangdoan982 trangdoan982 commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

https://entire.io/gh/DiscourseGraphs/discourse-graph/trails/30

Reviewer brief

Stacked on #1489 (ENG-2272). Merge that first; this PR targets its branch.

  • Result: Selecting a candidate result scrolls the preview to its tagged line and highlights it for about 3 s.
  • Review focus: How the preview finds the tagged line. The ticket's Solution proposes matching sanitized text against rendered blocks. This PR uses the line number the candidate already carries instead:
    • MarkdownRenderer.render has no source-line-to-DOM mapping.
    • It does emit one top-level element per metadataCache section, in order. I checked this live in Obsidian 1.13.7.
    • locateTaggedLine maps the line to a section index, then to a list item or table row.
    • Text matching is only a fallback. It runs when the cache's section offsets no longer line up with the loaded text (a stale cache), or when the rendered block count doesn't match. It prefers a single exact match, then a single element containing the line's text, and it covers table rows. Ambiguous matches select nothing, which avoids the substring misses that Devin flagged on ENG-2273 Scroll to and highlight the matched line when previewing a tagged result #1449.
  • Risk or follow-up:
    • When the target is a list item with nested items, the nested items flash too. The right item is still at the top of the highlight.
    • Clicking a result before the 250 ms search debounce settles can drop the highlight. When the new results arrive, the modal's existing selection handling briefly moves the active result to another note. That predates this change, so it's out of scope here.
flowchart TD
  A["Candidate selected<br/>(file, tagLine.line)"] --> B["PreviewPane render effect<br/>MarkdownRenderer.render + waitForImages"]
  B --> C["Scroll effect, keyed on renderedFile + line<br/>(same-note switch doesn't re-render)"]
  C --> D["locateTaggedLine(sections, listItems, line)<br/>taggedLineLocator.ts"]
  D --> E{"Cache offsets match the text<br/>and block/item counts match?"}
  E -- yes --> F["container.children[blockIndex]<br/>→ Nth li / tr"]
  E -- no --> G["Fallback: unique exact, then unique containing<br/>match on renderedLineText (p, li, h*, tr)"]
  F --> H["scrollIntoView center<br/>+ .dg-search-preview-flash"]
  G --> H
  G -- "none or several" --> I["scrollTop = 0"]
Loading

The diagram shows how a candidate's source line becomes a scroll target in apps/obsidian/src/utils/taggedLineLocator.ts.

Verification
  • pnpm ci:validate passes on the final head.
  • Unit tests: 14 new, in apps/obsidian/src/utils/__tests__/taggedLineLocator.test.ts. They cover locateTaggedLine and renderedLineText. To rerun: pnpm -C apps/obsidian test:unit.
  • Live checks: I drove Obsidian over CDP in a test vault using the dg-obsidian-cdp-verify skill. All 19 scenarios pass on the final tree.
Scenario Input Expected Actual Pass
Paragraph Tagged paragraph line far down the note That p centered and flashed P, scrollTop 1589, flashed ✅
List line Tagged list item That li LI, 3349 ✅
Heading Tagged ## heading, first result That h2 H2, 5113 ✅
Multi-line paragraph Tagged line inside a soft-wrapped paragraph The whole p P, 1965 ✅
Nested item Tagged level-2 list item The innermost li, not its parent LI "level2 B", 2112 ✅
Continuation line Tag on a list item's continuation line The item that owns the line LI "level3 C", 2122 ✅
Table row Tagged table body row That tr TR, 2635 ✅
Callout Tagged callout line The callout DIV.callout, 2424 ✅
Formatted line [[link|alias]], **bold**, _italic_, `code` That p P, 3290 ✅
Same-note switch Two candidates in one note Re-scrolls without re-rendering 2112 → 3290, DOM kept ✅
Node result A node after a candidate in the same note Back to top, no flash 1900 → 0 ✅
Text fallback Extra block injected, so counts mismatch Unique text match still found LI 2147, P 3325 ✅
Highlight clears Wait 3.5 s Class removed Gone at 3506 ms ✅
Unlocatable line Tag in a footnote definition, after a scrolled candidate Back to top, no flash 3290 → 0 ✅
Cache offsets line up Sections of both fixture notes vs. file text Section index used, not the fallback 99 and 174 sections line up ✅
Fallback: table row Extra block injected, table-row candidate That tr TR ✅
Fallback: multi-line paragraph Extra block injected, one line of a paragraph The whole p P ✅
File-switch race Candidate in note A, then one in note B No flash on A while B loads None on A; B scrolled and flashed ✅

Screenshots, one per scenario:

Scenario Screenshot
Paragraph candidate Paragraph candidate
List line candidate List line candidate
Heading candidate (auto-active) Heading candidate (auto-active)
Line inside a multi-line paragraph Line inside a multi-line paragraph
Nested level-2 list item Nested level-2 list item
List continuation line List continuation line
Table row Table row
Callout Callout
Formatted line (alias, bold, code) Formatted line (alias, bold, code)
Same-note switch re-scrolls without re-render Same-note switch re-scrolls without re-render
Node result resets to top Node result resets to top
Text fallback on block-count mismatch Text fallback on block-count mismatch
Highlight cleared after 3.5s Highlight cleared after 3.5s
Unlocatable line resets to top Unlocatable line resets to top
Cache offsets line up (section index used) Cache offsets line up (section index used)
Fallback: table row Fallback: table row
Fallback: multi-line paragraph Fallback: multi-line paragraph
File-switch race: no flash on old note File-switch race: no flash on old note

Not verified:

  • Mobile.
  • Themes other than the default. The flash uses --text-highlight-bg.
  • A stale metadata cache triggered through a real edit race. The fallback was tested by injecting an extra block into the preview.
## Loom video

https://www.loom.com/edit/6cd21e7aa52941e8949b1ba6add92d9e

Scope check

  • Ran $scope-check against ENG-2273 and the final diff.
  • Scope beyond Done When: Results with no tagged line, and lines that can't be located, reset the preview to the top (scrollTop = 0).
  • Required now: This PR adds the scrolling. Without the reset, selecting a node or an unlocatable line in the same note would leave the preview mid-note.
  • Anyone affected or consulted: Not documented
  • Decision: Not documented

Standards check

  • Ran $dg-pr-adherence-check against the final diff and PR metadata.

Local delegated full review

  • Ran a comprehensive review of the entire final diff in a subagent with a fresh context. Use $dg-delegated-full-review when no other full-review workflow is available.

It found one low-severity issue: a line that couldn't be located kept the previous scroll position. That's fixed in e6715c0. Devin's three review findings are fixed in 12dfa6b.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
discourse-graph Skipped Skipped Sep 30, 2026 3:25pm UTC

Request Review

@supabase

supabase Bot commented Sep 27, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@linear-code

linear-code Bot commented Sep 27, 2026

Copy link
Copy Markdown

ENG-2273

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread apps/obsidian/src/utils/taggedLineLocator.ts
Comment thread apps/obsidian/src/utils/taggedLineLocator.ts Outdated
Comment thread apps/obsidian/src/components/NodeSearchModal.tsx Outdated
@trangdoan982
trangdoan982 added this pull request to stack #1496 September 28, 2026 15:07
@trangdoan982
trangdoan982 force-pushed the eng-2273-scroll-to-and-highlight-the-matched-line-when-previewing-a branch from 12dfa6b to 6eff267 Compare September 28, 2026 15:08
Base automatically changed from eng-2272-show-candidate-nodes-as-results-in-advanced-node-search to main September 30, 2026 15:22
trangdoan982 and others added 4 commits September 30, 2026 08:22
…agged result

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3J54Y422F140AV66BB5NYM8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3J5CM30EQJKV9EHB765CWV0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3J5KSWXQJWTYT3PWBJ2GQS2
…witch race

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3J6HQZKQ6DYSAAWQW3F5CAH
@trangdoan982
trangdoan982 force-pushed the eng-2273-scroll-to-and-highlight-the-matched-line-when-previewing-a branch from 6eff267 to 672317e Compare September 30, 2026 15:24
@trangdoan982
trangdoan982 merged commit 6182ddf into main Sep 30, 2026
9 checks passed
@trangdoan982
trangdoan982 deleted the eng-2273-scroll-to-and-highlight-the-matched-line-when-previewing-a branch September 30, 2026 16:40

This branch was previously deployed

1 inactive deployment
Preview — 672317e0 Deployed Sep 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants