by lruijsink
Forked from Hard Wrap
Make Live Preview render Markdown the way CommonMark does: soft line breaks as spaces and nested lists with any valid indent, without touching your files.
CommonMark Live Preview
Make Obsidian's Live Preview editor render Markdown the way CommonMark says it should, without touching your files. It only changes what the editor shows, so it works with whatever formatter or linter you use.
What it fixes
- Soft line breaks: in CommonMark, a single line break inside a paragraph is a soft break and renders as a space. Obsidian's editor shows the break as is, so a paragraph that is wrapped in the file (at 80 columns, say) gets wrapped twice: once by the file and once by the editor. Here, such paragraphs show as single lines and the editor does the wrapping.
- Nested list indents: in CommonMark, a nested list item is indented under
its parent's content: 2 spaces under
-, 3 under1.. Live Preview only draws nested lists correctly with 4 spaces per level, and its Tab key always inserts 4. Here, the editor shows 4 spaces per level instead.
Only whitespace is changed, never the text. Reading view isn't affected.
Saving
The plugin remembers how each file looked on disk next to what the editor shows for it. On save:
- Lines you haven't touched are written back exactly as they were on disk.
- Lines you edited are written as the editor has them: a paragraph as a single long line, a new nested list item with 4 spaces.
The plugin never wraps or reindents anything itself. Wrapping and indentation on disk are up to whatever formatter or linter you run. Until it runs, lines you edited stay as the editor has them.
Formatters inside Obsidian
Plugins that format the note on save usually replace the whole document, which would bring the soft wraps and 2-space lists back into the editor. This plugin rewrites such a replacement before it is applied:
- The formatted text becomes the file's disk text, so saving writes exactly what the formatter produced.
- The editor shows the unwrapped, 4-space form of it, applied as the smallest change from what the editor has. If the formatter changed nothing meaningful, the document isn't touched: no flashing, and the cursor and scroll position stay.
- Undo reverts the whole format in one step.
Configuration
In Settings > CommonMark Live Preview:
| Setting | Default | Description |
|---|---|---|
| Render soft line breaks as spaces | on | Master toggle |
| Render nested lists with 4-space indents | on | See what it fixes |
Per-file opt-out: add commonmark-live-preview: false to the file's frontmatter.
How it works
The plugin monkey-patches MarkdownView.prototype using
monkey-around:
- On load (
setViewData): the text goes throughunwrapand the list indent expansion before reaching the editor. The original text and the converted text are stored as the file's baseline, with a mapping from each editor line to the disk lines it came from. - On save (
getViewData): the editor's text is compared with the baseline line by line. Unchanged lines map back to their original disk lines, changed lines are written as they are. Obsidian also callsgetViewDatafor change detection and for merging external changes, which needs a stable answer, so an unedited editor returns the disk text unchanged. - On mode switch (
setMode): when switching back to source mode,this.datais converted back to the editor form. Obsidian'ssetModebypassessetViewDataand feedsthis.datadirectly to the editor.
A CodeMirror transaction filter handles whole-document replacements that didn't come from the user, as described above.
What gets unwrapped
Anything a CommonMark renderer would join into a single paragraph is joined:
- Plain paragraphs
- Blockquote content (including nested blockquotes)
- List item content (unordered, ordered, nested)
- Footnote definitions
- Callout body text
Everything else passes through verbatim: frontmatter, fenced and indented code
blocks, headings, tables, thematic breaks, HTML blocks and callout headers.
Hard line breaks (trailing \ or two trailing spaces) are preserved.
List indentation is only changed for lists outside blockquotes and callouts, and not at all in documents indented with tabs.
Build
Requires Node.js >= 18.
npm install
npm run build # production build → main.js
npm run dev # watch mode (rebuilds on change)
npm test # run unit tests
The build uses esbuild. Output is a single main.js (CommonJS). The
obsidian package and @codemirror/* are externals (provided by
Obsidian at runtime). monkey-around is bundled.
Known limitations
- Search: Obsidian indexes on-disk content. A search for a phrase that spans a wrapped line break in the file won't match.
- Edited lines stay as the editor has them until your formatter runs, so a file you edited and autosaved has long lines and 4-space indents in the edited places.
- Unmatched baselines: if the editor text can't be matched to the disk text line by line (this shouldn't happen, since only whitespace differs), edited files are saved exactly as the editor shows them.
- Lists inside blockquotes and callouts keep the indentation they have on disk, so Live Preview may still mis-render them if it's under 4 spaces.
Credits
Forked from obsidian-hard-wrap
by alethiophile, MIT licensed. The idea of
showing a different text in the editor than is on disk, and the unwrap logic,
come from that plugin. This version stopped wrapping files itself and instead
keeps their on-disk text, and adds the list indentation rendering and the
formatter handling.
Note on code authorship
This plugin and its documentation were substantially created using AI. They have been tested and reviewed by the human author.
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.