extHostLanguageFeatures.ts 31.3 KB
Newer Older
J
Johannes Rieken 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  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';
import {TPromise} from 'vs/base/common/winjs.base';
J
Joao Moreno 已提交
9
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
10
import {IThreadService} from 'vs/workbench/services/thread/common/threadService';
J
Johannes Rieken 已提交
11
import * as vscode from 'vscode';
J
Johannes Rieken 已提交
12
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
13
import {Range, Disposable, SignatureHelp, CompletionList} from 'vs/workbench/api/node/extHostTypes';
14
import {IPosition, IRange, ISingleEditOperation} from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
15
import * as modes from 'vs/editor/common/modes';
16
import {ExtHostDocuments} from 'vs/workbench/api/node/extHostDocuments';
J
Johannes Rieken 已提交
17
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
18
import {ExtHostDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
19
import {IWorkspaceSymbolProvider, IWorkspaceSymbol} from 'vs/workbench/parts/search/common/search';
20
import {asWinJsPromise, ShallowCancelThenPromise} from 'vs/base/common/async';
A
Alex Dima 已提交
21
import {MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape} from './extHost.protocol';
22
import {regExpLeadsToEndlessLoop} from 'vs/base/common/strings';
J
Johannes Rieken 已提交
23 24 25

// --- adapter

26
class OutlineAdapter {
J
Johannes Rieken 已提交
27

28
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
29 30
	private _provider: vscode.DocumentSymbolProvider;

31
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentSymbolProvider) {
J
Johannes Rieken 已提交
32 33 34 35
		this._documents = documents;
		this._provider = provider;
	}

36
	provideDocumentSymbols(resource: URI): TPromise<modes.SymbolInformation[]> {
37
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
38 39
		return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
			if (Array.isArray(value)) {
40
				return value.map(TypeConverters.SymbolInformation.toOutlineEntry);
J
Johannes Rieken 已提交
41 42 43 44 45
			}
		});
	}
}

46 47 48 49
interface CachedCodeLens {
	symbols: modes.ICodeLensSymbol[];
	lenses: vscode.CodeLens[];
	disposables: IDisposable[];
J
Johannes Rieken 已提交
50
}
51

52
class CodeLensAdapter {
53

54
	private _documents: ExtHostDocuments;
55
	private _commands: ExtHostCommands;
56 57
	private _provider: vscode.CodeLensProvider;

58
	private _cache: { [uri: string]: { version: number; data: TPromise<CachedCodeLens>; } } = Object.create(null);
59

60
	constructor(documents: ExtHostDocuments, commands: ExtHostCommands, provider: vscode.CodeLensProvider) {
61
		this._documents = documents;
62
		this._commands = commands;
63 64 65
		this._provider = provider;
	}

66
	provideCodeLenses(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
67
		const doc = this._documents.getDocumentData(resource).document;
68 69
		const version = doc.version;
		const key = resource.toString();
70

71
		// from cache
72
		let entry = this._cache[key];
73
		if (entry && entry.version === version) {
74
			return new ShallowCancelThenPromise(entry.data.then(cached => cached.symbols));
75
		}
76

77 78
		const newCodeLensData = asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(lenses => {
			if (!Array.isArray(lenses)) {
79 80 81
				return;
			}

82 83 84 85
			const data: CachedCodeLens = {
				lenses,
				symbols: [],
				disposables: [],
J
Johannes Rieken 已提交
86
			};
87

88 89
			lenses.forEach((lens, i) => {
				data.symbols.push(<modes.ICodeLensSymbol>{
90
					id: String(i),
J
Johannes Rieken 已提交
91
					range: TypeConverters.fromRange(lens.range),
92
					command: TypeConverters.Command.from(lens.command, data.disposables)
93
				});
94
			});
95 96 97 98 99 100 101 102 103

			return data;
		});

		this._cache[key] = {
			version,
			data: newCodeLensData
		};

104
		return new ShallowCancelThenPromise(newCodeLensData.then(newCached => {
105 106
			if (entry) {
				// only now dispose old commands et al
J
Joao Moreno 已提交
107
				entry.data.then(oldCached => dispose(oldCached.disposables));
108 109
			}
			return newCached && newCached.symbols;
110
		}));
111

112 113
	}

114
	resolveCodeLens(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
115

116 117
		const entry = this._cache[resource.toString()];
		if (!entry) {
118 119 120
			return;
		}

121
		return entry.data.then(cachedData => {
122

123 124 125
			if (!cachedData) {
				return;
			}
126

127 128 129 130 131 132 133 134 135 136
			let lens = cachedData.lenses[Number(symbol.id)];
			if (!lens) {
				return;
			}

			let resolve: TPromise<vscode.CodeLens>;
			if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
				resolve = TPromise.as(lens);
			} else {
				resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
137
			}
J
Johannes Rieken 已提交
138

139 140 141 142 143 144 145 146 147 148
			return resolve.then(newLens => {
				lens = newLens || lens;
				let command = lens.command;
				if (!command) {
					command = {
						title: '<<MISSING COMMAND>>',
						command: 'missing',
					};
				}

149
				symbol.command = TypeConverters.Command.from(command, cachedData.disposables);
150 151
				return symbol;
			});
152 153 154 155
		});
	}
}

