Add lsp code action ui sample

This commit is contained in:
Dirk Baeumer
2019-11-15 19:19:44 +01:00
parent 92354b3a8a
commit 3fa2d68290
23 changed files with 5487 additions and 0 deletions

View File

@ -0,0 +1,18 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"env": {
"node": true
},
"rules": {
"semi": "error",
"no-extra-semi": "warn",
"curly": "warn",
"quotes": ["error", "single", { "allowTemplateLiterals": true } ],
"eqeqeq": "error",
"indent": ["warn", "tab", { "SwitchCase": 1 } ]
}
}

5
lsp-user-input-sample/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
node_modules
client/out
client/node_modules
server/out
server/node_modules

View File

@ -0,0 +1,33 @@
// A launch configuration that compiles the extension and then opens it inside a new window
{
"version": "0.2.0",
"configurations": [
{
"type": "extensionHost",
"request": "launch",
"name": "Launch Client",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceFolder}" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceFolder}/client/out/**/*.js"],
"preLaunchTask": "npm: watch"
},
{
"type": "node",
"request": "attach",
"name": "Attach to Server",
"address": "localhost",
"protocol": "inspector",
"port": 6011,
"sourceMaps": true,
"outFiles": ["${workspaceFolder}/server/out/**/*.js"]
}
],
"compounds": [
{
"name": "Client + Server",
"configurations": ["Launch Client", "Attach to Server"]
}
]
}

View File

@ -0,0 +1,29 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false
},
"search.exclude": {
"out": true,
"server": true
},
"files.trimTrailingWhitespace": true,
"editor.insertSpaces": false,
"editor.tabSize": 4,
"typescript.tsdk": "./node_modules/typescript/lib",
"typescript.tsc.autoDetect": "off",
"eslint.enable": true,
"eslint.validate": [
"typescript"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.workingDirectories": [
{ "directory": "./client", "changeProcessCWD": true },
{ "directory": "./server", "changeProcessCWD": true }
],
"eslint.trace.server": "off",
"eslint.lintTask.enable": false,
"eslint.format.enable": false
}

View File

@ -0,0 +1,36 @@
{
// 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",
"isBackground": true,
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "never",
"panel": "dedicated"
},
"problemMatcher": [
"$tsc-watch"
]
},
{
"type": "npm",
"script": "compile",
"isBackground": false,
"group": "build",
"presentation": {
"reveal": "never",
"panel": "dedicated"
},
"problemMatcher": [
"$tsc"
]
}
]
}

View File

@ -0,0 +1,34 @@
# LSP UI Example
Sample to demonstrate UI support for code actions in LSP
## Functionality
This Language Server works for plain text file. It has the following language features:
- Diagnostics
- Code Actions with UI
## Structure
```
.
├── client // Language Client
│ ├── src
│ │ └── extension.ts // Language Client entry point
├── package.json // The extension manifest.
└── server // Language Server
└── src
└── sampleServer.ts // Language Server entry point
```
## Running the Sample
- Run `npm install` in this folder. This installs all necessary npm modules in both the client and server folder
- Open VS Code on this folder.
- Press Ctrl+Shift+B to compile the client and server.
- Switch to the Debug viewlet.
- Select `Launch Client` from the drop down.
- Run the launch config.
- If you want to debug the server as well use the launch configuration `Attach to Server`
- In the [Extension Development Host] instance of VSCode, open a document in 'plain text' language mode.
- Activate code action on the error on the first line.

View File

@ -0,0 +1,5 @@
{
"extends": "../.eslintrc.base.json",
"rules": {
}
}

View File

