The Language Server
FantASM is also a language server, so an editor can show you errors as you type, jump to a label’s definition, and tell you what an instruction costs in T-states. It is the same binary — no separate download, and no second copy of the assembler that might disagree with the one building your program.
fantasm --lspStarting it
The server speaks JSON-RPC over stdin and stdout, which is how every LSP client expects to talk to one.
--lsp is handled before the banner would be printed, and logging goes to stderr, so stdout carries protocol and nothing else. --nologo is harmless but does nothing here.
An editor starts this for you; you never run it by hand except to check the binary works.
What it gives you
| Diagnostics | Errors and warnings, as you type |
| Go to definition | Jump to where a label, constant or macro is defined |
| Find references | Every place a name is used |
| Hover | What a name is worth, or what an instruction costs |
| Completion | Instructions, directives, and your own names |
| Workspace symbols | Search every symbol in the project |
| Signature help | The operand forms an instruction accepts |
Diagnostics
The file is assembled on every keystroke and the result reported in place — the same errors and warnings fantasm build produces, from the same code.
A diagnostic lands in the file it came from. An error inside an included file is reported against that file, at its own line, not against the include line that pulled it in.
Hover
A label or constant answers with its value and where it was defined:
Constant: MY_CONST = 100 (0x64)
test.asm, line 2An instruction answers with its timing, including the forms that have two answers:
Instruction: JR
Timing: 12/7 T-states (taken/not taken)Instruction: LDIR
Timing: 21/16 T-states (repeated/final)That is the same timing data assert_cycles checks against in Testing.
Completion
Instructions and directives are offered from a fixed list; labels, constants and macros come from your source as it stands. . triggers a completion, so typing Gfx. offers that module’s members — see Modules.
Signature help
Triggered by a space or a comma, so it appears as you start an operand and again after each one.
VSCodium and VS Code
Install 0x1DE from Open VSX (twistedraven.0x1de). It starts the language server for you and adds the rest of the environment around it:
| Syntax highlighting | A TextMate grammar and semantic tokens for the fantasm language |
| Snippets | For .asm and .inc files |
| Build task | Task type fantasm, taking a file and an optional target |
| Problem matcher | Named fantasm, so build errors land in the Problems panel |
| Debugging | Breakpoints and stepping under Bizmuth — see Debugging a Build |
Three commands: Assemble (FantASM), Run on Bizmuth, and Restart FantASM Language Server.
Settings, if the defaults do not suit:
| Setting | Default |
|---|---|
0x1de.fantasm.serverPath | fantasm — an absolute path if it is not on your PATH |
0x1de.fantasm.serverArgs | ["--lsp", "--nologo"] |
0x1de.fantasm.target | zxnext — passed as -t by the build task |
The extension is BSD-3-Clause, and its source is at codeberg.org/TwistedRaven/0x1DE.
Any other editor
Any LSP client will do. The command is fantasm --lsp, and the file extensions are whatever your project uses — .asm, .inc, .z80.
Neovim’s built-in client, as an example:
vim.lsp.start({
name = 'fantasm',
cmd = { 'fantasm', '--lsp' },
root_dir = vim.fs.dirname(vim.fs.find({ 'fantasm.toml', '.git' }, { upward = true })[1]),
init_options = { target = 'zxnext' },
})⛔ Send target in initializationOptions, or every Z80N instruction is an error. The server assembles as a bare zx48 otherwise, so a Next project shows E1016 Z80n extended instructions are not enabled on every nextreg and mul while the build succeeds on the same lines. It is read once at startup, so changing it means restarting the server.
You get diagnostics, hover, completion and the rest — everything in the table above — but none of the highlighting, snippets or debugging, which are the extension’s rather than the server’s.
How it finds your project
The workspace root is the nearest directory above the open file containing fantasm.toml, .git or Cargo.toml. Whichever is found first walking upwards wins.
include and incbin are then searched for in two places: the open file’s own directory, and that workspace root.
⛔ fantasm.toml is found but not read. It marks the root and nothing more, so include_dirs and [defines] are not applied. A project keeping sources in src/ and lib/ and listing both in include_dirs builds correctly from the command line while the editor reports file not found, because the server only ever looks in those two directories.
The machine is the exception: the editor can send a target in initializationOptions, as above. It still does not come from the project file.
Why an included file shows errors
The open file is assembled as its own root, whatever it is. A fragment written to be included — one that uses constants its parent defines, or continues from an org set elsewhere — has none of that context when the editor assembles it alone, so you get E1003 for names that are perfectly fine in a real build.
Nothing is wrong with your source. Assemble the project to see the truth of it:
fantasm buildWhat it does not do
No formatting, no rename, no code actions, and no inlay hints. The server advertises exactly the seven capabilities in the table above, and an editor offering a command outside that list will find nothing behind it.
What next
- Diagnostics — reading the messages the editor is showing you.
- The Project File — what
fantasm.tomlconfigures for the build, if not for the editor.