A premium, highly integrated WYSIWYG Markdown Editor custom-tailored for VS Code and agentic environments like Antigravity. Built on top of the robust Toast UI Editor engine, it replaces the standard raw text view with a stunning, interactive, and live-rendered workspace that feels natively embedded in the editor workspace.
Understanding how the extension host and webview communicate is key to contributing or extending the editor. The diagram below illustrates the lifecycle and event-flow of editing a markdown document:
sequenceDiagram
autonumber
participant User as VS Code Editor / User
participant Provider as MarkdownEditorProvider (Extension Host)
participant Webview as Webview HTML/JS (Toast UI & Mermaid)
participant Doc as vscode.TextDocument
User->>Provider: Open markdown file (*.md)
Provider->>Provider: resolveCustomTextEditor()
Provider->>Webview: Inject HTML template (with VS Code CSS tokens)
Webview->>Provider: Post "ready" message
Provider->>Webview: Send initial document text ("update" message)
Webview->>Webview: Parse frontmatter + markdown body
Webview->>Webview: Render WYSIWYG editor and overlay containers
rect rgb(28, 28, 38)
Note over Webview,Doc: Document Editing Loop
Webview->>Provider: Post "save" message with updated content
Provider->>Doc: Execute WorkspaceEdit (replace text range)
Doc-->>Provider: Trigger onDidChangeTextDocument event
Provider->>Webview: Dispatch "update" message (if text differs)
end
rect rgb(28, 28, 38)
Note over Webview,Provider: Event Hijacking & Native Commands
Webview->>Provider: Post "openLink" on local/relative path click
Provider->>User: Resolve workspace path & open in editor
User->>Webview: Press Cmd/Ctrl + F
Webview->>Webview: Display #custom-find overlay & search text using window.find()
end
Unlike generic Markdown previews, this extension operates as a custom VS Code editor matching *.md files. It includes highly advanced workarounds to solve standard webview limitations:
Most markdown editors choke on YAML frontmatter, showing raw dashes and config keys mixed in the WYSIWYG workspace.
- The Solution: The editor intercepts and extracts frontmatter on load.
- It displays a dedicated, collapsible "YAML Metadata (Skill Trigger Data)" text area at the top of the workspace.
- Edits to either the frontmatter pane or the markdown editor body are merged cleanly and synced back to VS Code's
TextDocumentin real-time.
ProseMirror (Toast UI's underlying document model) systematically strips out external DOM elements and custom HTML templates inside the rich editor surface, making live WYSIWYG rendering of diagram libraries like Mermaid extremely challenging.
- The Solution: The editor utilizes an invisible pointer-events wrapper (
#mermaid-overlays-container) positioned absolutely in the DOM. - It measures the exact bounding rectangles of mermaid codeblocks in the ProseMirror editing pane.
- It constructs corresponding absolute preview cards positioned directly under the code blocks.
- It automatically garbage-collects orphaned preview nodes when their source code blocks are deleted or modified.
Standard webview elements in VS Code cannot access the editor's global find widget due to iframe-level sandbox restrictions and focus traps.
- The Solution: We implement a custom search overlay widget (
#custom-find) that hooks directly into thecmd+f/ctrl+fkeystrokes. - Under the hood, it triggers Chromium's native
window.find()API. This allows searching directly inside the shadow DOM and editable fields instantly, bypassing IPC messaging overhead. - Includes full keyboard navigation:
Entermoves to the next match,Shift + Entermoves to the previous match, andEscapecloses the widget.
Updating text via the ProseMirror API causes heavy layout recalculations, causing the editor to jump and scroll erratic distances when synchronizing edits with the extension host.
- The Solution: A 60fps Scroll Lock mechanism triggers upon document update messages. Using
requestAnimationFrameover45consecutive frames, it anchorsscrollTop = 0to overpower erratic ProseMirror layout jumps and preserve layout stability.
Links in standard webview custom editors are normally unclickable or crash because they run in an isolated environment.
- The Solution: We intercept both
clickandmousedownevent bubbles in the webview. - Relative document links (e.g.
./another-fileorsubfolder/doc.md) are resolved contextually relative to the active document. - Local resources and external URLs are routed through
vscode.commands.executeCommand('vscode.open')orvscode.env.openExternalrespectively, facilitating fluid cross-document editing.
βββ .vscode-test/ # Generated electron runtimes for testing
βββ out/ # Compiled TypeScript outputs (git-ignored)
βββ src/
β βββ extension.ts # Extension entry point, registers MarkdownEditorProvider
β βββ markdownEditor.ts # Main class, webview HTML generation, event processing
β βββ test/
β βββ runTest.ts # Bootstraps the Electron VS Code test suite
β βββ suite/
β βββ extension.test.ts # Core mocha test specifications
β βββ index.ts # Test runner configuration
βββ sim.js # Headless JSDOM simulation script for CI/quick tests
βββ test_gen.js # Helper to extract and save HTML webview code for inspection
βββ tsconfig.json # TypeScript compiler settings
βββ package.json # Extension metadata and contribution details
Ensure you have Node.js installed before starting development.
npm installTo compile the TypeScript source files once:
npm run compileTo watch for file changes and auto-compile (recommended for development):
npm run watch- Open the project folder in VS Code.
- Press
F5(or clickRun and Debug->Run Extension). - A new Extension Development Host window will open.
- Open any
.mdfile to test the WYSIWYG editor!
This project is equipped with two unique testing strategies to ensure maximum reliability and developer velocity:
Spins up a headless virtual browser inside Node.js using jsdom to emulate VS Code postMessage interfaces and verify that Toast UI behaves as expected. Ideal for quick checks and automated CI environments:
# Compiles the TS code first
npm run compile
# Runs the simulator
node sim.jsThe simulator will parse markdownEditor.ts, extract the embedded HTML document, mock the acquireVsCodeApi method, trigger simulated markdown document update sequences, and assert if elements render successfully inside the virtual DOM.
Launches a real instance of VS Code inside a headless Electron context to verify editor registration, custom editor views, tab focus, and file-saving:
npm testThe extension contributes the following integration parameters to VS Code via package.json:
"contributes": {
"commands": [
{
"command": "richMarkdown.find",
"title": "Find in Rich Markdown Editor"
}
],
"keybindings": [
{
"command": "richMarkdown.find",
"key": "ctrl+f",
"mac": "cmd+f",
"when": "activeCustomEditorId == 'richMarkdown.wysiwygEditor'"
}
],
"customEditors": [
{
"viewType": "richMarkdown.wysiwygEditor",
"displayName": "Rich Markdown Editor",
"selector": [
{
"filenamePattern": "*.md"
}
],
"priority": "default"
}
]
}The editor inherits VS Codeβs high-fidelity design standards:
- Consistent Colors: Employs standard token variables like
var(--vscode-editor-background)andvar(--vscode-editor-foreground)to seamlessly blend in with the user's active theme. - Glassmorphic Panels: The custom find widget is decorated with smooth micro-borders and subtle translucent drop-shadow overlays to look premium and unobtrusive.
- Underlined Blue Hyperlinks: Overrides Toast UI content standards to color editable anchors cleanly (
#3794ff), reinforcing clear clickability patterns.
- HTML Injection Code: The HTML string template in
src/markdownEditor.tsis the heart of the webview interface. If editing DOM behaviors or importing new script resources, remember to update the corresponding simulation scripts (sim.js/test_gen.js) to maintain test alignment. - ProseMirror Schemas: Be cautious when extending DOM tags inside Toast UI's body; ProseMirror is strict and will discard nodes it doesn't recognize unless they are mapped as independent floating elements outside the main container, or integrated explicitly via Toast UI's Custom HTML Renderers.