fix(init): guard against unnamed buffer in public API

Problem: calling compile/toggle/clean/open on an unsaved scratch
buffer passed an empty string as ctx.file, producing nonsensical
output paths like ".pdf" and silently passing empty strings to
compiler binaries.

Solution: add an early return with a WARN notification in compile,
toggle, clean, and open when the buffer has no file name.
This commit is contained in:
Barrett Ruth 2026-03-04 13:49:37 -05:00
parent b1fe5597c6
commit bc22350692
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
2 changed files with 74 additions and 0 deletions

View file

@ -146,6 +146,10 @@ end
---@param bufnr? integer ---@param bufnr? integer
function M.compile(bufnr) function M.compile(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf() 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 name = M.resolve_provider(bufnr)
if not name then if not name then
vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN) vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN)
@ -165,6 +169,10 @@ end
---@param bufnr? integer ---@param bufnr? integer
function M.clean(bufnr) function M.clean(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf() 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 name = M.resolve_provider(bufnr)
if not name then if not name then
vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN) vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN)
@ -178,6 +186,10 @@ end
---@param bufnr? integer ---@param bufnr? integer
function M.toggle(bufnr) function M.toggle(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf() 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 name = M.resolve_provider(bufnr)
if not name then if not name then
vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN) vim.notify('[preview.nvim]: no provider configured for this filetype', vim.log.levels.WARN)
@ -190,6 +202,10 @@ end
---@param bufnr? integer ---@param bufnr? integer
function M.open(bufnr) function M.open(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf() 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 name = M.resolve_provider(bufnr)
local open_config = name and config.providers[name] and config.providers[name].open local open_config = name and config.providers[name] and config.providers[name].open
if not compiler.open(bufnr, open_config) then if not compiler.open(bufnr, open_config) then

View file

@ -108,4 +108,62 @@ describe('preview', function()
helpers.delete_buffer(bufnr) helpers.delete_buffer(bufnr)
end) end)
end) end)
describe('unnamed buffer guard', function()
before_each(function()
helpers.reset_config({ typst = true })
preview = require('preview')
end)
local function capture_notify(fn)
local msg = nil
local orig = vim.notify
vim.notify = function(m)
msg = m
end
fn()
vim.notify = orig
return msg
end
it('compile warns on unnamed buffer', function()
local bufnr = helpers.create_buffer({}, 'typst')
local msg = capture_notify(function()
preview.compile(bufnr)
end)
assert.is_not_nil(msg)
assert.is_truthy(msg:find('no file name'))
helpers.delete_buffer(bufnr)
end)
it('toggle warns on unnamed buffer', function()
local bufnr = helpers.create_buffer({}, 'typst')
local msg = capture_notify(function()
preview.toggle(bufnr)
end)
assert.is_not_nil(msg)
assert.is_truthy(msg:find('no file name'))
helpers.delete_buffer(bufnr)
end)
it('clean warns on unnamed buffer', function()
local bufnr = helpers.create_buffer({}, 'typst')
local msg = capture_notify(function()
preview.clean(bufnr)
end)
assert.is_not_nil(msg)
assert.is_truthy(msg:find('no file name'))
helpers.delete_buffer(bufnr)
end)
it('open warns on unnamed buffer', function()
local bufnr = helpers.create_buffer({}, 'typst')
local msg = capture_notify(function()
preview.open(bufnr)
end)
assert.is_not_nil(msg)
assert.is_truthy(msg:find('no file name'))
helpers.delete_buffer(bufnr)
end)
end)
end) end)