Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ GitHub Release.

Entries before this file existed were reconstructed from those release tags.

## [1.36.1] — 2026-10-03

The filter popup a column header opens now shows which comparison it is about to write, in every theme. The seven operator buttons mark the chosen one by painting its background, and that background came from a colour name the themes do not define — so instead of the colour, each button painted the pale blue literal written beside the name as a fallback, in all four themes at once. On a dark theme that is a pale blue tile under near-white text, 1.22:1 against its own glyph; on High Contrast Black, 1.31:1. The one element in the popup that says whether Apply will write `contains` or `≥` was the one element a dark-theme user could not read, and nothing anywhere reported a problem, because a colour name nothing declares is not a missing colour but a silent one — every reader of it quietly takes its own fallback. All four themes now measure past 7:1. The value is not a new choice: the extension already defines the colour it uses for a selected surface, mapped onto the one VS Code paints selections with, and the literal that had been shipping was that same colour with one digit changed — a misspelled name rather than a design. The `writes:` line beside it, which shows the literal text to retype into the search box, was reading a font name that is also undefined and so ignored the font you actually type code in; it now follows `editor.fontFamily` like the rest of the extension's monospace. High-contrast forced-colors mode was never affected and still marks the chosen operator with a system-colour outline. The underlying mistake is now caught by a test rather than by a customer: every theme colour this popup asks for must be one the themes define, so a name invented by accident fails in the test suite instead of going quiet in a theme nobody opened.

## [1.36.0] — 2026-10-02

A file too large to show whole now lists every entry it has and loads a row's contents when that row is opened, where before it hung with no table and no message. Reported against an 8 MB `allMidi.mat` — a cell array of MIDI songs — which "keeps spinning" and never opens: it flattens to 2,016,325 nodes over 7 levels, a row was built for every one of them, and the resulting `setRows` payload was 704 MiB of JSON. V8 cannot produce a string that long (the limit is 536,870,888), so `JSON.stringify` threw inside VS Code's own `postMessage`, which is `async` and serializes the message itself — the throw therefore arrived as a rejected promise that the `try`/`catch` around the post could not see, nothing posted `setRows`, nothing posted an error, and the table's spinner ended on nothing else. Three layers, because there were three faults. The post is now awaited and a rejection becomes the error banner, so an undeliverable payload can never again be silent. A hard cap of 100,000 rows sits in front of the read-only row payload — not a tuning knob but what keeps the payload serializable at all, sized for the worst row shape rather than the measured 366 B, and taken as a PREFIX because every builder emits a parent before its children and a prefix is the only cut in which every surviving row's parent is also present; a sample would leave orphans the webview cannot place. The editable `.sldd` views get the guard but not the cap, since a structural edit computed against a truncated row set is worse than an honest banner. And then the cap alone, which is where this version's real work is: a prefix of a 2-million-row pre-order traversal is the first cell's descendants and nothing else, so ten of the eleven top-level variables were not on screen and no gesture could reach them — the file opened and was still unusable. The rule now is breadth over depth, for every data source and every entry type: stop expanding large entries, but list all entries, because a name present matters more than a value shown. The payload is planned by whole LEVELS of the tree, level by level while the next one fits, and the first level that does not is omitted entirely rather than half-delivered — which is what makes a deferred row mean exactly "has children, none of them here" and makes one fetch the whole answer for that row. The reported file now delivers 238 rows, levels 1 through 4 complete, and paints them in 7 ms. One plan spans every section rather than one plan per section, and that is the half the rule actually turns on: a per-section plan would also deliver whole levels and also defer honestly while spending the budget on the depth of section 1 and leaving section 9's entries unnamed, so a dictionary's References heading would read as empty on a file whose Design Data is deep. Opening a deferred row fetches it: the twisty is driven by the deferred mark as well as by delivered children — through one predicate read by the click, the Space key and `aria-expanded` alike, so a tree a mouse can open is one a keyboard can open — the click asks the host, the host answers from the same planner that built the payload, and the rows are merged under their parent instead of being routed through a fresh payload, which would re-derive the columns and close an open grid view. Pairing the two halves on one choice of planner is deliberate: a fetch answered by a different rule than the payload was built with is a row that opens onto the wrong thing, with no error anywhere. The answer carries a count of children that got no row at all, for the one loss a fetch can still inflict — a node with more direct children than a whole delivery holds, since a cell's children are built uncapped — and the table says that number in the banner strip, because the file's own banner was composed before the user opened anything and cannot. Entry-scoped repaints, which is how an edit writes back, take the same budget: a 1000x1000 double is 1,000,001 rows from a single name, enough to be the whole problem by itself. That banner is also now in the strip rather than in the document's normal flow ahead of a full-bleed `position:absolute` table, which had been painting over it — an error message that was in the DOM and on screen nowhere, leaving the panel reading "No data". Qualified against the reported file in a real browser over the shipped bundle: all eleven variables named, the banner legible in both themes, descending to a frontier row costing no round trip until the frontier itself, and opening a 1x19252 struct array four levels down posting one request, answering in 90 ms and landing its rows under the row that was clicked. Unchanged by any of this: parsing that file still costs about 2.3 GiB of extension-host heap, so a file several times larger exhausts the host before a single row is built — that is the MAT reader in `data-explorer-core`, and no amount of planning on this side recovers it.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "simulink-data-explorer",
"displayName": "Simulink Data Explorer",
"description": "Explore Simulink models, data dictionaries, MAT-files, and projects as interactive tables and relationship trees.",
"version": "1.36.0",
"version": "1.36.1",
"publisher": "mathworks",
"icon": "media/icon.png",
"private": true,
Expand Down
Loading