## Features
- Support multi-page export in the server export command. Added an extra
arg to decide whether to write to the file or only return data for
client use (page preview in exporter). VSCode users can use this feature
via the quick-export command or code lens.
- (refactor) Move most export logic from tinymist to tinymist-task,
excluding typlite-related, which already depends on tinymist-task.
- Added relevant export tests. The export e2e test now includes hash
checking for all targets.
## Not done
- Support new args in `TypstExtraArgs` for CLI compilation.
---------
Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
Add a lint warning for unknown math variables[^1], powered by Tinymist's
existing reference analysis. This allows users to see all such undefined
variables at once if they have the linter enabled, instead of just the
first error from the compiler. The autofix from #2062 is also applicable
to these warnings.
Example:

(The first error is pre-existing and emitted by the Typst compiler; the
second warning is new from this PR and emitted by us.)
Implementation notes:
- The generated diagnostic tries to closely match the corresponding
Typst compiler error, with one deliberate change: to differentiate the
Tinymist warning and the compiler error, we use the message `potentially
unknown variable: ...` instead of `unknown variable: ...`. I am not the
biggest fan of this choice, but I think it is very important that users
don't blame the Typst compiler for warnings that we generate; changing
the message so that it isn't an exact clone is the best way I thought of
for now.
- We avoid duplicating a warning if the compiler has already generated
an error for a given identifier by computing a set of `KnownLintIssues`
from the compiler diagnostics and threading this information through the
lint routines.
[^1]: If users like this warning, we can extend it later to apply to
undefined variables outside of math as well.
---------
Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
This PR improves the help message of the CLL. Also, we change the verbs
in the help message from plural (e.g. `compiles`) to singular (e.g.
`compile`). This matches the style of `clap-rs`.
Added tests about critical help messages.
This PR fixes a latent cache invalidation issue with project snapshots.
I recommend reviewing commit-by-commit, even though this is a small
change. Only the last commit changes behavior; the rest are cleaning up
code to make it easier to see what is happening.
---
Here's what I think is the problem.
Project instance states (`ProjectInsState`) provide access to a snapshot
of the latest compilation result. This snapshot is cached for
performance:
```rust
match self.snapshot.as_ref() {
Some(snap) if snap.world().revision() == self.verse.revision => snap.clone(),
// otherwise recompute
}
```
Unfortunately, it turns out that the cached snapshot may be outdated
even if the revision matches. (In practice, it will usually just lag one
compilation behind, and I think this is why it hasn't caused any
observable issues--one compilation behind is not that much, especially
if the user is continuously typing.)
To see the issue, consider the following sequence of steps. Assume
initially all revisions are `0`.
1. User triggers a recompilation, say by typing into the file.
- This triggers an `Interrupt::Memory` or similar.
2. The changes are applied to the vfs and recompilation begins.
- `verse.revision` is incremented to `verse.revision = 1`.
3. Before compilation finishes, a project snapshot is requested.
- The project compiler checks the cached snapshot first, which still has
`snap.world().revision() == 0`.
- Since `verse.revision = 1` was already incremented before the
compilation finished, a new snapshot is created and cached--even though
nothing has actually been recompiled yet.
- The cached snapshot now has `snap.world().revision() == 1`.
4. Compilation finishes, and some data from the resulting compilation
artifact is recorded.
5. Another project snapshot is requested.
- Since the snapshot was recomputed already in (3), the revisions appear
to match and the outdated, cached snapshot is returned.
The fix here is to just clear the cached snapshot in (4) after
recompilation finishes.
---
I would add a regression test, but it didn't seem easy to write an
automated test that can differentiate the change here. I tested this
locally by adding some logging around when the cached snapshot is used
and when it is recomputed.
As mentioned on Discord, I noticed this problem when adding some more
data to project snapshots on a local fork of Tinymist, which caused the
slightly outdated state to become a little more obvious.
---------
Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
This change ensures that user-specified output paths in the compile
command are properly handled, including relative paths.
Previously, the export task would reject relative output paths with an
error. This change converts relative paths to absolute paths by joining
them with the current working directory, allowing users to specify
relative paths like 'output/test.pdf' when compiling documents.
The fix adds path normalization using PathClean and handles the
conversion gracefully while maintaining the existing behavior for
absolute paths.
Fixes the issue where commands like:
tinymist compile resume-en.typ ./output/test.pdf
would fail with "output path is relative" error.
This bugs involves two main component: the compiler and the exporter,
the compiler compiles first and then exporter exports then. it is useful
to emit `CompileSignal::by_fs_events` to exporter even if vfs is clean
at the time we save a document.
An example triggering this bug. When user sets `exportPdf` to `onSave`,
It *bugged*:
1. OnTyped first: User types some character at T1. compiler learns that
the file content is of revision R1. the compiler compiles with revision
R1, which is needed by diagnostics event.
2. OnSaved then: Editor saves the document at T2. the compilation is
skipped early because file content is still under revision R1. In
previous version, The compilation is skipped and therefore the export is
also skipped. This is *bugged* if user sets `exportPdf` to `onSave`,
because the exporter is not run in both steps.
This PR emits the onSaved signals to both the compiler and the exporter
in the step 2.
* fix(test): running test as root
The dummy root path /root conflicts with root user's home directory on Linux and redacts incorrectly. Our downstream CI environment builds tinymist in docker as root and encounters the problem. Change the path to `/dummy-root` fixes it. To ensure consistency, other similar occurences are also prefixed with `dummy-`.
* dev: deduplicate a bit
---------
Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
* fix: remove unnecessary &mut in FontResolverImpl::append_font()
* refactor: better readablity in FontResolverImpl::rebuild()
* feat: FontResovlerImpl::clone_and_rebuild()
Change FontSlot to store Arc to QueryRef<Font, FontLoader>, so we can
clone FontSlot and share the cached loaded font between different slots.
Since CompilerUniverse only holds a immutable Arc to FontResovlerImpl,
adding clone_and_rebuild method allow us to append and rebuild without
mutable access to FontResovlerImpl.
* refactor: remove partial_book and modify methods from FontResolverImpl
partial_book is removed from FontResolverImpl, all the modifying methods
are also removed.
new method get_fonts and new_with_fonts are added.
If you want to modify fonts, you can get all fonts and modify them, then
call new_with_fonts to create a new FontResolverImpl.
* refactor: SystemFontSearch, BrowserFontSearch
- Both font searcher now is just a wrapper for Vec<(FontInfo,
FontSlot)>, typst::FontBook will be built when converting into
FontResolverImpl.
- Provide a method with_fonts_mut() so user can get a direct mutable
access to the under lying fonts vector to do any changes.
- Support searcher -> resolver and resolver -> searcher conversion.
* refactor: api change to biulder pattern
Method new_with_resolver() is added since CompilerUniverse only holds
Arc reference to resolver, and we can't move it out.
* fix: add fontdb::Database to SystemFontSearcher
Store fonts info in db, load them in bulk when calling flush()
* chore: merge `FontResolverImpl` and `TinymistFontResolver`
* feat: remove font profile feature
* feat: remove project font
* docs: comment the font resolver trait
* docs: comment the font slot struct
* docs: comment the crate
* test: move system tests
* dev: clean resolver
* dev: clean searchers
* dev: clean par iters
* feat: enrich memory font resolver
* todo: useless reuse
* dev: remove reuse api
* dev: build font book in `fn build`
* fix: make clippy happy
* fix: bad use
---------
Co-authored-by: c0per <60544162+c0per@users.noreply.github.com>
* fix: remove system time deps from crates
* fix: remove system time deps from crates
* fix: smater feature gate
* docs: add some todos
* Update time.rs
* Update Cargo.toml
* build: remove hard dep chrono