snapshot when it writes, and passes the document’s generation with each call, so a call meant for a document that has since been replaced fails instead of changing the new one.
Document identity
Every load names the document with three values:
A generation names a load, not a file: when you open the same file again, give it a new generation. Order a document’s changes by
(generation, revision).
Every output carries these as a DocumentVersion (documentId, generation, revision): DocumentSnapshot, CommandState, ReadableTextSnapshot, Heading, ClipboardOutput, PrintableDocument, and the values that changed and commandStateChanged receive. Adapter calls receive a DocumentContext with the documentId and generation, and an operationId for that call.
What changes the revision
The revision increases by one for each change to the document’s content: typing, paste, drop, cut, undo, redo, a successful editing call such asformat or replaceSource, and typing in source mode. It is a counter, not a name for the text: undoing an edit increases it again.
These leave it unchanged: selection and caret moves, setEditingMode, setEditable, setTextInputPreferences, setCommentsVisible, find, reading calls such as snapshot, and any call that fails or edit that is refused.
Load a document
loadDocument(input) replaces the document. input is a DocumentInput:
A load:
- Sets the revision to 0 and clears the undo history.
- Returns a Markdown document to formatted mode.
- Cancels pending image imports and any copy or print still in progress.
- Puts the caret at the end, takes focus off the editor’s text surfaces and leaves focus in a host control where it is. It doesn’t scroll to the caret.
- Sends one
commandStateChangedand nochanged. - Works while the editor is read-only, and keeps editability, input preferences and the keymap as they are.
invalid-argument. Markdown that Inkkit can’t show without losing part of it throws preservation. Either way the load changes nothing, and the previous document stays loaded. A block that Inkkit can’t build in full loads as literal source and keeps its bytes; see Preservation.
Reload a changed document
reloadDocument(input, expectedGeneration?) loads a newer version of the document, for example after another app changed the file. It follows the same generation rule and does everything a load does, except that it keeps:
- The selection, where it still fits the new text.
- Focus and scroll position.
- Source mode, when both the old and the new text are Markdown.
expectedGeneration, the reload first checks that the loaded document is that generation and throws stale-document otherwise, even when the new generation isn’t greater. Without it, a reload also works when no document is loaded.
Save the document
Saving has two parts:changed tells you the text changed, and snapshot gives you the text to write.
1. An edit happens
changed tells your app that the document needs saving.2. Take a snapshot
Call
snapshot with the current generation when you are ready to save.3. Write or keep open
Write the returned text. If the snapshot fails, keep the document open and
do not overwrite the file.
changed to schedule a save. It fires after each change to the saved text. During one of your calls, it arrives just before the call returns, and not at all if the call fails. It doesn’t fire for a load, a reload or a refused edit. A change that leaves the saved text as it was increases the revision without sending changed. Its value is a DocumentSnapshot, and its revision is the one that a snapshot taken in the handler carries.
text is the exact source, including line endings. A document that was loaded and not edited returns the bytes that were loaded. In source mode, it includes everything typed so far.
When snapshot throws, its code says what to do:
not-ready, destroyed and invalid-argument mean that your app called snapshot at the wrong time or with a bad generation. Error codes describes every code.
Unsaved changes and dirty
A snapshot’s dirty is true when its text differs from the text of the last load or reload. It compares text, so undoing back to the loaded text makes it false again.
dirty doesn’t know about your saves: after you write a snapshot, it stays true. To show whether there are unsaved changes, record the revision of the snapshot you wrote and compare it with the revision that later changed events carry.
Expected generations
Pass the generation you loaded as the last argument of every call that takes one. When the loaded document has another generation, the call throwsstale-document, or rejects if it’s asynchronous, and changes nothing. Omitted or null means the current generation, which suits a page with one document. An app that calls Inkkit across a native bridge should always pass it.
- Required:
insertTextandkeyDown, which carry native input. - Optional, the last argument: the calls that read or change the document, its selection or focus, such as
snapshot,commandState,format,paste,undo,printableSnapshot,clipboardSnapshot,focusandblur. - Optional, checked only when given:
reloadDocument. - Carried by the argument: calls that take a text range or a heading check the version that the range’s
snapshotIdor the heading names. - None:
loadDocument, which brings its own generation, and editor settings such assetEditable,setTextInputPreferences,setKeymap,setViewportandsetCommentsVisible.
clipboardSnapshot, printableSnapshot and paste reject with stale-document when the document is replaced while they run; clipboardSnapshot and printableSnapshot also reject when the revision or editing mode changes meanwhile. A load cancels pending image imports, and Inkkit ignores adapter results for a document that is no longer loaded. In your own callbacks, compare the DocumentContext you received with the document you expect before you act on a result.
After stale-document, don’t retry with the same generation. Read the current state again and act again if the action still applies.
Read-only mode
setEditable(false), or editable: false at mount, stops the document from changing. The editable getter returns the current setting.
- Still allowed: selection, copying, find, navigation, folding callouts,
snapshot,printableSnapshot,clipboardSnapshot, switching between formatted and source modes, and loading and reloading. - Refused: every method that changes the document throws
read-only, and so doundoandredo, which keep their history for when editing returns. Typing, paste, drop, cut, task toggles and image resizing don’t change content. - When it starts: pending image imports are canceled, and a cut still waiting for your clipboard handler removes nothing.
- What it keeps: the text, revision,
dirty, selection, focus and undo history. Editability also stays as it is across loads and reloads.
setEditable throws composition while text is composing, and changes nothing. While the editor is read-only, every entry in commandState().commands is false.
Switch and close documents
Before you load another document or destroy the editor, take a snapshot of the current one. If the snapshot throws, stay on the current document.switchTo takes the snapshot and loads the next document without waiting in between, so no edit can land after the snapshot. If loadDocument throws, the previous document stays loaded. Keep the snapshot’s text until your write succeeds.
destroy() cancels pending work and releases the editor. It resolves when the editor is gone and never rejects. Keep the root element in the page, and leave its children alone, until it resolves. Afterwards every member except destroy throws destroyed, and calling destroy again does nothing.
