extHostLanguageFeatures.ts 41.6 KB
Newer Older
J
Johannes Rieken 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

7
import URI, { UriComponents } from 'vs/base/common/uri';
J
Johannes Rieken 已提交
8
import { TPromise } from 'vs/base/common/winjs.base';
9
import { mixin } from 'vs/base/common/objects';
J
Johannes Rieken 已提交
10
import * as vscode from 'vscode';
J
Johannes Rieken 已提交
11
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
12
import { Range, Disposable, CompletionList, SnippetString, Color } from 'vs/workbench/api/node/extHostTypes';
A
Alex Dima 已提交
13
import { ISingleEditOperation } from 'vs/editor/common/model';
J
Johannes Rieken 已提交
14
import * as modes from 'vs/editor/common/modes';
J
Johannes Rieken 已提交
15 16
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
17
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
18
import { ExtHostDiagnostics, DiagnosticCollection } from 'vs/workbench/api/node/extHostDiagnostics';
19
import { asWinJsPromise } from 'vs/base/common/async';
20
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, SymbolInformationDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto } from './extHost.protocol';
J
Johannes Rieken 已提交
21
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
22 23
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
24
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
J
Johannes Rieken 已提交
25 26 27

// --- adapter

28
class OutlineAdapter {
J
Johannes Rieken 已提交
29

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

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

38
	provideDocumentSymbols(resource: URI): TPromise<SymbolInformationDto[]> {
39
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
40 41
		return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
			if (Array.isArray(value)) {
42
				return value.map(symbol => IdObject.mixin(TypeConverters.fromSymbolInformation(symbol)));
J
Johannes Rieken 已提交
43
			}
M
Matt Bierner 已提交
44
			return undefined;
J
Johannes Rieken 已提交
45 46 47 48
		});
	}
}

49
class CodeLensAdapter {
50

51 52
	private static _badCmd: vscode.Command = { command: 'missing', title: '<<MISSING COMMAND>>' };

53
	private _documents: ExtHostDocuments;
54 55
	private _commands: CommandsConverter;
	private _heapService: ExtHostHeapService;
56 57
	private _provider: vscode.CodeLensProvider;

58
	constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CodeLensProvider) {
59
		this._documents = documents;
60
		this._commands = commands;
61
		this._heapService = heapService;
62 63 64
		this._provider = provider;
	}

65
	provideCodeLenses(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
66
		const doc = this._documents.getDocumentData(resource).document;
67

68 69 70 71 72 73 74 75
		return asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(lenses => {
			if (Array.isArray(lenses)) {
				return lenses.map(lens => {
					const id = this._heapService.keep(lens);
					return ObjectIdentifier.mixin({
						range: TypeConverters.fromRange(lens.range),
						command: this._commands.toInternal(lens.command)
					}, id);
76 77
				});
			}
M
Matt Bierner 已提交
78
			return undefined;
79
		});
80 81
	}

82
	resolveCodeLens(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
83

84 85
		const lens = this._heapService.get<vscode.CodeLens>(ObjectIdentifier.of(symbol));
		if (!lens) {
M
Matt Bierner 已提交
86
			return undefined;
87 88
		}

89 90 91 92 93 94
		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));
		}
95

96 97 98 99
		return resolve.then(newLens => {
			newLens = newLens || lens;
			symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd);
			return symbol;
100 101 102 103
		});
	}
}

104
class DefinitionAdapter {
105
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
106 107
	private _provider: vscode.DefinitionProvider;

108
	constructor(documents: ExtHostDocuments, provider: vscode.DefinitionProvider) {
J
Johannes Rieken 已提交
109 110 111 112
		this._documents = documents;
		this._provider = provider;
	}

113
	provideDefinition(resource: URI, position: IPosition): TPromise<modes.Definition> {
114
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
115 116 117
		let pos = TypeConverters.toPosition(position);
		return asWinJsPromise(token => this._provider.provideDefinition(doc, pos, token)).then(value => {
			if (Array.isArray(value)) {
J
Johannes Rieken 已提交
118
				return value.map(TypeConverters.location.from);
J
Johannes Rieken 已提交
119
			} else if (value) {
J
Johannes Rieken 已提交
120
				return TypeConverters.location.from(value);
J
Johannes Rieken 已提交
121
			}
M
Matt Bierner 已提交
122
			return undefined;
J
Johannes Rieken 已提交
123 124 125 126
		});
	}
}

127 128
class ImplementationAdapter {
	private _documents: ExtHostDocuments;
M
Matt Bierner 已提交
129
	private _provider: vscode.ImplementationProvider;
130

M
Matt Bierner 已提交
131
	constructor(documents: ExtHostDocuments, provider: vscode.ImplementationProvider) {
132 133 134 135
		this._documents = documents;
		this._provider = provider;
	}

M
Matt Bierner 已提交
136
	provideImplementation(resource: URI, position: IPosition): TPromise<modes.Definition> {
137 138
		let doc = this._documents.getDocumentData(resource).document;
		let pos = TypeConverters.toPosition(position);
M
Matt Bierner 已提交
139
		return asWinJsPromise(token => this._provider.provideImplementation(doc, pos, token)).then(value => {
140 141 142 143 144
			if (Array.isArray(value)) {
				return value.map(TypeConverters.location.from);
			} else if (value) {
				return TypeConverters.location.from(value);
			}
M
Matt Bierner 已提交
145
			return undefined;
146 147 148 149
		});
	}
}

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
class TypeDefinitionAdapter {
	private _documents: ExtHostDocuments;
	private _provider: vscode.TypeDefinitionProvider;

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

