diff --git a/extensions/typescript/src/features/folderingProvider.ts b/extensions/typescript/src/features/folderingProvider.ts new file mode 100644 index 00000000000..2020731d61b --- /dev/null +++ b/extensions/typescript/src/features/folderingProvider.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +import * as Proto from '../protocol'; +import { ITypeScriptServiceClient } from '../typescriptService'; + +// TODO: forward declarations for private TS API. + +interface TextSpan { + start: number; + length: number; +} + +interface OutliningSpan { + textSpan: TextSpan; + hintSpan: TextSpan; + bannerText: string; + autoCollapse: boolean; +} + +interface OutliningSpansRequestArgs extends Proto.FileRequestArgs { } + +interface OutliningSpansResponse extends Proto.Response { + body?: OutliningSpan[]; +} + +export default class TypeScriptFoldingProvider implements vscode.FoldingProvider { + public constructor( + private readonly client: ITypeScriptServiceClient + ) { } + + async provideFoldingRanges( + document: vscode.TextDocument, + token: vscode.CancellationToken + ): Promise { + if (!this.client.apiVersion.has270Features()) { + return; + } + + const file = this.client.normalizePath(document.uri); + if (!file) { + return; + } + + const args: OutliningSpansRequestArgs = { file }; + const response: OutliningSpansResponse = await this.client.execute('outliningSpans', args, token); + if (!response || !response.body) { + return; + } + + return new vscode.FoldingRangeList(response.body.map(span => { + const start = document.positionAt(span.textSpan.start); + const end = document.positionAt(span.textSpan.start + span.textSpan.length); + + return new vscode.FoldingRange(start.line, end.line); + })); + } +} \ No newline at end of file diff --git a/extensions/typescript/src/languageProvider.ts b/extensions/typescript/src/languageProvider.ts index 57d7f7c127d..1c4b9e0361e 100644 --- a/extensions/typescript/src/languageProvider.ts +++ b/extensions/typescript/src/languageProvider.ts @@ -125,6 +125,11 @@ export default class LanguageProvider { this.disposables.push(languages.registerRenameProvider(selector, new (await import('./features/renameProvider')).default(client))); this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/quickFixProvider')).default(client, this.formattingOptionsManager, commandManager, this.diagnosticsManager))); this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, commandManager))); + + if (workspace.getConfiguration('typescript').get('enableExperimentalFolding', false)) { + this.disposables.push(languages.registerFoldingProvider(selector, new (await import('./features/folderingProvider')).default(client))); + } + this.registerVersionDependentProviders(); const cachedResponse = new CachedNavTreeResponse();