add language-provider sample

This commit is contained in:
Martin Aeschlimann
2016-12-15 19:48:12 +01:00
parent b41b561a1f
commit 170f24add1
16 changed files with 453 additions and 5 deletions

26
.vscode/launch.json vendored
View File

@ -34,6 +34,30 @@
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/contentprovider-sample/out/**/*.js"],
"preLaunchTask": "compile-contentprovider"
},
{
"name": "Launch Language Provider Sample",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}/languageprovider-sample" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/languageprovider-sample/client/out/**/*.js"]
},
{
"name": "Attach Language Provider Sample Server",
"type": "node",
"request": "attach",
"port": 6004,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/languageprovider-sample/server/out/**/*.js"]
}
]
],
"compounds": [
{
"name": "Launch Language Provider Sample & Attach to Server",
"configurations": ["Launch Language Provider Sample", "Attach Language Provider Sample Server"]
}
]
}

13
.vscode/tasks.json vendored
View File

@ -56,6 +56,19 @@
// The tsc compiler is started in watching mode
"isWatching": true,
// use the standard tsc in watch mode problem matcher to find compile problems in the output.
"problemMatcher": "$tsc-watch"
},
{
// in package.json we have a compile task for each example
"taskName": "compile-languageprovider",
// show the output window only if unrecognized errors occur.
"showOutput": "silent",
// The tsc compiler is started in watching mode
"isWatching": true,
// use the standard tsc in watch mode problem matcher to find compile problems in the output.
"problemMatcher": "$tsc-watch"
}

View File

@ -4,6 +4,7 @@ Sample code illustrating the VS Code extension APIs.
* [Editor Decoration](/decorator-sample/README.md)
* [Virtual Documents](/contentprovider-sample/README.md)
* [Language Provider](/languageprovider-sample/README.md)
* [Preview Html](/previewhtml-sample/README.md)
* [Vim](/vim-sample/README.md)
* [Integrated Terminal](/terminal-example/README.md)
@ -12,5 +13,10 @@ Sample code illustrating the VS Code extension APIs.
# How to run locally
* `git clone`
* `npm run install-all`
* run one of `npm run compile-decorator`, `npm run compile-previewhtml`, or `compile-contentprovider`
* `npm install`
* run one of
* `npm run compile-decorator`,
* `npm run compile-previewhtml`
* `npm run compile-contentprovider`
* `npm run compile-languageprovider`
* launch the sample from the debug viewlet

29
build/postinstall.js Normal file
View File

@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const cp = require('child_process');
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
function npmInstall(location) {
const result = cp.spawnSync(npm, ['install'], {
cwd: location ,
stdio: 'inherit'
});
if (result.error || result.status !== 0) {
process.exit(1);
}
}
const samples = [
'contentprovider-sample',
'decorator-sample',
'languageprovider-sample',
'vim-sample',
'terminal-example',
'tree-explorer-sample'
];
samples.forEach(npmInstall);

2
languageprovider-sample/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
out
node_modules

View File

@ -0,0 +1,44 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/client/out/**/*.js"],
"preLaunchTask": "npm"
},
{
"name": "Launch Extension Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/client/out/test" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/client/out/test/**/*.js"],
"preLaunchTask": "npm"
},
{
"name": "Attach Language Server",
"type": "node",
"request": "attach",
"port": 6004,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/server/out/**/*.js"]
}
],
"compounds": [
{
"name": "Launch Client & Server",
"configurations": ["Launch Client", "Attach Language Server"]
}
]
}

View File

@ -0,0 +1,10 @@
{
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "silent",
"args": ["run", "watch"],
"isWatching": true,
"problemMatcher": "$tsc-watch"
}

View File

