Skip to main content
Inkkit saves the Markdown you loaded, not a fresh export of what the editor shows. An unedited document saves byte for byte, and an edit rewrites only the blocks it touches. When Inkkit can’t save an edit so that it reopens exactly as shown, it refuses the edit with the preservation error code and changes nothing. Inkkit keeps untouched source, writes edited blocks and checks the result before accepting an edit. Inkkit's source preservation and read-back check, in dark mode.

What Inkkit keeps

  • An unedited document comes back from snapshot() as the loaded text, byte for byte, including line endings, a byte order mark, trailing spaces and a missing final line ending.
  • Blocks that an edit doesn’t reach keep their bytes, and so does the text between blocks, such as extra blank lines. Link and footnote definitions stay, whether or not anything uses them.
  • An edited block keeps the spelling of what the edit didn’t change where it can: the other lines of a paragraph, __bold__ next to typed text, a list’s * or + markers, a setext underline, reference labels, and a code fence’s characters and info string.
  • Line endings follow the document. In a CRLF document, the lines an edit writes use CRLF.
  • Undo back to the loaded text returns the loaded bytes, and dirty is false again.
  • Presentation never changes the source. Folding a callout, showing comments, Mermaid previews, code highlighting and automatic language detection change neither the text nor the revision.
Markdown that Inkkit can’t show formatted, such as raw HTML, front matter and unresolved references, stays in the document as editable literal source. Markdown support lists what is kept that way.

When a block is written afresh

Inkkit writes a block in canonical form when it can’t keep the authored spelling: a new block, or an edited block whose own source can’t express the change. Canonical form uses - for bullets, * for emphasis, ** for strong, fenced code blocks and --- for rules. You notice it in these cases:
  • Indented code that you edit is saved as a fenced code block.
  • Moved blocks. A block moved with moveBlock or its shortcuts keeps its source, and an ordered item takes the number written at its new place. A block moved by cut and paste, or by drag and drop, is written in canonical form.
  • Repeated blocks. When the same block appears more than once, Inkkit can’t always tell which copy you edited or moved, and that copy can be written in canonical form.
  • Neighboring lists. Markdown reads two adjacent lists of one kind as one list unless their markers differ. A new, moved or rewritten list takes a bullet (-, * or +) or number delimiter (. or )) that the lists beside it don’t use. An item added to an authored list takes that list’s marker.
  • Thematic breaks. A --- rule that comes to open the document while another --- line follows it is written as ***, because it would otherwise read as front matter. A new rule inside a list item, quote, callout or footnote is written as ___.
  • Spaces at the edge of a block or table cell, or beside a soft line break are written as  , because Markdown would otherwise drop them.
  • A line break at the end of a paragraph isn’t saved until text follows it. See Line breaks.

How an edit is checked

In formatted mode, Inkkit checks every change to the document before it appears: typing, commands, paste, drop, table operations, find and replace, undo and redo. It writes the Markdown for the edited document and reads it back. If the result doesn’t read as the document the editor would show, Inkkit refuses the edit:
  • The document, selection, revision and undo history stay as they were.
  • No changed event fires.
  • The refusal is an InkKitError with the code preservation.
Source mode doesn’t parse as you type. Typing, paste and replaceSource take effect on the text exactly as written, and Inkkit reads the text when you switch back to formatted mode. Where a refusal arrives depends on what made the edit: A refusal that a call reports isn’t also sent to events.error. Errors describes how every failure arrives.

Why an edit is refused

Each reason below reports preservation, and each leaves the document, revision and history unchanged and the editor usable. A refused edit or load needs no recovery. A failed snapshot does: don’t save. Branch on the code, not the message, which is for logs.
  • Deleting the block between two lists that use the same marker, which would merge them.
  • Leaving an HTML comment at the start of a paragraph, or a paragraph that holds only an HTML comment. Markdown reads that line as an HTML block.
  • Ending a literal block with a line break, or typing text into one that would change how other blocks read.
  • Turning text into a code block when the code can’t be saved as the same text.
  • Removing a code block’s language when the rest of its info string would then read as the language.
  • Calling editReferenceDefinition with an empty title.