156
class DefinitionAdapter {
J
Johannes Rieken 已提交
157

158
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
159 160
	private _provider: vscode.DefinitionProvider;

161
	constructor(documents: ExtHostDocuments, provider: vscode.DefinitionProvider) {
J
Johannes Rieken 已提交
162 163 164 165
		this._documents = documents;
		this._provider = provider;
	}

166
	provideDefinition(resource: URI, position: IPosition): TPromise<modes.Definition> {
167
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
168 169 170
		let pos = TypeConverters.toPosition(position);
		return asWinJsPromise(token => this._provider.provideDefinition(doc, pos, token)).then(value => {
			if (Array.isArray(value)) {
171
				return value.map(DefinitionAdapter._convertLocation);
J
Johannes Rieken 已提交
172
			} else if (value) {
173
				return DefinitionAdapter._convertLocation(value);
J
Johannes Rieken 已提交
174 175 176 177
			}
		});
	}

178
	private static _convertLocation(location: vscode.Location): modes.Location {
J
Johannes Rieken 已提交
179 180 181
		if (!location) {
			return;
		}
182 183
		return <modes.Location>{
			uri: location.uri,
J
Johannes Rieken 已提交
184 185 186 187 188
			range: TypeConverters.fromRange(location.range)
		};
	}
}

189
class HoverAdapter {
J
Johannes Rieken 已提交
190

191
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
192 193
	private _provider: vscode.HoverProvider;

194
	constructor(documents: ExtHostDocuments, provider: vscode.HoverProvider) {
J
Johannes Rieken 已提交
195 196 197 198
		this._documents = documents;
		this._provider = provider;
	}

199
	public provideHover(resource: URI, position: IPosition): TPromise<modes.Hover> {
J
Johannes Rieken 已提交
200

201
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
202 203 204 205 206 207
		let pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideHover(doc, pos, token)).then(value => {
			if (!value) {
				return;
			}
208 209
			if (!value.range) {
				value.range = doc.getWordRangeAtPosition(pos);
J
Johannes Rieken 已提交
210
			}
211 212
			if (!value.range) {
				value.range = new Range(pos, pos);
J
Johannes Rieken 已提交
213 214
			}

215
			return TypeConverters.fromHover(value);
J
Johannes Rieken 已提交
216 217 218 219
		});
	}
}

220
class DocumentHighlightAdapter {
221

222
	private _documents: ExtHostDocuments;
223 224
	private _provider: vscode.DocumentHighlightProvider;

225
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentHighlightProvider) {
226 227 228 229
		this._documents = documents;
		this._provider = provider;
	}

230
	provideDocumentHighlights(resource: URI, position: IPosition): TPromise<modes.DocumentHighlight[]> {
231

232
		let doc = this._documents.getDocumentData(resource).document;
233 234 235 236
		let pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => {
			if (Array.isArray(value)) {
237
				return value.map(DocumentHighlightAdapter._convertDocumentHighlight);
238 239 240 241
			}
		});
	}

