extHostTypeConverters.ts 13.9 KB
Newer Older
E
Erich Gamma 已提交
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 { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
E
Erich Gamma 已提交
8
import Severity from 'vs/base/common/severity';
9 10 11
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IDisposable } from 'vs/base/common/lifecycle';
import { stringDiff } from 'vs/base/common/diff/diff';
12
import * as modes from 'vs/editor/common/modes';
13
import * as types from './extHostTypes';
14
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
15
import { IPosition, ISelection, IRange, IDecorationOptions, ISingleEditOperation } from 'vs/editor/common/editorCommon';
16
import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search';
J
Johannes Rieken 已提交
17
import * as vscode from 'vscode';
18
import URI from 'vs/base/common/uri';
19
import { SaveReason } from 'vs/workbench/parts/files/common/files';
E
Erich Gamma 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

export interface PositionLike {
	line: number;
	character: number;
}

export interface RangeLike {
	start: PositionLike;
	end: PositionLike;
}

export interface SelectionLike extends RangeLike {
	anchor: PositionLike;
	active: PositionLike;
}

36
export function toSelection(selection: ISelection): types.Selection {
E
Erich Gamma 已提交
37
	let {selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn} = selection;
38 39 40
	let start = new types.Position(selectionStartLineNumber - 1, selectionStartColumn - 1);
	let end = new types.Position(positionLineNumber - 1, positionColumn - 1);
	return new types.Selection(start, end);
E
Erich Gamma 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
}

export function fromSelection(selection: SelectionLike): ISelection {
	let {anchor, active} = selection;
	return {
		selectionStartLineNumber: anchor.line + 1,
		selectionStartColumn: anchor.character + 1,
		positionLineNumber: active.line + 1,
		positionColumn: active.character + 1
	};
}

export function fromRange(range: RangeLike): IRange {
	let {start, end} = range;
	return {
		startLineNumber: start.line + 1,
		startColumn: start.character + 1,
		endLineNumber: end.line + 1,
		endColumn: end.character + 1
	};
}

63
export function toRange(range: IRange): types.Range {
E
Erich Gamma 已提交
64
	let {startLineNumber, startColumn, endLineNumber, endColumn} = range;
65
	return new types.Range(startLineNumber - 1, startColumn - 1, endLineNumber - 1, endColumn - 1);
E
Erich Gamma 已提交
66 67
}

68 69
export function toPosition(position: IPosition): types.Position {
	return new types.Position(position.lineNumber - 1, position.column - 1);
E
Erich Gamma 已提交
70 71
}

72 73
export function fromPosition(position: types.Position): IPosition {
	return { lineNumber: position.line + 1, column: position.character + 1 };
74 75
}

E
Erich Gamma 已提交
76 77
export function fromDiagnosticSeverity(value: number): Severity {
	switch (value) {
78
		case types.DiagnosticSeverity.Error:
E
Erich Gamma 已提交
79
			return Severity.Error;
80
		case types.DiagnosticSeverity.Warning:
E
Erich Gamma 已提交
81
			return Severity.Warning;
82
		case types.DiagnosticSeverity.Information:
E
Erich Gamma 已提交
83
			return Severity.Info;
84
		case types.DiagnosticSeverity.Hint:
E
Erich Gamma 已提交
85 86 87 88 89
			return Severity.Ignore;
	}
	return Severity.Error;
}

90
export function toDiagnosticSeverty(value: Severity): types.DiagnosticSeverity {
E
Erich Gamma 已提交
91 92
	switch (value) {
		case Severity.Info:
93
			return types.DiagnosticSeverity.Information;
E
Erich Gamma 已提交
94
		case Severity.Warning:
95
			return types.DiagnosticSeverity.Warning;
E
Erich Gamma 已提交
96
		case Severity.Error:
97
			return types.DiagnosticSeverity.Error;
E
Erich Gamma 已提交
98
		case Severity.Ignore:
99
			return types.DiagnosticSeverity.Hint;
E
Erich Gamma 已提交
100
	}
101
	return types.DiagnosticSeverity.Error;
E
Erich Gamma 已提交
102 103 104 105 106 107
}

export function fromViewColumn(column?: vscode.ViewColumn): EditorPosition {
	let editorColumn = EditorPosition.LEFT;
	if (typeof column !== 'number') {
		// stick with LEFT
108
	} else if (column === <number>types.ViewColumn.Two) {
E
Erich Gamma 已提交
109
		editorColumn = EditorPosition.CENTER;
110
	} else if (column === <number>types.ViewColumn.Three) {
E
Erich Gamma 已提交
111 112 113 114 115
		editorColumn = EditorPosition.RIGHT;
	}
	return editorColumn;
}

