diff --git a/client/package.json b/client/package.json index 27d4518b0..9680437c6 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,7 @@ { "name": "vscode-languageclient", "description": "VSCode Language client implementation", - "version": "3.2.0-alpha.2", + "version": "3.2.0-alpha.3", "author": "Microsoft Corporation", "license": "MIT", "engines": { diff --git a/client/src/main.ts b/client/src/main.ts index 99127483b..7f7634efa 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -884,9 +884,7 @@ export class LanguageClient { clientOptions = clientOptions || {}; this._clientOptions = { - documentSelector: is.typedArray(clientOptions.documentSelector, is.string) - ? clientOptions.documentSelector.map(element => { return { language: element }; }) - : clientOptions.documentSelector, + documentSelector: clientOptions.documentSelector || [], synchronize: clientOptions.synchronize || {}, diagnosticCollectionName: clientOptions.diagnosticCollectionName, outputChannelName: clientOptions.outputChannelName || this._name, @@ -1440,6 +1438,7 @@ export class LanguageClient { } if (json.module) { let node: NodeModule = json; + let transport = node.transport || TransportKind.stdio; if (node.runtime) { let args: string[] = []; let options: ForkOptions = node.options || Object.create(null); @@ -1454,30 +1453,30 @@ export class LanguageClient { execOptions.cwd = options.cwd || Workspace.rootPath; execOptions.env = getEnvironment(options.env); let pipeName: string | undefined = undefined; - if (node.transport === TransportKind.ipc) { + if (transport === TransportKind.ipc) { // exec options not correctly typed in lib execOptions.stdio = [null, null, null, 'ipc']; args.push('--node-ipc'); - } else if (node.transport === TransportKind.stdio) { + } else if (transport === TransportKind.stdio) { args.push('--stdio'); - } else if (node.transport === TransportKind.pipe) { + } else if (transport === TransportKind.pipe) { pipeName = generateRandomPipeName(); args.push(`--pipe=${pipeName}`); } - if (node.transport === TransportKind.ipc || node.transport === TransportKind.stdio) { + if (transport === TransportKind.ipc || transport === TransportKind.stdio) { let process = cp.spawn(node.runtime, args, execOptions); if (!process || !process.pid) { return Promise.reject(`Launching server using runtime ${node.runtime} failed.`); } this._childProcess = process; process.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding))); - if (node.transport === TransportKind.ipc) { + if (transport === TransportKind.ipc) { process.stdout.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding))); return Promise.resolve(createConnection(new IPCMessageReader(process), new IPCMessageWriter(process), errorHandler, closeHandler)); } else { return Promise.resolve(createConnection(process.stdout, process.stdin, errorHandler, closeHandler)); } - } else if (node.transport == TransportKind.pipe) { + } else if (transport == TransportKind.pipe) { return createClientPipeTransport(pipeName!).then((transport) => { let process = cp.spawn(node.runtime!, args, execOptions); if (!process || !process.pid) { @@ -1495,25 +1494,25 @@ export class LanguageClient { let pipeName: string | undefined = undefined; return new Promise((resolve, reject) => { let args = node.args && node.args.slice() || []; - if (node.transport === TransportKind.ipc) { + if (transport === TransportKind.ipc) { args.push('--node-ipc'); - } else if (node.transport === TransportKind.stdio) { + } else if (transport === TransportKind.stdio) { args.push('--stdio'); - } else if (node.transport === TransportKind.pipe) { + } else if (transport === TransportKind.pipe) { pipeName = generateRandomPipeName(); args.push(`--pipe=${pipeName}`); } let options: ForkOptions = node.options || Object.create(null); options.execArgv = options.execArgv || []; options.cwd = options.cwd || Workspace.rootPath; - if (node.transport === TransportKind.ipc || node.transport === TransportKind.stdio) { + if (transport === TransportKind.ipc || transport === TransportKind.stdio) { electron.fork(node.module, args || [], options, (error, cp) => { if (error || !cp) { reject(error); } else { this._childProcess = cp; cp.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding))); - if (node.transport === TransportKind.ipc) { + if (transport === TransportKind.ipc) { cp.stdout.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding))); resolve(createConnection(new IPCMessageReader(this._childProcess), new IPCMessageWriter(this._childProcess), errorHandler, closeHandler)); } else { @@ -1521,7 +1520,7 @@ export class LanguageClient { } } }); - } else if (node.transport === TransportKind.pipe) { + } else if (transport === TransportKind.pipe) { createClientPipeTransport(pipeName!).then((transport) => { electron.fork(node.module, args || [], options, (error, cp) => { if (error || !cp) { diff --git a/client/src/protocol.ts b/client/src/protocol.ts index 649f9d14a..c62b095c7 100644 --- a/client/src/protocol.ts +++ b/client/src/protocol.ts @@ -4,6 +4,8 @@ * ------------------------------------------------------------------------------------------ */ 'use strict'; +import * as Is from './utils/is'; + import { RequestType, RequestType0, NotificationType, NotificationType0 } from 'vscode-jsonrpc'; import { @@ -23,21 +25,34 @@ import { * @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` * @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` */ -export interface DocumentFilter { - /** - * A language id, like `typescript`. - */ - language?: string; - - /** - * A Uri [scheme](#Uri.scheme), like `file` or `untitled`. - */ +export type DocumentFilter = { + /** A language id, like `typescript`. */ + language: string; + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ scheme?: string; - - /** - * A glob pattern, like `*.{ts,js}`. - */ + /** A glob pattern, like `*.{ts,js}`. */ + pattern?: string; +} | { + /** A language id, like `typescript`. */ + language?: string; + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme: string; + /** A glob pattern, like `*.{ts,js}`. */ pattern?: string; +} | { + /** A language id, like `typescript`. */ + language?: string; + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme?: string; + /** A glob pattern, like `*.{ts,js}`. */ + pattern: string; +}; + +export namespace DocumentFilter { + export function is(value: any): value is DocumentFilter { + let candidate: DocumentFilter = value; + return Is.string(candidate.language) || Is.string(candidate.scheme) || Is.string(candidate.pattern); + } } /** @@ -45,7 +60,7 @@ export interface DocumentFilter { * * @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; */ -export type DocumentSelector = DocumentFilter[]; +export type DocumentSelector = (string | DocumentFilter)[]; /** * General paramters to to regsiter for an notification or to register a provider. diff --git a/server/package.json b/server/package.json index 879a31884..fb373084a 100644 --- a/server/package.json +++ b/server/package.json @@ -1,7 +1,7 @@ { "name": "vscode-languageserver", "description": "Language server implementation for node", - "version": "3.2.0-alpha.1", + "version": "3.2.0-alpha.4", "author": "Microsoft Corporation", "license": "MIT", "repository": { diff --git a/server/src/protocol.ts b/server/src/protocol.ts index 649f9d14a..c62b095c7 100644 --- a/server/src/protocol.ts +++ b/server/src/protocol.ts @@ -4,6 +4,8 @@ * ------------------------------------------------------------------------------------------ */ 'use strict'; +import * as Is from './utils/is'; + import { RequestType, RequestType0, NotificationType, NotificationType0 } from 'vscode-jsonrpc'; import { @@ -23,21 +25,34 @@ import { * @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` * @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` */ -export interface DocumentFilter { - /** - * A language id, like `typescript`. - */ - language?: string; - - /** - * A Uri [scheme](#Uri.scheme), like `file` or `untitled`. - */ +export type DocumentFilter = { + /** A language id, like `typescript`. */ + language: string; + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ scheme?: string; - - /** - * A glob pattern, like `*.{ts,js}`. - */ + /** A glob pattern, like `*.{ts,js}`. */ + pattern?: string; +} | { + /** A language id, like `typescript`. */ + language?: string; + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme: string; + /** A glob pattern, like `*.{ts,js}`. */ pattern?: string; +} | { + /** A language id, like `typescript`. */ + language?: string; + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme?: string; + /** A glob pattern, like `*.{ts,js}`. */ + pattern: string; +}; + +export namespace DocumentFilter { + export function is(value: any): value is DocumentFilter { + let candidate: DocumentFilter = value; + return Is.string(candidate.language) || Is.string(candidate.scheme) || Is.string(candidate.pattern); + } } /** @@ -45,7 +60,7 @@ export interface DocumentFilter { * * @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; */ -export type DocumentSelector = DocumentFilter[]; +export type DocumentSelector = (string | DocumentFilter)[]; /** * General paramters to to regsiter for an notification or to register a provider.