242
	private static _convertDocumentHighlight(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
243 244
		return {
			range: TypeConverters.fromRange(documentHighlight.range),
245
			kind: documentHighlight.kind
B
Benjamin Pasero 已提交
246
		};
247 248 249
	}
}

250
class ReferenceAdapter {
J
Johannes Rieken 已提交
251

252
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
253 254
	private _provider: vscode.ReferenceProvider;

255
	constructor(documents: ExtHostDocuments, provider: vscode.ReferenceProvider) {
J
Johannes Rieken 已提交
256 257 258 259
		this._documents = documents;
		this._provider = provider;
	}

260
	provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> {
261
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
262 263
		let pos = TypeConverters.toPosition(position);

264
		return asWinJsPromise(token => this._provider.provideReferences(doc, pos, context, token)).then(value => {
J
Johannes Rieken 已提交
265 266 267 268 269 270
			if (Array.isArray(value)) {
				return value.map(ReferenceAdapter._convertLocation);
			}
		});
	}

271 272 273
	private static _convertLocation(location: vscode.Location): modes.Location {
		return <modes.Location>{
			uri: location.uri,
J
Johannes Rieken 已提交
274 275 276 277 278
			range: TypeConverters.fromRange(location.range)
		};
	}
}

279
class QuickFixAdapter {
J
Johannes Rieken 已提交
280

281
	private _documents: ExtHostDocuments;
282
	private _commands: ExtHostCommands;
283
	private _diagnostics: ExtHostDiagnostics;
J
Johannes Rieken 已提交
284 285
	private _provider: vscode.CodeActionProvider;

286 287
	private _cachedCommands: IDisposable[] = [];

288
	constructor(documents: ExtHostDocuments, commands: ExtHostCommands, diagnostics: ExtHostDiagnostics, provider: vscode.CodeActionProvider) {
J
Johannes Rieken 已提交
289 290
		this._documents = documents;
		this._commands = commands;
291
		this._diagnostics = diagnostics;
J
Johannes Rieken 已提交
292 293 294
		this._provider = provider;
	}

A
Alex Dima 已提交
295
	provideCodeActions(resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
J
Johannes Rieken 已提交
296

297
		const doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
298
		const ran = TypeConverters.toRange(range);
299 300 301 302 303 304 305 306 307 308
		const allDiagnostics: vscode.Diagnostic[] = [];

		this._diagnostics.forEach(collection => {
			if (collection.has(resource)) {
				for (let diagnostic of collection.get(resource)) {
					if (diagnostic.range.intersection(ran)) {
						allDiagnostics.push(diagnostic);
					}
				}
			}
J
Johannes Rieken 已提交
309 310
		});

J
Joao Moreno 已提交
311
		this._cachedCommands = dispose(this._cachedCommands);
312

313
		return asWinJsPromise(token => this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)).then(commands => {
J
Johannes Rieken 已提交
314 315 316 317
			if (!Array.isArray(commands)) {
				return;
			}
			return commands.map((command, i) => {
A
Alex Dima 已提交
318
				return <modes.CodeAction> {
319
					command: TypeConverters.Command.from(command, this._cachedCommands),
320
					score: i
J
Johannes Rieken 已提交
321 322 323 324 325 326
				};
			});
		});
	}
}

327
class DocumentFormattingAdapter {
328

329
	private _documents: ExtHostDocuments;
330 331
	private _provider: vscode.DocumentFormattingEditProvider;

332
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentFormattingEditProvider) {
333 334 335 336
		this._documents = documents;
		this._provider = provider;
	}

A
Alex Dima 已提交
337
	provideDocumentFormattingEdits(resource: URI, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
338

339 340 341
		const {document, version} = this._documents.getDocumentData(resource);

		return asWinJsPromise(token => this._provider.provideDocumentFormattingEdits(document, <any>options, token)).then(value => {
342
			if (Array.isArray(value)) {
343
				return TypeConverters.TextEdit.minimalEditOperations(value, document, version);
344 345 346 347 348
			}
		});
	}
}