@ -0,0 +1,20 @@
# README
## This is the README for the "languageprovider-sample"
-------------------
This folder contains a sample VS code extension that demonstrates an extension that runs a language server
The extension observes all 'plaintext' documents (documents from all editors not associated with a language)
and uses the server to provide validation and completion proposals.
The code for the extension is in the 'client' folder. It uses the 'vscode-languageclient' node module to launch the language server.
The language server is located in the 'server' folder.
# How to run locally
* `npm install` to initialize the extension and the server
* `npm run compile` to compile the extension and the server
* open this folder in VS Code. In the Debug viewlet, run 'Launch Client & Server' from drop-down to launch the extension and attach to both the extension and the server.
* create a file `foo.bar`, and type `typescript`. You should see a validation error.
* set breakpoints in the server or the client

View File

@ -0,0 +1,44 @@
/* --------------------------------------------------------------------------------------------
* 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 { workspace, Disposable, ExtensionContext } from 'vscode';
import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, TransportKind } from 'vscode-languageclient';
export function activate(context: ExtensionContext) {
// The server is implemented in node
let serverModule = context.asAbsolutePath(path.join('server', 'out', 'serverMain.js'));
// The debug options for the server
let debugOptions = { execArgv: ["--nolazy", "--debug=6004"] };
// If the extension is launched in debug mode then the debug server options are used
// Otherwise the run options are used
let serverOptions: ServerOptions = {
run : { module: serverModule, transport: TransportKind.ipc },
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions }
}
// Options to control the language client
let clientOptions: LanguageClientOptions = {
// Register the server for plain text documents
documentSelector: ['plaintext'],
synchronize: {
// Synchronize the setting section 'languageServerExample' to the server
configurationSection: 'languageServerExample',
// Notify the server about file changes to '.clientrc files contain in the workspace
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
}
}
// Create the language client and start the client.
let disposable = new LanguageClient('languageServerExample', 'Language Server Example', serverOptions, clientOptions).start();
// Push the disposable to the context's subscriptions so that the
// client can be deactivated on extension deactivation
context.subscriptions.push(disposable);
}

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"skipLibCheck": true,
"sourceMap": true,
"lib": [
"es5", "es2015.promise"
]
}
}

View File

@ -0,0 +1,56 @@
{
"name": "languageprovider-sample",
"description": "Language provider extension that launches a language server",
"author": "Microsoft Corporation",
"license": "MIT",
"version": "0.0.1",
"publisher": "vscode",
"engines": {
"vscode": "^1.4.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onLanguage:plaintext"
],
"main": "./client/out/clientMain",
"contributes": {
"configuration": {
"type": "object",
"title": "Example configuration",
"properties": {
"languageServerExample.maxNumberOfProblems": {
"type": "number",
"default": 100,
"description": "Controls the maximum number of problems produced by the server."
},
"languageServerExample.trace.server": {
"type": "string",
"enum": [
"off",
"messages",
"verbose"
],
"default": "off",
"description": "Traces the communication between VSCode and the languageServerExample service."
}
}
}
},
"scripts": {
"vscode:prepublish": "tsc -p ./",
"compile": "tsc -p ./client && cd server && npm run compile && cd ..",
"update-vscode": "node ./node_modules/vscode/bin/install",
"postinstall": "node ./node_modules/vscode/bin/install && cd server && npm install"
},
"devDependencies": {
"@types/mocha": "^2.2.33",
"@types/node": "^6.0.52",
"typescript": "^2.1.4",
"vscode": "^1.0.3"
},
"dependencies": {
"vscode-languageclient": "^2.6.3"
}
}

View File

@ -0,0 +1,21 @@
{
"name": "language-server-example",
"description": "Example implementation of a language server in node.",
"version": "0.0.1",
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
"node": "*"
},
"dependencies": {
"vscode-languageserver": "^2.6.2"
},
"devDependencies": {
"@types/node": "^6.0.52",
"typescript": "^2.1.4"
},
"scripts": {
"compile": "tsc -p .",
"watch": "tsc --watch -p ."
}
}

View File

@ -0,0 +1,153 @@
/* --------------------------------------------------------------------------------------------
* 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 {
IPCMessageReader, IPCMessageWriter,
createConnection, IConnection, TextDocumentSyncKind,
TextDocuments, TextDocument, Diagnostic, DiagnosticSeverity,
InitializeParams, InitializeResult, TextDocumentPositionParams,
CompletionItem, CompletionItemKind
} from 'vscode-languageserver';
// Create a connection for the server. The connection uses Node's IPC as a transport
let connection: IConnection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process));
// Create a simple text document manager. The text document manager
// supports full document sync only
let documents: TextDocuments = new TextDocuments();
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
// After the server has started the client sends an initilize request. The server receives
// in the passed params the rootPath of the workspace plus the client capabilites.
let workspaceRoot: string;
connection.onInitialize((params): InitializeResult => {
workspaceRoot = params.rootPath;
return {
capabilities: {
// Tell the client that the server works in FULL text document sync mode
textDocumentSync: documents.syncKind,
// Tell the client that the server support code complete
completionProvider: {
resolveProvider: true
}
}
}
});
// 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);
});
// The settings interface describe the server relevant settings part
interface Settings {
languageServerExample: ExampleSettings;
}
// These are the example settings we defined in the client's package.json
// file
interface ExampleSettings {
maxNumberOfProblems: number;
}
// hold the maxNumberOfProblems setting
let maxNumberOfProblems: number;
// The settings have changed. Is send on server activation
// as well.
connection.onDidChangeConfiguration((change) => {
let settings = <Settings>change.settings;
maxNumberOfProblems = settings.languageServerExample.maxNumberOfProblems || 100;
// Revalidate any open text documents
documents.all().forEach(validateTextDocument);
});
function validateTextDocument(textDocument: TextDocument): void {
let diagnostics: Diagnostic[] = [];
let lines = textDocument.getText().split(/\r?\n/g);
let problems = 0;
for (var i = 0; i < lines.length && problems < maxNumberOfProblems; i++) {
let line = lines[i];
let index = line.indexOf('typescript');
if (index >= 0) {
problems++;
diagnostics.push({
severity: DiagnosticSeverity.Warning,
range: {
start: { line: i, character: index},
end: { line: i, character: index + 10 }
},
message: `${line.substr(index, 10)} should be spelled TypeScript`,
source: 'ex'
});
}
}
// Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
}
connection.onDidChangeWatchedFiles((change) => {
// Monitored files have change in VSCode
connection.console.log('We recevied an 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 resolve 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;
});
/*
connection.onDidOpenTextDocument((params) => {
// A text document got opened in VSCode.
// params.uri uniquely identifies the document. For documents store on disk this is a file URI.
// params.text the initial full content of the document.
connection.console.log(`${params.textDocument.uri} opened.`);
});
connection.onDidChangeTextDocument((params) => {
// The content of a text document did change in VSCode.
// params.uri uniquely identifies the document.
// params.contentChanges describe the content changes to the document.
connection.console.log(`${params.textDocument.uri} changed: ${JSON.stringify(params.contentChanges)}`);
});
connection.onDidCloseTextDocument((params) => {
// A text document got closed in VSCode.
// params.uri uniquely identifies the document.
connection.console.log(`${params.textDocument.uri} closed.`);
});
*/
// Listen on the connection
connection.listen();

View File

@ -0,0 +1,2 @@
// We need this until the LSP node libraries are on TS 2.x as well.
interface Thenable<T> extends PromiseLike<T> {}

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./out",
"sourceMap": true,
"lib": [
"es5", "es2015.promise"
]
}
}

View File

@ -2,9 +2,10 @@
"name": "vsc-extension-samples",
"publisher": "Microsoft",
"scripts": {
"install-all": "npm --prefix decorator-sample i decorator-sample && npm --prefix previewhtml-sample i previewhtml-sample && npm --prefix contentprovider-sample i contentprovider-sample && npm --prefix vim-sample i vim-sample",
"postinstall": "node build/postinstall.js",
"compile-decorator": "cd decorator-sample && npm run compile",
"compile-previewhtml": "cd previewhtml-sample && npm run compile",
"compile-contentprovider": "cd contentprovider-sample && npm run compile"
"compile-contentprovider": "cd contentprovider-sample && npm run compile",
"compile-languageprovider": "cd languageprovider-sample && npm run compile && cd .."
}
}