tried to collect all files, that maight be necessary
This commit is contained in:
commit
8c1ade4505
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
out
|
||||
node_modules
|
||||
client/server
|
||||
.vscode-test
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
Thumbs.db
|
||||
**/node_modules/
|
||||
*/out/
|
||||
*/.vs/
|
||||
tsconfig.lsif.json
|
||||
*.lsif
|
||||
*.db
|
||||
*.tsbuildinfo
|
||||
1285
client/package-lock.json
generated
Normal file
1285
client/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
client/package.json
Normal file
23
client/package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "lsp-sample-client",
|
||||
"description": "VSCode part of a language server",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"version": "0.0.1",
|
||||
"publisher": "vscode",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.75.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": "^11.0.0",
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.75.1",
|
||||
"@vscode/test-electron": "^2.3.9"
|
||||
}
|
||||
}
|
||||
61
client/src/extension.ts
Normal file
61
client/src/extension.ts
Normal file
@ -0,0 +1,61 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as path from 'path';
|
||||
import { workspace, ExtensionContext } from 'vscode';
|
||||
|
||||
import {
|
||||
LanguageClient,
|
||||
LanguageClientOptions,
|
||||
ServerOptions,
|
||||
TransportKind
|
||||
} from 'vscode-languageclient/node';
|
||||
|
||||
let client: LanguageClient;
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
// The server is implemented in node
|
||||
const serverModule = context.asAbsolutePath(
|
||||
path.join('server', 'out', 'server.js')
|
||||
);
|
||||
|
||||
// If the extension is launched in debug mode then the debug server options are used
|
||||
// Otherwise the run options are used
|
||||
const serverOptions: ServerOptions = {
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
debug: {
|
||||
module: serverModule,
|
||||
transport: TransportKind.ipc,
|
||||
}
|
||||
};
|
||||
|
||||
// Options to control the language client
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
// Register the server for plain text documents
|
||||
documentSelector: [{ scheme: 'file', language: 'yaml' }, { scheme: 'file', language: 'plaintext' }],
|
||||
synchronize: {
|
||||
// Notify the server about file changes to '.clientrc files contained in the workspace
|
||||
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
|
||||
}
|
||||
};
|
||||
|
||||
// Create the language client and start the client.
|
||||
client = new LanguageClient(
|
||||
'languageServerExample',
|
||||
'Language Server Example',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
|
||||
// Start the client. This will also launch the server
|
||||
client.start();
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> | undefined {
|
||||
if (!client) {
|
||||
return undefined;
|
||||
}
|
||||
return client.stop();
|
||||
}
|
||||
43
client/src/test/completion.test.ts
Normal file
43
client/src/test/completion.test.ts
Normal file
@ -0,0 +1,43 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as assert from 'assert';
|
||||
import { getDocUri, activate } from './helper';
|
||||
|
||||
suite('Should do completion', () => {
|
||||
const docUri = getDocUri('completion.txt');
|
||||
|
||||
test('Completes JS/TS in txt file', async () => {
|
||||
await testCompletion(docUri, new vscode.Position(0, 0), {
|
||||
items: [
|
||||
{ label: 'JavaScript', kind: vscode.CompletionItemKind.Text },
|
||||
{ label: 'TypeScript', kind: vscode.CompletionItemKind.Text }
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function testCompletion(
|
||||
docUri: vscode.Uri,
|
||||
position: vscode.Position,
|
||||
expectedCompletionList: vscode.CompletionList
|
||||
) {
|
||||
await activate(docUri);
|
||||
|
||||
// Executing the command `vscode.executeCompletionItemProvider` to simulate triggering completion
|
||||
const actualCompletionList = (await vscode.commands.executeCommand(
|
||||
'vscode.executeCompletionItemProvider',
|
||||
docUri,
|
||||
position
|
||||
)) as vscode.CompletionList;
|
||||
|
||||
assert.ok(actualCompletionList.items.length >= 2);
|
||||
expectedCompletionList.items.forEach((expectedItem, i) => {
|
||||
const actualItem = actualCompletionList.items[i];
|
||||
assert.equal(actualItem.label, expectedItem.label);
|
||||
assert.equal(actualItem.kind, expectedItem.kind);
|
||||
});
|
||||
}
|
||||
41
client/src/test/diagnostics.test.ts
Normal file
41
client/src/test/diagnostics.test.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as assert from 'assert';
|
||||
import { getDocUri, activate } from './helper';
|
||||
|
||||
suite('Should get diagnostics', () => {
|
||||
const docUri = getDocUri('diagnostics.txt');
|
||||
|
||||
test('Diagnoses uppercase texts', async () => {
|
||||
await testDiagnostics(docUri, [
|
||||
{ message: 'ANY is all uppercase.', range: toRange(0, 0, 0, 3), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
|
||||
{ message: 'ANY is all uppercase.', range: toRange(0, 14, 0, 17), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' },
|
||||
{ message: 'OS is all uppercase.', range: toRange(0, 18, 0, 20), severity: vscode.DiagnosticSeverity.Warning, source: 'ex' }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
function toRange(sLine: number, sChar: number, eLine: number, eChar: number) {
|
||||
const start = new vscode.Position(sLine, sChar);
|
||||
const end = new vscode.Position(eLine, eChar);
|
||||
return new vscode.Range(start, end);
|
||||
}
|
||||
|
||||
async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: vscode.Diagnostic[]) {
|
||||
await activate(docUri);
|
||||
|
||||
const actualDiagnostics = vscode.languages.getDiagnostics(docUri);
|
||||
|
||||
assert.equal(actualDiagnostics.length, expectedDiagnostics.length);
|
||||
|
||||
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
|
||||
const actualDiagnostic = actualDiagnostics[i];
|
||||
assert.equal(actualDiagnostic.message, expectedDiagnostic.message);
|
||||
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range);
|
||||
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity);
|
||||
});
|
||||
}
|
||||
47
client/src/test/helper.ts
Normal file
47
client/src/test/helper.ts
Normal file
@ -0,0 +1,47 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
export let doc: vscode.TextDocument;
|
||||
export let editor: vscode.TextEditor;
|
||||
export let documentEol: string;
|
||||
export let platformEol: string;
|
||||
|
||||
/**
|
||||
* Activates the vscode.lsp-sample extension
|
||||
*/
|
||||
export async function activate(docUri: vscode.Uri) {
|
||||
// The extensionId is `publisher.name` from package.json
|
||||
const ext = vscode.extensions.getExtension('vscode-samples.lsp-sample')!;
|
||||
await ext.activate();
|
||||
try {
|
||||
doc = await vscode.workspace.openTextDocument(docUri);
|
||||
editor = await vscode.window.showTextDocument(doc);
|
||||
await sleep(2000); // Wait for server activation
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export const getDocPath = (p: string) => {
|
||||
return path.resolve(__dirname, '../../testFixture', p);
|
||||
};
|
||||
export const getDocUri = (p: string) => {
|
||||
return vscode.Uri.file(getDocPath(p));
|
||||
};
|
||||
|
||||
export async function setTestContent(content: string): Promise<boolean> {
|
||||
const all = new vscode.Range(
|
||||
doc.positionAt(0),
|
||||
doc.positionAt(doc.getText().length)
|
||||
);
|
||||
return editor.edit(eb => eb.replace(all, content));
|
||||
}
|
||||
40
client/src/test/index.ts
Normal file
40
client/src/test/index.ts
Normal file
@ -0,0 +1,40 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import * as path from 'path';
|
||||
import * as Mocha from 'mocha';
|
||||
import { glob } from 'glob';
|
||||
|
||||
export function run(): Promise<void> {
|
||||
// Create the mocha test
|
||||
const mocha = new Mocha({
|
||||
ui: 'tdd',
|
||||
color: true
|
||||
});
|
||||
mocha.timeout(100000);
|
||||
|
||||
const testsRoot = __dirname;
|
||||
|
||||
return glob.glob('**.test.js', { cwd: testsRoot }).then(async files => {
|
||||
|
||||
// Add files to the test suite
|
||||
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
|
||||
|
||||
try {
|
||||
// Run the mocha test
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
mocha.run(failures => {
|
||||
if (failures > 0) {
|
||||
reject(`${failures} tests failed.`);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
27
client/src/test/runTest.ts
Normal file
27
client/src/test/runTest.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as path from 'path';
|
||||
|
||||
import { runTests } from '@vscode/test-electron';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// The folder containing the Extension Manifest package.json
|
||||
// Passed to `--extensionDevelopmentPath`
|
||||
const extensionDevelopmentPath = path.resolve(__dirname, '../../../');
|
||||
|
||||
// The path to test runner
|
||||
// Passed to --extensionTestsPath
|
||||
const extensionTestsPath = path.resolve(__dirname, './index');
|
||||
|
||||
// Download VS Code, unzip it and run the integration test
|
||||
await runTests({ extensionDevelopmentPath, extensionTestsPath });
|
||||
} catch {
|
||||
console.error('Failed to run tests');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
0
client/testFixture/completion.txt
Normal file
0
client/testFixture/completion.txt
Normal file
1
client/testFixture/diagnostics.txt
Normal file
1
client/testFixture/diagnostics.txt
Normal file
@ -0,0 +1 @@
|
||||
ANY browsers, ANY OS.
|
||||
12
client/tsconfig.json
Normal file
12
client/tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2020",
|
||||
"lib": ["es2020"],
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
||||
44
eslint.config.mjs
Normal file
44
eslint.config.mjs
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* ESLint configuration for the project.
|
||||
*
|
||||
* See https://eslint.style and https://typescript-eslint.io for additional linting options.
|
||||
*/
|
||||
// @ts-check
|
||||
import js from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import stylistic from '@stylistic/eslint-plugin';
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
'**/.vscode-test',
|
||||
'**/out',
|
||||
]
|
||||
},
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
...tseslint.configs.stylistic,
|
||||
{
|
||||
plugins: {
|
||||
'@stylistic': stylistic
|
||||
},
|
||||
rules: {
|
||||
'curly': 'warn',
|
||||
'@stylistic/semi': ['warn', 'always'],
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'warn',
|
||||
{
|
||||
'selector': 'import',
|
||||
'format': ['camelCase', 'PascalCase']
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
'argsIgnorePattern': '^_'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
);
|
||||
81
package.json
Normal file
81
package.json
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "lsp-sample",
|
||||
"description": "A language server example",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
||||
},
|
||||
"publisher": "vscode-samples",
|
||||
"categories": [],
|
||||
"keywords": [
|
||||
"multi-root ready"
|
||||
],
|
||||
"engines": {
|
||||
"vscode": "^1.75.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"onLanguage:plaintext",
|
||||
"onLanguage",
|
||||
"onStartupFinished"
|
||||
],
|
||||
"main": "./client/out/extension",
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "yaml",
|
||||
"aliases": [
|
||||
"yml",
|
||||
"YAML"
|
||||
],
|
||||
"extensions": [
|
||||
".yaml",
|
||||
".yml"
|
||||
]
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Example configuration",
|
||||
"properties": {
|
||||
"languageServerExample.maxNumberOfProblems": {
|
||||
"scope": "resource",
|
||||
"type": "number",
|
||||
"default": 100,
|
||||
"description": "Controls the maximum number of problems produced by the server."
|
||||
},
|
||||
"languageServerExample.trace.server": {
|
||||
"scope": "window",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"off",
|
||||
"messages",
|
||||
"verbose"
|
||||
],
|
||||
"default": "off",
|
||||
"description": "Traces the communication between VS Code and the language server."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -b",
|
||||
"watch": "tsc -b -w",
|
||||
"lint": "eslint",
|
||||
"postinstall": "cd client && npm install && cd ../server && npm install && cd ..",
|
||||
"test": "sh ./scripts/e2e.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.13.0",
|
||||
"@stylistic/eslint-plugin": "^2.9.0",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^20",
|
||||
"eslint": "^9.13.0",
|
||||
"mocha": "^10.3.0",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.16.0"
|
||||
}
|
||||
}
|
||||
6
scripts/e2e.sh
Normal file
6
scripts/e2e.sh
Normal file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export CODE_TESTS_PATH="$(pwd)/client/out/test"
|
||||
export CODE_TESTS_WORKSPACE="$(pwd)/client/testFixture"
|
||||
|
||||
node "$(pwd)/client/out/test/runTest"
|
||||
92
server/package-lock.json
generated
Normal file
92
server/package-lock.json
generated
Normal file
@ -0,0 +1,92 @@
|
||||
{
|
||||
"name": "lsp-sample-server",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "lsp-sample-server",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"vscode-languageserver": "^9.0.1",
|
||||
"vscode-languageserver-textdocument": "^1.0.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"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-languageserver": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
|
||||
"integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
|
||||
"dependencies": {
|
||||
"vscode-languageserver-protocol": "3.17.5"
|
||||
},
|
||||
"bin": {
|
||||
"installServerIntoExtension": "bin/installServerIntoExtension"
|
||||
}
|
||||
},
|
||||
"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-textdocument": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz",
|
||||
"integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA=="
|
||||
},
|
||||
"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=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
|
||||
"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="
|
||||
},
|
||||
"vscode-languageserver": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
|
||||
"integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
|
||||
"requires": {
|
||||
"vscode-languageserver-protocol": "3.17.5"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"requires": {
|
||||
"vscode-jsonrpc": "8.2.0",
|
||||
"vscode-languageserver-types": "3.17.5"
|
||||
}
|
||||
},
|
||||
"vscode-languageserver-textdocument": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz",
|
||||
"integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA=="
|
||||
},
|
||||
"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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
19
server/package.json
Normal file
19
server/package.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "lsp-sample-server",
|
||||
"description": "Example implementation of a language server in node.",
|
||||
"version": "1.0.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageserver": "^9.0.1",
|
||||
"vscode-languageserver-textdocument": "^1.0.11"
|
||||
},
|
||||
"scripts": {}
|
||||
}
|
||||
298
server/src/server.ts
Normal file
298
server/src/server.ts
Normal file
@ -0,0 +1,298 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import {
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
ProposedFeatures,
|
||||
InitializeParams,
|
||||
DidChangeConfigurationNotification,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
TextDocumentPositionParams,
|
||||
TextDocumentSyncKind,
|
||||
InitializeResult,
|
||||
DocumentDiagnosticReportKind,
|
||||
type DocumentDiagnosticReport,
|
||||
DiagnosticRelatedInformation,
|
||||
Location
|
||||
} from 'vscode-languageserver/node';
|
||||
|
||||
import {
|
||||
TextDocument
|
||||
} from 'vscode-languageserver-textdocument';
|
||||
import { load_context, get_highlighting } from '../../vscode/out/yaml';
|
||||
// Create a connection for the server, using Node's IPC as a transport.
|
||||
// Also include all preview / proposed LSP features.
|
||||
const connection = createConnection(ProposedFeatures.all);
|
||||
load_context();
|
||||
// Create a simple text document manager.
|
||||
const documents = new TextDocuments(TextDocument);
|
||||
|
||||
let hasConfigurationCapability = true;
|
||||
let hasWorkspaceFolderCapability = true;
|
||||
let hasDiagnosticRelatedInformationCapability = true;
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
const capabilities = params.capabilities;
|
||||
|
||||
// Does the client support the `workspace/configuration` request?
|
||||
// If not, we fall back using global settings.
|
||||
hasConfigurationCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.configuration
|
||||
);
|
||||
hasWorkspaceFolderCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.workspaceFolders
|
||||
);
|
||||
hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
// Tell the client that this server supports code completion.
|
||||
completionProvider: {
|
||||
resolveProvider: true
|
||||
},
|
||||
diagnosticProvider: {
|
||||
interFileDependencies: false,
|
||||
workspaceDiagnostics: false
|
||||
}
|
||||
}
|
||||
};
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
result.capabilities.workspace = {
|
||||
workspaceFolders: {
|
||||
supported: true
|
||||
}
|
||||
};
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
connection.onInitialized(() => {
|
||||
if (hasConfigurationCapability) {
|
||||
// Register for all configuration changes.
|
||||
connection.client.register(DidChangeConfigurationNotification.type, undefined);
|
||||
}
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
connection.workspace.onDidChangeWorkspaceFolders(_event => {
|
||||
connection.console.log('Workspace folder change event received.');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// The example settings
|
||||
interface ExampleSettings {
|
||||
maxNumberOfProblems: number;
|
||||
}
|
||||
|
||||
// The global settings, used when the `workspace/configuration` request is not supported by the client.
|
||||
// Please note that this is not the case when using this server with the client provided in this example
|
||||
// but could happen with other clients.
|
||||
const defaultSettings: ExampleSettings = { maxNumberOfProblems: 1000 };
|
||||
let globalSettings: ExampleSettings = defaultSettings;
|
||||
|
||||
// Cache the settings of all open documents
|
||||
const documentSettings = new Map<string, Thenable<ExampleSettings>>();
|
||||
|
||||
connection.onDidChangeConfiguration(change => {
|
||||
if (hasConfigurationCapability) {
|
||||
// Reset all cached document settings
|
||||
documentSettings.clear();
|
||||
} else {
|
||||
globalSettings = (
|
||||
(change.settings.languageServerExample || defaultSettings)
|
||||
);
|
||||
}
|
||||
// Refresh the diagnostics since the `maxNumberOfProblems` could have changed.
|
||||
// We could optimize things here and re-fetch the setting first can compare it
|
||||
// to the existing setting, but this is out of scope for this example.
|
||||
connection.languages.diagnostics.refresh();
|
||||
});
|
||||
|
||||
function getDocumentSettings(resource: string): Thenable<ExampleSettings> {
|
||||
if (!hasConfigurationCapability) {
|
||||
return Promise.resolve(globalSettings);
|
||||
}
|
||||
let result = documentSettings.get(resource);
|
||||
if (!result) {
|
||||
result = connection.workspace.getConfiguration({
|
||||
scopeUri: resource,
|
||||
section: 'languageServerExample'
|
||||
});
|
||||
documentSettings.set(resource, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Only keep settings for open documents
|
||||
documents.onDidClose(e => {
|
||||
documentSettings.delete(e.document.uri);
|
||||
});
|
||||
|
||||
|
||||
connection.languages.diagnostics.on(async (params) => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document !== undefined) {
|
||||
return {
|
||||
kind: DocumentDiagnosticReportKind.Full,
|
||||
items: await validateTextDocument(document)
|
||||
} satisfies DocumentDiagnosticReport;
|
||||
} else {
|
||||
// We don't know the document. We can either try to read it from disk
|
||||
// or we don't report problems for it.
|
||||
return {
|
||||
kind: DocumentDiagnosticReportKind.Full,
|
||||
items: []
|
||||
} satisfies DocumentDiagnosticReport;
|
||||
}
|
||||
});
|
||||
|
||||
// The content of a text document has changed. This event is emitted
|
||||
// when the text document first opened or when its content has changed.
|
||||
documents.onDidChangeContent(change => {
|
||||
validateTextDocument(change.document);
|
||||
});
|
||||
|
||||
|
||||
|
||||
async function validateTextDocument(textDocument: TextDocument): Promise<Diagnostic[]> {
|
||||
// In this simple example we get the settings for every validate run.
|
||||
textDocument.languageId;
|
||||
console.log("FOOSL");
|
||||
// The validator creates diagnostics for all uppercase words length 2 and more
|
||||
const text = textDocument.getText();
|
||||
const diagnostics: Diagnostic[] = [];
|
||||
for (const err of get_highlighting(text)) {
|
||||
const diagnostic = {
|
||||
severity: err.severity,
|
||||
range: {
|
||||
start: textDocument.positionAt(err.start),
|
||||
end: textDocument.positionAt(err.end)
|
||||
},
|
||||
message: err.message,
|
||||
source: 'ex',
|
||||
relatedInformation: [
|
||||
DiagnosticRelatedInformation.create(
|
||||
Location.create(textDocument.uri, {
|
||||
start: textDocument.positionAt(err.start),
|
||||
end: textDocument.positionAt(err.end)
|
||||
}),
|
||||
err.message
|
||||
)
|
||||
]
|
||||
};
|
||||
/*
|
||||
const diagnostic: Diagnostic = {
|
||||
severity: err.severity,
|
||||
range: {
|
||||
start: textDocument.positionAt(err.start),
|
||||
end: textDocument.positionAt(err.end)
|
||||
},
|
||||
message: err.message,
|
||||
source: 'ex',
|
||||
relatedInformation: [
|
||||
new DiagnosticRelatedInformation(
|
||||
new Location(textDocument.uri, textDocument.positionAt(err.start)),
|
||||
)
|
||||
]
|
||||
};
|
||||
*/
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
return diagnostics;
|
||||
/*
|
||||
const pattern = /\b[A-Z]{2,}\b/g;
|
||||
let m: RegExpExecArray | null;
|
||||
console.log("FOOSL");
|
||||
let problems = 0;
|
||||
while ((m = pattern.exec(text)) && problems < 25) {
|
||||
problems++;
|
||||
const diagnostic: Diagnostic = {
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
range: {
|
||||
start: textDocument.positionAt(m.index),
|
||||
end: textDocument.positionAt(m.index + m[0].length)
|
||||
},
|
||||
message: `${m[0]} is all uppercase.`,
|
||||
source: 'ex'
|
||||
};
|
||||
if (hasDiagnosticRelatedInformationCapability) {
|
||||
diagnostic.relatedInformation = [
|
||||
{
|
||||
location: {
|
||||
uri: textDocument.uri,
|
||||
range: Object.assign({}, diagnostic.range)
|
||||
},
|
||||
message: 'Spelling matters'
|
||||
},
|
||||
{
|
||||
location: {
|
||||
uri: textDocument.uri,
|
||||
range: Object.assign({}, diagnostic.range)
|
||||
},
|
||||
message: 'Particularly for names'
|
||||
}
|
||||
];
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
return diagnostics;
|
||||
*/
|
||||
}
|
||||
|
||||
connection.onDidChangeWatchedFiles(_change => {
|
||||
// Monitored files have change in VSCode
|
||||
connection.console.log('We received a file change event');
|
||||
});
|
||||
|
||||
// This handler provides the initial list of the completion items.
|
||||
connection.onCompletion(
|
||||
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
|
||||
// The pass parameter contains the position of the text document in
|
||||
// which code complete got requested. For the example we ignore this
|
||||
// info and always provide the same completion items.
|
||||
return [
|
||||
{
|
||||
label: 'TypeScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 1
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
kind: CompletionItemKind.Text,
|
||||
data: 2
|
||||
}
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
// This handler resolves additional information for the item selected in
|
||||
// the completion list.
|
||||
connection.onCompletionResolve(
|
||||
(item: CompletionItem): CompletionItem => {
|
||||
if (item.data === 1) {
|
||||
item.detail = 'TypeScript details';
|
||||
item.documentation = 'TypeScript documentation';
|
||||
} else if (item.data === 2) {
|
||||
item.detail = 'JavaScript details';
|
||||
item.documentation = 'JavaScript documentation';
|
||||
}
|
||||
return item;
|
||||
}
|
||||
);
|
||||
|
||||
// Make the text document manager listen on the connection
|
||||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
14
server/tsconfig.json
Normal file
14
server/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"lib": ["es2020"],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"outDir": "out",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
||||
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2020",
|
||||
"lib": ["es2020"],
|
||||
"outDir": "out",
|
||||
"rootDir": "src",
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "./client" },
|
||||
{ "path": "./server" }
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user