Every language Thor highlights is a Lua plugin (plugins/<id>/plugin.lua),
backed either by a tree-sitter grammar or, for simpler formats, a pure-Lua
lexer. Plugins can also add commands, panels and key bindings — this page
covers using them; see plugins/README.md for
writing one.
Thor ships plugins for Odin, Lua, C, C++, Go, Jai, JavaScript/JSX, TypeScript,
TSX, Rust, Python, Ruby, Java, Kotlin, Zig, C#, PHP, Haskell, OCaml, assembly,
and config/markup formats such as JSON, Markdown, shell and batch. Nothing to
configure — a file's extension (or, for extensionless names like Makefile,
its basename) picks the plugin.
Assembly covers GAS (x86 AT&T and Intel, ARM, AArch64, RISC-V, MIPS), NASM,
YASM, MASM and the 8-bit assemblers in .asm, .s, .S and related files.
FASM and fasm2 have their own lexer, which colors macro names and their
parameters inside the macro body. It is used for .fasm, .fasmg, .fasm2
and .ash, and for a .asm file that starts like FASM: format, entry,
include '…', macro, end macro or calminstruction.
Code folds by the parse tree for a grammar language. A language with a pure-Lua
lexer folds by indentation: a line folds over the deeper-indented lines after
it, and a closing }, ] or ) at its indent folds with them. A plugin can
supply its own folds instead.
A plugin only gets capabilities it declares (exec, read, write, ui,
keys, tick) and only after you allow it. Plugins asking for nothing —
every syntax plugin — load silently. A plugin that asks for something holds
until you answer a prompt Thor shows once per session, batching every waiting
plugin into it. The prompt lists one row per plugin — its id and what it asks
for — and scrolls when there are more than fit. Allow (or Enter) runs all of
them; Not now (or Escape) leaves them all unloaded and asks again next
start.
Your answers are remembered (in sessions/plugin-grants.json), so the prompt
does not repeat unless a plugin starts asking for more. Settings > Plugin
Permissions lists every installed plugin, what it wants, and whether it is
allowed or blocked — allow one there and it loads immediately; block a running
one and the change takes effect on the next start.
A folder Thor opens can carry its own plugins in <workspace>/.thor/plugins/,
laid out the same way as the bundled ones. They are for something that
belongs to one project — a lexer for a repo-specific format, a panel over its
build output. Two differences from bundled plugins:
- The prompt is never skipped, even for a plugin that asks for no permissions — it is code the opened folder carries, so Thor asks before running it regardless.
- The answer is per folder. Allowing a workspace plugin in one repository says nothing about a plugin of the same name in another.
A workspace plugin whose id matches a bundled one replaces it for that workspace.
A bundled plugin or shipped theme updates with Thor: an app update replaces
plugins/ and assets/themes/. Any other plugin or theme is checked for
updates when it names a source:
- A GitHub release. The plugin's
manifest.luaor the theme file setsversion = "1.2.0"andsource = "owner/repo". Thor comparesversionwith the tag of the latest release (v1.3.0or1.3.0). An update downloads the source archive of that tag. For a plugin, the archive must holdplugin.luaat its root. For a theme, it must hold a file with the same name as the theme. - A git clone. A plugin folder that is a clone, or a
user/themes/folder that is a clone, is checked against its upstream branch. An update is a fast-forwardgit pull. A clone with local changes is not updated.
Thor checks shortly after it starts, at most once a day
(check_for_plugin_updates), and Help > Check for Plugin and Theme Updates
checks at any time. When an update is found, a puzzle button with a count shows
in the title bar, and the theme picker marks the theme. Settings > Plugin &
Theme Updates lists every item and its state. Click an item to update it, to
open its source page, or to hold it.
Hold Updates stops all updates of that item. A held bundled plugin or
shipped theme keeps your local copy when Thor updates. Use a hold to keep an
edit to a bundled plugin, which the next update would otherwise overwrite. The
holds are kept in sessions/update-holds.json.
A plugin that must remember something writes it to user/plugins/<id>/ beside
the binary. That folder
survives a workspace switch and an update, and it is never part of a project you
open. Files a plugin writes for the project itself still go to the workspace,
usually under its .thor/.
See plugins/README.md for the sandbox rules, the
permission table, and how to write a plugin — either a <workspace>/.thor/plugins/
folder for one project, or a bundled plugins/<id>/ folder for everyone using
that Thor install.