	provideTypeDefinition(resource: URI, position: IPosition): TPromise<modes.Definition> {
		const doc = this._documents.getDocumentData(resource).document;
		const pos = TypeConverters.toPosition(position);
		return asWinJsPromise(token => this._provider.provideTypeDefinition(doc, pos, token)).then(value => {
			if (Array.isArray(value)) {
				return value.map(TypeConverters.location.from);
			} else if (value) {
				return TypeConverters.location.from(value);
			}
			return undefined;
		});
	}
}


174
class HoverAdapter {
J
Johannes Rieken 已提交
175

176 177 178 179 180
	constructor(
		private readonly _documents: ExtHostDocuments,
		private readonly _provider: vscode.HoverProvider,
	) {
		//
J
Johannes Rieken 已提交
181 182
	}

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

185
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
186 187 188
		let pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideHover(doc, pos, token)).then(value => {
189
			if (!value || isFalsyOrEmpty(value.contents)) {
M
Matt Bierner 已提交
190
				return undefined;
J
Johannes Rieken 已提交
191
			}
192 193
			if (!value.range) {
				value.range = doc.getWordRangeAtPosition(pos);
J
Johannes Rieken 已提交
194
			}
195 196
			if (!value.range) {
				value.range = new Range(pos, pos);
J
Johannes Rieken 已提交
197 198
			}

199
			return TypeConverters.fromHover(value);
J
Johannes Rieken 已提交
200 201 202 203
		});
	}
}

204
class DocumentHighlightAdapter {
205

206
	private _documents: ExtHostDocuments;
207 208
	private _provider: vscode.DocumentHighlightProvider;

209
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentHighlightProvider) {
210 211 212 213
		this._documents = documents;
		this._provider = provider;
	}

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

216
		let doc = this._documents.getDocumentData(resource).document;
217 218 219 220
		let pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => {
			if (Array.isArray(value)) {
221
				return value.map(DocumentHighlightAdapter._convertDocumentHighlight);
222
			}
M
Matt Bierner 已提交
223
			return undefined;
224 225 226
		});
	}

227
	private static _convertDocumentHighlight(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
228 229
		return {
			range: TypeConverters.fromRange(documentHighlight.range),
230
			kind: documentHighlight.kind
B
Benjamin Pasero 已提交
231
		};
232 233 234
	}
}

235
class ReferenceAdapter {
J
Johannes Rieken 已提交
236

237
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
238 239
	private _provider: vscode.ReferenceProvider;

240
	constructor(documents: ExtHostDocuments, provider: vscode.ReferenceProvider) {
J
Johannes Rieken 已提交
241 242 243 244
		this._documents = documents;
		this._provider = provider;
	}

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

249
		return asWinJsPromise(token => this._provider.provideReferences(doc, pos, context, token)).then(value => {
J
Johannes Rieken 已提交
250
			if (Array.isArray(value)) {
J
Johannes Rieken 已提交
251
				return value.map(TypeConverters.location.from);
J
Johannes Rieken 已提交
252
			}
M
Matt Bierner 已提交
253
			return undefined;
J
Johannes Rieken 已提交
254 255 256 257
		});
	}
}

258 259 260 261 262
export interface CustomCodeAction extends modes.CodeAction {
	_isSynthetic?: boolean;
}

