docs(tabs): say what content, rawContent and originalContent each hold - #437
Merged
Conversation
The Tab interface documents its four newest fields at 8-23 lines each and its 17 original fields at zero. The first question the struct actually raises is the difference between `content`, `rawContent` and `originalContent` - three same-shaped strings that drive the whole dirty/save/render system - and nothing answered it. One block above the three, stating which one to use and what breaks if you pick another, plus four lines on `history`/`historyIndex` because that field's name says undo and it holds file paths. Comments only. No behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
The
Tabinterface documents its four newest fields at 8–23 lines each and its 17 original fields at zero between them.pathKeygets 23 lines; the question a first-time reader actually arrives with — what is the difference betweencontent,rawContentandoriginalContent? — gets none, and those three drive the entire dirty/save/render system.This is comments only.
npm test524/524,npm run check630 files / 0 errors,npm run buildclean.The distinction, with the evidence
rawContentupdateTabRawContent,setTabRawContent, the editor bindingsave_file_contentoriginalContentsetTabRawContent,saveContent,saveContentAsisDirtyonlycontentupdateTabContent{@html sanitizedHtml}rawContentis the document. The editor two-way binds to it —bind:value={tabManager.activeTab.rawContent}(MarkdownViewer.svelte:3288) — the preview renders from it (renderTabPreviewFromRaw,MarkdownViewer.svelte:831-834), the HTML export renders from it (export.ts:284, gated onctx.rawContentatexport.ts:376), and it is the exact string that reaches disk:const snapshot = tab.rawContent→invoke('save_file_content', { content: snapshot })(documentSession.svelte.ts:423-427, and again at:464-468for Save As).originalContentexists only to answer "changed?".isDirtyis literally the comparison —tab.isDirty = tab.rawContent !== tab.originalContent(tabs.svelte.ts:496, now line 534) — and discarding edits is the assignmenttab.rawContent = tab.originalContent(documentSession.svelte.ts:523). It has no other reader.git show 4c4e6f1is the commit that introduced it, and it is the whole story: it replacedtab.isDirty = truewith that comparison, turning a latch into a computed answer.contentis not Markdown. It is the output ofrenderMarkdownPreview, cached per tab and re-sanitized at the sink (htmlContent→sanitizedHtml,MarkdownViewer.svelte:233/244, injected at:3445).git show 0694991shows why the naming is backwards:contentpredates the editor, and when Monaco arrivedrawContentwas added beside it for the source rather than renaming anything.tabTransfer.ts:16already says this correctly for the transfer payload.contentis allowed to lagrawContent. The re-render effect only runs whentab.isSplit || (isEditing && settings.showToc)(MarkdownViewer.svelte:2358), andsyncPreviewForPrint(:1935-1975) exists specifically to repair that before an export prints the live DOM."Clean" does not mean "matches disk".
setTabRawContentassigns the read to both buffers and clearsisDirty(tabs.svelte.ts:509-517), and it is called with the 50KB preview slice on a large-file open (documentSession.svelte.ts:329).markTabContentUnavailabledoes the same with''when the read fails (tabs.svelte.ts:535-542). Both cases leave a tab that is not dirty and is not the file — which is exactly whatisTruncatedis for.Assigning
rawContentdirectly does not maintainisDirty. The editor writes throughbind:valueand callstabManager.updateTabRawContent(components/Editor.svelte:323-331); the paths that assign the field directly maintain the flag themselves (documentSession.svelte.ts:432-433,:475-476,:523-524;MarkdownViewer.svelte:482-483).Also documented:
history/historyIndexFour lines, chosen because it is the one remaining undocumented field whose name actively misleads in the same way
contentdoes: sitting between three text buffers andeditorViewState,history: string[]reads as undo history. It is the back/forward file path stack —createFileHistoryreturns[path],goBackInHistoryreturnshistory[historyIndex]and the caller navigates to it (utils/tabHistory.ts), andnavigatepushestargetPath(tabs.svelte.ts:713-737). Text undo is Monaco's (components/Editor.svelte:1517-1524).createFileHistory(path, _content = '')still takes an ignored content parameter, which suggests the confusion is not hypothetical.Nothing else was documented.
id,title,isDirty,isSplit,splitRatioand the rest are self-evident, and comment volume is the cost this change is reacting to.Traced
Fresh open (full and >50KB), keystroke, save, Save As, external-change reload and conflict, failed read, tab switch, cross-window transfer, session restore, discard-on-close. Each ends in one of
setTabRawContent/updateTabRawContent/ the two explicitoriginalContent = snapshotsites, and no path writescontentororiginalContentto disk.Not traced
liveMode) and the front-matter editor's rewrites beyond confirming they route throughupdateTabRawContent(MarkdownViewer.svelte:885,:967).scrollTop/scrollPercentage/anchorLine. Three fields for one concept, undocumented, and plausibly the second question this struct raises — left alone deliberately rather than overlooked.open_markdown_preview/read_file_content_checked; taken at their TypeScript call signatures.Two things that do not fit cleanly (reported, not fixed)
1.
TitleBar.svelte:480gates Export HTML / Export PDF on the rendered-HTML cache.{#if currentFile !== '' || (tabManager.activeTab && tabManager.activeTab.content)}exportAsHtmlitself gates onctx.rawContent(export.ts:376). For an unsaved untitled buffer being edited with the TOC closed,currentFileis''andcontentis''— nothing has re-rendered since the tab was created — whilerawContentholds the user's text. The menu hides an export that the export function would accept. This is acontent/rawContentmix-up of exactly the kind the new comment describes, and it became reachable when #421 let the preview work without a save. Fixing it is a behaviour change and is out of scope here.2.
addTab(path, content = '')still seedscontentfrom itscontentargument (tabs.svelte.ts:342, alongsiderawContent: contentandoriginalContent: content). That was coherent when the three fields were one; now it means the signature permits putting raw Markdown into the field that is injected as HTML. Both live callers pass''or nothing (documentSession.svelte.ts:254,MarkdownViewer.svelte:1428), so it is latent, not live. Not renamed or re-signatured here.No existing comment was found to contradict these findings.
tabTransfer.ts:16(content= rendered HTML) and theMarkdownViewer.svelte:1789claim that "every keystroke flows throughupdateTabRawContent" both check out.🤖 Generated with Claude Code