Native markup editor support
Editor tooling for .native markup views (see skill-data/native-ui/SKILL.md for the language itself).
-
TextMate grammar (
syntaxes/native-markup.tmLanguage.json) — tags, attribute names, strings, comments, and{...}binding expressions get their own scopes;on-*event attributes andfor/if/elsestructure tags are scoped distinctly. -
Language server —
native markup lspspeaks LSP over stdio:- diagnostics on open/change (the same parser + validator as
native markup check, with line/column teaching messages), - completion for element names after
<and attribute/event names inside a tag, - hover docs for element and attribute names.
Binding paths and
Msgtags are not checked by the server — they need your app's concrete Model/Msg types, which are validated when the app builds (and on hot reload). Build-integrated binding validation is future work. - diagnostics on open/change (the same parser + validator as
-
VS Code extension (
package.json+extension.js) — a dependency-free client: rather than depending onvscode-languageclient(an npm package that would require a build step),extension.jswires the protocol itself (spawn, framing, initialize, document sync, diagnostics, completion, hover). Nonpm install, no bundler.
Build the server
zig build # produces zig-out/bin/native
Any editor below just needs native markup lsp to be runnable — put
zig-out/bin on PATH or point your editor at the absolute path.
VS Code
Install by symlinking this folder into your extensions directory:
ln -s /path/to/native-sdk/editors/native-markup ~/.vscode/extensions/native-sdk.native-markup-0.1.0
Then reload VS Code and open a .native file. If native is not on
PATH, set the server path in settings:
{
"native-markup.serverPath": "/path/to/native-sdk/zig-out/bin/native"
}
Remove any old "files.associations" entry mapping *.native to html
so the file picks up the native-markup language id.
(code --install-extension expects a packaged .vsix; the symlink route
avoids needing vsce/npm entirely.)
Helix
~/.config/helix/languages.toml:
[language-server.native-markup-lsp]
command = "native"
args = ["markup", "lsp"]
[[language]]
name = "native-markup"
scope = "source.native-markup"
file-types = ["native"]
comment-tokens = []
block-comment-tokens = { start = "<!--", end = "-->" }
language-servers = ["native-markup-lsp"]
auto-pairs = { '<' = '>', '{' = '}', '"' = '"' }
Helix has no .native tree-sitter grammar; until one exists you can add
grammar = "html" to the [[language]] block for approximate
highlighting — diagnostics, completion, and hover come from the LSP
either way.
Neovim (0.10+)
vim.filetype.add({ extension = { native = "native-markup" } })
vim.api.nvim_create_autocmd("FileType", {
pattern = "native-markup",
callback = function(args)
vim.lsp.start({
name = "native-markup-lsp",
cmd = { "native", "markup", "lsp" },
root_dir = vim.fs.dirname(vim.fs.find({ "build.zig", ".git" }, { upward = true })[1]),
}, { bufnr = args.buf })
end,
})
For highlighting, either treat the buffer as HTML
(vim.treesitter.language.register("html", "native-markup")) or rely on an LSP-only
setup — diagnostics, completion, and hover work regardless.
Smoke test (no editor required)
scripts/lsp-smoke.py drives the server over stdio with real
Content-Length framing — initialize, didOpen with a broken document — and
asserts a publishDiagnostics notification with the right line/column:
python3 editors/native-markup/scripts/lsp-smoke.py zig-out/bin/native