class CodeActionAdapter {
J
Johannes Rieken 已提交
263

264
	private _documents: ExtHostDocuments;
265
	private _commands: CommandsConverter;
266
	private _diagnostics: ExtHostDiagnostics;
J
Johannes Rieken 已提交
267 268
	private _provider: vscode.CodeActionProvider;

J
Johannes Rieken 已提交
269
	constructor(documents: ExtHostDocuments, commands: CommandsConverter, diagnostics: ExtHostDiagnostics, provider: vscode.CodeActionProvider) {
J
Johannes Rieken 已提交
270 271
		this._documents = documents;
		this._commands = commands;
272
		this._diagnostics = diagnostics;
J
Johannes Rieken 已提交
273 274 275
		this._provider = provider;
	}

276
	provideCodeActions(resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
J
Johannes Rieken 已提交
277

278
		const doc = this._documents.getDocumentData(resource).document;
279
		const ran = <vscode.Range>TypeConverters.toRange(range);
280 281 282 283 284
		const allDiagnostics: vscode.Diagnostic[] = [];

		this._diagnostics.forEach(collection => {
			if (collection.has(resource)) {
				for (let diagnostic of collection.get(resource)) {
285
					if (ran.contains(diagnostic.range)) {
286 287 288 289
						allDiagnostics.push(diagnostic);
					}
				}
			}
J
Johannes Rieken 已提交
290 291
		});

292 293
		return asWinJsPromise(token =>
			this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)
294 295
		).then(commandsOrActions => {
			if (isFalsyOrEmpty(commandsOrActions)) {
M
Matt Bierner 已提交
296
				return undefined;
J
Johannes Rieken 已提交
297
			}
298 299 300 301
			const result: CustomCodeAction[] = [];
			for (const candidate of commandsOrActions) {
				if (!candidate) {
					continue;
302
				}
303 304 305 306 307 308 309 310 311 312 313 314 315
				if (CodeActionAdapter._isCommand(candidate)) {
					// old school: synthetic code action
					result.push({
						_isSynthetic: true,
						title: candidate.title,
						command: this._commands.toInternal(candidate),
					});
				} else {
					// new school: convert code action
					result.push({
						title: candidate.title,
						command: candidate.command && this._commands.toInternal(candidate.command),
						diagnostics: candidate.diagnostics && candidate.diagnostics.map(DiagnosticCollection.toMarkerData),
316
						edit: candidate.edit && TypeConverters.WorkspaceEdit.from(candidate.edit),
317
					});
318
				}
319
			}
320

321
			return result;
J
Johannes Rieken 已提交
322 323
		});
	}
324 325 326 327

	private static _isCommand(thing: any): thing is vscode.Command {
		return typeof (<vscode.Command>thing).command === 'string' && typeof (<vscode.Command>thing).title === 'string';
	}
J
Johannes Rieken 已提交
328 329
}

330
class DocumentFormattingAdapter {
331

332
	private _documents: ExtHostDocuments;
333 334
	private _provider: vscode.DocumentFormattingEditProvider;

335
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentFormattingEditProvider) {
336 337 338 339
		this._documents = documents;
		this._provider = provider;
	}

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

342
		const { document } = this._documents.getDocumentData(resource);
343 344

		return asWinJsPromise(token => this._provider.provideDocumentFormattingEdits(document, <any>options, token)).then(value => {
345
			if (Array.isArray(value)) {
346
				return value.map(TypeConverters.TextEdit.from);
347
			}
M
Matt Bierner 已提交
348
			return undefined;
349 350 351 352
		});
	}
}

353
class RangeFormattingAdapter {
354

355
	private _documents: ExtHostDocuments;
356 357
	private _provider: vscode.DocumentRangeFormattingEditProvider;

358
	constructor(documents: ExtHostDocuments, provider: vscode.DocumentRangeFormattingEditProvider) {
359 360 361 362
		this._documents = documents;
		this._provider = provider;
	}

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

365
		const { document } = this._documents.getDocumentData(resource);
366
		const ran = TypeConverters.toRange(range);
367

368
		return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(document, ran, <any>options, token)).then(value => {
369
			if (Array.isArray(value)) {
370
				return value.map(TypeConverters.TextEdit.from);
371
			}
M
Matt Bierner 已提交
372
			return undefined;
373 374 375 376
		});
	}
}

377
class OnTypeFormattingAdapter {
378

379
	private _documents: ExtHostDocuments;
380 381
	private _provider: vscode.OnTypeFormattingEditProvider;

382
	constructor(documents: ExtHostDocuments, provider: vscode.OnTypeFormattingEditProvider) {
383 384 385 386
		this._documents = documents;
		this._provider = provider;
	}

387
	autoFormatTriggerCharacters: string[] = []; // not here
388

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

391
		const { document } = this._documents.getDocumentData(resource);
392
		const pos = TypeConverters.toPosition(position);
393

J
Johannes Rieken 已提交
394
		return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(document, pos, ch, <any>options, token)).then(value => {
395
			if (Array.isArray(value)) {
396
				return value.map(TypeConverters.TextEdit.from);
397
			}
M
Matt Bierner 已提交
398
			return undefined;
399 400 401 402
		});
	}
}

403
class NavigateTypeAdapter {
404

405 406 407
	private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null);
	private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null);
	private readonly _provider: vscode.WorkspaceSymbolProvider;
408

409
	constructor(provider: vscode.WorkspaceSymbolProvider) {
410 411 412
		this._provider = provider;
	}

413 414
	provideWorkspaceSymbols(search: string): TPromise<WorkspaceSymbolsDto> {
		const result: WorkspaceSymbolsDto = IdObject.mixin({ symbols: [] });
415
		return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
416 417
			if (!isFalsyOrEmpty(value)) {
				for (const item of value) {
J
Johannes Rieken 已提交
418 419 420
					if (!item) {
						// drop
						continue;
M
Matt Bierner 已提交
421
					}
J
Johannes Rieken 已提交
422 423 424 425 426 427 428
					if (!item.name) {
						console.warn('INVALID SymbolInformation, lacks name', item);
						continue;
					}
					const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item));
					this._symbolCache[symbol._id] = item;
					result.symbols.push(symbol);
429
				}
430
			}
