Four principles are followed.
Multiple Actors
The main component, tinymist, starts as a thread or process, obeying the Language Server Protocol. tinymist will bootstrap multiple actors, each of which provides some typst feature.
The each actor holds and maintains some resources exclusively. For example, the compile server actor holds the well known trait World
resource.
The actors communicate with each other by channels. An actor should own many receivers as its input, and many senders as output. The actor will take input from receivers sequentially. For example, when some LSP request or notification is coming as an LSP event, multiple actors serve the event collaboratively, as shown in FigureĀ 1.
A Hover request is taken as example of that events.
A global unique LspActor
takes the event and mutates a global server state by the event. If the event requires some additional code analysis, it is converted into an analysis request, struct CompilerQueryRequest
, and pushed to the actors owning compiler resources. Otherwise, LspActor
responds to the event directly. Obviously, the Hover on code request requires code analysis.
The CompileServerActor
s are created for workspaces and main entries (files/documents) in workspaces. When a compiler query is coming, a subset of that actors will take it and give project-specific responses, combining into a final concluded LSP response. Some analysis requests even require rendering features, and those requests will be pushed to the actors owning rendering resources. If you enable the periscope feature, a Hover
on content request requires rendering on documents.
The RenderActor
s don't do compilations, but own project-specific rendering cache. They are designed for rendering documents in low latency. This is the last sink of Hover
requests. A RenderActor
will receive an additional compiled Document
object, and render the compiled frames in needed. After finishing rendering, a response attached with the rendered picture is sent to the LSP response channel intermediately.
Multi-level Analysis
he most critical features are lsp functions, built on the tinymist-query crate. To achieve higher concurrency, functions are classified into different levels of analysis.
query_source
āSyntaxRequest
ā locks and accesses a single source unit.query_world
āSemanticRequest
ā locks and accesses multiple source units.query_state
āStatefulRequest
ā acquires to accesses a specific version of compile results.
When an analysis request is coming, tinymist upgrades it to a suitable level as needed, as shown in FigureĀ 2. A higher level requires to hold more resources and takes longer time to prepare.
Optional Non-LSP Features
All non-LSP features in tinymist are optional. They are optional, as they can be disabled totally on compiling the tinymist binary. The significant features are enabled by default, but you can disable them with feature flags. For example, tinymist
provides preview server features powered by typst-preview
.
Minimal Editor Frontends
Leveraging the interface of LSP, tinymist provides frontends to each editor, located in the editor folders. They are minimal, meaning that LSP should finish its main LSP features as many as possible without help of editor frontends. The editor frontends just enhances your code experience. For example, the vscode frontend takes responsibility on providing some nice editor tools. It is recommended to install these editors frontend for your editors.