From 28dda6515efb0cf33dbb833d0c3a0be05c4a20e3 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 10:43:08 -0500 Subject: [PATCH 1/6] feat: add `mermaid` preset Problem: no built-in support for compiling mermaid diagrams via `mmdc`. Solution: add a `mermaid` preset that compiles `.mmd` files to SVG and parses `Parse error on line N` diagnostics from stderr. Add `mermaid-cli` to the nix dev shell. --- flake.nix | 1 + lua/preview/presets.lua | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/flake.nix b/flake.nix index 4ae4479..d5bdae4 100644 --- a/flake.nix +++ b/flake.nix @@ -33,6 +33,7 @@ pkgs.selene pkgs.lua-language-server pkgs.plantuml + pkgs.mermaid-cli ]; }; }); diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua index e7c51e3..1b5333e 100644 --- a/lua/preview/presets.lua +++ b/lua/preview/presets.lua @@ -302,6 +302,37 @@ M.plantuml = { open = true, } +---@type preview.ProviderConfig +M.mermaid = { + ft = 'mermaid', + cmd = { 'mmdc' }, + args = function(ctx) + return { '-i', ctx.file, '-o', ctx.output } + end, + output = function(ctx) + return (ctx.file:gsub('%.mmd$', '.svg')) + end, + error_parser = function(output) + local diagnostics = {} + for line in output:gmatch('[^\r\n]+') do + local lnum = line:match('^%s*Parse error on line (%d+)') + if lnum then + table.insert(diagnostics, { + lnum = tonumber(lnum) - 1, + col = 0, + message = line, + severity = vim.diagnostic.severity.ERROR, + }) + end + end + return diagnostics + end, + clean = function(ctx) + return { 'rm', '-f', (ctx.file:gsub('%.mmd$', '.svg')) } + end, + open = true, +} + ---@type preview.ProviderConfig M.quarto = { ft = 'quarto', From 6f090fdcf33155cb116b898109c6dcaa106e6e4a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 10:55:03 -0500 Subject: [PATCH 2/6] build: split nix dev shell into `default` and `presets` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the single dev shell mixed dev tooling (linters, test runner) with preset compiler tools, causing heavy rebuilds (e.g. Chromium for `mermaid-cli`) for contributors who only need the dev tools. Solution: extract dev tooling into a shared `devTools` list and expose two shells — `default` for development and `presets` for running all built-in preset compilers (`typst`, `texliveMedium`, `tectonic`, `pandoc`, `asciidoctor`, `quarto`, `plantuml`, `mermaid-cli`). --- flake.nix | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index 4ae4479..636f4d0 100644 --- a/flake.nix +++ b/flake.nix @@ -19,9 +19,9 @@ { formatter = forEachSystem (pkgs: pkgs.nixfmt-tree); - devShells = forEachSystem (pkgs: { - default = pkgs.mkShell { - packages = [ + devShells = forEachSystem (pkgs: + let + devTools = [ (pkgs.luajit.withPackages ( ps: with ps; [ busted @@ -32,9 +32,24 @@ pkgs.stylua pkgs.selene pkgs.lua-language-server - pkgs.plantuml ]; - }; - }); + in + { + default = pkgs.mkShell { + packages = devTools; + }; + presets = pkgs.mkShell { + packages = devTools ++ [ + pkgs.typst + pkgs.texliveMedium + pkgs.tectonic + pkgs.pandoc + pkgs.asciidoctor + pkgs.quarto + pkgs.plantuml + pkgs.mermaid-cli + ]; + }; + }); }; } From 8c9847e321bf277e5f8de8d7b7eca6a17dd86b8e Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Thu, 5 Mar 2026 11:05:16 -0500 Subject: [PATCH 3/6] build: split nix dev shell into `default` and `presets` (#48) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the single dev shell mixed dev tooling (linters, test runner) with preset compiler tools, causing heavy rebuilds (e.g. Chromium for `mermaid-cli`) for contributors who only need the dev tools. Solution: extract dev tooling into a shared `devTools` list and expose two shells — `default` for development and `presets` for running all built-in preset compilers (`typst`, `texliveMedium`, `tectonic`, `pandoc`, `asciidoctor`, `quarto`, `plantuml`, `mermaid-cli`). --- flake.nix | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index d5bdae4..636f4d0 100644 --- a/flake.nix +++ b/flake.nix @@ -19,9 +19,9 @@ { formatter = forEachSystem (pkgs: pkgs.nixfmt-tree); - devShells = forEachSystem (pkgs: { - default = pkgs.mkShell { - packages = [ + devShells = forEachSystem (pkgs: + let + devTools = [ (pkgs.luajit.withPackages ( ps: with ps; [ busted @@ -32,10 +32,24 @@ pkgs.stylua pkgs.selene pkgs.lua-language-server - pkgs.plantuml - pkgs.mermaid-cli ]; - }; - }); + in + { + default = pkgs.mkShell { + packages = devTools; + }; + presets = pkgs.mkShell { + packages = devTools ++ [ + pkgs.typst + pkgs.texliveMedium + pkgs.tectonic + pkgs.pandoc + pkgs.asciidoctor + pkgs.quarto + pkgs.plantuml + pkgs.mermaid-cli + ]; + }; + }); }; } From 59419e6003b2afb062d6a449c9b94fc41041994b Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 12:02:32 -0500 Subject: [PATCH 4/6] refactor(presets): simplify `mermaid` error parser Problem: the inline `mermaid` error_parser looped over every line and used the `Parse error on line N:` header as the message, losing the useful `Expecting ..., got ...` token detail. Solution: extract `parse_mermaid` alongside the other parse functions, use a single `output:match` (mermaid's JISON parser stops at the first error), and surface the `Expecting ..., got ...` line as the message. --- lua/preview/presets.lua | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua index 1b5333e..796a195 100644 --- a/lua/preview/presets.lua +++ b/lua/preview/presets.lua @@ -115,6 +115,20 @@ local function parse_asciidoctor(output) return diagnostics end +---@param output string +---@return preview.Diagnostic[] +local function parse_mermaid(output) + local lnum = output:match('Parse error on line (%d+)') + if not lnum then return {} end + local msg = output:match('(Expecting .+)') or 'parse error' + return { { + lnum = tonumber(lnum) - 1, + col = 0, + message = msg, + severity = vim.diagnostic.severity.ERROR, + } } +end + ---@type preview.ProviderConfig M.typst = { ft = 'typst', @@ -313,19 +327,7 @@ M.mermaid = { return (ctx.file:gsub('%.mmd$', '.svg')) end, error_parser = function(output) - local diagnostics = {} - for line in output:gmatch('[^\r\n]+') do - local lnum = line:match('^%s*Parse error on line (%d+)') - if lnum then - table.insert(diagnostics, { - lnum = tonumber(lnum) - 1, - col = 0, - message = line, - severity = vim.diagnostic.severity.ERROR, - }) - end - end - return diagnostics + return parse_mermaid(output) end, clean = function(ctx) return { 'rm', '-f', (ctx.file:gsub('%.mmd$', '.svg')) } From 8c04cf19eaeebf852525f60531712f764443e006 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 12:03:50 -0500 Subject: [PATCH 5/6] ci: format --- lua/preview/presets.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua index 796a195..d4b03cc 100644 --- a/lua/preview/presets.lua +++ b/lua/preview/presets.lua @@ -119,14 +119,18 @@ end ---@return preview.Diagnostic[] local function parse_mermaid(output) local lnum = output:match('Parse error on line (%d+)') - if not lnum then return {} end + if not lnum then + return {} + end local msg = output:match('(Expecting .+)') or 'parse error' - return { { - lnum = tonumber(lnum) - 1, - col = 0, - message = msg, - severity = vim.diagnostic.severity.ERROR, - } } + return { + { + lnum = tonumber(lnum) - 1, + col = 0, + message = msg, + severity = vim.diagnostic.severity.ERROR, + }, + } end ---@type preview.ProviderConfig From 22ffea117c72ca110036a9910da7796c1e28a599 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 12:05:25 -0500 Subject: [PATCH 6/6] ci: format --- flake.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 636f4d0..f6c279b 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,8 @@ { formatter = forEachSystem (pkgs: pkgs.nixfmt-tree); - devShells = forEachSystem (pkgs: + devShells = forEachSystem ( + pkgs: let devTools = [ (pkgs.luajit.withPackages ( @@ -50,6 +51,7 @@ pkgs.mermaid-cli ]; }; - }); + } + ); }; }