language server start

This commit is contained in:
nub31
2025-10-23 10:16:52 +02:00
parent e7b92e8194
commit b7525dde65
30 changed files with 3944 additions and 125 deletions

1
vscode-lsp/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

View File

@@ -0,0 +1,5 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

8
vscode-lsp/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint",
"ms-vscode.extension-test-runner"
]
}

21
vscode-lsp/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,21 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

11
vscode-lsp/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,11 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

20
vscode-lsp/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,20 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

11
vscode-lsp/.vscodeignore Normal file
View File

@@ -0,0 +1,11 @@
.vscode/**
.vscode-test/**
src/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*

View File

@@ -0,0 +1,28 @@
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
export default [{
files: ["**/*.ts"],
}, {
plugins: {
"@typescript-eslint": typescriptEslint,
},
languageOptions: {
parser: tsParser,
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"@typescript-eslint/naming-convention": ["warn", {
selector: "import",
format: ["camelCase", "PascalCase"],
}],
curly: "warn",
eqeqeq: "warn",
"no-throw-literal": "warn",
semi: "warn",
},
}];

View File

@@ -0,0 +1,69 @@
{
"comments": {
"lineComment": {
"comment": "//"
},
"blockComment": [
"/*",
"*/"
]
},
"brackets": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
]
],
"autoClosingPairs": [
{
"open": "{",
"close": "}"
},
{
"open": "[",
"close": "]"
},
{
"open": "(",
"close": ")"
},
{
"open": "\"",
"close": "\""
},
{
"open": "'",
"close": "'"
}
],
"surroundingPairs": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
],
[
"\"",
"\""
],
[
"'",
"'"
]
]
}

View File

@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode_1 = require("vscode");
const node_1 = require("vscode-languageclient/node");
let client;
function activate(context) {
const outputChannel = vscode_1.window.createOutputChannel('My Language Server');
outputChannel.appendLine('Extension activating...');
const serverExecutable = '/home/oliste/repos/nub-lang/compiler/NubLang.LSP/bin/Debug/net9.0/NubLang.LSP';
outputChannel.appendLine(`Server path: ${serverExecutable}`);
client = new node_1.LanguageClient('nub-lang', 'nub lang', {
run: {
command: serverExecutable,
transport: node_1.TransportKind.stdio,
},
debug: {
command: serverExecutable,
transport: node_1.TransportKind.stdio,
args: ['--debug'],
}
}, {
documentSelector: [
{ scheme: 'file', language: 'nub' },
{ scheme: 'file', pattern: '**/*.nub' }
],
synchronize: {
fileEvents: vscode_1.workspace.createFileSystemWatcher('**/.clientrc')
}
});
client.start();
}
function deactivate() {
if (!client) {
return undefined;
}
return client.stop();
}
//# sourceMappingURL=extension.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;AAKA,4BAkCC;AAED,gCAKC;AA9CD,mCAA6D;AAC7D,qDAA2E;AAE3E,IAAI,MAAsB,CAAC;AAE3B,SAAgB,QAAQ,CAAC,OAAyB;IACjD,MAAM,aAAa,GAAG,eAAM,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC;IACvE,aAAa,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;IAEpD,MAAM,gBAAgB,GAAG,+EAA+E,CAAC;IAEzG,aAAa,CAAC,UAAU,CAAC,gBAAgB,gBAAgB,EAAE,CAAC,CAAC;IAE7D,MAAM,GAAG,IAAI,qBAAc,CAC1B,UAAU,EACV,UAAU,EACV;QACC,GAAG,EAAE;YACJ,OAAO,EAAE,gBAAgB;YACzB,SAAS,EAAE,oBAAa,CAAC,KAAK;SAC9B;QACD,KAAK,EAAE;YACN,OAAO,EAAE,gBAAgB;YACzB,SAAS,EAAE,oBAAa,CAAC,KAAK;YAC9B,IAAI,EAAE,CAAC,SAAS,CAAC;SACjB;KACD,EACD;QACC,gBAAgB,EAAE;YACjB,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;YACnC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;SACvC;QACD,WAAW,EAAE;YACZ,UAAU,EAAE,kBAAS,CAAC,uBAAuB,CAAC,cAAc,CAAC;SAC7D;KACD,CACD,CAAC;IAEF,MAAM,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,SAAgB,UAAU;IACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC"}