349
class RangeFormattingAdapter {
350

351
	private _documents: ExtHostDocuments;
352 353
	private _provider: vscode.DocumentRangeFormattingEditProvider;

354
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentRangeFormattingEditProvider) {
355 356 357 358
		this._documents = documents;
		this._provider = provider;
	}

A
Alex Dima 已提交
359
	provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
360

361 362
		const {document, version} = this._documents.getDocumentData(resource);
		const ran = TypeConverters.toRange(range);
363

364
		return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(document, ran, <any>options, token)).then(value => {
365
			if (Array.isArray(value)) {
366
				return TypeConverters.TextEdit.minimalEditOperations(value, document, version);
367 368 369 370 371
			}
		});
	}
}

372
class OnTypeFormattingAdapter {
373

374
	private _documents: ExtHostDocuments;
375 376
	private _provider: vscode.OnTypeFormattingEditProvider;

377
	constructor(documents: ExtHostDocuments, provider: vscode.OnTypeFormattingEditProvider) {
378 379 380 381
		this._documents = documents;
		this._provider = provider;
	}

382
	autoFormatTriggerCharacters: string[] = []; // not here
383

A
Alex Dima 已提交
384
	provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
385

386 387
		const {document, version} = this._documents.getDocumentData(resource);
		const pos = TypeConverters.toPosition(position);
388

389
		return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(document, pos, ch, <any> options, token)).then(value => {
390
			if (Array.isArray(value)) {
391
				return TypeConverters.TextEdit.minimalEditOperations(value, document, version);
392 393 394 395 396
			}
		});
	}
}

397 398 399 400
interface MyWorkspaceSymbol extends IWorkspaceSymbol {
	idx: number;
}

401
class NavigateTypeAdapter implements IWorkspaceSymbolProvider {
402 403

	private _provider: vscode.WorkspaceSymbolProvider;
404
	private _cache: vscode.SymbolInformation[];
405 406 407 408 409

	constructor(provider: vscode.WorkspaceSymbolProvider) {
		this._provider = provider;
	}

410
	provideWorkspaceSymbols(search: string): TPromise<IWorkspaceSymbol[]> {
411 412 413

		this._cache = [];

414 415
		return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
			if (Array.isArray(value)) {
416 417 418 419 420 421
				this._cache = value;
				return value.map((item, idx) => {
					const result = <MyWorkspaceSymbol>TypeConverters.fromSymbolInformation(item);
					result.idx = idx;
					return result;
				});
422 423 424
			}
		});
	}
425 426

	resolveWorkspaceSymbol(item: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
427 428 429 430 431 432 433 434 435 436 437 438 439

		if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
			return;
		}

		const idx = (<MyWorkspaceSymbol>item).idx;
		if(typeof idx !== 'number') {
			return;
		}

		return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(this._cache[idx], token)).then(value => {
			return value && TypeConverters.fromSymbolInformation(value);
		});
440
	}
441 442
}

443
class RenameAdapter {
J
Johannes Rieken 已提交
444

445
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
446 447
	private _provider: vscode.RenameProvider;

448
	constructor(documents: ExtHostDocuments, provider: vscode.RenameProvider) {
J
Johannes Rieken 已提交
449 450 451 452
		this._documents = documents;
		this._provider = provider;
	}

453
	provideRenameEdits(resource: URI, position: IPosition, newName: string): TPromise<modes.WorkspaceEdit> {
J
Johannes Rieken 已提交
454

455
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
456 457 458 459 460 461 462 463
		let pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => {

			if (!value) {
				return;
			}

464
			let result = <modes.WorkspaceEdit>{
J
Johannes Rieken 已提交
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
				edits: []
			};

			for (let entry of value.entries()) {
				let [uri, textEdits] = entry;
				for (let textEdit of textEdits) {
					result.edits.push({
						resource: <URI>uri,
						newText: textEdit.newText,
						range: TypeConverters.fromRange(textEdit.range)
					});
				}
			}
			return result;
		}, err => {
			if (typeof err === 'string') {
481
				return <modes.WorkspaceEdit>{
J
Johannes Rieken 已提交
482 483 484 485 486 487 488 489 490
					edits: undefined,
					rejectReason: err
				};
			}
			return TPromise.wrapError(err);
		});
	}
}

