extHostApiCommands.ts 19.7 KB
Newer Older
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  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 URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
8 9
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable } from 'vs/base/common/lifecycle';
10
import * as vscode from 'vscode';
J
Johannes Rieken 已提交
11 12
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import * as types from 'vs/workbench/api/node/extHostTypes';
J
Johannes Rieken 已提交
13
import { ISingleEditOperation } from 'vs/editor/common/editorCommon';
14
import * as modes from 'vs/editor/common/modes';
J
Johannes Rieken 已提交
15 16 17
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { IOutline } from 'vs/editor/contrib/quickOpen/common/quickOpen';
18
import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
J
Johannes Rieken 已提交
19
import { ICodeLensData } from 'vs/editor/contrib/codelens/common/codelens';
J
Johannes Rieken 已提交
20

21
export class ExtHostApiCommands {
J
Johannes Rieken 已提交
22

23 24 25
	static register(commands: ExtHostCommands) {
		return new ExtHostApiCommands(commands).registerCommands();
	}
26

27
	private _commands: ExtHostCommands;
28 29
	private _disposables: IDisposable[] = [];

30
	private constructor(commands: ExtHostCommands) {
31
		this._commands = commands;
J
Johannes Rieken 已提交
32
	}
33

J
Johannes Rieken 已提交
34
	registerCommands() {
35 36
		this._register('vscode.executeWorkspaceSymbolProvider', this._executeWorkspaceSymbolProvider, {
			description: 'Execute all workspace symbol provider.',
J
Johannes Rieken 已提交
37
			args: [{ name: 'query', description: 'Search string', constraint: String }],
J
Johannes Rieken 已提交
38 39
			returns: 'A promise that resolves to an array of SymbolInformation-instances.'

40 41 42
		});
		this._register('vscode.executeDefinitionProvider', this._executeDefinitionProvider, {
			description: 'Execute all definition provider.',
J
Johannes Rieken 已提交
43 44 45 46 47
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position of a symbol', constraint: types.Position }
			],
			returns: 'A promise that resolves to an array of Location-instances.'
48
		});
M
Matt Bierner 已提交
49
		this._register('vscode.executeImplementationProvider', this._executeImplementationProvider, {
50 51 52 53 54 55 56
			description: 'Execute all implementation providers.',
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position of a symbol', constraint: types.Position }
			],
			returns: 'A promise that resolves to an array of Location-instance.'
		});
57
		this._register('vscode.executeHoverProvider', this._executeHoverProvider, {
J
Johannes Rieken 已提交
58
			description: 'Execute all hover provider.',
J
Johannes Rieken 已提交
59 60 61 62 63
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position of a symbol', constraint: types.Position }
			],
			returns: 'A promise that resolves to an array of Hover-instances.'
64 65 66
		});
		this._register('vscode.executeDocumentHighlights', this._executeDocumentHighlights, {
			description: 'Execute document highlight provider.',
J
Johannes Rieken 已提交
67 68 69 70 71
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position in a text document', constraint: types.Position }
			],
			returns: 'A promise that resolves to an array of DocumentHighlight-instances.'
72
		});
73 74
		this._register('vscode.executeReferenceProvider', this._executeReferenceProvider, {
			description: 'Execute reference provider.',
J
Johannes Rieken 已提交
75 76 77 78 79
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position in a text document', constraint: types.Position }
			],
			returns: 'A promise that resolves to an array of Location-instances.'
80 81 82
		});
		this._register('vscode.executeDocumentRenameProvider', this._executeDocumentRenameProvider, {
			description: 'Execute rename provider.',
J
Johannes Rieken 已提交
83 84 85 86 87 88
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position in a text document', constraint: types.Position },
				{ name: 'newName', description: 'The new symbol name', constraint: String }
			],
			returns: 'A promise that resolves to a WorkspaceEdit.'
89 90 91
		});
		this._register('vscode.executeSignatureHelpProvider', this._executeSignatureHelpProvider, {
			description: 'Execute signature help provider.',
J
Johannes Rieken 已提交
92 93
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
94
				{ name: 'position', description: 'Position in a text document', constraint: types.Position },
95
				{ name: 'triggerCharacter', description: '(optional) Trigger signature help when the user types the character, like `,` or `(`', constraint: value => value === void 0 || typeof value === 'string' }
J
Johannes Rieken 已提交
96 97
			],
			returns: 'A promise that resolves to SignatureHelp.'
98 99 100
		});
		this._register('vscode.executeDocumentSymbolProvider', this._executeDocumentSymbolProvider, {
			description: 'Execute document symbol provider.',
J
Johannes Rieken 已提交
101 102 103 104
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI }
			],
			returns: 'A promise that resolves to an array of SymbolInformation-instances.'