431
		}).then(() => {
432 433 434
			if (result.symbols.length > 0) {
				this._resultCache[result._id] = [result.symbols[0]._id, result.symbols[result.symbols.length - 1]._id];
			}
435
			return result;
436 437
		});
	}
438

439
	resolveWorkspaceSymbol(symbol: SymbolInformationDto): TPromise<SymbolInformationDto> {
440 441

		if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
442
			return TPromise.as(symbol);
443 444
		}

445 446 447 448
		const item = this._symbolCache[symbol._id];
		if (item) {
			return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => {
				return value && mixin(symbol, TypeConverters.fromSymbolInformation(value), true);
449
			});
450
		}
M
Matt Bierner 已提交
451
		return undefined;
452
	}
453 454 455 456 457 458 459 460 461 462

	releaseWorkspaceSymbols(id: number): any {
		const range = this._resultCache[id];
		if (range) {
			for (let [from, to] = range; from <= to; from++) {
				delete this._symbolCache[from];
			}
			delete this._resultCache[id];
		}
	}
463 464
}

465
class RenameAdapter {
J
Johannes Rieken 已提交
466

467
	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
468 469
	private _provider: vscode.RenameProvider;

470
	constructor(documents: ExtHostDocuments, provider: vscode.RenameProvider) {
J
Johannes Rieken 已提交
471 472 473 474
		this._documents = documents;
		this._provider = provider;
	}

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

477
		let doc = this._documents.getDocumentData(resource).document;
J
Johannes Rieken 已提交
478 479 480 481
		let pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => {
			if (!value) {
M
Matt Bierner 已提交
482
				return undefined;
J
Johannes Rieken 已提交
483
			}
484
			return TypeConverters.WorkspaceEdit.from(value);
J
Johannes Rieken 已提交
485 486
		}, err => {
			if (typeof err === 'string') {
487
				return <modes.WorkspaceEdit>{
J
Johannes Rieken 已提交
488 489 490
					edits: undefined,
					rejectReason: err
				};
J
Johannes Rieken 已提交
491 492 493 494 495 496 497 498
			} else if (err instanceof Error && typeof err.message === 'string') {
				return <modes.WorkspaceEdit>{
					edits: undefined,
					rejectReason: err.message
				};
			} else {
				// generic error
				return TPromise.wrapError<modes.WorkspaceEdit>(err);
J
Johannes Rieken 已提交
499 500 501 502 503
			}
		});
	}
}

504

505
class SuggestAdapter {
506

507 508 509 510
	static supportsResolving(provider: vscode.CompletionItemProvider): boolean {
		return typeof provider.resolveCompletionItem === 'function';
	}

511
	private _documents: ExtHostDocuments;
512
	private _commands: CommandsConverter;
513 514
	private _provider: vscode.CompletionItemProvider;

515 516 517 518
	private _cache = new Map<number, vscode.CompletionItem[]>();
	private _idPool = 0;

	constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) {
519
		this._documents = documents;
520
		this._commands = commands;
521 522 523
		this._provider = provider;
	}

524
	provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto> {
525

526
		const doc = this._documents.getDocumentData(resource).document;
527 528
		const pos = TypeConverters.toPosition(position);

529
		return asWinJsPromise<vscode.CompletionItem[] | vscode.CompletionList>(token => {
M
Matt Bierner 已提交
530
			return this._provider.provideCompletionItems(doc, pos, token, TypeConverters.CompletionContext.from(context));
531
		}).then(value => {
532

533 534
			const _id = this._idPool++;

535
			const result: SuggestResultDto = {
536
				_id,
537 538
				suggestions: [],
			};
539

540
			let list: CompletionList;
541
			if (!value) {
542
				// undefined and null are valid results
M
Matt Bierner 已提交
543
				return undefined;
544 545 546 547

			} else if (Array.isArray(value)) {
				list = new CompletionList(value);

548
			} else {
549 550
				list = value;
				result.incomplete = list.isIncomplete;
551
			}
552

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

557 558 559 560 561 562
			for (let i = 0; i < list.items.length; i++) {
				const suggestion = this._convertCompletionItem(list.items[i], pos, wordRangeBeforePos, i, _id);
				// check for bad completion item
				// for the converter did warn
				if (suggestion) {
					result.suggestions.push(suggestion);
563 564
				}
			}
565
			this._cache.set(_id, list.items);
566

567
			return result;
568 569 570
		});
	}

571
	resolveCompletionItem(resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
572 573

		if (typeof this._provider.resolveCompletionItem !== 'function') {
574 575
			return TPromise.as(suggestion);
		}
576

577
		const { _parentId, _id } = (<SuggestionDto>suggestion);
578
		const item = this._cache.has(_parentId) && this._cache.get(_parentId)[_id];
579 580 581
		if (!item) {
			return TPromise.as(suggestion);
		}
582

583
		return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
584 585 586 587 588 589 590 591

			if (!resolvedItem) {
				return suggestion;
			}

			const doc = this._documents.getDocumentData(resource).document;
			const pos = TypeConverters.toPosition(position);
			const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos)).with({ end: pos });