@ -0,0 +1,47 @@
{
"name": "client",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/vscode": {
"version": "1.38.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.38.0.tgz",
"integrity": "sha512-aGo8LQ4J1YF0T9ORuCO+bhQ5sGR1MXa7VOyOdEP685se3wyQWYUExcdiDi6rvaK61KUwfzzA19JRLDrUbDl7BQ==",
"dev": true
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"vscode-jsonrpc": {
"version": "5.0.0-next.4",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.4.tgz",
"integrity": "sha512-Tos3tXP62ZTB9WowWwhvfVNdu1mEwQF/j7DqJuVL4QKhk311gH+mda0PZpG95LWyh5CCRpHMns4vNmMgZQrvXQ=="
},
"vscode-languageclient": {
"version": "6.0.0-next.6",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.0-next.6.tgz",
"integrity": "sha512-Fd9dkQSgjVaSRXDFEMj4rGJEcTJ3sOzxb71wP2U91JJYr46rWxFLoxtZIfm7ABeajal69YUpo+5gHLLb5CCf9g==",
"requires": {
"semver": "^6.3.0",
"vscode-languageserver-protocol": "^3.15.0-next.11"
}
},
"vscode-languageserver-protocol": {
"version": "3.15.0-next.11",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.11.tgz",
"integrity": "sha512-tpRnPtyS6q0EYH5RH12AtdMecgu3HVL2bBdBGzeQRN8Tf93I9LY4Fl5TXUNkIBjuxjMshkCM8ikhb+hlnWvB2w==",
"requires": {
"vscode-jsonrpc": "^5.0.0-next.3",
"vscode-languageserver-types": "^3.15.0-next.7"
}
},
"vscode-languageserver-types": {
"version": "3.15.0-next.8",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.8.tgz",
"integrity": "sha512-AEfWrSNyeamWMKPehh/kd3nBnKD9ZGCPhzfxMnW9YNqElSh28G2+Puk3knIQWyaWyV6Bzh28ok9BRJsPzXFCkQ=="
}
}
}

View File

@ -0,0 +1,24 @@
{
"name": "client",
"displayName": "Code Action UI Sample - Client",
"version": "1.0.0",
"private": true,
"author": "Microsoft Corporation",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-extension-samples.git"
},
"bugs": {
"url": "https://github.com/Microsoft/vscode-extension-samples/issues"
},
"engines": {
"vscode": "^1.38.0"
},
"devDependencies": {
"@types/vscode": "1.38.0"
},
"dependencies": {
"vscode-languageclient": "6.0.0-next.6"
}
}

View File

@ -0,0 +1,51 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as path from 'path';
import { ExtensionContext, window as Window } from 'vscode';
import { LanguageClient, LanguageClientOptions, RevealOutputChannelOn, ServerOptions, TransportKind } from 'vscode-languageclient';
export function activate(context: ExtensionContext): void {
const serverModule = context.asAbsolutePath(path.join('server', 'out', 'sampleServer.js'));
let serverOptions: ServerOptions = {
run: { module: serverModule, transport: TransportKind.ipc, options: { cwd: process.cwd() } },
debug: { module: serverModule, transport: TransportKind.ipc, options: { execArgv: ['--nolazy', '--inspect=6011'], cwd: process.cwd() } }
};
let clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'plaintext' }],
diagnosticCollectionName: 'sample',
revealOutputChannelOn: RevealOutputChannelOn.Never,
progressOnInitialization: true,
middleware: {
executeCommand: async (command, args, next) => {
const selected = await Window.showQuickPick(['Visual Studio', 'Visual Studio Code']);
if (selected === undefined) {
return next(command, args);
}
args = args.slice(0);
args.push(selected);
return next(command, args);
}
}
};
let client: LanguageClient;
try {
client = new LanguageClient('UI Sample', serverOptions, clientOptions);
} catch (err) {
Window.showErrorMessage(`The extension couldn't be started. See the output channel for details.`);
return;
}
client.registerProposedFeatures();
context.subscriptions.push(
client.start(),
);
}
export function deactivate() {
}

View File

@ -0,0 +1,17 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"outDir": "out",
"rootDir": "src",
"lib": [ "es2017" ],
"sourceMap": true
},
"include": [
"src"
],
"exclude": [
"node_modules"
]
}

View File

@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const withDefaults = require('../shared.webpack.config');
const path = require('path');
module.exports = withDefaults({
context: path.join(__dirname),
entry: {
extension: './src/extension.ts',
},
output: {
filename: 'extension.js',
path: path.join(__dirname, 'out')
}
});