105 106 107
		});
		this._register('vscode.executeCompletionItemProvider', this._executeCompletionItemProvider, {
			description: 'Execute completion item provider.',
J
Johannes Rieken 已提交
108 109
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
110
				{ name: 'position', description: 'Position in a text document', constraint: types.Position },
111
				{ name: 'triggerCharacter', description: '(optional) Trigger completion when the user types the character, like `,` or `(`', constraint: value => value === void 0 || typeof value === 'string' }
J
Johannes Rieken 已提交
112
			],
113
			returns: 'A promise that resolves to a CompletionList-instance.'
114 115 116
		});
		this._register('vscode.executeCodeActionProvider', this._executeCodeActionProvider, {
			description: 'Execute code action provider.',
J
Johannes Rieken 已提交
117 118 119 120
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'range', description: 'Range in a text document', constraint: types.Range }
			],
X
xzper 已提交
121
			returns: 'A promise that resolves to an array of Command-instances.'
122 123
		});
		this._register('vscode.executeCodeLensProvider', this._executeCodeLensProvider, {
124
			description: 'Execute CodeLens provider.',
J
Johannes Rieken 已提交
125 126 127
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI }
			],
X
xzper 已提交
128
			returns: 'A promise that resolves to an array of CodeLens-instances.'
129 130 131
		});
		this._register('vscode.executeFormatDocumentProvider', this._executeFormatDocumentProvider, {
			description: 'Execute document format provider.',
J
Johannes Rieken 已提交
132 133 134 135 136
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'options', description: 'Formatting options' }
			],
			returns: 'A promise that resolves to an array of TextEdits.'
137 138 139
		});
		this._register('vscode.executeFormatRangeProvider', this._executeFormatRangeProvider, {
			description: 'Execute range format provider.',
J
Johannes Rieken 已提交
140 141 142 143 144 145
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'range', description: 'Range in a text document', constraint: types.Range },
				{ name: 'options', description: 'Formatting options' }
			],
			returns: 'A promise that resolves to an array of TextEdits.'
146 147 148
		});
		this._register('vscode.executeFormatOnTypeProvider', this._executeFormatOnTypeProvider, {
			description: 'Execute document format provider.',
J
Johannes Rieken 已提交
149 150 151 152 153 154 155
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI },
				{ name: 'position', description: 'Position in a text document', constraint: types.Position },
				{ name: 'ch', description: 'Character that got typed', constraint: String },
				{ name: 'options', description: 'Formatting options' }
			],
			returns: 'A promise that resolves to an array of TextEdits.'
156
		});
157 158 159 160 161 162 163
		this._register('vscode.executeLinkProvider', this._executeDocumentLinkProvider, {
			description: 'Execute document link provider.',
			args: [
				{ name: 'uri', description: 'Uri of a text document', constraint: URI }
			],
			returns: 'A promise that resolves to an array of DocumentLink-instances.'
		});
164

165
		this._register('vscode.previewHtml', (uri: URI, position?: vscode.ViewColumn, label?: string) => {
166 167 168
			return this._commands.executeCommand('_workbench.previewHtml',
				uri,
				typeof position === 'number' && typeConverters.fromViewColumn(position),
169
				label);
170
		}, {
171 172 173
				description: `
					Render the html of the resource in an editor view.

174
					See [working with the html preview](https://code.visualstudio.com/docs/extensionAPI/vscode-api-commands#working-with-the-html-preview) for more information about the html preview's intergration with the editor and for best practices for extension authors.
175
				`,
J
Johannes Rieken 已提交
176 177 178 179 180 181
				args: [
					{ name: 'uri', description: 'Uri of the resource to preview.', constraint: value => value instanceof URI || typeof value === 'string' },
					{ name: 'column', description: '(optional) Column in which to preview.', constraint: value => typeof value === 'undefined' || (typeof value === 'number' && typeof types.ViewColumn[value] === 'string') },
					{ name: 'label', description: '(optional) An human readable string that is used as title for the preview.', constraint: v => typeof v === 'string' || typeof v === 'undefined' }
				]
			});
