@@ -11,7 +11,7 @@ import {
1111} from './rowBuilder.js' ;
1212import { buildMatRows } from './matRowBuilder.js' ;
1313import { readProjectStore } from './projectStore.js' ;
14- import { isEditableJsonSlddBytes } from './slddFormat.js' ;
14+ import { isEditableJsonSlddBytes , exceedsTextSyncLimit } from './slddFormat.js' ;
1515import { annotateDataRows , annotateModelRows } from './usageGraph.js' ;
1616import { onNavigateSelect , consumePendingSelect } from './navigate.js' ;
1717
@@ -65,6 +65,12 @@ export class BinaryEditorProvider implements vscode.CustomReadonlyEditorProvider
6565 const uriString = document . uri . toString ( ) ;
6666 const name = document . uri . path . split ( '/' ) . pop ( ) ?? 'document' ;
6767
68+ // A read-only banner shown above the table. Set only for the surprising case:
69+ // a JSON .sldd that WOULD be editable but is over VS Code's TextDocument sync
70+ // limit (see below). Binary/zip .sldd — expected read-only — leave this unset
71+ // so no banner appears. Passed to the webview in the setRows payload.
72+ let notice : string | undefined ;
73+
6874 // This byte-backed editor is the DEFAULT for *.sldd because it can open any
6975 // bytes (binary/zip .sldd fail to load as a TextDocument, so the text-backed
7076 // tableView can't be the default). But editable JSON .sldd should open in the
@@ -74,7 +80,12 @@ export class BinaryEditorProvider implements vscode.CustomReadonlyEditorProvider
7480 if ( name . endsWith ( '.sldd' ) ) {
7581 try {
7682 const bytes = await vscode . workspace . fs . readFile ( document . uri ) ;
77- if ( isEditableJsonSlddBytes ( bytes ) ) {
83+ // Editable JSON .sldd redirects to the text-backed table view — BUT only
84+ // when VS Code can actually mirror it as a TextDocument. Over the sync
85+ // limit, the tableView provider can't resolve (the ext host throws
86+ // "Unable to retrieve document from URI"), so keep such files here and
87+ // render them read-only. See exceedsTextSyncLimit in slddFormat.ts.
88+ if ( isEditableJsonSlddBytes ( bytes ) && ! exceedsTextSyncLimit ( bytes ) ) {
7889 // Carry the incoming tab's preview state through the redirect: an
7990 // Explorer single-click opens this binary tab as a PREVIEW tab, and the
8091 // table it redirects to should stay a preview tab too (not pin). VS
@@ -92,6 +103,17 @@ export class BinaryEditorProvider implements vscode.CustomReadonlyEditorProvider
92103 webviewPanel . dispose ( ) ;
93104 return ;
94105 }
106+ // A JSON .sldd that stayed here (not redirected) did so ONLY because it's
107+ // over the sync limit — otherwise it would be editable. That's surprising
108+ // (a JSON dictionary the user expects to edit), so explain the read-only
109+ // downgrade. Binary/zip .sldd skips this (isEditableJsonSlddBytes false).
110+ if ( isEditableJsonSlddBytes ( bytes ) ) {
111+ const mb = Math . round ( bytes . byteLength / ( 1024 * 1024 ) ) ;
112+ notice =
113+ `Read-only: this dictionary is ${ mb } MB, above VS Code's 50 MB editing limit. ` +
114+ `To edit the JSON directly, use "Reopen Editor With… → Text Editor"; ` +
115+ `this view refreshes when you save.` ;
116+ }
95117 } catch {
96118 // Unreadable → fall through and let the read-only render report the error.
97119 }
@@ -161,6 +183,7 @@ export class BinaryEditorProvider implements vscode.CustomReadonlyEditorProvider
161183 columns : COLUMNS ,
162184 columnLabels : COLUMN_LABELS ,
163185 editable : false ,
186+ notice,
164187 } ) ;
165188 drainNavSelect ( ) ;
166189 } catch ( err ) {
@@ -194,19 +217,32 @@ export class BinaryEditorProvider implements vscode.CustomReadonlyEditorProvider
194217 webview . postMessage ( { type : 'selectByName' , name : e . name } ) ;
195218 } ) ;
196219
197- // Live-sync when the underlying document changes: covers external /
198- // text-view edits to the file. Re-parse and repaint the read-only view.
199- const changeSub = vscode . workspace . onDidChangeTextDocument ( ( e ) => {
200- if ( e . document . uri . toString ( ) === uriString ) {
201- invalidate ( uriString ) ;
202- void post ( ) ;
203- }
204- } ) ;
220+ // Live-sync when the file on disk changes: covers external edits AND edits
221+ // made in the plain-text view once saved. We watch the DISK, not the
222+ // TextDocument, on purpose: a JSON .sldd routed here is over VS Code's 50 MB
223+ // sync limit, so the ext host holds no mirror of it and
224+ // onDidChangeTextDocument NEVER fires for it (the same limit that forced the
225+ // read-only downgrade — see slddFormat.ts). A FileSystemWatcher observes the
226+ // disk directly, independent of document syncing, so it fires on save at any
227+ // size. Because this view always reads bytes from disk, unsaved edits can't
228+ // be reflected anyway — refresh-on-save is the achievable contract, and the
229+ // banner tells the user so.
230+ const watcher = vscode . workspace . createFileSystemWatcher (
231+ new vscode . RelativePattern ( vscode . Uri . joinPath ( document . uri , '..' ) , name ) ,
232+ ) ;
233+ const onDiskChange = ( ) => {
234+ invalidate ( uriString ) ;
235+ void post ( ) ;
236+ } ;
237+ const changeSub = watcher . onDidChange ( onDiskChange ) ;
238+ const createSub = watcher . onDidCreate ( onDiskChange ) ;
205239
206240 webview . html = this . getHtml ( webview , distRoot ) ;
207241 webviewPanel . onDidDispose ( ( ) => {
208242 sub . dispose ( ) ;
243+ watcher . dispose ( ) ;
209244 changeSub . dispose ( ) ;
245+ createSub . dispose ( ) ;
210246 navSub . dispose ( ) ;
211247 } ) ;
212248 }
@@ -231,6 +267,7 @@ export class BinaryEditorProvider implements vscode.CustomReadonlyEditorProvider
231267 scriptFile : 'table.js' ,
232268 title : 'Data Explorer' ,
233269 body : ` <div id="dex-error" role="alert" style="display:none;color:var(--vscode-errorForeground,#f14c4c);padding:8px;font-family:var(--vscode-font-family,sans-serif);"></div>
270+ <div id="dex-notice" role="status" style="display:none;position:absolute;top:0;left:0;right:0;z-index:2;box-sizing:border-box;padding:6px 10px;font-family:var(--vscode-font-family,sans-serif);font-size:12px;color:var(--vscode-inputValidation-infoForeground,var(--vscode-foreground));background:var(--vscode-inputValidation-infoBackground,rgba(100,148,237,0.12));border-bottom:1px solid var(--vscode-inputValidation-infoBorder,#4084d0);"></div>
234271 <dex-tree-table style="position:absolute;inset:0;"></dex-tree-table>
235272 <dex-context-menu></dex-context-menu>` ,
236273 } ) ;
0 commit comments