GeezerVison is showing github.com — Cache the JSON tree per tab instead of drawing it on tab switch by leoshone · Pull Request #253 · NPP-JSONViewer/JSON-Viewer
Conversation
leoshone
commented
Sep 3, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Problem
With Follow current tab disabled (the default), the plugin neither follows
the active tab nor clears the tree. The tree keeps showing whichever document
happened to be parsed last, with nothing indicating that it belongs to a
different tab. Reproduce:
- Open
a.json, press Refresh JSON Tree.
- Switch to
b.json — the tree still shows a.json.
- Switch back — no way to tell which document the tree belongs to.
Enabling the option instead parses on every tab switch, which is not always
wanted either (large files, and it re-parses even when the user only wanted a
look at the tree of one tab).
Change
The tree is now drawn only when the user asks for it (Refresh JSON Tree).
Switching tabs stores the tree of the tab being left and puts it back verbatim
when that tab comes back, so:
- no re-parsing happens on tab switch, and
- expansion state and selection survive.
The "Follow current tab" option is kept and behaves exactly as before when it
is enabled — the document of the activated tab is parsed immediately. Only its
off path changes, from "do nothing" to "remember per tab". Users who rely on
the follow behaviour are unaffected, and no visible setting is removed.
Details:
- Snapshots live in memory only. They are dropped when the buffer is closed,
together with the association to the current buffer (Notepad++ does not
guarantee whether NPPN_FILECLOSED or NPPN_BUFFERACTIVATED arrives first).
- Auto format on open now formats the document without drawing the tree
(FormatJsonDocument() is FormatJson() minus the redraw), so opening a file
can no longer trigger a parse.
- Formatting now redraws the tree while preserving its expansion state, which
keeps it consistent with Refresh (see Keep the tree expansion state when refreshing the JSON tree #252).
- New
TreeState model (nodes + expansion + selection) next to the
TreeExpansion helpers. TreeExpansion is the "same document, tree rebuilt"
case; TreeState is the "whole tree carried across tabs" case.
Optional: draw the tree when a json file is opened
"Never parse on its own" is the right default, but it also means a user who
wants the tree right away has to press Refresh on every file. A new option,
Draw tree when a json file is opened (DRAW_ON_OPEN, off by default),
draws the tree once when a json document is opened.
It is deliberately built on top of the snapshot mechanism rather than next to
it: the check lives in RestoreTabState(), the single place reached when the
tree of a tab has never been drawn. So the document is parsed exactly once, and
from then on the tab behaves like any other — switching back replays the stored
snapshot and does not parse again. Opening a file, switching back to a tab and
showing the panel are all covered by that one code path.
Two details worth reviewing:
- The tree is drawn for documents whose language is JSON, the same criterion
the existing Follow current tab uses.
- Drawing on open is initiated by the plugin, not by the user, so a parse
failure must not stop the user with a dialog. DrawJsonTree() takes a
bSilent flag for that and reports the failure as a node inside the tree
instead. Manual Refresh is unchanged and still reports errors as before.
Note on the diff
This branch is built on top of #252 (TreeExpansion.h/.cpp), so its diff
currently includes that PR as well. The change specific to this PR is
+602/-28 over 17 files; the total against master is +1073/-31 over 20
files. If #252 is merged first, this PR collapses to its own commits.
Verification
- Unit tests: 167/167 (143 pre-existing, 14 from Keep the tree expansion state when refreshing the JSON tree #252, 9
TreeStateTest
cases for snapshot capture/compare, 1 ProfileTest round-trip for the new
setting).
- Fork CI: all six jobs green (Debug/Release × Win32/x64/ARM64).
- Manual end-to-end on a portable Notepad++ x64 build, driven through
SendMessage (this host runs non-interactively, so no keyboard injection):
- 21/21 assertions for the per-tab caching, including the decisive one —
after rewriting the document behind the tab's back, switching away and back
still shows the old snapshot, and only an explicit Refresh picks up the
new text. That distinguishes "replay a snapshot" from "re-parse quietly".
- 20/20 assertions for draw tree on open: a json file is drawn without
pressing Refresh; a second file gets its own tree; switching back shows the
right document; after the document is changed behind the plugin's back the
stale snapshot is kept (no re-parse); a new non-json file is not parsed;
Refresh still re-reads; with the option off nothing is drawn and manual
Refresh still works; and a malformed json file reports the error inside
the tree with no modal dialog, leaving Notepad++ responsive.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
"Refresh JSON Tree" rebuilds every node, so the tree always came back
fully collapsed - even when the user only wanted to re-read a document
they were already looking at.
Capture which nodes are expanded and which one is selected before the
tree is thrown away, then re-apply that state onto the freshly built
tree, matching nodes by path. Paths that no longer exist (the document
changed in the meantime) are silently dropped, and nodes that are new
stay collapsed.
The state is keyed by node path, which is the list of keys from the
tree root down to a node. The pure path arithmetic lives in the new
TreeExpansion.h/.cpp so it can be unit tested without a window.
DrawJsonTree() gained a bPreserveExpansion parameter that defaults to
false, so every other caller (panel opening, formatting, compressing,
sorting) keeps behaving exactly as before; only the refresh button
opts in.
When "Follow current tab" is off (the default) the plugin never drew the
tree on its own, but it also never cleared it: the tree kept showing the
document of some earlier tab, with no indication that it belonged there.
With this change the tree is only ever drawn when the user asks for it
("Refresh JSON Tree"). Switching tabs stores the tree of the tab being
left and puts it back verbatim when the tab is activated again, so no
re-parsing happens and the expansion state and selection survive.
The "Follow current tab" option is kept and behaves exactly as before
when enabled: the document of the activated tab is parsed immediately.
Only its "off" path changes, from "do nothing" to "remember per tab".
Notes:
- Snapshots live in memory only and are dropped when the buffer is
closed, together with the association to the current buffer.
- "Auto format on open" now formats the document without drawing the
tree, so opening a file still cannot trigger a parse.
- Formatting now redraws the tree while preserving its expansion state,
which keeps it consistent with Refresh.
- Built on top of the TreeExpansion helpers introduced for Refresh.
Adds an option, off by default, that draws the tree of a json document as soon as the file is opened. It complements the per-tab snapshot caching: the document is parsed exactly once, and switching back to the tab afterwards replays the stored snapshot instead of parsing again.
The check lives in RestoreTabState(), the single place reached when the tree of a tab has never been drawn, so opening a file, switching back to a tab and showing the panel are all covered by one code path.
Drawing on open is initiated by the plugin, not by the user, so parse errors are reported as a node inside the tree rather than through a modal dialog: DrawJsonTree() takes a bSilent flag for that.
The tree is drawn for documents whose language is JSON, the same criterion the existing "follow current tab" uses.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|