182

J
Joao Moreno 已提交
183
		this._register('vscode.openFolder', (uri?: URI, forceNewWindow?: boolean) => {
184
			if (!uri) {
J
Joao Moreno 已提交
185
				return this._commands.executeCommand('_files.openFolderPicker', forceNewWindow);
186 187
			}

188
			return this._commands.executeCommand('_files.windowOpen', [uri.fsPath], forceNewWindow);
189
		}, {
J
Johannes Rieken 已提交
190 191 192
				description: 'Open a folder in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder unless the newWindow parameter is set to true.',
				args: [
					{ name: 'uri', description: '(optional) Uri of the folder to open. If not provided, a native dialog will ask the user for the folder', constraint: value => value === void 0 || value instanceof URI },
193
					{ name: 'newWindow', description: '(optional) Whether to open the folder in a new window or the same. Defaults to opening in the same window.', constraint: value => value === void 0 || typeof value === 'boolean' }
J
Johannes Rieken 已提交
194 195
				]
			});
I
isidor 已提交
196

197 198
		this._register('vscode.startDebug', (configuration?: any) => {
			return this._commands.executeCommand('_workbench.startDebug', configuration);
I
isidor 已提交
199
		}, {
J
Johannes Rieken 已提交
200 201 202 203 204
				description: 'Start a debugging session.',
				args: [
					{ name: 'configuration', description: '(optional) Name of the debug configuration from \'launch.json\' to use. Or a configuration json object to use.' }
				]
			});
205

206 207
		this._register('vscode.diff', (left: URI, right: URI, label: string, options?: { preserveFocus?: boolean, pinned?: boolean }) => {
			return this._commands.executeCommand('_workbench.diff', [left, right, label, undefined, options]);
208
		}, {
J
Johannes Rieken 已提交
209 210 211 212
				description: 'Opens the provided resources in the diff editor to compare their contents.',
				args: [
					{ name: 'left', description: 'Left-hand side resource of the diff editor', constraint: URI },
					{ name: 'right', description: 'Right-hand side resource of the diff editor', constraint: URI },
213 214
					{ name: 'title', description: '(optional) Human readable title for the diff editor', constraint: v => v === void 0 || typeof v === 'string' },
					{ name: 'options', description: '(optional) Editor options' }
J
Johannes Rieken 已提交
215 216
				]
			});
217 218 219 220

		this._register('vscode.open', (resource: URI, column: vscode.ViewColumn) => {
			return this._commands.executeCommand('_workbench.open', [resource, typeConverters.fromViewColumn(column)]);
		}, {
J
Johannes Rieken 已提交
221
				description: 'Opens the provided resource in the editor. Can be a text or binary file, or a http(s) url',
222 223 224 225 226
				args: [
					{ name: 'resource', description: 'Resource to open', constraint: URI },
					{ name: 'column', description: '(optional) Column in which to open', constraint: v => v === void 0 || typeof v === 'number' }
				]
			});
227 228 229 230
	}

	// --- command impl

231 232 233
	private _register(id: string, handler: (...args: any[]) => any, description?: ICommandHandlerDescription): void {
		let disposable = this._commands.registerCommand(id, handler, this, description);
		this._disposables.push(disposable);
J
Johannes Rieken 已提交
234 235
	}

236 237 238 239 240 241
	/**
	 * Execute workspace symbol provider.
	 *
	 * @param query Search string to match query symbol names
	 * @return A promise that resolves to an array of symbol information.
	 */
242
	private _executeWorkspaceSymbolProvider(query: string): Thenable<types.SymbolInformation[]> {
243
		return this._commands.executeCommand<[IWorkspaceSymbolProvider, modes.SymbolInformation[]][]>('_executeWorkspaceSymbolProvider', { query }).then(value => {
244
			const result: types.SymbolInformation[] = [];
245
			if (Array.isArray(value)) {
J
Johannes Rieken 已提交
246
				for (let tuple of value) {
247 248
					result.push(...tuple[1].map(typeConverters.toSymbolInformation));
				}
249
			}
250
			return result;
251 252 253 254 255 256 257 258
		});
	}

	private _executeDefinitionProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position)
		};