4842
lsp-user-input-sample/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
{
"name": "vscode-codeaction-ui-sample",
"displayName": "Code Action UI Sample",
"description": "Sample to demonstrate code actions with UI",
"version": "1.0.0",
"author": "Microsoft Corporation",
"license": "MIT",
"keywords": [
"multi-root ready"
],
"engines": {
"vscode": "^1.41.0"
},
"activationEvents": [
"onLanguage:plaintext"
],
"main": "./client/out/extension",
"scripts": {
"vscode:prepublish": "npm run webpack",
"webpack": "npm run clean && webpack --mode production --config ./client/webpack.config.js && webpack --mode production --config ./server/webpack.config.js",
"webpack:dev": "npm run clean && webpack --mode none --config ./client/webpack.config.js && webpack --mode none --config ./server/webpack.config.js",
"compile": "tsc -b",
"compile:client": "tsc -b ./client/tsconfig.json",
"compile:server": "tsc -b ./server/tsconfig.json",
"watch": "tsc -b -w",
"lint": "npm run lint:client && npm run lint:server",
"lint:client": "eslint --config ./client/.eslintrc.json ./client/src/*.ts",
"lint:server": "eslint --config ./server/.eslintrc.json ./server/src/*.ts",
"clean": "rimraf client/out && rimraf server/out",
"postinstall": "cd client && npm install && cd ../server && npm install && cd .."
},
"devDependencies": {
"@types/node": "^12.12.6",
"typescript": "^3.7.2",
"eslint": "^6.6.0",
"@typescript-eslint/parser": "^2.6.1",
"webpack": "^4.39.2",
"webpack-cli": "^3.3.7",
"ts-loader": "^5.4.5",
"merge-options": "^1.0.1",
"rimraf": "^3.0.0"
}
}

View File

@ -0,0 +1,6 @@
{
"extends": "../.eslintrc.base.json",
"rules": {
"no-console": "error"
}
}

View File

@ -0,0 +1,45 @@
{
"name": "server",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"vscode-jsonrpc": {
"version": "5.0.0-next.4",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.4.tgz",
"integrity": "sha512-Tos3tXP62ZTB9WowWwhvfVNdu1mEwQF/j7DqJuVL4QKhk311gH+mda0PZpG95LWyh5CCRpHMns4vNmMgZQrvXQ=="
},
"vscode-languageserver": {
"version": "6.0.0-next.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-6.0.0-next.5.tgz",
"integrity": "sha512-KMEyRR/cEhgPym7k3MOn7GUz70TjRYDcmvVIKJlmfknBEIrDU1GgI2DK0zasjfKdMGJWbLyU/rLfXJe46rynlw==",
"requires": {
"vscode-languageserver-protocol": "^3.15.0-next.11"
}
},
"vscode-languageserver-protocol": {
"version": "3.15.0-next.11",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.11.tgz",
"integrity": "sha512-tpRnPtyS6q0EYH5RH12AtdMecgu3HVL2bBdBGzeQRN8Tf93I9LY4Fl5TXUNkIBjuxjMshkCM8ikhb+hlnWvB2w==",
"requires": {
"vscode-jsonrpc": "^5.0.0-next.3",
"vscode-languageserver-types": "^3.15.0-next.7"
}
},
"vscode-languageserver-textdocument": {
"version": "1.0.0-next.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.0-next.5.tgz",
"integrity": "sha512-1jp/zAidN/bF/sqPimhBX1orH5G4rzRw63k75TesukJDuxm8yW79ECStWbDSy41BHGOwSGN4M69QFvhancSr5A=="
},
"vscode-languageserver-types": {
"version": "3.15.0-next.8",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.8.tgz",
"integrity": "sha512-AEfWrSNyeamWMKPehh/kd3nBnKD9ZGCPhzfxMnW9YNqElSh28G2+Puk3knIQWyaWyV6Bzh28ok9BRJsPzXFCkQ=="
},
"vscode-uri": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.0.3.tgz",
"integrity": "sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw=="
}
}
}

View File

