From 2888c5bb09e88b1d0c64f7816edbf4d4d66afe53 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Tue, 3 Mar 2026 17:41:53 -0500 Subject: [PATCH 1/2] fix(reload): bind SSE server to port 0 for OS-assigned port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the SSE reload server hardcoded port 5554, causing silent failure when that port was already in use. bind() would fail but its return value was never checked; listen() would also error and silently drop via the if err then return end guard. inject() still wrote the dead EventSource URL into the HTML, so the browser would connect to whatever was on 5554 — or nothing — and live reload would silently stop working. Solution: bind to port or 0 so the OS assigns a free port, then call getsockname() after bind to capture the actual port into actual_port. inject() reads actual_port in preference to the hardcoded constant, and stop() resets it. PORT = 5554 is kept only as a last-resort fallback in inject() if actual_port is unset. --- lua/preview/reload.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lua/preview/reload.lua b/lua/preview/reload.lua index fd64309..d2c1de9 100644 --- a/lua/preview/reload.lua +++ b/lua/preview/reload.lua @@ -2,6 +2,7 @@ local M = {} local PORT = 5554 local server_handle = nil +local actual_port = nil local clients = {} local function make_script(port) @@ -14,12 +15,15 @@ local function make_script(port) end function M.start(port) - port = port or PORT if server_handle then return end local server = vim.uv.new_tcp() - server:bind('127.0.0.1', port) + server:bind('127.0.0.1', port or 0) + local sockname = server:getsockname() + if sockname then + actual_port = sockname.port + end server:listen(128, function(err) if err then return @@ -66,6 +70,7 @@ function M.stop() server_handle:close() server_handle = nil end + actual_port = nil end function M.broadcast() @@ -85,7 +90,7 @@ function M.broadcast() end function M.inject(path, port) - port = port or PORT + port = actual_port or port or PORT local f = io.open(path, 'r') if not f then return From ea783e9983dc637565bb95d94e33050d7194ff45 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Tue, 3 Mar 2026 17:49:23 -0500 Subject: [PATCH 2/2] fix(compiler): resolve output into ctx before evaluating clean command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: M.clean() passes the raw ctx (no output field) to the provider's clean function. Built-in presets work around this by recomputing the output path inline, but custom providers using ctx.output in their clean function receive nil. Solution: resolve output_file from provider.output before eval, extend ctx into resolved_ctx with the output field, and use resolved_ctx when evaluating clean and cwd — consistent with how M.compile() handles args. --- lua/preview/compiler.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lua/preview/compiler.lua b/lua/preview/compiler.lua index e19cbf0..6f9b312 100644 --- a/lua/preview/compiler.lua +++ b/lua/preview/compiler.lua @@ -396,10 +396,16 @@ function M.clean(bufnr, name, provider, ctx) return end - local cmd = eval_list(provider.clean, ctx) - local cwd = ctx.root + 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 = eval_list(provider.clean, resolved_ctx) + local cwd = resolved_ctx.root if provider.cwd then - cwd = eval_string(provider.cwd, ctx) + cwd = eval_string(provider.cwd, resolved_ctx) end log.dbg('cleaning buffer %d with provider "%s": %s', bufnr, name, table.concat(cmd, ' '))