592
			const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos, _id, _parentId);
593 594 595 596
			if (newSuggestion) {
				mixin(suggestion, newSuggestion, true);
			}

597
			return suggestion;
598 599
		});
	}
600

601 602 603 604
	releaseCompletionItems(id: number): any {
		this._cache.delete(id);
	}

605
	private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): SuggestionDto {
J
Johannes Rieken 已提交
606
		if (typeof item.label !== 'string' || item.label.length === 0) {
607
			console.warn('INVALID text edit -> must have at least a label');
M
Matt Bierner 已提交
608
			return undefined;
609 610
		}

611
		const result: SuggestionDto = {
612 613 614
			//
			_id,
			_parentId,
615 616 617 618 619 620 621 622 623 624
			//
			label: item.label,
			type: TypeConverters.CompletionItemKind.from(item.kind),
			detail: item.detail,
			documentation: item.documentation,
			filterText: item.filterText,
			sortText: item.sortText,
			//
			insertText: undefined,
			additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TypeConverters.TextEdit.from),
625 626
			command: this._commands.toInternal(item.command),
			commitCharacters: item.commitCharacters
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
		};

		// 'insertText'-logic
		if (item.textEdit) {
			result.insertText = item.textEdit.newText;
			result.snippetType = 'internal';

		} else if (typeof item.insertText === 'string') {
			result.insertText = item.insertText;
			result.snippetType = 'internal';

		} else if (item.insertText instanceof SnippetString) {
			result.insertText = item.insertText.value;
			result.snippetType = 'textmate';

		} else {
			result.insertText = item.label;
			result.snippetType = 'internal';
		}

		// 'overwrite[Before|After]'-logic
		let range: vscode.Range;
		if (item.textEdit) {
			range = item.textEdit.range;
		} else if (item.range) {
			range = item.range;
		} else {
			range = defaultRange;
		}
		result.overwriteBefore = position.character - range.start.character;
		result.overwriteAfter = range.end.character - position.character;

		if (!range.isSingleLine || range.start.line !== position.line) {
			console.warn('INVALID text edit -> must be single line and on the same line');
M
Matt Bierner 已提交
661
			return undefined;
662 663 664 665
		}

		return result;
	}
666 667
}

A
Alex Dima 已提交
668
class SignatureHelpAdapter {
669

670
	private _documents: ExtHostDocuments;
671 672
	private _provider: vscode.SignatureHelpProvider;

673
	constructor(documents: ExtHostDocuments, provider: vscode.SignatureHelpProvider) {
674 675 676 677
		this._documents = documents;
		this._provider = provider;
	}

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

680
		const doc = this._documents.getDocumentData(resource).document;
681 682 683
		const pos = TypeConverters.toPosition(position);

		return asWinJsPromise(token => this._provider.provideSignatureHelp(doc, pos, token)).then(value => {
684
			if (value) {
685
				return TypeConverters.SignatureHelp.from(value);
686
			}
M
Matt Bierner 已提交
687
			return undefined;
688 689 690 691
		});
	}
}

J
Johannes Rieken 已提交
692 693 694
class LinkProviderAdapter {

	private _documents: ExtHostDocuments;
J
Johannes Rieken 已提交
695
	private _heapService: ExtHostHeapService;
J
Johannes Rieken 已提交
696 697
	private _provider: vscode.DocumentLinkProvider;

J
Johannes Rieken 已提交
698
	constructor(documents: ExtHostDocuments, heapService: ExtHostHeapService, provider: vscode.DocumentLinkProvider) {
J
Johannes Rieken 已提交
699
		this._documents = documents;
J
Johannes Rieken 已提交
700
		this._heapService = heapService;
J
Johannes Rieken 已提交
701 702 703 704 705 706 707
		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 => {
J
Johannes Rieken 已提交
708 709
			if (!Array.isArray(links)) {
				return undefined;
J
Johannes Rieken 已提交
710
			}
J
Johannes Rieken 已提交
711 712 713 714 715 716 717 718
			const result: modes.ILink[] = [];
			for (const link of links) {
				let data = TypeConverters.DocumentLink.from(link);
				let id = this._heapService.keep(link);
				ObjectIdentifier.mixin(data, id);
				result.push(data);
			}
			return result;
J
Johannes Rieken 已提交
719 720
		});
	}
721 722

	resolveLink(link: modes.ILink): TPromise<modes.ILink> {
J
Johannes Rieken 已提交
723 724
		if (typeof this._provider.resolveDocumentLink !== 'function') {
			return undefined;
725
		}
J
Johannes Rieken 已提交
726 727 728 729 730 731 732 733 734 735 736 737 738

		const id = ObjectIdentifier.of(link);
		const item = this._heapService.get<vscode.DocumentLink>(id);
		if (!item) {
			return undefined;
		}

		return asWinJsPromise(token => this._provider.resolveDocumentLink(item, token)).then(value => {
			if (value) {
				return TypeConverters.DocumentLink.from(value);
			}
			return undefined;
		});
739
	}
J
Johannes Rieken 已提交
740 741
}

