feat: live LSP error underlines + improved VS Code extension
ci / build (ubuntu) (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / build (ubuntu) (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
bux-lsp 0.17 publishes in-process diagnostics on open/change/save so editors show red squiggles for lex/parse/type errors in the live buffer. VS Code client discovers tools/bux-lsp, adds status bar/restart, richer syntax/snippets, and docs (docs/LSP.md) for forum/editor setup.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
out/
|
||||
*.vsix
|
||||
.vscode-test/
|
||||
*.tsbuildinfo
|
||||
@@ -0,0 +1,15 @@
|
||||
.vscode/**
|
||||
.vscode-test/**
|
||||
src/**
|
||||
.gitignore
|
||||
.vscodeignore
|
||||
tsconfig.json
|
||||
**/*.ts
|
||||
**/*.map
|
||||
node_modules/**
|
||||
!node_modules/vscode-languageclient/**
|
||||
!node_modules/vscode-jsonrpc/**
|
||||
!node_modules/vscode-languageserver-protocol/**
|
||||
!node_modules/vscode-languageserver-types/**
|
||||
!node_modules/semver/**
|
||||
*.vsix
|
||||
@@ -0,0 +1,89 @@
|
||||
# Bux Language Support for VS Code
|
||||
|
||||
Syntax highlighting, snippets, editor defaults, and **Language Server Protocol** integration for the [Bux](https://github.com/katehonz/bux) programming language.
|
||||
|
||||
## Features
|
||||
|
||||
| Area | What you get |
|
||||
|------|----------------|
|
||||
| **Syntax** | Keywords, types, `f"..."` interpolation, raw `` `...` `` strings, C-strings, macros (`macro!` / `name!()`), attributes (`@[Checked]`), numbers (hex/bin/oct + suffixes), lifetimes |
|
||||
| **Snippets** | `main`, `func`, `struct`, `enum`, `match`, `interface`, `extend`, `macro`, `checked`, … |
|
||||
| **LSP** | **Live error underlines** (red squiggles on edit), completion, hover, go-to-definition, references, rename, document/workspace symbols, call hierarchy, type hierarchy, go-to-implementation |
|
||||
| **Editor** | Bracket colorization, smart indent / on-enter, fold regions (`// region`) |
|
||||
| **Build** | `buxc` problem matcher for Tasks |
|
||||
|
||||
## Requirements
|
||||
|
||||
1. **VS Code** ≥ 1.85
|
||||
2. **`bux-lsp`** binary (from this repo):
|
||||
|
||||
```bash
|
||||
# from the Bux repository root
|
||||
make lsp
|
||||
# → tools/bux-lsp
|
||||
```
|
||||
|
||||
The extension auto-discovers the server in this order:
|
||||
|
||||
1. Setting `bux.lsp.path` (absolute, relative, or command name)
|
||||
2. `tools/bux-lsp` under any workspace folder (and parent folders for monorepos)
|
||||
3. `bux-lsp` on your `PATH`
|
||||
|
||||
## Install (development)
|
||||
|
||||
```bash
|
||||
cd vscode
|
||||
npm install
|
||||
npm run compile
|
||||
|
||||
# Launch Extension Development Host: F5 in VS Code,
|
||||
# or install the folder as an extension:
|
||||
code --install-extension .
|
||||
# or package:
|
||||
npx @vscode/vsce package
|
||||
code --install-extension bux-lang-0.2.0.vsix
|
||||
```
|
||||
|
||||
Symlink into your extensions dir (Linux):
|
||||
|
||||
```bash
|
||||
ln -sfn "$(pwd)/vscode" ~/.vscode/extensions/bux-lang.bux-lang-0.2.0
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| **Bux: Restart Language Server** | Stop and start `bux-lsp` |
|
||||
| **Bux: Stop Language Server** | Disconnect the client |
|
||||
| **Bux: Show Output Channel** | Open the Bux log |
|
||||
|
||||
Status bar item **Bux** (left): click to restart. Red = missing binary / start failure.
|
||||
|
||||
## Settings
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| `bux.lsp.enabled` | `true` | Master switch for the language server |
|
||||
| `bux.lsp.path` | `"bux-lsp"` | Path or command for the server binary |
|
||||
| `bux-lsp.trace.server` | `off` | LSP wire trace (`off` / `messages` / `verbose`) |
|
||||
|
||||
## LSP capabilities (bux-lsp)
|
||||
|
||||
Provided by `tools/lsp_server.nim` (see `make lsp` / `make test-lsp`):
|
||||
|
||||
- `textDocument/completion`, `hover`, `definition`, `references`, `rename`
|
||||
- `documentSymbol`, `workspace/symbol`
|
||||
- Call hierarchy, type hierarchy, `implementation`
|
||||
- Diagnostics on open/save (via analyzer / `buxc`)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
1. Status bar shows **error** → run `make lsp` and ensure `tools/bux-lsp` exists and is executable.
|
||||
2. **Bux: Show Output Channel** for client logs.
|
||||
3. Set `"bux-lsp.trace.server": "verbose"` for JSON-RPC traffic.
|
||||
4. Confirm language mode is **Bux** for `.bux` files (status bar language indicator).
|
||||
|
||||
## License
|
||||
|
||||
MIT — same as the Bux project.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.8 KiB |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" fill="none">
|
||||
<rect width="128" height="128" rx="28" fill="#0d1117"/>
|
||||
<rect x="8" y="8" width="112" height="112" rx="22" fill="#161b22" stroke="#30363d" stroke-width="2"/>
|
||||
<path d="M34 32h28c12 0 20 6.5 20 16.5 0 7-3.5 12-9.5 14.5 8 2.5 12.5 8.5 12.5 16.5C85 92 76 99 62 99H34V32zm14 11v16h12c5.5 0 8.5-2.5 8.5-8s-3-8-8.5-8H48zm0 27v18h14c6.5 0 10.5-3 10.5-9.5S68.5 70 62 70H48z" fill="#6ee7b7"/>
|
||||
<circle cx="96" cy="40" r="8" fill="#38bdf8" opacity=".9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 533 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
||||
<rect width="32" height="32" rx="6" fill="#1a1f2e"/>
|
||||
<path d="M8 8h6.5c2.8 0 4.5 1.5 4.5 3.8 0 1.6-.8 2.8-2.2 3.4 1.8.6 2.9 2 2.9 3.9 0 2.7-2 4.4-5.2 4.4H8V8zm3.2 2.5v3.8h2.8c1.3 0 2-.6 2-1.9s-.7-1.9-2-1.9h-2.8zm0 6.2v4.3h3.2c1.5 0 2.4-.7 2.4-2.2s-.9-2.1-2.4-2.1h-3.2z" fill="#6ee7b7"/>
|
||||
<path d="M20.5 22.5c1.8-1.2 3-3.2 3-5.5 0-3.7-2.8-6.5-6.5-6.5" stroke="#38bdf8" stroke-width="1.6" stroke-linecap="round" opacity=".85"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 511 B |
@@ -8,29 +8,81 @@
|
||||
["[", "]"],
|
||||
["(", ")"]
|
||||
],
|
||||
"colorizedBracketPairs": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"]
|
||||
],
|
||||
"autoClosingPairs": [
|
||||
{ "open": "{", "close": "}" },
|
||||
{ "open": "[", "close": "]" },
|
||||
{ "open": "(", "close": ")" },
|
||||
{ "open": "\"", "close": "\"" },
|
||||
{ "open": "`", "close": "`" }
|
||||
{ "open": "\"", "close": "\"", "notIn": ["string", "comment"] },
|
||||
{ "open": "`", "close": "`", "notIn": ["string", "comment"] },
|
||||
{ "open": "'", "close": "'", "notIn": ["string", "comment"] },
|
||||
{ "open": "/*", "close": " */", "notIn": ["string"] }
|
||||
],
|
||||
"surroundingPairs": [
|
||||
{ "open": "{", "close": "}" },
|
||||
{ "open": "[", "close": "]" },
|
||||
{ "open": "(", "close": ")" },
|
||||
{ "open": "\"", "close": "\"" },
|
||||
{ "open": "`", "close": "`" }
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["`", "`"],
|
||||
["'", "'"]
|
||||
],
|
||||
"autoCloseBefore": ";:.,=}])>` \n\t",
|
||||
"folding": {
|
||||
"markers": {
|
||||
"start": "^\\s*//\\s*region\\b",
|
||||
"end": "^\\s*//\\s*endregion\\b"
|
||||
}
|
||||
"start": "^\\s*//\\s*#?region\\b",
|
||||
"end": "^\\s*//\\s*#?endregion\\b"
|
||||
},
|
||||
"offSide": false
|
||||
},
|
||||
"wordPattern": "[a-zA-Z_][a-zA-Z0-9_]*",
|
||||
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)",
|
||||
"indentationRules": {
|
||||
"increaseIndentPattern": "\\{[^}]*$",
|
||||
"decreaseIndentPattern": "^\\s*\\}"
|
||||
}
|
||||
"increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)\\s*$",
|
||||
"decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\}\\]\\)].*$"
|
||||
},
|
||||
"onEnterRules": [
|
||||
{
|
||||
"beforeText": "^\\s*/\\*(?!/).*[^*/]\\s*$",
|
||||
"afterText": "^\\s*\\*/$",
|
||||
"action": {
|
||||
"indent": "indentOutdent",
|
||||
"appendText": " * "
|
||||
}
|
||||
},
|
||||
{
|
||||
"beforeText": "^\\s*/\\*(?!/).*[^*/]\\s*$",
|
||||
"action": {
|
||||
"indent": "none",
|
||||
"appendText": " * "
|
||||
}
|
||||
},
|
||||
{
|
||||
"beforeText": "^(\\t|(\\ \\ ))*\\ \\*(\\ ([^*]|\\*(?!/))*)?$",
|
||||
"action": {
|
||||
"indent": "none",
|
||||
"appendText": "* "
|
||||
}
|
||||
},
|
||||
{
|
||||
"beforeText": "^(\\t|(\\ \\ ))*\\ */.*$",
|
||||
"action": {
|
||||
"indent": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"beforeText": "^\\s*(func|async\\s+func|struct|enum|union|interface|extend|module|macro!|if|else|while|for|do|loop|match|switch|case)\\b.*\\{\\s*$",
|
||||
"action": {
|
||||
"indent": "indent"
|
||||
}
|
||||
},
|
||||
{
|
||||
"beforeText": "^\\s*.*=>\\s*$",
|
||||
"action": {
|
||||
"indent": "indent"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Generated
+128
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"name": "bux-lang",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bux-lang",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.0",
|
||||
"@types/vscode": "^1.85.0",
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.85.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
|
||||
"integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/vscode": {
|
||||
"version": "1.125.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.125.0.tgz",
|
||||
"integrity": "sha512-0icm/ZQAaism87P0ekHqi4/Ju9du+Tm0RUW+y7vqRsxY2cY0FNRX1nAnaW7nT6npPt2tfHiheZ55Zm9UhqonFA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz",
|
||||
"integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.8.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
||||
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vscode-jsonrpc": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
|
||||
"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageclient": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
|
||||
"integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
|
||||
"dependencies": {
|
||||
"minimatch": "^5.1.0",
|
||||
"semver": "^7.3.7",
|
||||
"vscode-languageserver-protocol": "3.17.5"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.82.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-protocol": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
|
||||
"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": "8.2.0",
|
||||
"vscode-languageserver-types": "3.17.5"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-types": {
|
||||
"version": "3.17.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
|
||||
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
+129
-14
@@ -1,37 +1,60 @@
|
||||
{
|
||||
"name": "bux-lang",
|
||||
"displayName": "Bux Language Support",
|
||||
"description": "Syntax highlighting, snippets, and LSP support for the Bux programming language",
|
||||
"version": "0.1.0",
|
||||
"description": "Syntax highlighting, snippets, and full LSP support for Bux — live error underlines, hover, go-to-def, rename, call/type hierarchy",
|
||||
"version": "0.2.1",
|
||||
"publisher": "bux-lang",
|
||||
"license": "MIT",
|
||||
"icon": "icon.png",
|
||||
"galleryBanner": {
|
||||
"color": "#0d1117",
|
||||
"theme": "dark"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/katehonz/bux"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/katehonz/bux/issues"
|
||||
},
|
||||
"homepage": "https://github.com/katehonz/bux",
|
||||
"engines": {
|
||||
"vscode": "^1.85.0"
|
||||
},
|
||||
"categories": [
|
||||
"Programming Languages",
|
||||
"Snippets",
|
||||
"Linters"
|
||||
"Linters",
|
||||
"Other"
|
||||
],
|
||||
"keywords": [
|
||||
"bux",
|
||||
"bux-lang",
|
||||
"programming-language",
|
||||
"lsp",
|
||||
"syntax"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:bux"
|
||||
"onLanguage:bux",
|
||||
"workspaceContains:**/*.bux",
|
||||
"workspaceContains:bux.toml"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "bux",
|
||||
"aliases": ["Bux", "bux"],
|
||||
"extensions": [".bux"],
|
||||
"aliases": [
|
||||
"Bux",
|
||||
"bux"
|
||||
],
|
||||
"extensions": [
|
||||
".bux"
|
||||
],
|
||||
"configuration": "./language-configuration.json",
|
||||
"icon": {
|
||||
"dark": "./icon.png",
|
||||
"light": "./icon.png"
|
||||
"dark": "./icons/bux-file.svg",
|
||||
"light": "./icons/bux-file.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -48,30 +71,122 @@
|
||||
"path": "./snippets/bux.json"
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "bux.restartLsp",
|
||||
"title": "Bux: Restart Language Server",
|
||||
"category": "Bux"
|
||||
},
|
||||
{
|
||||
"command": "bux.stopLsp",
|
||||
"title": "Bux: Stop Language Server",
|
||||
"category": "Bux"
|
||||
},
|
||||
{
|
||||
"command": "bux.showOutput",
|
||||
"title": "Bux: Show Output Channel",
|
||||
"category": "Bux"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "bux.restartLsp"
|
||||
},
|
||||
{
|
||||
"command": "bux.stopLsp"
|
||||
},
|
||||
{
|
||||
"command": "bux.showOutput"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "Bux",
|
||||
"properties": {
|
||||
"bux.lsp.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable LSP server for diagnostics and autocomplete"
|
||||
"description": "Enable the Bux language server (diagnostics, hover, go-to-definition, rename, hierarchy)."
|
||||
},
|
||||
"bux.lsp.path": {
|
||||
"type": "string",
|
||||
"default": "bux-lsp",
|
||||
"description": "Path to the bux-lsp binary"
|
||||
"description": "Path to the bux-lsp binary. Absolute path, workspace-relative path, or command on PATH. If unset/default, the extension also searches tools/bux-lsp under workspace folders."
|
||||
},
|
||||
"bux-lsp.trace.server": {
|
||||
"type": "string",
|
||||
"scope": "window",
|
||||
"enum": [
|
||||
"off",
|
||||
"messages",
|
||||
"verbose"
|
||||
],
|
||||
"default": "off",
|
||||
"description": "Traces the communication between VS Code and the Bux language server."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"configurationDefaults": {
|
||||
"[bux]": {
|
||||
"editor.semanticHighlighting.enabled": true,
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.quickSuggestions": {
|
||||
"other": true,
|
||||
"comments": false,
|
||||
"strings": false
|
||||
},
|
||||
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
||||
"editor.wordBasedSuggestions": "off"
|
||||
}
|
||||
},
|
||||
"problemMatchers": [
|
||||
{
|
||||
"name": "buxc",
|
||||
"owner": "bux",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"pattern": {
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s+(error|warning|note):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
}
|
||||
],
|
||||
"taskDefinitions": [
|
||||
{
|
||||
"type": "bux",
|
||||
"required": [
|
||||
"task"
|
||||
],
|
||||
"properties": {
|
||||
"task": {
|
||||
"type": "string",
|
||||
"description": "bux subcommand (build, run, test, check)"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"watch": "tsc -watch -p ./"
|
||||
"watch": "tsc -watch -p ./",
|
||||
"package": "vsce package --no-dependencies 2>/dev/null || npx @vscode/vsce package --no-dependencies"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.0",
|
||||
"@types/vscode": "^1.85.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vscode-languageclient": "^9.0.0"
|
||||
"typescript": "^5.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
+169
-27
@@ -9,11 +9,23 @@
|
||||
],
|
||||
"description": "Main entry point function"
|
||||
},
|
||||
"Hello World": {
|
||||
"prefix": "hello",
|
||||
"body": [
|
||||
"import Std::Io::{PrintLine};",
|
||||
"",
|
||||
"func Main() -> int {",
|
||||
" PrintLine(\"${1:Hello, Bux!}\");",
|
||||
" return 0;",
|
||||
"}"
|
||||
],
|
||||
"description": "Minimal Hello World program"
|
||||
},
|
||||
"Function": {
|
||||
"prefix": "func",
|
||||
"body": [
|
||||
"func ${1:Name}(${2:params}) -> ${3:void} {",
|
||||
" $4",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Function declaration"
|
||||
@@ -22,11 +34,20 @@
|
||||
"prefix": "afunc",
|
||||
"body": [
|
||||
"async func ${1:Name}(${2:params}) -> ${3:void} {",
|
||||
" $4",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Async function declaration"
|
||||
},
|
||||
"Generic function": {
|
||||
"prefix": "gfunc",
|
||||
"body": [
|
||||
"func ${1:Name}<${2:T}>(${3:param}: ${2:T}) -> ${2:T} {",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Generic function"
|
||||
},
|
||||
"Variable (let)": {
|
||||
"prefix": "let",
|
||||
"body": [
|
||||
@@ -41,6 +62,13 @@
|
||||
],
|
||||
"description": "Mutable variable"
|
||||
},
|
||||
"Const": {
|
||||
"prefix": "const",
|
||||
"body": [
|
||||
"const ${1:NAME}: ${2:Type} = ${3:value};"
|
||||
],
|
||||
"description": "Constant declaration"
|
||||
},
|
||||
"Struct": {
|
||||
"prefix": "struct",
|
||||
"body": [
|
||||
@@ -60,11 +88,52 @@
|
||||
],
|
||||
"description": "Enum declaration"
|
||||
},
|
||||
"Generic enum": {
|
||||
"prefix": "genum",
|
||||
"body": [
|
||||
"enum ${1:Name}<${2:T}> {",
|
||||
" ${3:Some}(${2:T}),",
|
||||
" ${4:None},",
|
||||
"}"
|
||||
],
|
||||
"description": "Generic enum declaration"
|
||||
},
|
||||
"Interface": {
|
||||
"prefix": "interface",
|
||||
"body": [
|
||||
"interface ${1:Name} {",
|
||||
" func ${2:Method}(${3:self}) -> ${4:void};",
|
||||
"}"
|
||||
],
|
||||
"description": "Interface declaration"
|
||||
},
|
||||
"Extend methods": {
|
||||
"prefix": "extend",
|
||||
"body": [
|
||||
"extend ${1:Type} {",
|
||||
" func ${2:Method}(self) -> ${3:void} {",
|
||||
" $0",
|
||||
" }",
|
||||
"}"
|
||||
],
|
||||
"description": "Extend block for inherent methods"
|
||||
},
|
||||
"Extend for interface": {
|
||||
"prefix": "extendfor",
|
||||
"body": [
|
||||
"extend ${1:Type} for ${2:Interface} {",
|
||||
" func ${3:Method}(self) -> ${4:void} {",
|
||||
" $0",
|
||||
" }",
|
||||
"}"
|
||||
],
|
||||
"description": "Implement interface for type"
|
||||
},
|
||||
"If statement": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if ${1:condition} {",
|
||||
" ${2:body}",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "If statement"
|
||||
@@ -75,7 +144,7 @@
|
||||
"if ${1:condition} {",
|
||||
" ${2:body}",
|
||||
"} else {",
|
||||
" ${3:elseBody}",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "If-else statement"
|
||||
@@ -84,20 +153,29 @@
|
||||
"prefix": "while",
|
||||
"body": [
|
||||
"while ${1:condition} {",
|
||||
" ${2:body}",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "While loop"
|
||||
},
|
||||
"For loop": {
|
||||
"For-in loop": {
|
||||
"prefix": "for",
|
||||
"body": [
|
||||
"for ${1:item} in ${2:iterable} {",
|
||||
" ${3:body}",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "For-in loop"
|
||||
},
|
||||
"Loop": {
|
||||
"prefix": "loop",
|
||||
"body": [
|
||||
"loop {",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Infinite loop"
|
||||
},
|
||||
"Match": {
|
||||
"prefix": "match",
|
||||
"body": [
|
||||
@@ -108,40 +186,61 @@
|
||||
],
|
||||
"description": "Pattern match expression"
|
||||
},
|
||||
"Switch": {
|
||||
"prefix": "switch",
|
||||
"body": [
|
||||
"switch ${1:expr} {",
|
||||
" case ${2:value}:",
|
||||
" $0",
|
||||
" break;",
|
||||
" default:",
|
||||
" break;",
|
||||
"}"
|
||||
],
|
||||
"description": "Switch statement"
|
||||
},
|
||||
"Import": {
|
||||
"prefix": "import",
|
||||
"body": [
|
||||
"import Std::${1:Module}::{${2:items}};"
|
||||
"import Std::${1:Io}::{${2:PrintLine}};"
|
||||
],
|
||||
"description": "Import statement"
|
||||
"description": "Import from Std"
|
||||
},
|
||||
"Module": {
|
||||
"prefix": "module",
|
||||
"body": [
|
||||
"module ${1:Name} {",
|
||||
"${2:body}",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Module declaration"
|
||||
},
|
||||
"Extend": {
|
||||
"prefix": "extend",
|
||||
"body": [
|
||||
"extend ${1:Type} {",
|
||||
" ${2:methods}",
|
||||
"}"
|
||||
],
|
||||
"description": "Extend block for methods"
|
||||
},
|
||||
"@Checked": {
|
||||
"@Checked function": {
|
||||
"prefix": "checked",
|
||||
"body": [
|
||||
"@[Checked]",
|
||||
"func ${1:Name}(${2:params}) -> ${3:void} {",
|
||||
" ${4:body}",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Checked function with borrow checker enabled"
|
||||
"description": "Checked function with borrow checker"
|
||||
},
|
||||
"@Release function": {
|
||||
"prefix": "release",
|
||||
"body": [
|
||||
"@[Release]",
|
||||
"func ${1:Name}(${2:params}) -> ${3:void} {",
|
||||
" $0",
|
||||
"}"
|
||||
],
|
||||
"description": "Release (unchecked) function"
|
||||
},
|
||||
"Defer": {
|
||||
"prefix": "defer",
|
||||
"body": [
|
||||
"defer ${1:cleanup};"
|
||||
],
|
||||
"description": "Defer cleanup"
|
||||
},
|
||||
"PrintLine": {
|
||||
"prefix": "pl",
|
||||
@@ -150,13 +249,56 @@
|
||||
],
|
||||
"description": "Print with newline"
|
||||
},
|
||||
"Generic function": {
|
||||
"prefix": "gfunc",
|
||||
"Interpolated string": {
|
||||
"prefix": "fstr",
|
||||
"body": [
|
||||
"func ${1:Name}<${2:T}>(${3:param}: ${2:T}) -> ${2:T} {",
|
||||
" ${4:body}",
|
||||
"f\"${1:Hello, }{${2:name}}\""
|
||||
],
|
||||
"description": "Interpolated f-string"
|
||||
},
|
||||
"Macro definition": {
|
||||
"prefix": "macro",
|
||||
"body": [
|
||||
"macro! ${1:name} {",
|
||||
" (\\$${2:x}:expr) => {",
|
||||
" $0",
|
||||
" }",
|
||||
"}"
|
||||
],
|
||||
"description": "Generic function"
|
||||
"description": "Declarative macro! definition"
|
||||
},
|
||||
"Test assert": {
|
||||
"prefix": "tassert",
|
||||
"body": [
|
||||
"Test_AssertEq${1:Int}(${2:got}, ${3:want});"
|
||||
],
|
||||
"description": "Test equality assertion"
|
||||
},
|
||||
"Spawn task": {
|
||||
"prefix": "spawn",
|
||||
"body": [
|
||||
"let ${1:handle}: *void = spawn ${2:Worker}(${3:args});"
|
||||
],
|
||||
"description": "Spawn green-thread task"
|
||||
},
|
||||
"Result Ok/Err match": {
|
||||
"prefix": "resultmatch",
|
||||
"body": [
|
||||
"match ${1:result} {",
|
||||
" Ok(${2:value}) => ${3:value},",
|
||||
" Err(${4:err}) => ${5:/* handle */},",
|
||||
"}"
|
||||
],
|
||||
"description": "Match on Result"
|
||||
},
|
||||
"Option Some/None match": {
|
||||
"prefix": "optmatch",
|
||||
"body": [
|
||||
"match ${1:opt} {",
|
||||
" Some(${2:value}) => ${3:value},",
|
||||
" None => ${4:/* handle */},",
|
||||
"}"
|
||||
],
|
||||
"description": "Match on Option"
|
||||
}
|
||||
}
|
||||
|
||||
+231
-33
@@ -1,54 +1,252 @@
|
||||
/* Bux Language Server Protocol client for VS Code
|
||||
* Launches bux-lsp binary and connects via stdin/stdout.
|
||||
* Discovers and launches the bux-lsp binary, connects via stdio.
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind
|
||||
TransportKind,
|
||||
RevealOutputChannelOn,
|
||||
} from 'vscode-languageclient/node';
|
||||
|
||||
let client: LanguageClient;
|
||||
let client: LanguageClient | undefined;
|
||||
let outputChannel: vscode.OutputChannel | undefined;
|
||||
let statusBar: vscode.StatusBarItem | undefined;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
const config = vscode.workspace.getConfiguration('bux.lsp');
|
||||
const enabled = config.get<boolean>('enabled', true);
|
||||
if (!enabled) {
|
||||
vscode.window.showInformationMessage('Bux LSP is disabled in settings');
|
||||
return;
|
||||
}
|
||||
const SETTING_SECTION = 'bux';
|
||||
|
||||
const lspPath = config.get<string>('path', 'bux-lsp');
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
outputChannel = vscode.window.createOutputChannel('Bux');
|
||||
context.subscriptions.push(outputChannel);
|
||||
|
||||
const serverOptions: ServerOptions = {
|
||||
command: lspPath,
|
||||
transport: TransportKind.stdio
|
||||
};
|
||||
statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 50);
|
||||
statusBar.command = 'bux.restartLsp';
|
||||
statusBar.tooltip = 'Bux Language Server — click to restart';
|
||||
context.subscriptions.push(statusBar);
|
||||
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [{ scheme: 'file', language: 'bux' }],
|
||||
synchronize: {
|
||||
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.bux')
|
||||
}
|
||||
};
|
||||
|
||||
client = new LanguageClient(
|
||||
'bux-lsp',
|
||||
'Bux Language Server',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('bux.restartLsp', async () => {
|
||||
await restartClient(true);
|
||||
}),
|
||||
vscode.commands.registerCommand('bux.stopLsp', async () => {
|
||||
await stopClient();
|
||||
setStatus('off', 'Bux LSP stopped');
|
||||
outputChannel?.appendLine('[bux] LSP stopped by user');
|
||||
}),
|
||||
vscode.commands.registerCommand('bux.showOutput', () => {
|
||||
outputChannel?.show(true);
|
||||
}),
|
||||
vscode.workspace.onDidChangeConfiguration(async (e) => {
|
||||
if (
|
||||
e.affectsConfiguration('bux.lsp.enabled') ||
|
||||
e.affectsConfiguration('bux.lsp.path')
|
||||
) {
|
||||
outputChannel?.appendLine('[bux] Configuration changed — restarting LSP');
|
||||
await restartClient(false);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
client.start();
|
||||
vscode.window.showInformationMessage('Bux LSP started');
|
||||
await startClient();
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> | undefined {
|
||||
if (!client) {
|
||||
return undefined;
|
||||
}
|
||||
return client.stop();
|
||||
return stopClient();
|
||||
}
|
||||
|
||||
async function restartClient(userInitiated: boolean): Promise<void> {
|
||||
await stopClient();
|
||||
await startClient();
|
||||
if (userInitiated) {
|
||||
vscode.window.setStatusBarMessage('Bux LSP restarted', 3000);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopClient(): Promise<void> {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
const c = client;
|
||||
client = undefined;
|
||||
try {
|
||||
await c.stop();
|
||||
} catch (err) {
|
||||
outputChannel?.appendLine(`[bux] Error stopping client: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function startClient(): Promise<void> {
|
||||
const config = vscode.workspace.getConfiguration(SETTING_SECTION);
|
||||
const enabled = config.get<boolean>('lsp.enabled', true);
|
||||
|
||||
if (!enabled) {
|
||||
setStatus('off', 'Bux LSP disabled');
|
||||
outputChannel?.appendLine('[bux] LSP disabled in settings (bux.lsp.enabled)');
|
||||
return;
|
||||
}
|
||||
|
||||
const configuredPath = config.get<string>('lsp.path', 'bux-lsp') || 'bux-lsp';
|
||||
const resolved = resolveLspPath(configuredPath);
|
||||
|
||||
if (!resolved) {
|
||||
setStatus('error', 'bux-lsp not found');
|
||||
const msg =
|
||||
'Bux LSP binary not found. Build with `make lsp` (produces tools/bux-lsp) ' +
|
||||
'or set bux.lsp.path to the full path of the binary.';
|
||||
outputChannel?.appendLine(`[bux] ${msg}`);
|
||||
outputChannel?.appendLine(`[bux] Configured path: ${configuredPath}`);
|
||||
const choice = await vscode.window.showWarningMessage(
|
||||
'Bux: language server (bux-lsp) not found',
|
||||
'Open Output',
|
||||
'Open Settings'
|
||||
);
|
||||
if (choice === 'Open Output') {
|
||||
outputChannel?.show(true);
|
||||
} else if (choice === 'Open Settings') {
|
||||
await vscode.commands.executeCommand('workbench.action.openSettings', 'bux.lsp');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
outputChannel?.appendLine(`[bux] Using LSP binary: ${resolved}`);
|
||||
setStatus('starting', 'Starting Bux LSP…');
|
||||
|
||||
const serverOptions: ServerOptions = {
|
||||
command: resolved,
|
||||
transport: TransportKind.stdio,
|
||||
options: { env: process.env },
|
||||
};
|
||||
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [
|
||||
{ scheme: 'file', language: 'bux' },
|
||||
{ scheme: 'untitled', language: 'bux' },
|
||||
],
|
||||
synchronize: {
|
||||
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.{bux,toml}'),
|
||||
},
|
||||
outputChannel,
|
||||
revealOutputChannelOn: RevealOutputChannelOn.Error,
|
||||
traceOutputChannel: outputChannel,
|
||||
};
|
||||
|
||||
client = new LanguageClient('bux-lsp', 'Bux Language Server', serverOptions, clientOptions);
|
||||
|
||||
try {
|
||||
await client.start();
|
||||
setStatus('ready', `Bux LSP ready (${path.basename(resolved)})`);
|
||||
outputChannel?.appendLine('[bux] Language server started');
|
||||
} catch (err) {
|
||||
setStatus('error', 'Bux LSP failed to start');
|
||||
outputChannel?.appendLine(`[bux] Failed to start language server: ${err}`);
|
||||
vscode.window.showErrorMessage(
|
||||
`Bux LSP failed to start: ${err instanceof Error ? err.message : String(err)}`
|
||||
);
|
||||
client = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve bux-lsp:
|
||||
* 1. Configured absolute / relative path
|
||||
* 2. Workspace tools/bux-lsp (and nearby monorepo parents)
|
||||
* 3. Command on PATH
|
||||
*/
|
||||
function resolveLspPath(configured: string): string | undefined {
|
||||
const candidates: string[] = [];
|
||||
|
||||
if (path.isAbsolute(configured)) {
|
||||
candidates.push(configured);
|
||||
} else if (configured.includes('/') || configured.includes('\\')) {
|
||||
candidates.push(path.resolve(configured));
|
||||
for (const folder of vscode.workspace.workspaceFolders ?? []) {
|
||||
candidates.push(path.join(folder.uri.fsPath, configured));
|
||||
}
|
||||
}
|
||||
|
||||
for (const folder of vscode.workspace.workspaceFolders ?? []) {
|
||||
const root = folder.uri.fsPath;
|
||||
candidates.push(
|
||||
path.join(root, 'tools', 'bux-lsp'),
|
||||
path.join(root, 'tools', 'bux-lsp.exe'),
|
||||
path.join(root, 'bin', 'bux-lsp'),
|
||||
path.join(root, 'bux-lsp'),
|
||||
path.resolve(root, '..', 'tools', 'bux-lsp'),
|
||||
path.resolve(root, '..', '..', 'tools', 'bux-lsp')
|
||||
);
|
||||
}
|
||||
|
||||
for (const c of candidates) {
|
||||
if (isExecutable(c)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
// Bare name: search PATH
|
||||
const bare = configured.includes('/') || configured.includes('\\') ? 'bux-lsp' : configured;
|
||||
return findInPath(bare);
|
||||
}
|
||||
|
||||
function findInPath(cmd: string): string | undefined {
|
||||
const pathEnv = process.env.PATH ?? process.env.Path ?? '';
|
||||
const sep = process.platform === 'win32' ? ';' : ':';
|
||||
const exts =
|
||||
process.platform === 'win32'
|
||||
? (process.env.PATHEXT ?? '.EXE;.CMD;.BAT').split(';')
|
||||
: [''];
|
||||
|
||||
for (const dir of pathEnv.split(sep)) {
|
||||
if (!dir) continue;
|
||||
for (const ext of exts) {
|
||||
const candidate = path.join(dir, cmd + ext);
|
||||
if (isExecutable(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isExecutable(filePath: string): boolean {
|
||||
try {
|
||||
const st = fs.statSync(filePath);
|
||||
if (!st.isFile()) {
|
||||
return false;
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
return true;
|
||||
}
|
||||
fs.accessSync(filePath, fs.constants.X_OK);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setStatus(state: 'ready' | 'starting' | 'error' | 'off', text: string): void {
|
||||
if (!statusBar) return;
|
||||
switch (state) {
|
||||
case 'ready':
|
||||
statusBar.text = '$(check) Bux';
|
||||
statusBar.backgroundColor = undefined;
|
||||
break;
|
||||
case 'starting':
|
||||
statusBar.text = '$(sync~spin) Bux';
|
||||
statusBar.backgroundColor = undefined;
|
||||
break;
|
||||
case 'error':
|
||||
statusBar.text = '$(error) Bux';
|
||||
statusBar.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground');
|
||||
break;
|
||||
case 'off':
|
||||
statusBar.text = '$(circle-slash) Bux';
|
||||
statusBar.backgroundColor = undefined;
|
||||
break;
|
||||
}
|
||||
statusBar.tooltip = text;
|
||||
statusBar.show();
|
||||
}
|
||||
|
||||
@@ -3,33 +3,19 @@
|
||||
"name": "Bux",
|
||||
"scopeName": "source.bux",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"include": "#keywords"
|
||||
},
|
||||
{
|
||||
"include": "#types"
|
||||
},
|
||||
{
|
||||
"include": "#functions"
|
||||
},
|
||||
{
|
||||
"include": "#constants"
|
||||
},
|
||||
{
|
||||
"include": "#operators"
|
||||
},
|
||||
{
|
||||
"include": "#numbers"
|
||||
},
|
||||
{
|
||||
"include": "#attributes"
|
||||
}
|
||||
{ "include": "#comments" },
|
||||
{ "include": "#attributes" },
|
||||
{ "include": "#macros" },
|
||||
{ "include": "#strings" },
|
||||
{ "include": "#chars" },
|
||||
{ "include": "#keywords" },
|
||||
{ "include": "#types" },
|
||||
{ "include": "#constants" },
|
||||
{ "include": "#lifetimes" },
|
||||
{ "include": "#functions" },
|
||||
{ "include": "#paths" },
|
||||
{ "include": "#numbers" },
|
||||
{ "include": "#operators" }
|
||||
],
|
||||
"repository": {
|
||||
"comments": {
|
||||
@@ -37,20 +23,129 @@
|
||||
{
|
||||
"name": "comment.block.bux",
|
||||
"begin": "/\\*",
|
||||
"end": "\\*/"
|
||||
"end": "\\*/",
|
||||
"patterns": [
|
||||
{ "include": "#comments" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "comment.line.bux",
|
||||
"name": "comment.line.double-slash.bux",
|
||||
"match": "//.*$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"attributes": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "meta.attribute.bux",
|
||||
"begin": "@\\[",
|
||||
"end": "\\]",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "punctuation.definition.attribute.bux" }
|
||||
},
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.definition.attribute.bux" }
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"name": "storage.modifier.attribute.bux",
|
||||
"match": "\\b(Checked|Release|Shared|Import|Drop)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "storage.modifier.attribute.bux",
|
||||
"match": "@(Checked|Release|Shared|Import|Drop)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"macros": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "meta.macro.definition.bux",
|
||||
"begin": "\\b(macro!)\\s+([A-Za-z_][A-Za-z0-9_]*)",
|
||||
"beginCaptures": {
|
||||
"1": { "name": "keyword.declaration.macro.bux" },
|
||||
"2": { "name": "entity.name.function.macro.bux" }
|
||||
},
|
||||
"end": "(?<=\\})",
|
||||
"patterns": [
|
||||
{ "include": "$self" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "meta.macro.invocation.bux",
|
||||
"begin": "\\b([A-Za-z_][A-Za-z0-9_]*!)\\s*(\\()",
|
||||
"beginCaptures": {
|
||||
"1": { "name": "entity.name.function.macro.bux" },
|
||||
"2": { "name": "punctuation.section.parens.begin.bux" }
|
||||
},
|
||||
"end": "\\)",
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.section.parens.end.bux" }
|
||||
},
|
||||
"patterns": [
|
||||
{ "include": "$self" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "variable.other.macro.fragment.bux",
|
||||
"match": "\\$([A-Za-z_][A-Za-z0-9_]*)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.macro.repeat.bux",
|
||||
"match": "\\$\\(|\\)\\s*[*+?]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.double.bux",
|
||||
"begin": "\"",
|
||||
"name": "string.interpolated.bux",
|
||||
"begin": "f\"",
|
||||
"end": "\"",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.begin.bux" }
|
||||
},
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.end.bux" }
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.bux",
|
||||
"match": "\\\\[ntr\\\\\"'{}]|\\\\u\\{[0-9a-fA-F]+\\}|\\\\x[0-9a-fA-F]{2}"
|
||||
},
|
||||
{
|
||||
"name": "meta.interpolation.bux",
|
||||
"begin": "\\{",
|
||||
"end": "\\}",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "punctuation.section.embedded.begin.bux" }
|
||||
},
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.section.embedded.end.bux" }
|
||||
},
|
||||
"patterns": [
|
||||
{ "include": "#keywords" },
|
||||
{ "include": "#types" },
|
||||
{ "include": "#constants" },
|
||||
{ "include": "#numbers" },
|
||||
{ "include": "#functions" },
|
||||
{ "include": "#operators" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.double.cstr.bux",
|
||||
"begin": "c(8|16|32)\"",
|
||||
"end": "\"",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.begin.bux" }
|
||||
},
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.end.bux" }
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.bux",
|
||||
@@ -59,9 +154,40 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.backtick.bux",
|
||||
"name": "string.quoted.double.bux",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.begin.bux" }
|
||||
},
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.end.bux" }
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.bux",
|
||||
"match": "\\\\[ntr\\\\\"']|\\\\u\\{[0-9a-fA-F]+\\}|\\\\x[0-9a-fA-F]{2}|\\\\."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.raw.bux",
|
||||
"begin": "`",
|
||||
"end": "`"
|
||||
"end": "`",
|
||||
"beginCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.begin.bux" }
|
||||
},
|
||||
"endCaptures": {
|
||||
"0": { "name": "punctuation.definition.string.end.bux" }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"chars": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.single.bux",
|
||||
"match": "c?(8|16|32)?'(\\\\.|[^'\\\\])'"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -69,55 +195,87 @@
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.control.bux",
|
||||
"match": "\\b(if|else|while|for|do|loop|in|break|continue|return|match|case|default|spawn|async|await|try|catch|throw|discard)\\b"
|
||||
"match": "\\b(if|else|while|for|do|loop|in|break|continue|return|match|switch|case|default|spawn|async|await|try|catch|throw|discard|defer)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.declaration.bux",
|
||||
"match": "\\b(func|var|let|const|type|struct|enum|union|interface|extend|module|import|extern|pub)\\b"
|
||||
"match": "\\b(func|var|let|const|type|struct|enum|union|interface|extend|module|import|extern|pub|macro)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.bux",
|
||||
"name": "keyword.operator.word.bux",
|
||||
"match": "\\b(as|is|sizeof|comptime|static_assert|dyn)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.ownership.bux",
|
||||
"match": "\\b(own|mut|borrow)\\b"
|
||||
},
|
||||
{
|
||||
"name": "storage.modifier.bux",
|
||||
"match": "@\\[(Checked|Shared|Import)\\]"
|
||||
"match": "\\b(own|mut|borrow|checked)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"types": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "support.type.bux",
|
||||
"match": "\\b(int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|float32|float64|bool|char8|char32|String|void)\\b"
|
||||
"name": "support.type.primitive.bux",
|
||||
"match": "\\b(int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|float32|float64|bool|char8|char16|char32|String|void)\\b"
|
||||
},
|
||||
{
|
||||
"name": "support.type.stdlib.bux",
|
||||
"match": "\\b(Result|Option|Array|Map|Set|Slice|Channel|TaskHandle)\\b"
|
||||
},
|
||||
{
|
||||
"name": "entity.name.type.bux",
|
||||
"match": "\\b[A-Z][a-zA-Z0-9_]*\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"functions": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "entity.name.function.bux",
|
||||
"match": "\\b([a-z_][a-zA-Z0-9_]*)(?=\\s*\\()"
|
||||
"match": "\\b[A-Z][A-Za-z0-9_]*\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"constants": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.language.bux",
|
||||
"match": "\\b(true|false|null)\\b"
|
||||
"name": "constant.language.boolean.bux",
|
||||
"match": "\\b(true|false)\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.bux",
|
||||
"match": "\\b(true|false|null|self|super)\\b"
|
||||
"name": "constant.language.null.bux",
|
||||
"match": "\\bnull\\b"
|
||||
},
|
||||
{
|
||||
"name": "variable.language.bux",
|
||||
"match": "\\b(self|super)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lifetimes": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "storage.modifier.lifetime.bux",
|
||||
"match": "'[A-Za-z_][A-Za-z0-9_]*\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"functions": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "meta.function.declaration.bux",
|
||||
"match": "\\b(func|async\\s+func)\\s+([A-Za-z_][A-Za-z0-9_]*)",
|
||||
"captures": {
|
||||
"1": { "name": "keyword.declaration.bux" },
|
||||
"2": { "name": "entity.name.function.bux" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "entity.name.function.bux",
|
||||
"match": "\\b([A-Za-z_][A-Za-z0-9_]*)(?=\\s*[<(])"
|
||||
}
|
||||
]
|
||||
},
|
||||
"paths": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "meta.path.bux",
|
||||
"match": "\\b([A-Za-z_][A-Za-z0-9_]*)\\s*(::)",
|
||||
"captures": {
|
||||
"1": { "name": "entity.name.namespace.bux" },
|
||||
"2": { "name": "punctuation.accessor.bux" }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -125,31 +283,67 @@
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.numeric.float.bux",
|
||||
"match": "\\b[0-9]+\\.[0-9]+(?:[eE][+-]?[0-9]+)?\\b"
|
||||
"match": "\\b[0-9]+\\.[0-9]+(?:[eE][+-]?[0-9]+)?(?:f32|f64)?\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.hex.bux",
|
||||
"match": "\\b0[xX][0-9a-fA-F]+\\b"
|
||||
"match": "\\b0[xX][0-9a-fA-F_]+(?:[iu](?:8|16|32|64)?)?\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.bux",
|
||||
"match": "\\b[0-9]+\\b"
|
||||
"name": "constant.numeric.octal.bux",
|
||||
"match": "\\b0[oO][0-7_]+(?:[iu](?:8|16|32|64)?)?\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.binary.bux",
|
||||
"match": "\\b0[bB][01_]+(?:[iu](?:8|16|32|64)?)?\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.integer.bux",
|
||||
"match": "\\b[0-9][0-9_]*(?:[iu](?:8|16|32|64)?|f32|f64)?\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"operators": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.operator.bux",
|
||||
"match": "->|=>|==|!=|<=|>=|&&|\\|\\||[+\\-*/%<>=!&|^~@]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"attributes": {
|
||||
"patterns": [
|
||||
"name": "keyword.operator.arrow.bux",
|
||||
"match": "->|=>"
|
||||
},
|
||||
{
|
||||
"name": "storage.modifier.bux",
|
||||
"match": "@(Checked|Shared|Import)"
|
||||
"name": "keyword.operator.range.bux",
|
||||
"match": "\\.\\.=|\\.\\.\\.|\\.\\."
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.comparison.bux",
|
||||
"match": "==|!=|<=|>=|<|>"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.logical.bux",
|
||||
"match": "&&|\\|\\||!"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.bux",
|
||||
"match": "\\+=|-=|\\*=|/=|%=|=|:=|\\*\\*="
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.arithmetic.bux",
|
||||
"match": "\\*\\*|[+\\-*/%]"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.bitwise.bux",
|
||||
"match": "&|\\||\\^|~|<<|>>"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.try.bux",
|
||||
"match": "\\?"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.borrow.bux",
|
||||
"match": "&mut\\b|&"
|
||||
},
|
||||
{
|
||||
"name": "punctuation.accessor.bux",
|
||||
"match": "::|\\."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "ES2020",
|
||||
"lib": ["ES2020"],
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"types": ["node", "vscode"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
"exclude": ["node_modules", ".vscode-test", "out"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user