From 99263dec9f33712eacf001b703acff5166a9f6a6 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:12:14 -0500 Subject: [PATCH 01/33] refactor(compiler): resolve output before args (#17) Problem: presets that need the output path in their args function (markdown, github) had to recompute it inline, duplicating the same gsub expression already in the output field. Solution: resolve output_file first in M.compile, then extend ctx with output = output_file into a resolved_ctx before evaluating args and cwd. Presets can now reference ctx.output directly. Add output? to the preview.Context type annotation. --- lua/preview/compiler.lua | 16 +++++++++------- lua/preview/init.lua | 1 + lua/preview/presets.lua | 6 ++---- spec/presets_spec.lua | 2 ++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lua/preview/compiler.lua b/lua/preview/compiler.lua index 0643ccd..eca9f4d 100644 --- a/lua/preview/compiler.lua +++ b/lua/preview/compiler.lua @@ -53,19 +53,21 @@ function M.compile(bufnr, name, provider, ctx) M.stop(bufnr) end + local output_file = '' + if provider.output then + output_file = eval_string(provider.output, ctx) + end + + local resolved_ctx = vim.tbl_extend('force', ctx, { output = output_file }) + local cmd = vim.list_extend({}, provider.cmd) if provider.args then - vim.list_extend(cmd, eval_list(provider.args, ctx)) + vim.list_extend(cmd, eval_list(provider.args, resolved_ctx)) end local cwd = ctx.root if provider.cwd then - cwd = eval_string(provider.cwd, ctx) - end - - local output_file = '' - if provider.output then - output_file = eval_string(provider.output, ctx) + cwd = eval_string(provider.cwd, resolved_ctx) end if output_file ~= '' then diff --git a/lua/preview/init.lua b/lua/preview/init.lua index f4f2831..2bee03a 100644 --- a/lua/preview/init.lua +++ b/lua/preview/init.lua @@ -19,6 +19,7 @@ ---@field file string ---@field root string ---@field ft string +---@field output? string ---@class preview.Diagnostic ---@field lnum integer diff --git a/lua/preview/presets.lua b/lua/preview/presets.lua index 8b9faab..c1de0df 100644 --- a/lua/preview/presets.lua +++ b/lua/preview/presets.lua @@ -138,8 +138,7 @@ M.markdown = { ft = 'markdown', cmd = { 'pandoc' }, args = function(ctx) - local output = ctx.file:gsub('%.md$', '.html') - return { ctx.file, '-s', '--embed-resources', '-o', output } + return { ctx.file, '-s', '--embed-resources', '-o', ctx.output } end, output = function(ctx) return (ctx.file:gsub('%.md$', '.html')) @@ -158,7 +157,6 @@ M.github = { ft = 'markdown', cmd = { 'pandoc' }, args = function(ctx) - local output = ctx.file:gsub('%.md$', '.html') return { '-f', 'gfm', @@ -168,7 +166,7 @@ M.github = { '--css', 'https://cdn.jsdelivr.net/gh/pixelbrackets/gfm-stylesheet@master/dist/gfm.css', '-o', - output, + ctx.output, } end, output = function(ctx) diff --git a/spec/presets_spec.lua b/spec/presets_spec.lua index 904a4f4..6eaa613 100644 --- a/spec/presets_spec.lua +++ b/spec/presets_spec.lua @@ -150,6 +150,7 @@ describe('presets', function() file = '/tmp/document.md', root = '/tmp', ft = 'markdown', + output = '/tmp/document.html', } it('has ft', function() @@ -233,6 +234,7 @@ describe('presets', function() file = '/tmp/document.md', root = '/tmp', ft = 'markdown', + output = '/tmp/document.html', } it('has ft', function() From bce3cec0e66654eb7b13ad46c5dbe8f9209e72de Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:12:28 -0500 Subject: [PATCH 02/33] docs: update help file for recent additions (#18) --- doc/preview.nvim.txt | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/doc/preview.nvim.txt b/doc/preview.nvim.txt index 0b44a91..c8bc708 100644 --- a/doc/preview.nvim.txt +++ b/doc/preview.nvim.txt @@ -74,9 +74,16 @@ Provider fields:~ `output` string|function Output file path. If a function, receives a |preview.Context|. - `error_parser` function Receives (stderr, |preview.Context|) + `error_parser` function Receives (output, |preview.Context|) and returns vim.Diagnostic[]. + `errors` false|'diagnostic'|'quickfix' + How parse errors are reported. + `false` suppresses error handling. + `'quickfix'` populates the quickfix + list and opens it. Default: + `'diagnostic'`. + `clean` string[]|function Command to remove build artifacts. If a function, receives a |preview.Context|. @@ -85,7 +92,6 @@ Provider fields:~ successful compilation. `true` uses |vim.ui.open()|. A string[] is run as a command with the output path appended. - Presets default to `{ 'xdg-open' }`. *preview.Context* Context fields:~ @@ -94,6 +100,8 @@ Context fields:~ `file` string Absolute file path. `root` string Project root (git root or file directory). `ft` string Filetype. + `output` string? Resolved output file path (set after `output` + is evaluated, available to `args` functions). Example enabling presets:~ >lua @@ -156,7 +164,8 @@ COMMANDS *preview.nvim-commands* `stop` Kill active compilation for the current buffer. `clean` Run the provider's clean command. `toggle` Toggle auto-compile on save for the current buffer. - `status` Echo compilation status (idle, compiling, toggled). + `open` Open the last compiled output without recompiling. + `status` Echo compilation status (idle, compiling, watching). ============================================================================== API *preview.nvim-api* @@ -175,9 +184,16 @@ preview.toggle({bufnr?}) *preview.toggle()* immediately compiled and automatically recompiled on each save (`BufWritePost`). Call again to stop. +preview.open({bufnr?}) *preview.open()* + Open the last compiled output for the buffer without recompiling. + preview.status({bufnr?}) *preview.status()* Returns a |preview.Status| table. +preview.statusline({bufnr?}) *preview.statusline()* + Returns a short status string for statusline integration: + `'compiling'`, `'watching'`, or `''` (idle). + *preview.Status* Status fields:~ From 62961c854168cec9ae30e52c3e1b2e914248f1f2 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:41:47 -0500 Subject: [PATCH 03/33] feat: unified reload field for live-preview (SSE + long-running watch) (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(reload): add SSE live-reload server module Problem: HTML output from pandoc has no live-reload; the browser must be refreshed manually after each compile. Solution: add lua/preview/reload.lua — a minimal SSE-only TCP server. start() binds 127.0.0.1:5554 and keeps EventSource connections alive; broadcast() pushes a reload event to all clients; inject() appends an EventSource script before
hello