View File

@@ -0,0 +1,48 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const assert = __importStar(require("assert"));
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
const vscode = __importStar(require("vscode"));
// import * as myExtension from '../../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});
//# sourceMappingURL=extension.test.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"extension.test.js","sourceRoot":"","sources":["../../src/test/extension.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAEjC,0DAA0D;AAC1D,8CAA8C;AAC9C,+CAAiC;AACjC,kDAAkD;AAElD,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}

3434
vscode-lsp/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

58
vscode-lsp/package.json Normal file
View File

@@ -0,0 +1,58 @@
{
"name": "nub-lang",
"displayName": "Nub Language Support",
"description": "Language server client for nub-lang",
"version": "0.0.0",
"publisher": "nub31",
"repository": {
"type": "git",
"url": "https://git.oliste.no/nub31/nub-lang"
},
"engines": {
"vscode": "^1.105.0"
},
"categories": [
"Programming Languages"
],
"main": "./out/extension.js",
"contributes": {
"languages": [
{
"id": "nub-lang",
"extensions": [
".nub"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "nub-lang",
"scopeName": "source.nub",
"path": "./syntaxes/nub.tmLanguage.json"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile && npm run lint",
"lint": "eslint src",
"test": "vscode-test"
},
"devDependencies": {
"@types/mocha": "^10.0.10",
"@types/node": "22.x",
"@types/vscode": "^1.105.0",
"@typescript-eslint/eslint-plugin": "^8.45.0",
"@typescript-eslint/parser": "^8.45.0",
"@vscode/test-cli": "^0.0.11",
"@vscode/test-electron": "^2.5.2",
"eslint": "^9.36.0",
"typescript": "^5.9.3"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
}
}

View File

@@ -0,0 +1,47 @@
import { workspace, ExtensionContext, window } from 'vscode';
import { LanguageClient, TransportKind } from 'vscode-languageclient/node';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
const outputChannel = window.createOutputChannel('My Language Server');
outputChannel.appendLine('Extension activating...');
const serverExecutable = '/home/oliste/repos/nub-lang/compiler/NubLang.LSP/bin/Debug/net9.0/NubLang.LSP';
outputChannel.appendLine(`Server path: ${serverExecutable}`);
client = new LanguageClient(
'nub-lang',
'nub lang',
{
run: {
command: serverExecutable,
transport: TransportKind.stdio,
},
debug: {
command: serverExecutable,
transport: TransportKind.stdio,
args: ['--debug'],
}
},
{
documentSelector: [
{ scheme: 'file', language: 'nub' },
{ scheme: 'file', pattern: '**/*.nub' }
],
synchronize: {
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
}
}
);
client.start();
}
export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
}

View File

@@ -0,0 +1,304 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "nub-lang",
"scopeName": "source.nub",
"patterns": [
{
"include": "#comments"
},
{
"include": "#keywords"
},
{
"include": "#modifiers"
},
{
"include": "#types"
},
{
"include": "#strings"
},
{
"include": "#numbers"
},
{
"include": "#operators"
},
{
"include": "#function-definition"
},
{
"include": "#struct-definition"
},
{
"include": "#function-call"
},
{
"include": "#identifiers"
}
],
"repository": {
"comments": {
"patterns": [
{
"name": "comment.line.double-slash.nub",
"begin": "//",
"end": "$"
},
{
"name": "comment.block.nub",
"begin": "/\\*",
"end": "\\*/"
}
]
},
"keywords": {
"patterns": [
{
"name": "keyword.control.nub",
"match": "\\b(if|else|while|for|in|break|continue|return|let|defer)\\b"
},
{
"name": "keyword.other.nub",
"match": "\\b(func|struct|module|import)\\b"
}
]
},
"modifiers": {
"patterns": [
{
"name": "storage.modifier.nub",
"match": "\\b(export|extern)\\b"
}
]
},
"types": {
"patterns": [
{
"include": "#function-type"
},
{
"name": "storage.type.primitive.nub",
"match": "\\b(i8|i16|i32|i64|u8|u16|u32|u64|f32|f64|bool|string|cstring|void|any)\\b"
},
{
"name": "storage.type.array.nub",
"match": "\\[\\]"
},
{
"name": "storage.type.pointer.nub",
"match": "\\^"
}
]
},
"function-type": {
"patterns": [
{
"begin": "\\b(func)\\s*\\(",
"beginCaptures": {
"1": {
"name": "storage.type.function.nub"
}
},
"end": "(?<=\\))(?:\\s*:\\s*([^\\s,;{}()]+))?",
"endCaptures": {
"1": {
"name": "storage.type.nub"
}
},
"patterns": [
{
"include": "#function-type-parameters"
}
]
}
]
},
"function-type-parameters": {
"patterns": [
{
"match": "\\.\\.\\.",
"name": "keyword.operator.variadic.nub"
},
{
"include": "#types"
},
{
"match": ",",
"name": "punctuation.separator.nub"
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double.nub",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.nub",
"match": "\\\\(n|t|r|\\\\|\"|')"
},
{
"name": "constant.character.escape.nub",
"match": "\\\\[0-7]{1,3}"
},
{
"name": "constant.character.escape.nub",
"match": "\\\\x[0-9A-Fa-f]{1,2}"
}
]
},
{
"name": "string.quoted.single.nub",
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape.nub",
"match": "\\\\(n|t|r|\\\\|\"|')"
}
]
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.float.nub",
"match": "\\b\\d+\\.\\d*([eE][+-]?\\d+)?[fF]?\\b"
},
{
"name": "constant.numeric.integer.decimal.nub",
"match": "\\b\\d+\\b"
},
{
"name": "constant.numeric.integer.hexadecimal.nub",
"match": "\\b0[xX][0-9A-Fa-f]+\\b"
},
{
"name": "constant.numeric.integer.binary.nub",
"match": "\\b0[bB][01]+\\b"
}
]
},
"operators": {
"patterns": [
{
"name": "keyword.operator.assignment.nub",
"match": "="
},
{
"name": "keyword.operator.comparison.nub",
"match": "(==|!=|<=|>=|<|>)"
},
{
"name": "keyword.operator.arithmetic.nub",
"match": "(\\+|\\-|\\*|/)"
},
{
"name": "keyword.operator.logical.nub",
"match": "(&&|\\|\\||!)"
},
{
"name": "keyword.operator.address.nub",
"match": "&"
},
{
"name": "keyword.operator.dereference.nub",
"match": "\\^"
},
{
"name": "keyword.operator.member-access.nub",
"match": "\\."
},
{
"name": "keyword.operator.module-access.nub",
"match": "::"
}
]
},
"function-definition": {
"patterns": [
{
"begin": "\\b(export\\s+|extern\\s+)?(func)\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\(",
"beginCaptures": {
"1": {
"name": "storage.modifier.nub"
},
"2": {
"name": "keyword.other.nub"
},
"3": {
"name": "entity.name.function.nub"
}
},
"end": "\\)",
"patterns": [
{
"include": "#function-parameters"
}
]
}
]
},
"struct-definition": {
"patterns": [
{
"match": "\\b(struct)\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\b",
"captures": {
"1": {
"name": "keyword.other.nub"
},
"2": {
"name": "entity.name.type.struct.nub"
}
}
}
]
},
"function-parameters": {
"patterns": [
{
"match": "\\.\\.\\.",
"name": "keyword.operator.variadic.nub"
},
{
"match": "([a-zA-Z_][a-zA-Z0-9_]*)\\s*:\\s*",
"captures": {
"1": {
"name": "variable.parameter.nub"
}
}
},
{
"include": "#types"
},
{
"include": "#identifiers"
}
]
},
"function-call": {
"patterns": [
{
"match": "([a-zA-Z_][a-zA-Z0-9_]*)\\s*(?=\\()",
"captures": {
"1": {
"name": "entity.name.function.call.nub"
}
}
}
]
},
"identifiers": {
"patterns": [
{
"name": "variable.other.nub",
"match": "\\b[a-zA-Z_][a-zA-Z0-9_]*\\b"
}
]
}
}
}

15
vscode-lsp/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"outDir": "out",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}