Rebuild the memo editor as a single CodeMirror 6 "decorated source"
editor. The document is the raw markdown, stored verbatim and styled in
place (markers stay visible), so the editor never serializes a tree back
to markdown — removing the round-trip fidelity bug class (inline images,
setext headings, ordered-list indentation, HTML entities) that the old
editor needed per-case patches for.
- MemoEditor/Editor: CodeMirror 6 + lang-markdown (GFM). Tokens, heading
lines, #tag/@mention, and the autocomplete popover are styled in plain
CSS (Editor/editor.css) with theme tokens, not a CSS-in-JS theme.
- Tab/Shift-Tab nest/outdent list items (marker-aware, ordered items
renumbered so nesting is CommonMark-valid); Escape blurs; #tag
autocomplete sourced from useTagCounts.
- Focus-mode toolbar reimplemented as markdown-text ops; active state read
from the Lezer tree via the backend-agnostic formatting/commands catalog.
- Remove the old serialize-back-to-markdown editor (its Editor dir,
PlainEditor, the editor-mode system) and its now-unused dependencies
(marked, textarea-caret, and the rich-text editor packages).
- Consolidate toolbar components under Toolbar/. Read-only MemoContent
rendering is unchanged.
Memos layers #tag syntax on top of CommonMark, but there was no way to
write a literal "#NAS" — it always became a clickable tag (issue #6035).
Handle escapes lexically, the way TipTap/prosemirror-markdown do, with no
"escaped tag" node in the document model:
- Parse: marked's built-in backslash escape already turns "\#NAS" into
plain text; the read-only renderer (remark-tag) now honors the same
escape by lexing from the original source slice and falling back to the
prior value-based parse when it can't faithfully reconstruct the text.
- Serialize: a tag-aware Markdown extension (tagMarkdown.ts) backslash-
escapes a "#" that would re-parse into a tag, skipping links and code
where tags never form.
- The editor's #tag lexing moves to the canonical @tiptap/markdown
markdownTokenizer; tag-in-link skipping moves to a tree pass so the
editor and renderer agree.
The capped tag-run grammar is consolidated into utils/tag-grammar.ts
(TAG_RUN), shared by the tokenizer, the serialize-escape, and the
renderer so they can't drift. README documents why the markdown manager
is worked around in three places.
Add a rich-text formatting toolbar as the focus-mode header when the
WYSIWYG editor is active: heading dropdown, bold/italic/code, lists, and
link, with a priority+overflow responsive layout and live active-state
highlighting. The toolbar is a self-contained component driven through a
new FormattingController surface routed via EditorContent.
Remove the now-redundant slash-command feature (/todo, /code, /link,
/table) and its "Type / for commands" hint, since the toolbar covers
those actions; the shared suggestion renderer stays for #tag.