value: displayPartsToString()

in src/typescript/languageFeatures.ts [657:1132]


						value: displayPartsToString(p.documentation)
					}
				};
				signature.label += label;
				signature.parameters.push(parameter);
				if (i < a.length - 1) {
					signature.label += displayPartsToString(item.separatorDisplayParts);
				}
			});
			signature.label += displayPartsToString(item.suffixDisplayParts);
			ret.signatures.push(signature);
		});

		return {
			value: ret,
			dispose() {}
		};
	}
}

// --- hover ------

export class QuickInfoAdapter extends Adapter implements languages.HoverProvider {
	public async provideHover(
		model: editor.ITextModel,
		position: Position,
		token: CancellationToken
	): Promise<languages.Hover | undefined> {
		const resource = model.uri;
		const offset = model.getOffsetAt(position);
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const info = await worker.getQuickInfoAtPosition(resource.toString(), offset);

		if (!info || model.isDisposed()) {
			return;
		}

		const documentation = displayPartsToString(info.documentation);
		const tags = info.tags ? info.tags.map((tag) => tagToString(tag)).join('  \n\n') : '';
		const contents = displayPartsToString(info.displayParts);
		return {
			range: this._textSpanToRange(model, info.textSpan),
			contents: [
				{
					value: '```typescript\n' + contents + '\n```\n'
				},
				{
					value: documentation + (tags ? '\n\n' + tags : '')
				}
			]
		};
	}
}

// --- occurrences ------

export class OccurrencesAdapter extends Adapter implements languages.DocumentHighlightProvider {
	public async provideDocumentHighlights(
		model: editor.ITextModel,
		position: Position,
		token: CancellationToken
	): Promise<languages.DocumentHighlight[] | undefined> {
		const resource = model.uri;
		const offset = model.getOffsetAt(position);
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const entries = await worker.getOccurrencesAtPosition(resource.toString(), offset);

		if (!entries || model.isDisposed()) {
			return;
		}

		return entries.map((entry) => {
			return <languages.DocumentHighlight>{
				range: this._textSpanToRange(model, entry.textSpan),
				kind: entry.isWriteAccess
					? languages.DocumentHighlightKind.Write
					: languages.DocumentHighlightKind.Text
			};
		});
	}
}

// --- definition ------

export class DefinitionAdapter extends Adapter {
	constructor(
		private readonly _libFiles: LibFiles,
		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
	) {
		super(worker);
	}

	public async provideDefinition(
		model: editor.ITextModel,
		position: Position,
		token: CancellationToken
	): Promise<languages.Definition | undefined> {
		const resource = model.uri;
		const offset = model.getOffsetAt(position);
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const entries = await worker.getDefinitionAtPosition(resource.toString(), offset);

		if (!entries || model.isDisposed()) {
			return;
		}

		// Fetch lib files if necessary
		await this._libFiles.fetchLibFilesIfNecessary(
			entries.map((entry) => Uri.parse(entry.fileName))
		);

		if (model.isDisposed()) {
			return;
		}

		const result: languages.Location[] = [];
		for (let entry of entries) {
			const refModel = this._libFiles.getOrCreateModel(entry.fileName);
			if (refModel) {
				result.push({
					uri: refModel.uri,
					range: this._textSpanToRange(refModel, entry.textSpan)
				});
			}
		}
		return result;
	}
}

// --- references ------

export class ReferenceAdapter extends Adapter implements languages.ReferenceProvider {
	constructor(
		private readonly _libFiles: LibFiles,
		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
	) {
		super(worker);
	}

	public async provideReferences(
		model: editor.ITextModel,
		position: Position,
		context: languages.ReferenceContext,
		token: CancellationToken
	): Promise<languages.Location[] | undefined> {
		const resource = model.uri;
		const offset = model.getOffsetAt(position);
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const entries = await worker.getReferencesAtPosition(resource.toString(), offset);

		if (!entries || model.isDisposed()) {
			return;
		}

		// Fetch lib files if necessary
		await this._libFiles.fetchLibFilesIfNecessary(
			entries.map((entry) => Uri.parse(entry.fileName))
		);

		if (model.isDisposed()) {
			return;
		}

		const result: languages.Location[] = [];
		for (let entry of entries) {
			const refModel = this._libFiles.getOrCreateModel(entry.fileName);
			if (refModel) {
				result.push({
					uri: refModel.uri,
					range: this._textSpanToRange(refModel, entry.textSpan)
				});
			}
		}
		return result;
	}
}