116 117 118 119 120
export function toViewColumn(position?: EditorPosition): vscode.ViewColumn {
	if (typeof position !== 'number') {
		return;
	}
	if (position === EditorPosition.LEFT) {
121
		return <number>types.ViewColumn.One;
122
	} else if (position === EditorPosition.CENTER) {
123
		return <number>types.ViewColumn.Two;
124
	} else if (position === EditorPosition.RIGHT) {
125
		return <number>types.ViewColumn.Three;
126 127
	}
}
E
Erich Gamma 已提交
128

M
Martin Aeschlimann 已提交
129
function isDecorationOptions(something: any): something is vscode.DecorationOptions {
130
	return (typeof something.range !== 'undefined');
E
Erich Gamma 已提交
131 132
}

133
function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOptions[]): something is vscode.DecorationOptions[] {
E
Erich Gamma 已提交
134 135 136
	if (something.length === 0) {
		return true;
	}
M
Martin Aeschlimann 已提交
137
	return isDecorationOptions(something[0]) ? true : false;
E
Erich Gamma 已提交
138 139
}

140
export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.DecorationOptions[]): IDecorationOptions[] {
M
Martin Aeschlimann 已提交
141 142
	if (isDecorationOptionsArr(ranges)) {
		return ranges.map((r): IDecorationOptions => {
E
Erich Gamma 已提交
143 144
			return {
				range: fromRange(r.range),
145
				hoverMessage: r.hoverMessage,
146
				renderOptions: r.renderOptions
E
Erich Gamma 已提交
147 148 149
			};
		});
	} else {
M
Martin Aeschlimann 已提交
150
		return ranges.map((r): IDecorationOptions => {
E
Erich Gamma 已提交
151 152
			return {
				range: fromRange(r)
B
Benjamin Pasero 已提交
153
			};
E
Erich Gamma 已提交
154 155 156
		});
	}
}
157

158
export const TextEdit = {
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

	minimalEditOperations(edits: vscode.TextEdit[], document: vscode.TextDocument, beforeDocumentVersion: number): ISingleEditOperation[] {

		// document has changed in the meantime and we shouldn't do
		// offset math as it's likely to be all wrong
		if (document.version !== beforeDocumentVersion) {
			return edits.map(TextEdit.from);
		}

		const result: ISingleEditOperation[] = [];

		for (let edit of edits) {

			const original = document.getText(edit.range);
			const modified = edit.newText;
			const changes = stringDiff(original, modified);

			if (changes.length <= 1) {
				result.push(TextEdit.from(edit));
				continue;
			}

181 182
			const editOffset = document.offsetAt(edit.range.start);

183 184
			for (let j = 0; j < changes.length; j++) {
				const {originalStart, originalLength, modifiedStart, modifiedLength} = changes[j];
185 186
				const start = fromPosition(<types.Position>document.positionAt(editOffset + originalStart));
				const end = fromPosition(<types.Position>document.positionAt(editOffset + originalStart + originalLength));
187 188 189 190 191 192 193 194 195 196 197

				result.push({
					text: modified.substr(modifiedStart, modifiedLength),
					range: { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column }
				});
			}
		}

		return result;
	},

198
	from(edit: vscode.TextEdit): ISingleEditOperation {
199 200 201
		return <ISingleEditOperation>{
			text: edit.newText,
			range: fromRange(edit.range)
B
Benjamin Pasero 已提交
202
		};
203 204 205
	},
	to(edit: ISingleEditOperation): vscode.TextEdit {
		return new types.TextEdit(toRange(edit.range), edit.text);
206
	}
B
Benjamin Pasero 已提交
207
};
208

209 210
export namespace SymbolInformation {

211 212 213 214 215 216 217 218
	export function fromOutlineEntry(entry: modes.SymbolInformation): types.SymbolInformation {
		return new types.SymbolInformation(
			entry.name,
			entry.kind,
			toRange(entry.location.range),
			entry.location.uri,
			entry.containerName
		);
219 220
	}

221 222 223 224 225 226 227 228 229
	export function toOutlineEntry(symbol: vscode.SymbolInformation): modes.SymbolInformation {
		return <modes.SymbolInformation>{
			name: symbol.name,
			kind: symbol.kind,
			containerName: symbol.containerName,
			location: {
				uri: <URI>symbol.location.uri,
				range: fromRange(symbol.location.range)
			}
230 231 232 233
		};
	}
}

