Slim for VS Code
Syntax highlighting for the Slim language (.slim).
The grammar builds on the JavaScript grammar (Slim is a JavaScript superset), and adds Slim-specific highlighting for:
- declarations —
struct, enum, type, func, component (including export, async, element and isolated modifiers)
- component lifecycle hooks —
onMount, onConnect, onUnmount
- keywords —
use, lock, mode, extends, match, when, elif
use imports — imported names, as, from, and the module path, whether quoted ("functions") or bare (@slim/types/mails), which gets the same string colour as a JavaScript import path
- operators —
sizeof, kindof, empty, copyof, and, or, ~/, ::, =>
struct and enum bodies — field names, built-in types (int, float, string, bool, any, object, array, null, number, function, element), user-defined types, Enum::Member references, T[], A | B, enum members, and optional fields written either *key or key?
- function return types — the type after
-> (for example func calc(x: number) -> number) is highlighted with the same type rules as struct fields; the ): Type form is already handled by the JavaScript grammar
- component parameter types — a
component's parameter list highlights type annotations in both forms: component El(props: SomeStruct) and the inline destructured component El({ id: int, name: string }), where each field name is a parameter and its type gets the type colour. Component calls like Wrapper({ ... }) are left as ordinary object literals
- declaration references — a
struct, enum, class, custom type or component name used elsewhere in code (for example User.verify(data), new Server(), a : number annotation, or a Wrapper({ ... }) call) is highlighted at every use, and a const keeps its constant colour. Each kind gets a distinct semantic token type — struct, enum, class, type, and function for a component (so a component reads in the function colour, like its declaration) — so a theme, or an editor.semanticTokenColorCustomizations setting, can colour structs and types differently. This works for imported names too, not just local ones. All of it lives in extension.js / constants.js, since remembering declarations across the file is beyond what a TextMate grammar can do
- hover for structs, enums, components, custom types, classes, constants and variables — hovering the name shows a simplified signature: struct fields (a field whose type is another local struct is expanded inline, with reference cycles guarded), enum members, a component's parameters and full body including its
return (the isolated / element("tag") modifier is shown when present), a custom type's body (both the type X(v) { ... } validator form and the type X = ... alias form), a class's method signatures, or the declaration of a const, let or var. This also works for names brought in with use: relative imports (./x) resolve next to the file, and @scope/x imports resolve against whichever package layout exists — the old one keeps sources in packages/ at the project root (overridable with the packages key in slimconfig.json), and the npm one ships them inside the installed package at node_modules/@slim-lang/core/packages. The first location that holds the file wins; the target file is read and its definition shown with an "imported from" note
- snippets — tab-completed templates for the Slim constructs (
snippets/slim.json): struct / estruct, enum, component / icomponent / elcomponent, func / efunc / afunc / tfunc, type / typealias, use / usedefault / usens, match / matchwhen, lock / lockconst, log, and the onMount / onConnect / onUnmount lifecycle hooks
- semantic highlighting is force-enabled for Slim files (
contributes.configurationDefaults), so constant, built-in and type colouring shows even under colour themes that do not opt into semantic highlighting themselves
- Slim constructs nested inside JavaScript — a
struct, component, func, enum or type declared inside a function body or callback is highlighted the same way as at top level (via an injection grammar, see syntaxes/slim-nested-injection.json)
- constants — names introduced with
const / lock const keep their constant colour at every later use in the same scope (a small semantic token provider in extension.js, since a TextMate grammar alone cannot remember declarations; this matches what the TypeScript service does for .js files)
- object keys —
{ id: "email" } keys get a property semantic token, again as the TypeScript service does for .js, so themes whose string and object-key colours are close (for example Dark 2026) still tell keys and string values apart
- built-in objects —
Object, JSON, Math, Promise, document, console, process, fetch, setTimeout, Slim's log and friends, and so on are highlighted like in .js files (semantic tokens with the defaultLibrary modifier). The list lives in builtins.js, split into classes, variables and functions; a const or parameter with the same name shadows the built-in in its scope
- component markup — HTML/custom-element tags, attributes, self-closing tags and
${...} interpolations. HTML void tags without a slash (<img>, <br>, <input>, <source>, …) are recognised as self-contained (syntaxes/slim-void-tag.json); otherwise the JSX grammar would treat them as unclosed and mis-highlight everything after them
- HTML inside JavaScript template literals — tags and attributes inside backtick strings are highlighted as HTML while
${...} keeps JavaScript highlighting
.spm package manifests — the TOML-like manifest format is highlighted (source.spm, in syntaxes/spm.tmLanguage.json): # comments, @ section headers (including /-nested names), and key = "value" entries with the key, =, and the quoted string each scoped distinctly
- Slim JavaScript files — files matching
*-slim.js use the slim-js-file language for their own icon, and get full JavaScript highlighting through a grammar that embeds source.js (syntaxes/slim-js.tmLanguage.json)
- JSON config files —
slimconfig.json, slimserver.json and spm.lock.json each have their own language (for a per-file icon that works under any icon theme) whose grammar embeds source.json for highlighting. Because a custom language id does not receive VS Code's built-in JSON service, the extension supplies the two features that matter for a config file itself: a Format Document provider (extension.js) and key/value completion driven by the JSON schemas under schemas/. Full error-squiggle schema validation is not provided, since that needs the built-in json/jsonc language
- file icons —
.slim files use assets/slim-ico-dark.svg and .spm package manifests use assets/spm-ic.svg. The language id is slim-lang rather than slim (its display name is still "Slim"): icon themes such as vscode-icons ship a built-in icon keyed on the language id slim for the Ruby Slim template engine, and that mapping would otherwise override the extension's own .slim icon. Using a distinct id keeps the extension icon in control under those themes
Try it (development)
- Open this folder (
editors/vscode) in VS Code.
- Press F5 to launch an Extension Development Host.
- Open any
.slim file.
Install locally
Package the extension into a .vsix and install it:
npx @vscode/vsce package
code --install-extension slim-lang-0.2.9.vsix
Alternatively, copy this folder into your VS Code extensions directory (~/.vscode/extensions) and reload.
| |