@ -0,0 +1,22 @@
{
"name": "server",
"version": "1.0.0",
"private": true,
"author": "Microsoft Corporation",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-extension-samples.git"
},
"bugs": {
"url": "https://github.com/Microsoft/vscode-extension-samples/issues"
},
"engines": {
"node": "*"
},
"dependencies": {
"vscode-uri": "^2.0.3",
"vscode-languageserver": "6.0.0-next.5",
"vscode-languageserver-textdocument": "1.0.0-next.5"
}
}

View File

@ -0,0 +1,80 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import {
CodeAction, CodeActionKind, Command, createConnection, Diagnostic, DiagnosticSeverity, Position, Range, TextDocumentEdit,
TextDocuments, TextDocumentSyncKind, TextEdit
} from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
const connection = createConnection();
connection.console.info(`Sample server running in node ${process.version}`);
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
documents.listen(connection);
connection.onInitialize(() => {
return {
capabilities: {
codeActionProvider: true,
textDocumentSync: {
openClose: true,
change: TextDocumentSyncKind.Incremental
},
executeCommandProvider: {
commands: ['sample.fixMe']
}
}
};
});
function validate(document: TextDocument): void {
connection.sendDiagnostics({
uri: document.uri,
version: document.version,
diagnostics: [
Diagnostic.create(Range.create(0,0,0, 10), 'Something is wrong here', DiagnosticSeverity.Warning)
]
});
}
documents.onDidOpen((event) => {
validate(event.document);
});
documents.onDidChangeContent((event) => {
validate(event.document);
});
connection.onCodeAction((params) => {
const textDocument = documents.get(params.textDocument.uri);
if (textDocument === undefined) {
return undefined;
}
const title = 'With User Input';
return [CodeAction.create(title, Command.create(title, 'sample.fixMe', textDocument.uri), CodeActionKind.QuickFix)];
});
connection.onExecuteCommand(async (params) => {
if (params.command !== 'sample.fixMe' || params.arguments === undefined) {
return;
}
const textDocument = documents.get(params.arguments[0]);
if (textDocument === undefined) {
return;
}
const newText = typeof params.arguments[1] === 'string' ? params.arguments[1] : 'Eclipse';
connection.workspace.applyEdit({
documentChanges: [
TextDocumentEdit.create({ uri: textDocument.uri, version: textDocument.version }, [
TextEdit.insert(Position.create(0, 0), newText)
])
]
});
});
connection.listen();

View File

@ -0,0 +1,18 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "out",
"rootDir": "src",
"lib": [ "es2017" ]
},
"include": [
"src"
],
"exclude": [
"node_modules"
]
}

View File

@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const withDefaults = require('../shared.webpack.config');
const path = require('path');
module.exports = withDefaults({
context: path.join(__dirname),
entry: {
extension: './src/eslintServer.ts',
},
output: {
filename: 'eslintServer.js',
path: path.join(__dirname, 'out')
}
});

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/
'use strict';
const path = require('path');
const merge = require('merge-options');
module.exports = function withDefaults(/**@type WebpackConfig*/extConfig) {
/** @type WebpackConfig */
let defaultConfig = {
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
target: 'node', // extensions run in a node context
node: {
__dirname: false // leave the __dirname-behaviour intact
},
resolve: {
mainFields: ['module', 'main'],
extensions: ['.ts', '.js'] // support ts-files and js-files
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
use: [{
// configure TypeScript loader:
// * enable sources maps for end-to-end source maps
loader: 'ts-loader',
options: {
compilerOptions: {
"sourceMap": true,
}
}
}]
}]
},
externals: {
'vscode': 'commonjs vscode', // ignored because it doesn't exist
},
output: {
// all output goes into `dist`.
// packaging depends on that and this must always be like it
filename: '[name].js',
path: path.join(extConfig.context, 'out'),
libraryTarget: "commonjs",
},
// yes, really source maps
devtool: 'source-map'
};
return merge(defaultConfig, extConfig);
};

View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true
}
}

View File

@ -0,0 +1,21 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "out",
"rootDir": "src",
"lib": [ "es6" ],
"sourceMap": true
},
"include": [
"src"
],
"exclude": [
"node_modules"
],
"references": [
{ "path": "./client" },
{ "path": "./server" }
]
}