234 235
export function fromSymbolInformation(info: vscode.SymbolInformation): IWorkspaceSymbol {
	return <IWorkspaceSymbol>{
236 237
		name: info.name,
		type: types.SymbolKind[info.kind || types.SymbolKind.Property].toLowerCase(),
238 239 240
		containerName: info.containerName,
		range: info.location && fromRange(info.location.range),
		resource: info.location && info.location.uri,
241 242 243
	};
}

244
export function toSymbolInformation(bearing: IWorkspaceSymbol): types.SymbolInformation {
245 246
	return new types.SymbolInformation(bearing.name,
		types.SymbolKind[bearing.type.charAt(0).toUpperCase() + bearing.type.substr(1)],
247 248 249
		bearing.containerName,
		new types.Location(bearing.resource, toRange(bearing.range))
	);
250 251 252
}


253
export const location = {
254
	from(value: types.Location): modes.Location {
255 256
		return {
			range: fromRange(value.range),
257
			uri: value.uri
J
Johannes Rieken 已提交
258
		};
259
	},
260 261
	to(value: modes.Location): types.Location {
		return new types.Location(value.uri, toRange(value.range));
262
	}
J
Johannes Rieken 已提交
263
};
264

265 266
export function fromHover(hover: vscode.Hover): modes.Hover {
	return <modes.Hover>{
267
		range: fromRange(hover.range),
268
		contents: hover.contents
B
Benjamin Pasero 已提交
269
	};
270 271
}

272
export function toHover(info: modes.Hover): types.Hover {
273
	return new types.Hover(info.contents, toRange(info.range));
274 275
}

276 277
export function toDocumentHighlight(occurrence: modes.DocumentHighlight): types.DocumentHighlight {
	return new types.DocumentHighlight(toRange(occurrence.range), occurrence.kind);
278 279
}

J
Johannes Rieken 已提交
280 281 282 283
export const CompletionItemKind = {

	from(kind: types.CompletionItemKind): modes.SuggestionType {
		switch (kind) {
284
			case types.CompletionItemKind.Method: return 'method';
J
Johannes Rieken 已提交
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
			case types.CompletionItemKind.Function: return 'function';
			case types.CompletionItemKind.Constructor: return 'constructor';
			case types.CompletionItemKind.Field: return 'field';
			case types.CompletionItemKind.Variable: return 'variable';
			case types.CompletionItemKind.Class: return 'class';
			case types.CompletionItemKind.Interface: return 'interface';
			case types.CompletionItemKind.Module: return 'module';
			case types.CompletionItemKind.Property: return 'property';
			case types.CompletionItemKind.Unit: return 'unit';
			case types.CompletionItemKind.Value: return 'value';
			case types.CompletionItemKind.Enum: return 'enum';
			case types.CompletionItemKind.Keyword: return 'keyword';
			case types.CompletionItemKind.Snippet: return 'snippet';
			case types.CompletionItemKind.Text: return 'text';
			case types.CompletionItemKind.Color: return 'color';
			case types.CompletionItemKind.File: return 'file';
			case types.CompletionItemKind.Reference: return 'reference';
		}
303
		return 'property';
J
Johannes Rieken 已提交
304 305 306 307
	},

	to(type: modes.SuggestionType): types.CompletionItemKind {
		if (!type) {
308
			return types.CompletionItemKind.Property;
J
Johannes Rieken 已提交
309 310 311 312 313 314
		} else {
			return types.CompletionItemKind[type.charAt(0).toUpperCase() + type.substr(1)];
		}
	}
};

315 316
export const Suggest = {

317
	from(item: vscode.CompletionItem, disposables: IDisposable[]): modes.ISuggestion {
318
		const suggestion: modes.ISuggestion = {
319
			label: item.label || '<missing label>',
320
			insertText: item.insertText || item.label,
J
Johannes Rieken 已提交
321
			type: CompletionItemKind.from(item.kind),
322 323
			detail: item.detail,
			documentation: item.documentation,
324
			sortText: item.sortText,
325 326 327
			filterText: item.filterText,
			command: Command.from(item.command, disposables),
			additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TextEdit.from)
328
		};
329
		return suggestion;
330 331
	},

