Tinymist Docs

Project Model

This section documents the experimental project management feature. Implementation may change in future releases.

The Core Configuration: tinymist.projectResolutiontinymist.projectResolution

This setting controls how Tinymist resolves projects:

  • singleFilesingleFile (Default): Treats each Typst file as an independent document (similar to Markdown workflows). No lock files or project caches are generated, which is suitable for most people who work with single Typst files or small projects.

  • lockDatabaselockDatabase: Mimics Rust's project management by tracking compilation/preview history. Stores data in lock files (tinymist.locktinymist.lock) and cache directories, enabling automatic main file selection based on historical context.

The Challenge to Handle Multiple-File Projects

When working with multiple-file projects, Tinymist faces the challenge of determining which file to use as the main file for compilation and preview. This is because:

  1. All project files (entries, includes, imports) share .typ.typ extensions.
  2. No inherent distinction exists between entry files and dependencies.
  3. Automatic detection is ambiguous without context.

This resembles the situation in C++, where the language server also struggles to determine the header files and source files in a project. In C++, the language servers and IDEs relies on the compile_commands.jsoncompile_commands.json file to understand the compilation context.

Inspired by C++ and Rust, we introduced the lockDatabaselockDatabase resolution method to relieve pain of handling multiple-file projects.

The classic way: singleFilesingleFile

This is the default resolution method and has been used for years. Despite using singleFilesingleFile, you can still work with multiple files:

  • The language server will serve the previewed file as the main file when previewing a file.
  • Pinning a main file manually by commands is possible:

    • Use command Typst Pin MainTypst Pin Main (tinymist.pinMainToCurrent) to set the current file as the main file.
    • Use command Typst Unpin MainTypst Unpin Main (tinymist.unpinMain) to unset the main file.

A Sample Usage of lockDatabaselockDatabase

This feature is in early development stage, and may contain bugs or incomplete features. The following sample demonstrates how to use the lockDatabaselockDatabase resolution method. Here is the related test.

  1. Set projectResolution = "lockDatabase"projectResolution = "lockDatabase" in LSP settings.
  2. Like scriptsscripts/​test-lock.shtest-lock.sh, compile a file using tinymist CLI with --save-lock--save-lock flag: tinymist compile --save-lock main.typtinymist compile --save-lock main.typ. This will create a tinymist.locktinymist.lock file in the current directory, which contains the Compilation History and project routes.
  3. back to the editor, editing chapterschapters/​chapter1.typchapter1.typ will trigger PDF export of main.typmain.typ automatically.

Please report issue on GitHub if you find any bugs, missing features, or have any questions about this feature.

Stability Notice: tinymist.locktinymist.lock

We have been aware of backward compatibility issues, but any change of the schema of tinymist.locktinymist.lock may corrupt the tinymist.locktinymist.lock intentionally or unintentionally. The schema is unstable and in beta stage. You have to remove the tinymist.locktinymist.lock file to recovery from errors, and you could open an issue to discuss with us. To reliably keep compilation commands, please put tinymist compiletinymist compile commands in build system such as MakefileMakefile or justfilejustfile.

Compilation History

The Project Model only relies on the concept of Compilation History and we will explain how it works and how to use.

The Compilation History (tinymist.locktinymist.lock) is a set of records. Each record contains the following information about compilation:

  • Input Args: Main file path, fonts, features (e.g., HTML/Paged as export target).
  • Export Args: Output path, PDF standard to use.

The source of Compilation History:

  • (Implemented) CLI commands: tinymist compile/preview --save-locktinymist compile/preview --save-lock, suitable for all the editor clients.
  • (Not Implemented) LSP commands: tinymist.exportXXXtinymist.exportXXX/previewXXXpreviewXXX, suitable for vscode or neovim clients, which allows client-side extension.
  • (Not Implemented) External tools: Tools that update the lock file directly. For example, the tytanic could update all example documents once executed test commands. The official typst could also do this to tell whether a test case is compiled targeting HTML or PDF.

Utilizing Compilation History

There are several features that can be implemented using the Compilation History:

  • Correct Entry Detection: When a user runs the compile or preview commands, Tinymist will save the Compilation History to the lock file and the language server will identify the main file correctly.
  • Dynamic Entry Switching: When a user runs another compile command, the newer command will have higher priorit, and Tinymist will "switch" the main file accordingly.
  • Per-Document Flags: Some documents are compiled to HTML, while others are compiled to PDF. The users can specify more compile flags for each document.
  • Session Persistence: Users can open the recently previewed file and continue editing it. More state such as the scroll position could be remembered in future.
  • Sharing and VCS: The lock file can be shared with other users by tools like git, allowing them to compile the same project with the same settings.

Storing Compilation History

  • Storage in file system: stored in tinymist.locktinymist.lock (TOML) files. When resolving a depended file, the nearest lock file will be used to determine the compilation arguments.
  • Storage in memory: The language server also maintains a Compilation History and project routes in memory. We may enable in-memory Compilation History by default in the future, which will allow Tinymist to resolve projects smarter.

Project Route

The language server will load route entries from disk or memory, combine, and perform entry lookup based on the route table. Specificially, The depended files of a single compilation will be stored as route entries in the cache directory after compilation. A single route entry is a triple, (Dependent Path, Project ID, Priority), where:

  • "Dependent Path" is an absoulte dependent file path, like paths to assets and source files in packages.
  • "Project ID" is the project id (main file) indexing an entry in the Compilation History (tinymist.locktinymist.lock).
  • "Priority" is a priority number.

And the language server determines a project id associating some dependent file by the following rules:

  1. Highest priority routes take precedence.
  2. Most recent updated projects in Compilation History prioritized automatically.

The cache directory contains cache of project routes. Currently, we haven't implemented a way clean up or garbage collect the project route cache, and disk cache may be deprecated in future. It is safe to remove all the project routes in the cache directory, as Tinymist will regenerate them when needed.