742 743
class ColorProviderAdapter {

J
Joao Moreno 已提交
744 745 746 747
	constructor(
		private _documents: ExtHostDocuments,
		private _provider: vscode.DocumentColorProvider
	) { }
748

749
	provideColors(resource: URI): TPromise<IRawColorInfo[]> {
750
		const doc = this._documents.getDocumentData(resource).document;
J
Joao Moreno 已提交
751 752 753
		return asWinJsPromise(token => this._provider.provideDocumentColors(doc, token)).then(colors => {
			if (!Array.isArray(colors)) {
				return [];
754 755
			}

J
Joao Moreno 已提交
756 757 758
			const colorInfos: IRawColorInfo[] = colors.map(ci => {
				return {
					color: [ci.color.red, ci.color.green, ci.color.blue, ci.color.alpha] as [number, number, number, number],
759
					range: TypeConverters.fromRange(ci.range)
J
Joao Moreno 已提交
760 761 762 763
				};
			});

			return colorInfos;
764 765
		});
	}
766

767 768 769 770 771 772
	provideColorPresentations(resource: URI, raw: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
		const document = this._documents.getDocumentData(resource).document;
		const range = TypeConverters.toRange(raw.range);
		const color = new Color(raw.color[0], raw.color[1], raw.color[2], raw.color[3]);
		return asWinJsPromise(token => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => {
			return value.map(TypeConverters.ColorPresentation.from);
773
		});
774
	}
775 776
}

777
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
778
	| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
779
	| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
780
	| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | ColorProviderAdapter;
J
Johannes Rieken 已提交
781

782
export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
J
Johannes Rieken 已提交
783

784
	private static _handlePool: number = 0;
J
Johannes Rieken 已提交
785

786
	private _proxy: MainThreadLanguageFeaturesShape;
787
	private _documents: ExtHostDocuments;
788
	private _commands: ExtHostCommands;
789
	private _heapService: ExtHostHeapService;
790
	private _diagnostics: ExtHostDiagnostics;
J
Johannes Rieken 已提交
791
	private _adapter = new Map<number, Adapter>();
J
Johannes Rieken 已提交
792

793
	constructor(
794
		mainContext: IMainContext,
795
		documents: ExtHostDocuments,
796
		commands: ExtHostCommands,
J
Johannes Rieken 已提交
797
		heapMonitor: ExtHostHeapService,
798 799
		diagnostics: ExtHostDiagnostics
	) {
800
		this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures);
801 802
		this._documents = documents;
		this._commands = commands;
803
		this._heapService = heapMonitor;
804
		this._diagnostics = diagnostics;
J
Johannes Rieken 已提交
805 806 807 808
	}

	private _createDisposable(handle: number): Disposable {
		return new Disposable(() => {
J
Johannes Rieken 已提交
809
			this._adapter.delete(handle);
J
Johannes Rieken 已提交
810 811 812 813
			this._proxy.$unregister(handle);
		});
	}

814 815 816 817
	private _nextHandle(): number {
		return ExtHostLanguageFeatures._handlePool++;
	}

818
	private _withAdapter<A, R>(handle: number, ctor: { new(...args: any[]): A }, callback: (adapter: A) => TPromise<R>): TPromise<R> {
J
Johannes Rieken 已提交
819
		let adapter = this._adapter.get(handle);
J
Johannes Rieken 已提交
820
		if (!(adapter instanceof ctor)) {
821
			return TPromise.wrapError<R>(new Error('no adapter found'));
J
Johannes Rieken 已提交
822
		}
J
Johannes Rieken 已提交
823
		return callback(<any>adapter);
824 825
	}

826 827 828 829 830 831
	private _addNewAdapter(adapter: Adapter): number {
		const handle = this._nextHandle();
		this._adapter.set(handle, adapter);
		return handle;
	}

J
Johannes Rieken 已提交
832 833 834
	// --- outline

	registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
835
		const handle = this._addNewAdapter(new OutlineAdapter(this._documents, provider));
836
		this._proxy.$registerOutlineSupport(handle, selector);
J
Johannes Rieken 已提交
837 838 839
		return this._createDisposable(handle);
	}

840
	$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<SymbolInformationDto[]> {
841
		return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource)));
J
Johannes Rieken 已提交
842
	}
843 844 845 846 847

	// --- code lens

	registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
		const handle = this._nextHandle();
848 849
		const eventHandle = typeof provider.onDidChangeCodeLenses === 'function' ? this._nextHandle() : undefined;

J
Johannes Rieken 已提交
850
		this._adapter.set(handle, new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider));
851 852 853 854 855 856 857 858 859
		this._proxy.$registerCodeLensSupport(handle, selector, eventHandle);
		let result = this._createDisposable(handle);

		if (eventHandle !== undefined) {
			const subscription = provider.onDidChangeCodeLenses(_ => this._proxy.$emitCodeLensEvent(eventHandle));
			result = Disposable.from(result, subscription);
		}

		return result;
860 861
	}

862 863
	$provideCodeLenses(handle: number, resource: UriComponents): TPromise<modes.ICodeLensSymbol[]> {
		return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource)));
