Typstar
Neovim plugin for efficient note taking in Typst
Features
- Powerful autosnippets using LuaSnip and Tree-sitter (inspired by fastex.nvim)
- Easy insertion of drawings using Obsidian Excalidraw
- Export of Anki flashcards [No Neovim required]
Usage
Snippets
Use :TypstarToggleSnippets to toggle all snippets at any time.
Available snippets can mostly be intuitively derived from here, they include:
Markup snippets:
- Begin inline math with
lland multiline math withdm - Markup shorthands (e.g.
HIG→#highlight[<cursor>],IMP→$==>$) - ctheorems shorthands (e.g.
tem→ empty theorem,exa→ empty example) - Flashcards:
flaandflA - All above snippets support visual mode via the selection key
Math snippets:
- Many shorthands for mathematical expressions
- Alphanumeric characters:
:<char>→$<char>$in markup (e.g.:X→$X$,:5→$5$) - Greek letters:
;<latin>→<greek>in math and$<greek>$in markup (e.g.;a→alpha/$alpha$) - Common indices (numbers and letters
i-n):<letter><index>→<letter>_<index>in math and$<letter>$<index>→$<letter>_<index>$in markup (e.gA314→A_314,$alpha$n→$alpha_n$) - Series of numbered letters:
<letter> ot<optional last index>→<letter>_1, <letter>_2, ...(e.g.a ot→a_1, a_2, ...,a ot4→a_1, a_2, a_3, a_4,alpha otk→alpha_1, alpha_2, ..., alpha_k) - Wrapping of any mathematical expression (see operations, works nested, multiline and in visual mode via the selection key):
<expression><operation>→<operation>(<expression>)(e.g.(a^2+b^2)rt→sqrt(a^2+b^2),lambdatd→tilde(lambda),(1+1)sQ→[1+1],(1+1)sq→[(1+1)]) - Matrices:
<size>maand<size>lma(e.g.23ma→ 2x3 matrix)
Note that you can customize (enable, disable and modify) every snippet.
Excalidraw
- Use
:TypstarInsertExcalidrawto create a new drawing using the configured template, insert a figure displaying it and open it in Obsidian. - To open an inserted drawing in Obsidian, simply run
:TypstarOpenExcalidrawwhile your cursor is on a line referencing the drawing.
Anki
Use the flA snippet to create a new flashcard
#flashcard(0, "My first flashcard")[
Typst is awesome $a^2+b^2=c^2$
]
or the fla snippet to add a more complex front
#flashcard(0)[I love Typst $pi$][
This is the back of my second flashcard
]
To render the flashcard in your document as well add some code like this
#let flashcard(id, front, back) = {
strong(front)
[\ ]
back
}
- Add a comment like
// ANKI: MY::DECKto your document to set a deck used for all flashcards after this comment (You can use multiple decks per file) - Add a file named
.ankicontaining a deck name to define a default deck on a directory base - Add a file named
.anki.typto define a preamble on a directory base. You can find the default preamble here. - Tip: Despite the use of SVGs you can still search your flashcards in Anki as the typst source is added into an invisible html paragraph
Neovim
- Use
:TypstarAnkiScanto scan the current nvim working directory and compile all flashcards in its context, unchanged files will be ignored - Use
:TypstarAnkiForceto force compilation of all flashcards in the current working directory even if the files haven't changed since the last scan (e.g. on preamble change) - Use
:TypstarAnkiForceCurrentto force compilation of all flashcards in the file currently edited - Use
:TypstarAnkiReimportto also add flashcards that have already been asigned an id but are not currently present in Anki - Use
:TypstarAnkiForceReimportand:TypstarAnkiForceCurrentReimportto combine features accordingly
Standalone
- Run
typstar-anki --helpto show the available options
Installation
Install the plugin in Neovim (see Nix instructions) and run the plugin setup.
require('typstar').setup({ -- depending on your neovim plugin system
-- your typstar config goes here
})
Snippets
- Install LuaSnip, set
enable_autosnippets = trueand set a visual mode selection key (e.g.store_selection_keys = '<Tab>') in the configuration - Install jsregexp as described here (You will see a warning on startup if jsregexp isn't installed properly)
- Install nvim-treesitter and run
:TSInstall typst - Optional: Setup ctheorems with names like here
Excalidraw
- Install Obsidian and create a vault in your typst note taking directory
- Install the obsidian-excalidraw-plugin and enable
Auto-export SVG(in plugin settings atEmbedding Excalidraw into your Notes and Exporting > Export Settings > Auto-export Settings) - Have the
xdg-opencommand working or set a different command aturiOpenCommandin the config - If you encounter issues try cloning the repo into
~/typstaror setting thetypstarRootconfig accordingly, feel free to open an issue
Anki
- Typst version
0.12.0or higher is required - Install Anki
- Install Anki-Connect and make sure
http://localhostis added towebCorsOriginListin the Add-on config (should be added by default) - Install the typstar python package (I recommend using pipx via
pipx install git+https://github.com/arne314/typstar, you will need to have python build tools and clang installed) [Note: this may take a while] - Make sure the
typstar-ankicommand is available in yourPATHor modify thetypstarAnkiCmdoption in the config
In a Nix Flake (optional)
You can add typstar to your nix-flake like so
# `flake.nix`
inputs = {
# ... other inputs
typstar = {
url = "github:arne314/typstar";
flake = false;
};
}
Now you can use typstar in any package-set
with pkgs; [
# ... other packges
(pkgs.vimUtils.buildVimPlugin {
name = "typstar";
src = inputs.typstar;
buildInputs = [
vimPlugins.luasnip
vimPlugins.nvim-treesitter-parsers.typst
];
})
]
Configuration
Configuration options can be intuitively derived from the table here.
Custom snippets
The config allows you to
- disable all snippets via
snippets.enable = false - only include specific modules from the snippets folder via e.g.
snippets.modules = { 'letters' } - exclude specific triggers via e.g.
snippets.exclude = { 'dx', 'ddx' }
For further customization you can make use of the provided wrappers from within your LuaSnip config.
Let's say you prefer the short => arrow over the long ==> one and would like to change the ip trigger to imp.
Your typstar config could look like
require('typstar').setup({
snippets = {
exclude = { 'ip' },
},
})
while your LuaSnip typst.lua could look like this (< and > require escaping as <> introduces a new node)
local tp = require('typstar.autosnippets')
local snip = tp.snip
local math = tp.in_math
local markup = tp.in_markup
return {
-- add a new snippet (the old one is excluded via the config)
snip('imp', '=>> ', {}, math),
-- override existing triggers by setting a high priority
snip('ib', '<<= ', {}, math, 2000),
snip('iff', '<<=>> ', {}, math, 2000),
-- setup markup snippets accordingly
snip('IMP', '$=>>$ ', {}, markup, 2000),
snip('IFF', '$<<=>>$ ', {}, markup, 2000),
}