Miranda Language Support for VS Code
A VS Code extension providing rich editing support for the
Miranda
lazy functional programming language via the Language Server Protocol (LSP).
Features
| Feature |
Description |
| Syntax highlighting |
Keywords, types, constructors, operators, \|\| comments, strings |
| Completions |
Miranda prelude (80+ built-ins), keywords, directives, user-defined names |
| Hover documentation |
Type signatures + prose for every prelude function; picks up \|\| doc-comments for user definitions |
| Diagnostics |
Unmatched (, ), [, ]; unclosed string literals |
| Document symbols |
Outline of top-level functions, type definitions, type synonyms, and abstract types |
File extensions
.m and .mir are registered as Miranda source files.
Note: .m is also used by Objective-C. If you work in both languages,
VS Code will ask which language to use when you first open a .m file.
You can set "files.associations": {"*.m": "miranda"} in your workspace
settings.json to prefer Miranda.
Architecture
miranda-lsp/
├── package.json Extension manifest (languages, grammars, config)
├── language-configuration.json Bracket pairs, comment token, word pattern
├── syntaxes/
│ └── miranda.tmLanguage.json TextMate grammar for syntax highlighting
├── client/
│ └── src/extension.ts VS Code extension entry point (starts the server)
└── server/
└── src/server.ts LSP server (completions, hover, diagnostics, symbols)
How it works
- VS Code activates the extension for any file whose language ID is
miranda.
client/src/extension.ts spawns server/out/server.js as a child Node.js
process and connects to it over IPC using vscode-languageclient.
- The server registers its capabilities (completions, hover, diagnostics,
document symbols) during the LSP
initialize handshake.
- As you edit a
.m file, VS Code sends LSP requests to the server and
renders the responses (underlines, completions pop-up, hover tooltips, etc.).
Syntax highlighting
The TextMate grammar (syntaxes/miranda.tmLanguage.json) uses regex rules to
colour:
|| … – line comments
"…" / 'x' – string and character literals
%include, %export, %insert – preprocessor directives
::= / :: / == – type operators
where, if, then, else, otherwise, abstype, with, div, mod – keywords
num, bool, char – primitive types
True, False – boolean literals
[A-Z]… – constructors / type names
- Arithmetic and relational operators
Language server
The server (server/src/server.ts) is a standalone Node.js process using the
vscode-languageserver package. Key subsystems:
Completions (onCompletion / onCompletionResolve)
Returns three layers of items:
- Keywords –
where, if, True, %include, type names, etc.
- Prelude built-ins – every function in the Miranda standard library,
with full type signature as the
detail string.
- User-defined names – scanned from
name :: … type signature lines in
the current file.
onCompletionResolve fills in the Markdown documentation popup when a
built-in item is selected.
Hover (onHover)
- Identifies the word under the cursor with a simple regex scan.
- Checks the built-in map first.
- Falls back to searching the document for a type signature
name :: ….
If one is found, any || … comment lines immediately above it are shown
as the description.
Diagnostics (validateDocument)
Each line is processed by stripLine, which removes comments and string/char
literals (preserving column positions). The remaining "logical" content is
scanned character-by-character to track bracket balance. Errors are reported
for:
- Unexpected
) or ] with no matching opener
- Still-open
( or [ at end of file
- Unclosed
" string literals
Document symbols (onDocumentSymbol)
Regex patterns are applied to each non-comment line to detect:
| Pattern |
Symbol kind |
^abstype name |
Class |
^name ::= |
Enum (algebraic type) |
^name == |
Interface (type synonym) |
^name :: |
Function (type signature) |
^name …= |
Function (definition, only if no type sig was seen) |
Miranda quick-reference
|| Line comment
|| Type signature
factorial :: num -> num
|| Guarded definition
factorial n = 1, n = 0
= n * factorial (n-1), otherwise
|| List comprehension
evens = [ x | x <- [1..20]; x mod 2 = 0 ]
|| Algebraic type
tree * ::= Leaf | Node (tree *) * (tree *)
|| Type synonym
string == [char]
|| Abstract type
abstype stack *
with
empty :: stack *
push :: * -> stack * -> stack *
pop :: stack * -> stack *
top :: stack * -> *
isempty :: stack * -> bool
|| Lambda
double = map (\x . x * 2)
|| Where clause
hypotenuse a b = sqrt (sq a + sq b)
where sq x = x * x
|| Include another file
%include "prelude.m"
| |