Supported Formats
VMark opens every file format below directly. The differentiator is schema-aware previews: when the file is a known artifact, VMark renders the right view, not a generic JSON tree.
Enabling formats
Markdown, plain text, and YAML/YML always open in their full editors — those are the calm defaults. Every other format below is off by default and gated behind a category toggle in Settings → Formats:
| Toggle | Enables |
|---|---|
| Data formats | .json, .jsonl, .toml (split-pane source + tree, with Cargo / package.json / pyproject schema renderers) |
| Diagrams & SVG | .mmd, .svg (split-pane source + sanitized live render) |
| HTML preview | .html, .htm (sandboxed iframe — see Security model for HTML) |
| Code viewers | 12 read-only code viewers (.ts, .tsx, .js, .jsx, .py, .rs, .go, .css, .sh, .bash, .rb, .lua) |
When a category is off, the matching extensions fall through to the plain-text fallback so the file still opens — just without the preview / schema view. Flip a toggle and the registry rebuilds in place; open tabs remount with the proper adapter.
On the first launch after upgrading to multi-format support, VMark surfaces a one-time toast nudging you to Settings → Formats. If you dismissed it (or installed fresh), the panel is at Settings → Formats any time.
At a glance
| Family | Extensions | Default | Editor | Preview |
|---|---|---|---|---|
| Markdown | .md, .markdown, .mdown, .mkd, .mdx | always on | WYSIWYG + Source modes | rendered prose |
| Plain text | .txt | always on | source | — |
| Data — YAML | .yaml, .yml | always on | source + tree | navigable tree, schema-aware (GitHub Actions) |
| Data — JSON | .json, .jsonl | requires Data formats toggle | source + tree | navigable JSON tree, schema-aware (package.json) |
| Data — TOML | .toml | requires Data formats toggle | source + tree | navigable tree, schema-aware (Cargo.toml, pyproject.toml) |
| Diagrams | .mmd | requires Diagrams & SVG toggle | source + render | live Mermaid diagram |
| Vector | .svg | requires Diagrams & SVG toggle | source + render | sanitized inline render |
| Web | .html, .htm | requires HTML preview toggle | source + render | sandboxed iframe (empty sandbox="", DOMPurify, CSP); trusted mode is opt-in per file |
| Code (read-only) | .ts, .tsx, .js, .jsx, .py, .rs, .go, .css, .sh, .bash, .rb, .lua | requires Code viewers toggle | viewer (toggle to edit) | — |
| Media | images (.png, .jpg, .gif, .webp, .heic, .tiff, …), video (.mp4, .webm, .mov, …), audio (.mp3, .wav, .flac, …) | always on | viewer (read-only) | native image / <video> / <audio> |
Code files default to read-only with a banner offering Enable editing or Open in external editor.
View modes (Source / Split / Preview)
Any format that has a preview — HTML, SVG, Mermaid, JSON, YAML, TOML — opens with a small Source · Split · Preview toggle in the top-right corner:
- Source — the editable source pane, full width.
- Split — source and preview side by side (the default).
- Preview — the rendered result, full width. Preview is a read-only render; to edit, switch back to Source or Split.
You can also switch from the keyboard: F6 toggles Source ⇄ Split and Shift + F6 toggles Preview ⇄ Split (Split is the base state). The choice is remembered per tab. Set the default for newly-opened files under Settings → Formats → Default view mode.
Formats without a preview (plain text, code viewers) always show source only, so no toggle appears.
Media files (images, video, audio)
Open a picture, video, or audio file and VMark shows it inline — like Quick Look in Finder. Two ways to preview:
- Open it (double-click / Enter in the file explorer,
Cmd+O, or drag-in) to view it in a tab. - Quick Look: select a file in the explorer and press Space for a full-window preview overlay. Press Space, Esc, or click the backdrop to close.
How it works and what to expect:
- Never loaded as text. Media is binary — VMark streams the file straight to the viewer through the native asset pipeline. It is never read as UTF-8, never held in memory as a document, and never editable or saved. Even multi-gigabyte videos open instantly and seek natively.
- Edits on disk show up. Re-export the image from your editor, or let a script rewrite it, and the open tab picks up the new version by itself — no reopening, no closing and re-opening the file.
- Broad format coverage. VMark hands the file to the platform's media engine, so support tracks what your system's webview can decode. On macOS that is wide — HEIC, TIFF,
.mov/H.264, and FLAC all play. Formats the webview can't decode (e.g..mkv,.avi,.wmv) still open, showing a fallback panel with Open with default app and Reveal in Finder. - Read-only. Media tabs never become dirty and close without a save prompt.
Schema-aware previews
When the path or content matches a known schema, VMark substitutes the right view for the generic tree.
GitHub Actions workflow (.github/workflows/*.yml)
Opens with the workflow workbench: the interactive job-DAG canvas plus a structured forms editor with Save / Discard (see the Workflow Viewer guide). The source pane is workflow-aware too — $ expression completion, cursor-to-canvas job highlighting, and Cmd-click on local uses: references.
- Path detection: a
.yml/.yamlfile under.github/workflows/routes to the workflow renderer — even with malformed YAML, so you see the degraded view with diagnostics rather than a blank tree. (The file must reach the YAML adapter first; that requires the.yml/.yamlextension.) - Content detection: top-level
on:andjobs:keys.
Cargo.toml
Opens with a Rust dependency tree — runtime, dev, and build dependencies, with version specs and feature flags.
- Path detection: filename
Cargo.toml(case-insensitive) on POSIX or Windows paths. - Content detection:
[package]or[workspace]header. - No network calls — VMark never resolves crates.io.
package.json
Opens with an npm dependency tree — dependencies, devDependencies, peerDependencies, optionalDependencies.
- Path detection: filename
package.json. - Content detection: top-level
nameplus any ofdependencies/devDependencies/peerDependencies.
pyproject.toml
Opens with a Python dependency tree — both PEP 621 ([project] + [project.optional-dependencies]) and Poetry ([tool.poetry.dependencies], [tool.poetry.dev-dependencies], [tool.poetry.group.<name>.dependencies]).
- Path detection: filename
pyproject.toml. - Content detection:
[project]or[tool.poetry]header (gated on a clean TOML parse).
Editing rules
- Markdown ships the full toolbar, paragraph formatting, CJK rules, math, mermaid, footnotes — every existing markdown feature.
- Data formats (JSON, YAML, TOML) ship in the source pane with parse-error gutter markers; the tree preview updates as you type. Markdown-only menu actions are disabled (CJK formatting, insert-block, paragraph formatting); mode-relevant controls remain active. The right-click context menu is reduced to clipboard actions (Cut/Copy/Paste/Select All).
- Visual formats (Mermaid, SVG, HTML) ship in the source pane with the rendered view in the right pane. The preview renders at lower priority than your typing, so on a large document it catches up a beat behind the caret rather than re-rendering on every keystroke.
- Code formats open as syntax-highlighted viewers; toggle to edit in place or open in your external editor (see below).
How VMark decides a file's type
VMark treats markdown as an allowlist, not a default. The rule, in order:
- A markdown-family extension (
.md,.markdown,.mdown,.mkd,.mdx) opens in the rich markdown editor. - A registered non-markdown extension (when its category is enabled — JSON, YAML, code viewers, etc.) opens in that format's source pane.
- Everything else —
.env,.env.local,Dockerfile,Makefile,.gitignore, unknown extensions — opens in the plain-text source pane, never the markdown editor.
This means a config file is never silently rendered as markdown. A .env.local opens as plain text, with its KEY=value lines, # comments, and underscores left exactly as typed.
Dotfile families are recognized as a group: an override on .env covers .env.local, .env.production, and so on.
Syntax highlighting for plain files
Even when a file opens as plain text, VMark colorizes it when it recognizes the type — .env/.ini/.conf (properties), .sh/.bash (shell), Dockerfile, .toml, .sql, .diff, and the usual languages. This is purely cosmetic; it never changes which editor the file opened in, and it works regardless of whether the code-viewer category is enabled.
Override: "Set File Type"
The detection is the default, not a cage. Open the command palette and run:
- Set File Type: Plain Text — force the current file family to open as plain text (e.g. stop a
.txtyou keep as raw notes from being rendered). - Set File Type: Markdown — render a non-
.mdfile with the markdown editor (e.g. a.txtyou actually write markdown in). - Set File Type: Reset to Default — drop the override.
Overrides are remembered per file family (by extension, or by dotfile stem for files like .env) and persist across sessions. They take precedence over the built-in rules above.
Find, save, content search
- Cmd+O filters: a single "All Supported" preset covering every registered format. Save-As filters and the default save extension are derived from the active tab's format adapter, so saving a
.tomlfile proposes.tomlas the extension. - Drag-drop accepts any registered extension.
- Save As filters and the default extension on save are derived from the active tab's format adapter.
- Cmd+Shift+H content search ("Find in Files") indexes every text-like format (markdown, txt, json, yaml, toml, html, svg, mermaid). Code files are excluded by default — they're code-viewer mode.
Security model for HTML
Per ADR-4 in the multi-format plan, HTML preview rests on three independent layers of defense:
<iframe sandbox="">with an empty allow-list — no scripts, no same-origin, no forms, no popups. Sandboxing is enforced by the iframe attribute alone (CSP via<meta>is not a sandbox per MDN).- DOMPurify sanitization runs first — strips
<script>,javascript:URLs, inline event handlers, base-href tricks. - CSP
<meta>injection —default-src 'none'; img-src data:; style-src 'unsafe-inline'; font-src data:; base-uri 'none';— restricts in-iframe resource loading.
The validator surfaces script tags, javascript: URLs, and inline event handlers as warnings so you can see what's being blocked.
Trusted HTML preview (opt-in)
The safe preview above is the default and never changes. For a document you wrote yourself — an interactive lab, a local dashboard, a self-contained demo — you can authorize script execution for that one file, for this session.
Use Enable trusted preview… in the bar above the preview. You get a warning first; nothing runs until you confirm. While it is active the bar stays visible and says Trusted — scripts enabled, and Revoke trust is one click away.
What trusted mode grants, and what it does not:
| Trusted preview | |
|---|---|
JavaScript, DOM, pointer events, requestAnimationFrame, Web Audio | ✅ runs |
Network (fetch, XMLHttpRequest, WebSocket, remote images/scripts) | ❌ blocked by default-src 'none' |
| VMark's own page, Tauri commands, your filesystem | ❌ unreachable — the document runs in an opaque origin of its own |
| Top-level navigation, popups, form submission, downloads, modals | ❌ not granted (sandbox="allow-scripts" and nothing else) |
| Camera, microphone, geolocation, clipboard | ❌ no feature is delegated to the frame |
localStorage / sessionStorage | ❌ unavailable — an opaque origin has no same-origin storage |
eval / new Function | ❌ not permitted |
Three properties worth knowing:
- Trust is never inferred. Not from the
.htmlextension, not from where the file came from, not from a sibling file you already trusted. Only the confirmation grants it. - Trust is never persisted. Close VMark and every grant is gone. It is also unavailable for an unsaved document, which has no identity to attach a grant to — save the file first.
- A trusted preview never re-runs itself. Editing the source marks it May not match the current source and waits for Reload, so a running simulation is not reset by every keystroke. The same marker appears when VMark cannot know what the frame is running — after you switch away from the tab and back, or close and reopen it, the preview keeps executing whatever was last published for that file, so it says so rather than claiming to be up to date. Reload re-publishes the file as it stands now.
Windows serves it over a local http origin
WebView2 has no custom URL schemes, so on Windows the trusted document is served from http://vmark-trusted.localhost instead of vmark-trusted:// — the same grant, the same sandbox and the same CSP, under the URL form Tauri uses for every custom protocol there. The safe preview works on every platform.
Trusted content is served from a vmark-trusted:// origin (http://vmark-trusted.localhost on Windows) with its own restrictive CSP. That indirection is required rather than decorative: a srcdoc, blob: or data: frame inherits VMark's own script-src 'self' policy, and a CSP inside the frame can only tighten an inherited one, never relax it — so no iframe attribute alone can make an inline script run.
Open in external editor
For code files, the read-only banner's Open in external editor button launches your editor of choice. Resolution order:
- Settings → Formats → External editor (the GUI field — see Settings). Pick an
.appbundle on macOS, an executable on Linux/Windows, or anything your shell would resolve. $VMARK_EXTERNAL_EDITOR(project-level env override)$VISUAL$EDITOR- Platform default (
open -ton macOS,notepad.exeon Windows,xdg-openon Linux)
The GUI setting wins over the environment variables — explicit beats implicit. Leave the field empty to use the env-var fallback chain.
VMark routes through a login-shell PATH so VS Code / Cursor / JetBrains wrappers resolve correctly when launched from a macOS GUI app.
Security gate
The open_in_external_editor Tauri command rejects:
- non-existent paths
- directories and other non-regular files (sockets, devices)
- paths whose canonicalized extension is not in VMark's registered format set
- symlinks whose canonical target fails any of the checks above
A compromised webview cannot use the button to launch the external editor on arbitrary system files (passwords, keys, etc.) — only on paths VMark would itself open.
What's not supported
Per the plan's non-goals:
- Not a code editor. No LSP, no autocomplete, no refactoring, no debugger, no git gutters.
- Not "every plain-text format." Bounded scope — see the table above.
- No HTML script execution by default. Sandboxed render only, unless you explicitly authorize one file via Trusted HTML preview.
- No print / export / copy-as-HTML for non-markdown formats in v1.
- Not yet supported as code viewers: Zig, Swift, Kotlin, Java, Elixir, OCaml, and other languages outside the 12-extension set. The decision rule is "languages we ourselves use" — file an issue if you'd like one added.
If a format you want isn't listed and isn't deliberately out of scope, file an issue.