// --- outline ------

export class OutlineAdapter extends Adapter implements languages.DocumentSymbolProvider {
	public async provideDocumentSymbols(
		model: editor.ITextModel,
		token: CancellationToken
	): Promise<languages.DocumentSymbol[] | undefined> {
		const resource = model.uri;
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const items = await worker.getNavigationBarItems(resource.toString());

		if (!items || model.isDisposed()) {
			return;
		}

		const convert = (
			bucket: languages.DocumentSymbol[],
			item: ts.NavigationBarItem,
			containerLabel?: string
		): void => {
			let result: languages.DocumentSymbol = {
				name: item.text,
				detail: '',
				kind: <languages.SymbolKind>(outlineTypeTable[item.kind] || languages.SymbolKind.Variable),
				range: this._textSpanToRange(model, item.spans[0]),
				selectionRange: this._textSpanToRange(model, item.spans[0]),
				tags: []
			};

			if (containerLabel) result.containerName = containerLabel;

			if (item.childItems && item.childItems.length > 0) {
				for (let child of item.childItems) {
					convert(bucket, child, result.name);
				}
			}

			bucket.push(result);
		};

		let result: languages.DocumentSymbol[] = [];
		items.forEach((item) => convert(result, item));
		return result;
	}
}

export class Kind {
	public static unknown: string = '';
	public static keyword: string = 'keyword';
	public static script: string = 'script';
	public static module: string = 'module';
	public static class: string = 'class';
	public static interface: string = 'interface';
	public static type: string = 'type';
	public static enum: string = 'enum';
	public static variable: string = 'var';
	public static localVariable: string = 'local var';
	public static function: string = 'function';
	public static localFunction: string = 'local function';
	public static memberFunction: string = 'method';
	public static memberGetAccessor: string = 'getter';
	public static memberSetAccessor: string = 'setter';
	public static memberVariable: string = 'property';
	public static constructorImplementation: string = 'constructor';
	public static callSignature: string = 'call';
	public static indexSignature: string = 'index';
	public static constructSignature: string = 'construct';
	public static parameter: string = 'parameter';
	public static typeParameter: string = 'type parameter';
	public static primitiveType: string = 'primitive type';
	public static label: string = 'label';
	public static alias: string = 'alias';
	public static const: string = 'const';
	public static let: string = 'let';
	public static warning: string = 'warning';
}

let outlineTypeTable: {
	[kind: string]: languages.SymbolKind;
} = Object.create(null);
outlineTypeTable[Kind.module] = languages.SymbolKind.Module;
outlineTypeTable[Kind.class] = languages.SymbolKind.Class;
outlineTypeTable[Kind.enum] = languages.SymbolKind.Enum;
outlineTypeTable[Kind.interface] = languages.SymbolKind.Interface;
outlineTypeTable[Kind.memberFunction] = languages.SymbolKind.Method;
outlineTypeTable[Kind.memberVariable] = languages.SymbolKind.Property;
outlineTypeTable[Kind.memberGetAccessor] = languages.SymbolKind.Property;
outlineTypeTable[Kind.memberSetAccessor] = languages.SymbolKind.Property;
outlineTypeTable[Kind.variable] = languages.SymbolKind.Variable;
outlineTypeTable[Kind.const] = languages.SymbolKind.Variable;
outlineTypeTable[Kind.localVariable] = languages.SymbolKind.Variable;
outlineTypeTable[Kind.variable] = languages.SymbolKind.Variable;
outlineTypeTable[Kind.function] = languages.SymbolKind.Function;
outlineTypeTable[Kind.localFunction] = languages.SymbolKind.Function;

// --- formatting ----

export abstract class FormatHelper extends Adapter {
	protected static _convertOptions(options: languages.FormattingOptions): ts.FormatCodeOptions {
		return {
			ConvertTabsToSpaces: options.insertSpaces,
			TabSize: options.tabSize,
			IndentSize: options.tabSize,
			IndentStyle: IndentStyle.Smart,
			NewLineCharacter: '\n',
			InsertSpaceAfterCommaDelimiter: true,
			InsertSpaceAfterSemicolonInForStatements: true,
			InsertSpaceBeforeAndAfterBinaryOperators: true,
			InsertSpaceAfterKeywordsInControlFlowStatements: true,
			InsertSpaceAfterFunctionKeywordForAnonymousFunctions: true,
			InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
			InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
			InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
			PlaceOpenBraceOnNewLineForControlBlocks: false,
			PlaceOpenBraceOnNewLineForFunctions: false
		};
	}