259
		return this._commands.executeCommand<modes.Location[]>('_executeDefinitionProvider', args).then(value => {
260
			if (Array.isArray(value)) {
261
				return value.map(typeConverters.location.to);
262
			}
M
Matt Bierner 已提交
263
			return undefined;
264 265 266
		});
	}

M
Matt Bierner 已提交
267
	private _executeImplementationProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
268 269 270 271
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position)
		};
M
Matt Bierner 已提交
272
		return this._commands.executeCommand<modes.Location[]>('_executeImplementationProvider', args).then(value => {
273 274 275
			if (Array.isArray(value)) {
				return value.map(typeConverters.location.to);
			}
M
Matt Bierner 已提交
276
			return undefined;
277 278 279
		});
	}

280 281 282 283 284
	private _executeHoverProvider(resource: URI, position: types.Position): Thenable<types.Hover[]> {
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position)
		};
285
		return this._commands.executeCommand<modes.Hover[]>('_executeHoverProvider', args).then(value => {
286
			if (Array.isArray(value)) {
B
Benjamin Pasero 已提交
287
				return value.map(typeConverters.toHover);
288
			}
M
Matt Bierner 已提交
289
			return undefined;
290 291
		});
	}
292 293 294 295 296 297

	private _executeDocumentHighlights(resource: URI, position: types.Position): Thenable<types.DocumentHighlight[]> {
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position)
		};
298
		return this._commands.executeCommand<modes.DocumentHighlight[]>('_executeDocumentHighlights', args).then(value => {
299
			if (Array.isArray(value)) {
B
Benjamin Pasero 已提交
300
				return value.map(typeConverters.toDocumentHighlight);
301
			}
M
Matt Bierner 已提交
302
			return undefined;
303 304
		});
	}
J
Johannes Rieken 已提交
305 306 307 308 309 310

	private _executeReferenceProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position)
		};
311
		return this._commands.executeCommand<modes.Location[]>('_executeReferenceProvider', args).then(value => {
J
Johannes Rieken 已提交
312
			if (Array.isArray(value)) {
313
				return value.map(typeConverters.location.to);
J
Johannes Rieken 已提交
314
			}
M
Matt Bierner 已提交
315
			return undefined;
J
Johannes Rieken 已提交
316 317
		});
	}
318 319 320 321 322 323 324

	private _executeDocumentRenameProvider(resource: URI, position: types.Position, newName: string): Thenable<types.WorkspaceEdit> {
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position),
			newName
		};
325
		return this._commands.executeCommand<modes.WorkspaceEdit>('_executeDocumentRenameProvider', args).then(value => {
326
			if (!value) {
M
Matt Bierner 已提交
327
				return undefined;
328 329
			}
			if (value.rejectReason) {
330
				return TPromise.wrapError<types.WorkspaceEdit>(value.rejectReason);
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
			}
			let workspaceEdit = new types.WorkspaceEdit();
			for (let edit of value.edits) {
				workspaceEdit.replace(edit.resource, typeConverters.toRange(edit.range), edit.newText);
			}
			return workspaceEdit;
		});
	}

	private _executeSignatureHelpProvider(resource: URI, position: types.Position, triggerCharacter: string): Thenable<types.SignatureHelp> {
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position),
			triggerCharacter
		};
346
		return this._commands.executeCommand<modes.SignatureHelp>('_executeSignatureHelpProvider', args).then(value => {
347 348 349
			if (value) {
				return typeConverters.SignatureHelp.to(value);
			}
M
Matt Bierner 已提交
350
			return undefined;
351 352
		});
	}
353

354
	private _executeCompletionItemProvider(resource: URI, position: types.Position, triggerCharacter: string): Thenable<types.CompletionList> {
355 356 357 358 359
		const args = {
			resource,
			position: position && typeConverters.fromPosition(position),
			triggerCharacter
		};
360 361 362 363
		return this._commands.executeCommand<modes.ISuggestResult>('_executeCompletionItemProvider', args).then(result => {
			if (result) {
				const items = result.suggestions.map(suggestion => typeConverters.Suggest.to(position, suggestion));
				return new types.CompletionList(items, result.incomplete);
364
			}
M
Matt Bierner 已提交
365
			return undefined;
366 367 368
		});
	}