491 492 493 494
interface ISuggestion2 extends modes.ISuggestion {
	id: string;
}

495
class SuggestAdapter {
496

497
	private _documents: ExtHostDocuments;
498
	private _provider: vscode.CompletionItemProvider;
499
	private _cache: { [key: string]: CompletionList } = Object.create(null);
500

501
	constructor(documents: ExtHostDocuments, provider: vscode.CompletionItemProvider) {
502 503 504 505
		this._documents = documents;
		this._provider = provider;
	}

506
	provideCompletionItems(resource: URI, position: IPosition): TPromise<modes.ISuggestResult> {
507

508
		const doc = this._documents.getDocumentData(resource).document;
509 510 511 512 513
		const pos = TypeConverters.toPosition(position);

		const key = resource.toString();
		delete this._cache[key];

514
		return asWinJsPromise<vscode.CompletionItem[]|vscode.CompletionList>(token => this._provider.provideCompletionItems(doc, pos, token)).then(value => {
515

516
			const result: modes.ISuggestResult = {
517
				suggestions: [],
518
				currentWord: ''
519
			};
520 521 522 523

			// the default text edit range
			const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
				.with({ end: pos });
524

525 526 527 528 529
			let list: CompletionList;
			if (Array.isArray(value)) {
				list = new CompletionList(value);
			} else if (value instanceof CompletionList) {
				list = value;
530
				result.incomplete = list.isIncomplete;
531 532 533
			} else if (!value) {
				// undefined and null are valid results
				return;
534
			} else {
535 536
				// warn about everything else
				console.warn('INVALID result from completion provider. expected CompletionItem-array or CompletionList but got:', value);
537 538
				return;
			}
539

540
			for (let i = 0; i < list.items.length; i++) {
541

542
				const item = list.items[i];
543
				const suggestion = <ISuggestion2> TypeConverters.Suggest.from(item);
544 545 546

				if (item.textEdit) {

547
					const editRange = item.textEdit.range;
548 549 550 551 552 553 554 555 556

					// invalid text edit
					if (!editRange.isSingleLine || editRange.start.line !== pos.line) {
						console.warn('INVALID text edit, must be single line and on the same line');
						continue;
					}

					// insert the text of the edit and create a dedicated
					// suggestion-container with overwrite[Before|After]
557
					suggestion.insertText = item.textEdit.newText;
B
Benjamin Pasero 已提交
558 559
					suggestion.overwriteBefore = pos.character - editRange.start.character;
					suggestion.overwriteAfter = editRange.end.character - pos.character;
560 561

				} else {
562 563 564
					// default text edit
					suggestion.overwriteBefore = pos.character - wordRangeBeforePos.start.character;
					suggestion.overwriteAfter = 0;
565 566 567 568
				}

				// assign identifier to suggestion
				suggestion.id = String(i);
569 570 571

				// store suggestion
				result.suggestions.push(suggestion);
572 573 574
			}

			// cache for details call
575
			this._cache[key] = list;
576

577
			return result;
578 579 580
		});
	}

581
	resolveCompletionItem(resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
582 583 584
		if (typeof this._provider.resolveCompletionItem !== 'function') {
			return TPromise.as(suggestion);
		}
585 586
		let list = this._cache[resource.toString()];
		if (!list) {
587 588
			return TPromise.as(suggestion);
		}
589
		let item = list.items[Number((<ISuggestion2> suggestion).id)];
590 591 592 593
		if (!item) {
			return TPromise.as(suggestion);
		}
		return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
594
			return TypeConverters.Suggest.from(resolvedItem || item);
595 596 597 598
		});
	}
}

