Commit graph

13 commits

Author SHA1 Message Date
Barrett Ruth
39406c559c
feat: compile notifications and long-running provider feedback (#55)
* feat(compiler): add compile start/complete notifications

Problem: No user-facing feedback when compilation starts or finishes.
Long-running compilers like pandoc with `--embed-resources` leave the
user staring at nothing for 15+ seconds.

Solution: Notify "compiling..." at compile start and "compilation
complete" on success. The initial `toggle` call uses a combined
"compiling with <name>..." message to avoid stacking two notifications.

* refactor(presets): use `--katex` instead of `--embed-resources --mathml`

Problem: `--embed-resources` with `--mathml` caused pandoc to inline all
assets at compile time, adding ~15s per save for KaTeX-heavy documents.

Solution: Default to `--katex`, which inserts a CDN `<script>` tag and
defers rendering to the browser. Users can opt into `--embed-resources`
or `--mathml` via `extra_args`.

* docs(presets): rewrite math rendering section for `--katex` default

* refactor(compiler): simplify notification flow, add failure notify

Problem: `compile()` used an `opts.silent` escape hatch so `toggle()`
could suppress duplicate notifications. Compilation failures had no
user-facing notification.

Solution: Remove `opts.silent` — `compile()` unconditionally notifies
on start, success, and failure. `toggle()` no longer emits its own
message.

* feat(compiler): add per-recompile notifications for long-running providers

Problem: long-running providers like `typst watch` had no per-recompile
feedback — the process stays alive and individual success/failure was
never reported.

Solution: add a persistent `output_watcher` fs_event that fires
"compilation complete" on every output mtime bump, and track
`has_errors` on `BufState` so stderr diagnostics trigger a one-shot
"compilation failed" notification. `diagnostic.set()` now returns the
diagnostic count to support this flow.

* ci: format

* chore: remove testing files
2026-03-06 14:58:10 -05:00
Barrett Ruth
36e49cbd41
fix(presets): add --mathml to pandoc markdown args (#53)
* fix(presets): add `--mathml` to `markdown` and `github` pandoc args

Problem: pandoc's default HTML math renderer cannot handle most TeX and
dumps raw LaTeX source into the output. `--mathjax` and `--katex` are
incompatible with `--embed-resources` because pandoc cannot inline
dynamically-loaded JavaScript modules and fonts.

Solution: add `--mathml` to both `markdown` and `github` preset args.
MathML is rendered natively by all modern browsers with no external
dependencies, making it the only math option compatible with
self-contained HTML output.

* docs(presets): add math rendering section with KaTeX recipe

Problem: the `markdown` and `github` presets now default to `--mathml`
but users may want KaTeX or MathJax rendering instead, and the
incompatibility with `--embed-resources` is non-obvious.

Solution: add a `preview-math` section to the presets docs explaining
the default, why `--katex`/`--mathjax` require dropping
`--embed-resources`, and a concrete recipe for KaTeX with `github`.

* test(presets): update `markdown` and `github` args assertions for `--mathml`
2026-03-06 13:39:22 -05:00
Barrett Ruth
3e6ba580e4
fix: quickfix support for long-running providers (#41)
* fix(compiler): open quickfix in background, retain focus on source buffer

* fix(compiler): use cwindow and win_gotoid for quickfix focus management

* fix: unused var warning and update typst reload test for short format

* fix: remove testing files
2026-03-04 17:23:06 -05:00
Barrett Ruth
68e2e82232
fix(presets): add --failure-level ERROR to asciidoctor, add clean to typst/pdflatex/tectonic, skip auto-open on one-shot compile (#35)
Problem: asciidoctor exits 0 on errors so error_parser never ran.
typst, pdflatex, and tectonic had no clean subcommand. auto-open
fired on :Preview compile, surprising users who just want a build.

Solution: pass --failure-level ERROR in asciidoctor args. Add clean
commands to typst (rm pdf), pdflatex (rm pdf/aux/log/synctex.gz),
and tectonic (rm pdf). Gate auto-open on not opts.oneshot so it
only fires during toggle/watch mode.
2026-03-04 14:57:36 -05:00
Barrett Ruth
180c672983
feat(presets): add pdflatex, tectonic, asciidoctor, and quarto presets (#30)
* feat(presets): add pdflatex preset

Adds a direct pdflatex preset for users who want single-pass
compilation without latexmk orchestration. Uses -file-line-error
for parseable diagnostics and reuses the existing parse_latexmk
error parser since both emit the same file:line: message format.

* 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.

* feat(presets): add asciidoctor preset

Adds an asciidoctor preset for AsciiDoc → HTML compilation with SSE
live-reload. Includes a parse_asciidoctor error parser handling the
"asciidoctor: SEVERITY: file: line N: message" format for both
ERROR and WARNING diagnostics.

* feat(presets): add quarto preset

Adds a quarto preset for .qmd scientific documents rendering to
self-contained HTML with SSE live-reload. Uses --embed-resources
to avoid a _files directory in the common case. No error_parser
since quarto errors are heterogeneous (mixed R/Python/pandoc output).

* refactor: apply stylua formatting to new preset code
2026-03-04 14:02:30 -05:00
Barrett Ruth
62961c8541
feat: unified reload field for live-preview (SSE + long-running watch) (#19)
* 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 </body> (or at EOF) on every compile so
pandoc overwrites do not lose the tag.

* refactor(presets): add reload field, remove synctex field

Problem: the synctex field only handled PDF forward search and left
HTML live-preview and typst watch mode unsupported.

Solution: add reload = function(ctx) returning { 'typst', 'watch',
ctx.file } to typst (long-running watch mode), reload = true to
markdown and github (SSE push after each pandoc compile), and remove
synctex = true from latex (the -synctex=1 arg in latex.args remains
for .synctex.gz generation).

* refactor(init): replace synctex field and validation with reload

Problem: ProviderConfig still declared synctex and validated it, but
the field is being dropped in favour of the general-purpose reload.

Solution: replace the synctex annotation and vim.validate call with the
reload field, accepting boolean | string[] | function.

* feat(compiler): support long-running watch processes and SSE reload

Problem: compile() only supports one-shot invocations, requiring a
BufWritePost autocmd for watch mode and leaving HTML without live-
reload.

Solution: resolve_reload_cmd() maps provider.reload (function or table)
to a command; when present, compile() spawns it as a long-running
process instead of building a one-shot cmd from provider.cmd + args.
toggle() detects long-running providers and toggles the process
directly instead of registering a BufWritePost autocmd. When
reload = true and output is .html, the SSE server is invoked after
each successful compile. status() reports is_reload processes as
watching, not compiling. stop_all() also stops the SSE server.

* fix(compiler): format is_longrunning and annotate is_reload field

Problem: stylua required is_longrunning to be on one line; lua-ls
warned about undefined field is_reload on preview.Process.

Solution: inline the boolean expression and add is_reload? to the
preview.Process annotation.

* refactor: rename compile/toggle commands to build/watch

Problem: `compile` and `toggle` are accurate but unintuitive — `compile`
sounds academic and `toggle` says nothing about what it toggles.

Solution: rename the public API and `:Preview` subcommands to `build`
(one-shot) and `watch` (live preview). Internal compiler functions are
unchanged. No aliases for old names — clean break.
2026-03-03 16:41:47 -05:00
Barrett Ruth
99263dec9f
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.
2026-03-03 15:12:14 -05:00
Barrett Ruth
0f353446b6
fix(presets): correct error parsers for real compiler output (#11)
Problem: all three built-in error parsers were broken against real
compiler output. Typst set source to the relative file path, overriding
the provider name. LaTeX errors go to stdout but the parser only
received stderr. Pandoc's pattern matched "Error at" but not the real
"Error parsing YAML metadata at" format, and single-line parsing missed
multiline messages.

Solution: pass combined stdout+stderr to error_parser so LaTeX stdout
errors are visible. Remove source = file from the Typst parser so
diagnostic.lua defaults it to the provider name. Rewrite the Pandoc
parser with line-based lookahead: match (line N, column N) regardless
of prefix text, skip YAML parse exception lines when looking ahead for
the human-readable message. Rename stderr param to output throughout
diagnostic.lua, presets.lua, and init.lua annotations.
2026-03-03 14:14:59 -05:00
Barrett Ruth
277daa63ca
feat(presets): add error parsers for built-in presets (#9)
Problem: none of the four presets defined an error_parser, so the
diagnostic infrastructure went unused out of the box.

Solution: add parsers for typst (file:line:col short format), latexmk
(pdflatex file-line-error + summary), and pandoc (parse errors, YAML
exceptions, generic errors). Enable machine-parseable output flags in
typst and latex args. Pandoc parser is shared between markdown and
github presets.
2026-03-03 13:42:59 -05:00
Barrett Ruth
187474bb3d
refactor(presets): replace xdg-open with vim.ui.open (#7)
Problem: all presets hardcoded `open = { 'xdg-open' }`, making them
Linux-only. The compiler already handles `open = true` via
`vim.ui.open()`, which is cross-platform.

Solution: change all four presets to `open = true`.
2026-03-03 13:37:16 -05:00
Barrett Ruth
2d212aa220
refactor(config): replace array preset syntax with preset_name = true (#3)
* refactor(config): replace array preset syntax with preset_name = true

Problem: setup() mixed array entries (preset names) and hash entries
(custom providers keyed by filetype), requiring verbose
vim.tbl_deep_extend boilerplate to override presets.

Solution: unify under a single key=value model. Keys are preset names
or filetypes; true registers the preset as-is, a table deep-merges
with the matching preset (or registers a custom provider if no preset
matches), and false is a no-op. Array entries are dropped. Also adds
-f gfm to presets.github args so pandoc parses input as GFM.

* ci: format

* fix(presets): parenthesize gsub output to suppress redundant-return-value
2026-03-03 00:25:49 -05:00
673573044f
feat: rename watch → toggle, auto-compile on start, built-in opener
Problem: :Preview watch only registered a BufWritePost autocmd without
compiling immediately, required boilerplate to open output files after
first compilation, and was misleadingly named.

Solution: Rename watch → toggle throughout. M.toggle now compiles
immediately on activation. Add an open field to ProviderConfig: true
calls vim.ui.open(), a string[] runs the command with the output path
appended, tracked per-buffer so the file opens only once. All presets
default to { 'xdg-open' }. Health check validates opener binaries.
Guard the async compile callback against invalid buffer ids.
2026-03-02 23:37:44 -05:00
942438f817
feat: rename 2026-03-02 21:23:40 -05:00