Skip to content

Global entry-name search across data sources - #8

Merged
ww-mw merged 10 commits into
mainfrom
feature/global-search-data-sources
Aug 14, 2026
Merged

Global entry-name search across data sources#8
ww-mw merged 10 commits into
mainfrom
feature/global-search-data-sources

Conversation

@ww-mw

@ww-mw ww-mw commented Aug 14, 2026

Copy link
Copy Markdown
Member

Adds a workspace-wide search over entry names inside data sources (dictionary/MAT variables, model-workspace params, block names) — distinct from the built-in Search panel (file names) and each table's in-tab search (cell values). Picking a result opens the owning source and selects the matching row.

Feature

  • Standalone name index (nameIndex.ts + pure nameExtract.ts): a complete, dup-preserving, per-file-bucketed index built independently of the relationship/usage graph, name-only extraction (.sldd JSON+zip, .mat, full .slx parse for block→param), lazy+cached, incrementally synced on create/change/delete/live-edit.
  • QuickPick overlay (searchSources.ts + pure searchFilter.ts): VS Code's native QuickPick. Starts empty and filters on type (case-insensitive substring on name or source label, capped at 500) rather than dumping the whole index into the un-virtualized list.
  • Triggers: search icon in the Data Explorer tree title bar, Command Palette, and Cmd+Alt+E / Ctrl+Alt+E (verified unbound against the bundled VS Code default keymap).

Fixes made along the way

  • Wire cross-tab row selection into the writable binary .sldd view (it was the one table provider missing it); extracted a shared drainNavigateSelect helper so a future view can't omit it.
  • Loading spinner now shows in all three table views, and only after a 500ms delay (no flash on fast opens).
  • Fixed a "Maximum call stack size exceeded" crash on data sources with tens of thousands of entries (push(...bucket) spread → nested loop).

Tests

  • Unit: nameExtract (11), filterEntries (6) — pure cores.
  • Integration: nameIndex.test.ts — builds the index from unopened fixtures across JSON/zip .sldd, preserves the cross-file dup.
  • Full suite: 1186 unit passing; integration green.

Known follow-up (not in this PR)

  • Row selection + scroll-into-view can miss on very large virtualized tables — under investigation in dex-tree-table.ts.

🤖 Generated with Claude Code

ww-mw and others added 10 commits August 14, 2026 14:16
Complete, dup-preserving index of entry names inside .sldd/.mat/.slx
sources, independent of the relationship and usage graphs. Pure
extractor (nameExtract.ts) split from vscode I/O (nameIndex.ts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
QuickPick overlay over the name index, reached via a search icon in the
Data Explorer tree title bar and the command palette. Picking an entry
opens its source and selects the row (reuses navigate.requestSelect).
Watcher + live-edit handlers keep the index in sync per file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Proves the eager, standalone name index end-to-end in a real VS Code:
builds a complete list from UNOPENED fixture files, spans JSON + zip .sldd,
and preserves the cross-file `structArray` duplicate. Pure extraction rules
stay unit-tested in test/nameExtract.test.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The writable compressed-binary .sldd editor (BinarySlddEditorProvider) was the
one table provider missing the navigate-select wiring the other two have, so a
global-search / Usage-link click opened the tab but never selected the target
row. Mirror BinaryEditorProvider: drain consumePendingSelect() on first paint
(just-opened case) and subscribe wireNavigateSelect() for live navigations to an
already-open view, disposing it on teardown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
All three table providers had their own copy of the first-paint "drain the
pending cross-tab selection" logic (BinaryEditorProvider even wrapped it in a
local closure). Hoist it into navigate.ts as drainNavigateSelect(webview, uri),
have wireNavigateSelect reuse it for the live case, and make consumePendingSelect
module-private now that it has no external callers. No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A discoverable shortcut alongside the tree title-bar search icon. Uses the
Cmd/Ctrl+K G chord, which is unbound in VS Code's defaults (verified against a
clean profile) so it overrides no built-in. Global (no when clause) to match the
workspace-wide scope of the search.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cmd+K is VS Code's chord leader, so Cmd+K <key> bindings shadow / race with
built-in chords. Switch to a leaderless single combo. Verified Cmd+Alt+E is
unbound on all platforms by decoding the default keymap from the bundled VS Code
1.133.0 build (Cmd+Alt+F is Replace, Cmd+Alt+S is taken, Cmd+Alt+G is mac-only —
E is free everywhere and mnemonic for "Entries").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The loading overlay lived only in BinaryEditorProvider, so opening a large
editable JSON .sldd (SlddTextEditorProvider) or compressed-binary .sldd
(BinarySlddEditorProvider) showed a blank table with no feedback during the
synchronous host parse. Hoist the overlay markup into a shared
LOADING_OVERLAY_HTML in webviewHtml.ts and include it in all three table views.

Also change the reveal to be delay-gated: the webview arms a 500ms timer at boot
and only shows the spinner if the first setRows/error hasn't arrived by then, so
a fast open never flashes a spinner. The webview renderer runs this timer
independently of the busy extension host, so the delay is honored during parse.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
listEntries flattened the per-file buckets with `out.push(...bucket)`. A single
data source can hold tens of thousands of entries, and spreading a large array
as call arguments overflows the engine's argument limit, throwing "Maximum call
stack size exceeded" — the search failed even though the file's table opened
fine (that path doesn't flatten the index). Append with a nested loop instead.

Verified: push(...bucket) throws on a 200k-element array; the loop does not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The QuickPick list has no virtual scrolling, so handing it the entire name index
(tens of thousands of entries for a large data source) made the overlay open and
filter sluggishly — the same length as the table, minus the table's virtual
scroll. Now the list starts empty and populates only as the user types: we
filter the in-memory index ourselves (case-insensitive substring on name or
source label) and show at most 500 matches, so a broad query is capped rather
than dumped.

Pure match/cap rule extracted to searchFilter.ts (vscode-free) and unit-tested,
mirroring the nameExtract.ts / nameIndex.ts split.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ww-mw
ww-mw merged commit b39949e into main Aug 14, 2026
1 check passed
@ww-mw
ww-mw deleted the feature/global-search-data-sources branch August 15, 2026 00:42
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.

1 participant