A
Alex Dima 已提交
599
class SignatureHelpAdapter {
600

601
	private _documents: ExtHostDocuments;
602 603
	private _provider: vscode.SignatureHelpProvider;

604
	constructor(documents: ExtHostDocuments, provider: vscode.SignatureHelpProvider) {
605 606 607 608
		this._documents = documents;
		this._provider = provider;
	}

609
	provideSignatureHelp(resource: URI, position: IPosition): TPromise<modes.SignatureHelp> {
610

611
		const doc = this._documents.getDocumentData(resource).document;
612 613 614 615
		const pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideSignatureHelp(doc, pos, token)).then(value => {
			if (value instanceof SignatureHelp) {
616
				return TypeConverters.SignatureHelp.from(value);
617 618 619 620 621
			}
		});
	}
}

J
Johannes Rieken 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
class LinkProviderAdapter {

	private _documents: ExtHostDocuments;
	private _provider: vscode.DocumentLinkProvider;

	constructor(documents: ExtHostDocuments, provider: vscode.DocumentLinkProvider) {
		this._documents = documents;
		this._provider = provider;
	}

	provideLinks(resource: URI): TPromise<modes.ILink[]> {
		const doc = this._documents.getDocumentData(resource).document;

		return asWinJsPromise(token => this._provider.provideDocumentLinks(doc, token)).then(links => {
			if (Array.isArray(links)) {
				return links.map(TypeConverters.DocumentLink.from);
			}
		});
	}
641 642 643 644 645 646 647 648 649 650

	resolveLink(link: modes.ILink): TPromise<modes.ILink> {
		if (typeof this._provider.resolveDocumentLink === 'function') {
			return asWinJsPromise(token => this._provider.resolveDocumentLink(TypeConverters.DocumentLink.to(link), token)).then(value => {
				if (value) {
					return TypeConverters.DocumentLink.from(value);
				}
			});
		}
	}
J
Johannes Rieken 已提交
651 652
}

653
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
654
	| DocumentHighlightAdapter | ReferenceAdapter | QuickFixAdapter | DocumentFormattingAdapter
655
	| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
J
Johannes Rieken 已提交
656
	| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter;
J
Johannes Rieken 已提交
657

A
Alex Dima 已提交
658
export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
J
Johannes Rieken 已提交
659

660
	private static _handlePool: number = 0;
J
Johannes Rieken 已提交
661

662
	private _proxy: MainThreadLanguageFeaturesShape;
663
	private _documents: ExtHostDocuments;
664
	private _commands: ExtHostCommands;
665
	private _diagnostics: ExtHostDiagnostics;
J
Johannes Rieken 已提交
666 667
	private _adapter: { [handle: number]: Adapter } = Object.create(null);

668 669
	constructor(
		threadService: IThreadService,
670
		documents: ExtHostDocuments,
671 672 673
		commands: ExtHostCommands,
		diagnostics: ExtHostDiagnostics
	) {
A
Alex Dima 已提交
674
		super();
675 676 677 678
		this._proxy = threadService.get(MainContext.MainThreadLanguageFeatures);
		this._documents = documents;
		this._commands = commands;
		this._diagnostics = diagnostics;
J
Johannes Rieken 已提交
679 680 681 682 683 684 685 686 687
	}

	private _createDisposable(handle: number): Disposable {
		return new Disposable(() => {
			delete this._adapter[handle];
			this._proxy.$unregister(handle);
		});
	}

688 689 690 691
	private _nextHandle(): number {
		return ExtHostLanguageFeatures._handlePool++;
	}

J
Johannes Rieken 已提交
692 693 694 695 696 697
	private _withAdapter<A, R>(handle: number, ctor: { new (...args: any[]): A }, callback: (adapter: A) => TPromise<R>): TPromise<R> {
		let adapter = this._adapter[handle];
		if (!(adapter instanceof ctor)) {
			return TPromise.wrapError(new Error('no adapter found'));
		}
		return callback(<any> adapter);
698 699
	}

J
Johannes Rieken 已提交
700 701 702
	// --- outline

	registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
703 704
		const handle = this._nextHandle();
		this._adapter[handle] = new OutlineAdapter(this._documents, provider);