369 370 371 372 373 374
	private _executeDocumentSymbolProvider(resource: URI): Thenable<types.SymbolInformation[]> {
		const args = {
			resource
		};
		return this._commands.executeCommand<IOutline>('_executeDocumentSymbolProvider', args).then(value => {
			if (value && Array.isArray(value.entries)) {
375
				return value.entries.map(typeConverters.toSymbolInformation);
376
			}
M
Matt Bierner 已提交
377
			return undefined;
378 379
		});
	}
380 381 382 383 384 385

	private _executeCodeActionProvider(resource: URI, range: types.Range): Thenable<vscode.Command[]> {
		const args = {
			resource,
			range: typeConverters.fromRange(range)
		};
386
		return this._commands.executeCommand<modes.CodeAction[]>('_executeCodeActionProvider', args).then(value => {
387
			if (!Array.isArray(value)) {
M
Matt Bierner 已提交
388
				return undefined;
389
			}
390
			return value.map(quickFix => this._commands.converter.fromInternal(quickFix.command));
391 392
		});
	}
J
Johannes Rieken 已提交
393

J
Johannes Rieken 已提交
394
	private _executeCodeLensProvider(resource: URI): Thenable<vscode.CodeLens[]> {
395
		const args = { resource };
J
Johannes Rieken 已提交
396
		return this._commands.executeCommand<ICodeLensData[]>('_executeCodeLensProvider', args).then(value => {
J
Johannes Rieken 已提交
397
			if (Array.isArray(value)) {
J
Johannes Rieken 已提交
398
				return value.map(item => {
399 400
					return new types.CodeLens(
						typeConverters.toRange(item.symbol.range),
401
						this._commands.converter.fromInternal(item.symbol.command));
J
Johannes Rieken 已提交
402
				});
J
Johannes Rieken 已提交
403
			}
M
Matt Bierner 已提交
404
			return undefined;
J
Johannes Rieken 已提交
405 406
		});
	}
407 408 409 410 411 412 413 414 415 416

	private _executeFormatDocumentProvider(resource: URI, options: vscode.FormattingOptions): Thenable<vscode.TextEdit[]> {
		const args = {
			resource,
			options
		};
		return this._commands.executeCommand<ISingleEditOperation[]>('_executeFormatDocumentProvider', args).then(value => {
			if (Array.isArray(value)) {
				return value.map(edit => new types.TextEdit(typeConverters.toRange(edit.range), edit.text));
			}
M
Matt Bierner 已提交
417
			return undefined;
418 419 420 421 422 423 424 425 426 427 428 429 430
		});
	}

	private _executeFormatRangeProvider(resource: URI, range: types.Range, options: vscode.FormattingOptions): Thenable<vscode.TextEdit[]> {
		const args = {
			resource,
			range: typeConverters.fromRange(range),
			options
		};
		return this._commands.executeCommand<ISingleEditOperation[]>('_executeFormatRangeProvider', args).then(value => {
			if (Array.isArray(value)) {
				return value.map(edit => new types.TextEdit(typeConverters.toRange(edit.range), edit.text));
			}
M
Matt Bierner 已提交
431
			return undefined;
432 433
		});
	}
434

J
Johannes Rieken 已提交
435
	private _executeFormatOnTypeProvider(resource: URI, position: types.Position, ch: string, options: vscode.FormattingOptions): Thenable<vscode.TextEdit[]> {
436 437 438 439 440 441 442 443 444 445
		const args = {
			resource,
			position: typeConverters.fromPosition(position),
			ch,
			options
		};
		return this._commands.executeCommand<ISingleEditOperation[]>('_executeFormatOnTypeProvider', args).then(value => {
			if (Array.isArray(value)) {
				return value.map(edit => new types.TextEdit(typeConverters.toRange(edit.range), edit.text));
			}
M
Matt Bierner 已提交
446
			return undefined;
447 448
		});
	}
449 450 451 452 453 454

	private _executeDocumentLinkProvider(resource: URI): Thenable<vscode.DocumentLink[]> {
		return this._commands.executeCommand<modes.ILink[]>('_executeLinkProvider', resource).then(value => {
			if (Array.isArray(value)) {
				return value.map(typeConverters.DocumentLink.to);
			}
M
Matt Bierner 已提交
455
			return undefined;
456 457
		});
	}
458
}