332
	to(container: modes.ISuggestResult, position: types.Position, suggestion: modes.ISuggestion): types.CompletionItem {
333
		const result = new types.CompletionItem(suggestion.label);
334
		result.insertText = suggestion.insertText;
J
Johannes Rieken 已提交
335
		result.kind = CompletionItemKind.to(suggestion.type);
336 337
		result.detail = suggestion.detail;
		result.documentation = suggestion.documentation;
338 339
		result.sortText = suggestion.sortText;
		result.filterText = suggestion.filterText;
340

M
Martin Aeschlimann 已提交
341 342 343 344
		let overwriteBefore = (typeof suggestion.overwriteBefore === 'number') ? suggestion.overwriteBefore : container.currentWord.length;
		let startPosition = new types.Position(position.line, Math.max(0, position.character - overwriteBefore));
		let endPosition = position;
		if (typeof suggestion.overwriteAfter === 'number') {
345 346 347
			endPosition = new types.Position(position.line, position.character + suggestion.overwriteAfter);
		}

348
		result.textEdit = types.TextEdit.replace(new types.Range(startPosition, endPosition), suggestion.insertText);
349 350
		return result;
	}
B
Benjamin Pasero 已提交
351
};
352

353 354
export namespace SignatureHelp {

355 356
	export function from(signatureHelp: types.SignatureHelp): modes.SignatureHelp {
		return signatureHelp;
357 358
	}

359 360
	export function to(hints: modes.SignatureHelp): types.SignatureHelp {
		return hints;
361
	}
J
Johannes Rieken 已提交
362 363
}

J
Johannes Rieken 已提交
364 365
export namespace DocumentLink {

366
	export function from(link: vscode.DocumentLink): modes.ILink {
J
Johannes Rieken 已提交
367 368
		return {
			range: fromRange(link.range),
369
			url: link.target && link.target.toString()
J
Johannes Rieken 已提交
370 371 372
		};
	}

373
	export function to(link: modes.ILink): vscode.DocumentLink {
374
		return new types.DocumentLink(toRange(link.range), link.url && URI.parse(link.url));
J
Johannes Rieken 已提交
375 376
	}
}
377 378 379

export namespace Command {

380
	const _delegateId = '_internal_delegate_command';
381 382 383
	const _cache: { [id: string]: vscode.Command } = Object.create(null);
	let _idPool = 1;

384
	export function initialize(commands: ExtHostCommands) {
385
		return commands.registerCommand(_delegateId, (id: string) => {
386 387 388 389 390 391 392 393 394
			const command = _cache[id];
			if (!command) {
				// handle already disposed delegations graceful
				return;
			}
			return commands.executeCommand(command.command, ...command.arguments);
		});
	}

A
Alex Dima 已提交
395
	export function from(command: vscode.Command, disposables: IDisposable[]): modes.Command {
396 397 398

		if (!command) {
			return;
J
Johannes Rieken 已提交
399 400
		}

A
Alex Dima 已提交
401
		const result = <modes.Command>{
402 403 404 405 406 407
			id: command.command,
			title: command.title
		};

		if (!isFalsyOrEmpty(command.arguments)) {

408 409 410 411 412
			// redirect to delegate command and store actual command
			const id = `delegate/${_idPool++}/for/${command.command}`;

			result.id = _delegateId;
			result.arguments = [id];
413 414
			_cache[id] = command;

415 416 417 418 419
			disposables.push({
				dispose() {
					delete _cache[id];
				}
			});
420 421 422 423 424
		}

		return result;
	}

A
Alex Dima 已提交
425
	export function to(command: modes.Command): vscode.Command {
426 427 428 429 430
		let result: vscode.Command;
		if (command.id === _delegateId) {
			let [key] = command.arguments;
			result = _cache[key];
		}
431 432
		if (!result) {
			result = {
J
Johannes Rieken 已提交
433
				command: command.id,
434
				title: command.title
J
Johannes Rieken 已提交
435
			};
J
Johannes Rieken 已提交
436
		}
437
		return result;
J
Johannes Rieken 已提交
438
	}
439
}
440 441 442 443 444 445

export namespace TextDocumentSaveReason {

	export function to(reason: SaveReason): vscode.TextDocumentSaveReason {
		switch (reason) {
			case SaveReason.AUTO:
446
				return types.TextDocumentSaveReason.AfterDelay;
447
			case SaveReason.EXPLICIT:
448
				return types.TextDocumentSaveReason.Manual;
449 450 451 452 453 454
			case SaveReason.FOCUS_CHANGE:
			case SaveReason.WINDOW_CHANGE:
				return types.TextDocumentSaveReason.FocusOut;
		}
	}
}