From c1734eec8f9cd57d9585549a14dd314034c64ded Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Fri, 13 Mar 2026 08:19:57 -0400 Subject: [PATCH] fix: fall back to /tmp for buffers without a backing file Problem: markdown and gfm presets fail when the buffer has no file on disk (e.g. unnamed buffer with `ft=markdown`, or a named buffer whose path doesn't exist yet) because `build_context` passes a nonexistent path to pandoc and `compile` guards reject empty buffer names. Solution: `build_context` now detects missing files and redirects `ctx.file` to `/tmp/{bufnr}-{name}`. `compile` writes buffer contents to that temp path via `vim.fn.writefile` instead of `:silent! update`. --- lua/preview/compiler.lua | 10 +++++++-- lua/preview/init.lua | 46 ++++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/lua/preview/compiler.lua b/lua/preview/compiler.lua index 672b02f..c3ffbfa 100644 --- a/lua/preview/compiler.lua +++ b/lua/preview/compiler.lua @@ -215,8 +215,14 @@ function M.compile(bufnr, name, provider, ctx, opts) return end - if vim.bo[bufnr].modified then - vim.cmd('silent! update') + local buf_file = vim.api.nvim_buf_get_name(bufnr) + if buf_file ~= '' and buf_file == ctx.file then + if vim.bo[bufnr].modified then + vim.cmd('silent! update') + end + else + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + vim.fn.writefile(lines, ctx.file) end local s = get_state(bufnr) diff --git a/lua/preview/init.lua b/lua/preview/init.lua index 489679f..5383623 100644 --- a/lua/preview/init.lua +++ b/lua/preview/init.lua @@ -139,27 +139,49 @@ function M.resolve_provider(bufnr) return ft end +local ft_ext = { + markdown = 'md', + typst = 'typ', + tex = 'tex', + asciidoc = 'adoc', + plantuml = 'puml', + mermaid = 'mmd', + quarto = 'qmd', +} + ---@param bufnr? integer ---@return preview.Context function M.build_context(bufnr) bufnr = bufnr or vim.api.nvim_get_current_buf() local file = vim.api.nvim_buf_get_name(bufnr) - local root = vim.fs.root(bufnr, { '.git' }) or vim.fn.fnamemodify(file, ':h') + local ft = vim.bo[bufnr].filetype + local root + + if file ~= '' and vim.uv.fs_stat(file) then + root = vim.fs.root(bufnr, { '.git' }) or vim.fn.fnamemodify(file, ':h') + else + local basename + if file ~= '' then + basename = string.format('%d-%s', bufnr, vim.fn.fnamemodify(file, ':t')) + else + local ext = ft_ext[ft] or ft + basename = string.format('preview-%d.%s', bufnr, ext) + end + file = '/tmp/' .. basename + root = '/tmp' + end + return { bufnr = bufnr, file = file, root = root, - ft = vim.bo[bufnr].filetype, + ft = ft, } end ---@param bufnr? integer function M.compile(bufnr) bufnr = bufnr or vim.api.nvim_get_current_buf() - if vim.api.nvim_buf_get_name(bufnr) == '' then - vim.notify('[preview.nvim]: buffer has no file name', vim.log.levels.WARN) - return - end local name = M.resolve_provider(bufnr) if not name then vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN) @@ -179,10 +201,6 @@ end ---@param bufnr? integer function M.clean(bufnr) bufnr = bufnr or vim.api.nvim_get_current_buf() - if vim.api.nvim_buf_get_name(bufnr) == '' then - vim.notify('[preview.nvim]: buffer has no file name', vim.log.levels.WARN) - return - end local name = M.resolve_provider(bufnr) if not name then vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN) @@ -196,10 +214,6 @@ end ---@param bufnr? integer function M.toggle(bufnr) bufnr = bufnr or vim.api.nvim_get_current_buf() - if vim.api.nvim_buf_get_name(bufnr) == '' then - vim.notify('[preview.nvim]: buffer has no file name', vim.log.levels.WARN) - return - end local name = M.resolve_provider(bufnr) if not name then vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN) @@ -212,10 +226,6 @@ end ---@param bufnr? integer function M.open(bufnr) bufnr = bufnr or vim.api.nvim_get_current_buf() - if vim.api.nvim_buf_get_name(bufnr) == '' then - vim.notify('[preview.nvim]: buffer has no file name', vim.log.levels.WARN) - return - end local name = M.resolve_provider(bufnr) local open_config = name and config.providers[name] and config.providers[name].open if not compiler.open(bufnr, open_config) then