	protected _convertTextChanges(
		model: editor.ITextModel,
		change: ts.TextChange
	): languages.TextEdit {
		return {
			text: change.newText,
			range: this._textSpanToRange(model, change.span)
		};
	}
}

export class FormatAdapter
	extends FormatHelper
	implements languages.DocumentRangeFormattingEditProvider
{
	public async provideDocumentRangeFormattingEdits(
		model: editor.ITextModel,
		range: Range,
		options: languages.FormattingOptions,
		token: CancellationToken
	): Promise<languages.TextEdit[] | undefined> {
		const resource = model.uri;
		const startOffset = model.getOffsetAt({
			lineNumber: range.startLineNumber,
			column: range.startColumn
		});
		const endOffset = model.getOffsetAt({
			lineNumber: range.endLineNumber,
			column: range.endColumn
		});
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const edits = await worker.getFormattingEditsForRange(
			resource.toString(),
			startOffset,
			endOffset,
			FormatHelper._convertOptions(options)
		);

		if (!edits || model.isDisposed()) {
			return;
		}

		return edits.map((edit) => this._convertTextChanges(model, edit));
	}
}

export class FormatOnTypeAdapter
	extends FormatHelper
	implements languages.OnTypeFormattingEditProvider
{
	get autoFormatTriggerCharacters() {
		return [';', '}', '\n'];
	}

	public async provideOnTypeFormattingEdits(
		model: editor.ITextModel,
		position: Position,
		ch: string,
		options: languages.FormattingOptions,
		token: CancellationToken
	): Promise<languages.TextEdit[] | undefined> {
		const resource = model.uri;
		const offset = model.getOffsetAt(position);
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const edits = await worker.getFormattingEditsAfterKeystroke(
			resource.toString(),
			offset,
			ch,
			FormatHelper._convertOptions(options)
		);

		if (!edits || model.isDisposed()) {
			return;
		}

		return edits.map((edit) => this._convertTextChanges(model, edit));
	}
}

// --- code actions ------

export class CodeActionAdaptor extends FormatHelper implements languages.CodeActionProvider {
	public async provideCodeActions(
		model: editor.ITextModel,
		range: Range,
		context: languages.CodeActionContext,
		token: CancellationToken
	): Promise<languages.CodeActionList | undefined> {
		const resource = model.uri;
		const start = model.getOffsetAt({
			lineNumber: range.startLineNumber,
			column: range.startColumn
		});
		const end = model.getOffsetAt({
			lineNumber: range.endLineNumber,
			column: range.endColumn
		});
		const formatOptions = FormatHelper._convertOptions(model.getOptions());
		const errorCodes = context.markers
			.filter((m) => m.code)
			.map((m) => m.code)
			.map(Number);
		const worker = await this._worker(resource);

		if (model.isDisposed()) {
			return;
		}

		const codeFixes = await worker.getCodeFixesAtPosition(
			resource.toString(),
			start,
			end,
			errorCodes,
			formatOptions
		);

		if (!codeFixes || model.isDisposed()) {
			return { actions: [], dispose: () => {} };
		}

		const actions = codeFixes
			.filter((fix) => {
				// Removes any 'make a new file'-type code fix
				return fix.changes.filter((change) => change.isNewFile).length === 0;
			})
			.map((fix) => {
				return this._tsCodeFixActionToMonacoCodeAction(model, context, fix);
			});

		return {
			actions: actions,
			dispose: () => {}
		};
	}

	private _tsCodeFixActionToMonacoCodeAction(
		model: editor.ITextModel,
		context: languages.CodeActionContext,
		codeFix: ts.CodeFixAction
	): languages.CodeAction {
		const edits: languages.WorkspaceTextEdit[] = [];
		for (const change of codeFix.changes) {
			for (const textChange of change.textChanges) {
				edits.push({
					resource: model.uri,
					edit: {