705
		this._proxy.$registerOutlineSupport(handle, selector);
J
Johannes Rieken 已提交
706 707 708
		return this._createDisposable(handle);
	}

709 710
	$provideDocumentSymbols(handle: number, resource: URI): TPromise<modes.SymbolInformation[]> {
		return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(resource));
J
Johannes Rieken 已提交
711
	}
712 713 714 715 716

	// --- code lens

	registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
		const handle = this._nextHandle();
717
		this._adapter[handle] = new CodeLensAdapter(this._documents, this._commands, provider);
718 719 720 721
		this._proxy.$registerCodeLensSupport(handle, selector);
		return this._createDisposable(handle);
	}

722 723
	$provideCodeLenses(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]> {
		return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(resource));
724 725
	}

726 727
	$resolveCodeLens(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
		return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(resource, symbol));
J
Johannes Rieken 已提交
728 729 730 731 732 733
	}

	// --- declaration

	registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
		const handle = this._nextHandle();
734
		this._adapter[handle] = new DefinitionAdapter(this._documents, provider);
J
Johannes Rieken 已提交
735 736
		this._proxy.$registerDeclaractionSupport(handle, selector);
		return this._createDisposable(handle);
737 738
	}

739 740
	$provideDefinition(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition> {
		return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(resource, position));
J
Johannes Rieken 已提交
741
	}
J
Johannes Rieken 已提交
742 743 744 745 746

	// --- extra info

	registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
		const handle = this._nextHandle();
747
		this._adapter[handle] = new HoverAdapter(this._documents, provider);
A
Alex Dima 已提交
748
		this._proxy.$registerHoverProvider(handle, selector);
J
Johannes Rieken 已提交
749 750 751
		return this._createDisposable(handle);
	}

752
	$provideHover(handle: number, resource: URI, position: IPosition): TPromise<modes.Hover> {
753
		return this._withAdapter(handle, HoverAdapter, adpater => adpater.provideHover(resource, position));
J
Johannes Rieken 已提交
754
	}
755

J
Johannes Rieken 已提交
756
	// --- occurrences
757 758 759

	registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
		const handle = this._nextHandle();
760 761
		this._adapter[handle] = new DocumentHighlightAdapter(this._documents, provider);
		this._proxy.$registerDocumentHighlightProvider(handle, selector);
762 763 764
		return this._createDisposable(handle);
	}

765 766
	$provideDocumentHighlights(handle: number, resource: URI, position: IPosition): TPromise<modes.DocumentHighlight[]> {
		return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(resource, position));
767
	}
J
Johannes Rieken 已提交
768 769 770 771 772 773 774 775 776 777

	// --- references

	registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new ReferenceAdapter(this._documents, provider);
		this._proxy.$registerReferenceSupport(handle, selector);
		return this._createDisposable(handle);
	}

778 779
	$provideReferences(handle: number, resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> {
		return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(resource, position, context));
J
Johannes Rieken 已提交
780 781
	}

J
Johannes Rieken 已提交
782 783 784 785
	// --- quick fix

	registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
		const handle = this._nextHandle();
786
		this._adapter[handle] = new QuickFixAdapter(this._documents, this._commands, this._diagnostics, provider);
J
Johannes Rieken 已提交
787 788 789 790
		this._proxy.$registerQuickFixSupport(handle, selector);
		return this._createDisposable(handle);
	}

A
Alex Dima 已提交
791
	$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
792
		return this._withAdapter(handle, QuickFixAdapter, adapter => adapter.provideCodeActions(resource, range));
J
Johannes Rieken 已提交
793
	}
794 795 796 797 798 799 800 801 802 803

	// --- formatting

	registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new DocumentFormattingAdapter(this._documents, provider);
		this._proxy.$registerDocumentFormattingSupport(handle, selector);
		return this._createDisposable(handle);
	}

A
Alex Dima 已提交
804
	$provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
805
		return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(resource, options));
806 807 808 809 810 811 812 813 814
	}

	registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new RangeFormattingAdapter(this._documents, provider);
		this._proxy.$registerRangeFormattingSupport(handle, selector);
		return this._createDisposable(handle);
	}