864 865
	}

866 867
	$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
		return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol));
J
Johannes Rieken 已提交
868 869 870 871 872
	}

	// --- declaration

	registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
873
		const handle = this._addNewAdapter(new DefinitionAdapter(this._documents, provider));
J
Johannes Rieken 已提交
874 875
		this._proxy.$registerDeclaractionSupport(handle, selector);
		return this._createDisposable(handle);
876 877
	}

878 879
	$provideDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Definition> {
		return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(URI.revive(resource), position));
J
Johannes Rieken 已提交
880
	}
J
Johannes Rieken 已提交
881

M
Matt Bierner 已提交
882
	registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
883
		const handle = this._addNewAdapter(new ImplementationAdapter(this._documents, provider));
884 885 886 887
		this._proxy.$registerImplementationSupport(handle, selector);
		return this._createDisposable(handle);
	}

888 889
	$provideImplementation(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Definition> {
		return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(URI.revive(resource), position));
890 891
	}

892
	registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
893
		const handle = this._addNewAdapter(new TypeDefinitionAdapter(this._documents, provider));
894 895 896 897
		this._proxy.$registerTypeDefinitionSupport(handle, selector);
		return this._createDisposable(handle);
	}

898 899
	$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Definition> {
		return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(URI.revive(resource), position));
900 901
	}

J
Johannes Rieken 已提交
902 903
	// --- extra info

904
	registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable {
905
		const handle = this._addNewAdapter(new HoverAdapter(this._documents, provider));
A
Alex Dima 已提交
906
		this._proxy.$registerHoverProvider(handle, selector);
J
Johannes Rieken 已提交
907 908 909
		return this._createDisposable(handle);
	}

910 911
	$provideHover(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Hover> {
		return this._withAdapter(handle, HoverAdapter, adpater => adpater.provideHover(URI.revive(resource), position));
J
Johannes Rieken 已提交
912
	}
913

J
Johannes Rieken 已提交
914
	// --- occurrences
915 916

	registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
917
		const handle = this._addNewAdapter(new DocumentHighlightAdapter(this._documents, provider));
918
		this._proxy.$registerDocumentHighlightProvider(handle, selector);
919 920 921
		return this._createDisposable(handle);
	}

922 923
	$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DocumentHighlight[]> {
		return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position));
924
	}
J
Johannes Rieken 已提交
925 926 927 928

	// --- references

	registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
929
		const handle = this._addNewAdapter(new ReferenceAdapter(this._documents, provider));
J
Johannes Rieken 已提交
930 931 932 933
		this._proxy.$registerReferenceSupport(handle, selector);
		return this._createDisposable(handle);
	}

934 935
	$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> {
		return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(URI.revive(resource), position, context));
J
Johannes Rieken 已提交
936 937
	}

J
Johannes Rieken 已提交
938 939 940
	// --- quick fix

	registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
941
		const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
J
Johannes Rieken 已提交
942 943 944 945
		this._proxy.$registerQuickFixSupport(handle, selector);
		return this._createDisposable(handle);
	}

946 947
	$provideCodeActions(handle: number, resource: UriComponents, range: IRange): TPromise<modes.CodeAction[]> {
		return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), range));
J
Johannes Rieken 已提交
948
	}
949 950 951 952

	// --- formatting

	registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
953
		const handle = this._addNewAdapter(new DocumentFormattingAdapter(this._documents, provider));
954 955 956 957
		this._proxy.$registerDocumentFormattingSupport(handle, selector);
		return this._createDisposable(handle);
	}

958 959
	$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
		return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options));
960 961 962
	}

	registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
963
		const handle = this._addNewAdapter(new RangeFormattingAdapter(this._documents, provider));
964 965 966 967
		this._proxy.$registerRangeFormattingSupport(handle, selector);
		return this._createDisposable(handle);
	}

968 969
	$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
		return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(URI.revive(resource), range, options));
970 971 972
	}

	registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
973
		const handle = this._addNewAdapter(new OnTypeFormattingAdapter(this._documents, provider));
974 975 976 977
		this._proxy.$registerOnTypeFormattingSupport(handle, selector, triggerCharacters);
		return this._createDisposable(handle);
	}

978 979
	$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
		return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(URI.revive(resource), position, ch, options));
980 981
	}

982 983 984
	// --- navigate types

	registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
985
		const handle = this._addNewAdapter(new NavigateTypeAdapter(provider));
986 987 988 989
		this._proxy.$registerNavigateTypeSupport(handle);
		return this._createDisposable(handle);
	}

990
	$provideWorkspaceSymbols(handle: number, search: string): TPromise<WorkspaceSymbolsDto> {
991 992 993
		return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
	}

994
	$resolveWorkspaceSymbol(handle: number, symbol: SymbolInformationDto): TPromise<SymbolInformationDto> {
995
		return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
996
	}
J
Johannes Rieken 已提交
997

998 999 1000 1001
	$releaseWorkspaceSymbols(handle: number, id: number) {
		this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id));
	}

