feat(presets): add tectonic preset

Adds a tectonic preset for the modern Rust-based LaTeX engine, which
auto-downloads packages and requires no TeX installation. Reuses
parse_latexmk since tectonic emits the same file:line: message
diagnostic format.
This commit is contained in:
Barrett Ruth 2026-03-04 13:53:01 -05:00
parent 8ebe2ed80b
commit 3a3a0783e8
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
3 changed files with 68 additions and 0 deletions

View file

@ -158,6 +158,7 @@ Import them from `preview.presets`:
`presets.typst` typst compile → PDF
`presets.latex` latexmk -pdf → PDF (with clean support)
`presets.pdflatex` pdflatex → PDF (single pass, no latexmk)
`presets.tectonic` tectonic → PDF (Rust-based LaTeX engine)
`presets.markdown` pandoc → HTML (standalone, embedded)
`presets.github` pandoc → HTML (GitHub-styled, `-f gfm` input)

View file

@ -153,6 +153,22 @@ M.pdflatex = {
open = true,
}
---@type preview.ProviderConfig
M.tectonic = {
ft = 'tex',
cmd = { 'tectonic' },
args = function(ctx)
return { ctx.file }
end,
output = function(ctx)
return (ctx.file:gsub('%.tex$', '.pdf'))
end,
error_parser = function(output)
return parse_latexmk(output)
end,
open = true,
}
---@type preview.ProviderConfig
M.markdown = {
ft = 'markdown',

View file

@ -212,6 +212,57 @@ describe('presets', function()
end)
end)
describe('tectonic', function()
local tex_ctx = {
bufnr = 1,
file = '/tmp/document.tex',
root = '/tmp',
ft = 'tex',
}
it('has ft', function()
assert.are.equal('tex', presets.tectonic.ft)
end)
it('has cmd', function()
assert.are.same({ 'tectonic' }, presets.tectonic.cmd)
end)
it('returns args with file path', function()
assert.are.same({ '/tmp/document.tex' }, presets.tectonic.args(tex_ctx))
end)
it('returns pdf output path', function()
assert.are.equal('/tmp/document.pdf', presets.tectonic.output(tex_ctx))
end)
it('has open enabled', function()
assert.is_true(presets.tectonic.open)
end)
it('has no clean command', function()
assert.is_nil(presets.tectonic.clean)
end)
it('has no reload', function()
assert.is_nil(presets.tectonic.reload)
end)
it('parses file-line-error format', function()
local output = './document.tex:5: Missing $ inserted.'
local diagnostics = presets.tectonic.error_parser(output, tex_ctx)
assert.are.equal(1, #diagnostics)
assert.are.equal(4, diagnostics[1].lnum)
assert.are.equal(0, diagnostics[1].col)
assert.are.equal('Missing $ inserted.', diagnostics[1].message)
assert.are.equal(vim.diagnostic.severity.ERROR, diagnostics[1].severity)
end)
it('returns empty table for clean output', function()
assert.are.same({}, presets.tectonic.error_parser('', tex_ctx))
end)
end)
describe('markdown', function()
local md_ctx = {
bufnr = 1,