A
Alex Dima 已提交
815
	$provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
816
		return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(resource, range, options));
817 818 819 820 821 822 823 824 825
	}

	registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new OnTypeFormattingAdapter(this._documents, provider);
		this._proxy.$registerOnTypeFormattingSupport(handle, selector, triggerCharacters);
		return this._createDisposable(handle);
	}

A
Alex Dima 已提交
826
	$provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
827
		return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(resource, position, ch, options));
828 829
	}

830 831 832 833 834 835 836 837 838
	// --- navigate types

	registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new NavigateTypeAdapter(provider);
		this._proxy.$registerNavigateTypeSupport(handle);
		return this._createDisposable(handle);
	}

839 840 841 842 843 844
	$provideWorkspaceSymbols(handle: number, search: string): TPromise<IWorkspaceSymbol[]> {
		return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
	}

	$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
		return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
845
	}
J
Johannes Rieken 已提交
846 847 848 849 850 851 852 853 854 855

	// --- rename

	registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new RenameAdapter(this._documents, provider);
		this._proxy.$registerRenameSupport(handle, selector);
		return this._createDisposable(handle);
	}

856 857
	$provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise<modes.WorkspaceEdit> {
		return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(resource, position, newName));
J
Johannes Rieken 已提交
858
	}
859 860 861 862 863 864 865 866 867 868

	// --- suggestion

	registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new SuggestAdapter(this._documents, provider);
		this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters);
		return this._createDisposable(handle);
	}

869
	$provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise<modes.ISuggestResult> {
870
		return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position));
871 872
	}

873 874
	$resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
		return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(resource, position, suggestion));
875
	}
876 877 878 879 880

	// --- parameter hints

	registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable {
		const handle = this._nextHandle();
A
Alex Dima 已提交
881 882
		this._adapter[handle] = new SignatureHelpAdapter(this._documents, provider);
		this._proxy.$registerSignatureHelpProvider(handle, selector, triggerCharacters);
883 884 885
		return this._createDisposable(handle);
	}

886
	$provideSignatureHelp(handle: number, resource: URI, position: IPosition): TPromise<modes.SignatureHelp> {
A
Alex Dima 已提交
887
		return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(resource, position));
888
	}
J
Johannes Rieken 已提交
889

J
Johannes Rieken 已提交
890 891 892 893 894 895 896 897 898
	// --- links

	registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
		const handle = this._nextHandle();
		this._adapter[handle] = new LinkProviderAdapter(this._documents, provider);
		this._proxy.$registerDocumentLinkProvider(handle, selector);
		return this._createDisposable(handle);
	}

899
	$provideDocumentLinks(handle: number, resource: URI): TPromise<modes.ILink[]> {
J
Johannes Rieken 已提交
900 901 902
		return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(resource));
	}

903 904 905 906
	$resolveDocumentLink(handle: number, link: modes.ILink): TPromise<modes.ILink> {
		return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(link));
	}

907
	// --- configuration
J
Johannes Rieken 已提交
908

909 910
	setLanguageConfiguration(languageId:string, configuration: vscode.LanguageConfiguration): vscode.Disposable {
		let {wordPattern} = configuration;
J
Johannes Rieken 已提交
911

912 913 914
		// check for a valid word pattern
		if (wordPattern && regExpLeadsToEndlessLoop(wordPattern)) {
			throw new Error(`Invalid language configuration: wordPattern '${wordPattern}' is not allowed to match the empty string.`);
J
Johannes Rieken 已提交
915
		}
J
Johannes Rieken 已提交
916

917 918 919 920 921 922
		// word definition
		if (wordPattern) {
			this._documents.setWordDefinitionFor(languageId, wordPattern);
		} else {
			this._documents.setWordDefinitionFor(languageId, null);
		}
923

924 925 926
		const handle = this._nextHandle();
		this._proxy.$setLanguageConfiguration(handle, languageId, configuration);
		return this._createDisposable(handle);
927
	}
928
}