J
Johannes Rieken 已提交
1002 1003 1004
	// --- rename

	registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
1005
		const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider));
J
Johannes Rieken 已提交
1006 1007 1008 1009
		this._proxy.$registerRenameSupport(handle, selector);
		return this._createDisposable(handle);
	}

1010 1011
	$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<modes.WorkspaceEdit> {
		return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName));
J
Johannes Rieken 已提交
1012
	}
1013 1014 1015

	// --- suggestion

1016
	registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
1017
		const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider));
1018
		this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters, SuggestAdapter.supportsResolving(provider));
1019 1020 1021
		return this._createDisposable(handle);
	}

1022
	$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto> {
1023
		return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context));
1024 1025
	}

1026 1027
	$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
		return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, suggestion));
1028
	}
1029

1030 1031 1032 1033
	$releaseCompletionItems(handle: number, id: number): void {
		this._withAdapter(handle, SuggestAdapter, adapter => adapter.releaseCompletionItems(id));
	}

1034 1035 1036
	// --- parameter hints

	registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable {
1037
		const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider));
A
Alex Dima 已提交
1038
		this._proxy.$registerSignatureHelpProvider(handle, selector, triggerCharacters);
1039 1040 1041
		return this._createDisposable(handle);
	}

1042 1043
	$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.SignatureHelp> {
		return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position));
1044
	}
J
Johannes Rieken 已提交
1045

J
Johannes Rieken 已提交
1046 1047 1048
	// --- links

	registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
1049
		const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, this._heapService, provider));
J
Johannes Rieken 已提交
1050 1051 1052 1053
		this._proxy.$registerDocumentLinkProvider(handle, selector);
		return this._createDisposable(handle);
	}

1054 1055
	$provideDocumentLinks(handle: number, resource: UriComponents): TPromise<modes.ILink[]> {
		return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource)));
J
Johannes Rieken 已提交
1056 1057
	}

1058 1059 1060 1061
	$resolveDocumentLink(handle: number, link: modes.ILink): TPromise<modes.ILink> {
		return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(link));
	}

1062
	registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
1063
		const handle = this._addNewAdapter(new ColorProviderAdapter(this._documents, provider));
1064 1065
		this._proxy.$registerDocumentColorProvider(handle, selector);
		return this._createDisposable(handle);
1066 1067
	}

1068 1069
	$provideDocumentColors(handle: number, resource: UriComponents): TPromise<IRawColorInfo[]> {
		return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource)));
1070 1071
	}

1072 1073
	$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
		return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo));
1074 1075
	}

1076
	// --- configuration
J
Johannes Rieken 已提交
1077

1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
	private static _serializeRegExp(regExp: RegExp): ISerializedRegExp {
		if (typeof regExp === 'undefined') {
			return undefined;
		}
		if (regExp === null) {
			return null;
		}
		return {
			pattern: regExp.source,
			flags: (regExp.global ? 'g' : '') + (regExp.ignoreCase ? 'i' : '') + (regExp.multiline ? 'm' : ''),
		};
	}

	private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): ISerializedIndentationRule {
		if (typeof indentationRule === 'undefined') {
			return undefined;
		}
		if (indentationRule === null) {
			return null;
		}
		return {
			decreaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.decreaseIndentPattern),
			increaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.increaseIndentPattern),
			indentNextLinePattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.indentNextLinePattern),
			unIndentedLinePattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.unIndentedLinePattern),
		};
	}

	private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): ISerializedOnEnterRule {
		return {
			beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText),
			afterText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText),
			action: onEnterRule.action
		};
	}

	private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): ISerializedOnEnterRule[] {
		if (typeof onEnterRules === 'undefined') {
			return undefined;
		}
		if (onEnterRules === null) {
			return null;
		}
		return onEnterRules.map(ExtHostLanguageFeatures._serializeOnEnterRule);
	}

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

1127 1128 1129
		// 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 已提交
1130
		}
J
Johannes Rieken 已提交
1131

1132 1133 1134 1135 1136 1137
		// word definition
		if (wordPattern) {
			this._documents.setWordDefinitionFor(languageId, wordPattern);
		} else {
			this._documents.setWordDefinitionFor(languageId, null);
		}
1138

1139
		const handle = this._nextHandle();
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
		const serializedConfiguration: ISerializedLanguageConfiguration = {
			comments: configuration.comments,
			brackets: configuration.brackets,
			wordPattern: ExtHostLanguageFeatures._serializeRegExp(configuration.wordPattern),
			indentationRules: ExtHostLanguageFeatures._serializeIndentationRule(configuration.indentationRules),
			onEnterRules: ExtHostLanguageFeatures._serializeOnEnterRules(configuration.onEnterRules),
			__electricCharacterSupport: configuration.__electricCharacterSupport,
			__characterPairSupport: configuration.__characterPairSupport,
		};
		this._proxy.$setLanguageConfiguration(handle, languageId, serializedConfiguration);
1150
		return this._createDisposable(handle);
1151
	}
1152
}