diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index ac1a1b7493e..c03c44b6cd6 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, window, commands, ExtensionContext, Range, Position, TextDocument, CompletionItem, CompletionItemKind, TextEdit, SnippetString, FoldingRangeList, FoldingRange, FoldingContext, CancellationToken } from 'vscode'; +import { languages, window, commands, ExtensionContext, Range, Position, TextDocument, CompletionItem, CompletionItemKind, TextEdit, SnippetString, FoldingRangeKind, FoldingRange, FoldingContext, CancellationToken } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Disposable } from 'vscode-languageclient'; import { FoldingRangeRequest, FoldingRangeRequestParam, FoldingRangeClientCapabilities } from 'vscode-languageserver-protocol-foldingprovider'; @@ -117,14 +117,26 @@ export function activate(context: ExtensionContext) { } function initFoldingProvider(): Disposable { - return languages.registerFoldingProvider(documentSelector, { + const kinds: { [value: string]: FoldingRangeKind } = Object.create(null); + function getKind(value: string | undefined) { + if (!value) { + return void 0; + } + let kind = kinds[value]; + if (!kind) { + kind = new FoldingRangeKind(value); + kinds[value] = kind; + } + return kind; + } + return languages.registerFoldingRangeProvider(documentSelector, { provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { const param: FoldingRangeRequestParam = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) }; return client.sendRequest(FoldingRangeRequest.type, param, token).then(ranges => { if (Array.isArray(ranges)) { - return new FoldingRangeList(ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.kind))); + return ranges.map(r => new FoldingRange(r.startLine, r.endLine, getKind(r.kind))); } return null; }, error => { diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 1cde186c175..6e25547a896 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, FoldingRangeList, FoldingRange, FoldingContext } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, FoldingRangeKind, FoldingRange, FoldingContext } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams, Disposable, CancellationToken } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; @@ -174,14 +174,26 @@ export function activate(context: ExtensionContext) { }); function initFoldingProvider(): Disposable { - return languages.registerFoldingProvider(documentSelector, { + const kinds: { [value: string]: FoldingRangeKind } = Object.create(null); + function getKind(value: string | undefined) { + if (!value) { + return void 0; + } + let kind = kinds[value]; + if (!kind) { + kind = new FoldingRangeKind(value); + kinds[value] = kind; + } + return kind; + } + return languages.registerFoldingRangeProvider(documentSelector, { provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { const param: FoldingRangeRequestParam = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) }; return client.sendRequest(FoldingRangeRequest.type, param, token).then(ranges => { if (Array.isArray(ranges)) { - return new FoldingRangeList(ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.kind))); + return ranges.map(r => new FoldingRange(r.startLine, r.endLine, getKind(r.kind))); } return null; }, error => { diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index ee895024bae..53c19c4c22f 100644 --- a/extensions/json-language-features/client/src/jsonMain.ts +++ b/extensions/json-language-features/client/src/jsonMain.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { workspace, languages, ExtensionContext, extensions, Uri, LanguageConfiguration, TextDocument, FoldingRangeList, FoldingRange, Disposable, FoldingContext } from 'vscode'; +import { workspace, languages, ExtensionContext, extensions, Uri, LanguageConfiguration, TextDocument, FoldingRangeKind, FoldingRange, Disposable, FoldingContext } from 'vscode'; import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, CancellationToken } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; @@ -156,14 +156,26 @@ export function activate(context: ExtensionContext) { languages.setLanguageConfiguration('jsonc', languageConfiguration); function initFoldingProvider(): Disposable { - return languages.registerFoldingProvider(documentSelector, { + const kinds: { [value: string]: FoldingRangeKind } = Object.create(null); + function getKind(value: string | undefined) { + if (!value) { + return void 0; + } + let kind = kinds[value]; + if (!kind) { + kind = new FoldingRangeKind(value); + kinds[value] = kind; + } + return kind; + } + return languages.registerFoldingRangeProvider(documentSelector, { provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken) { const param: FoldingRangeRequestParam = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) }; return client.sendRequest(FoldingRangeRequest.type, param, token).then(ranges => { if (Array.isArray(ranges)) { - return new FoldingRangeList(ranges.map(r => new FoldingRange(r.startLine, r.endLine, r.kind))); + return ranges.map(r => new FoldingRange(r.startLine, r.endLine, getKind(r.kind))); } return null; }, error => { diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index 6bac15639fb..e260737797b 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -39,7 +39,7 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider)); context.subscriptions.push(vscode.languages.registerDocumentLinkProvider(selector, new LinkProvider())); - context.subscriptions.push(vscode.languages.registerFoldingProvider(selector, new MarkdownFoldingProvider(engine))); + context.subscriptions.push(vscode.languages.registerFoldingRangeProvider(selector, new MarkdownFoldingProvider(engine))); context.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(new MarkdownWorkspaceSymbolProvider(symbolProvider))); const previewSecuritySelector = new PreviewSecuritySelector(cspArbiter, previewManager); diff --git a/extensions/markdown-language-features/src/features/foldingProvider.ts b/extensions/markdown-language-features/src/features/foldingProvider.ts index 637cdb11d14..236908a1f1f 100644 --- a/extensions/markdown-language-features/src/features/foldingProvider.ts +++ b/extensions/markdown-language-features/src/features/foldingProvider.ts @@ -8,7 +8,9 @@ import * as vscode from 'vscode'; import { MarkdownEngine } from '../markdownEngine'; import { TableOfContentsProvider } from '../tableOfContentsProvider'; -export default class MarkdownFoldingProvider implements vscode.FoldingProvider { +const rangeLimit = 5000; + +export default class MarkdownFoldingProvider implements vscode.FoldingRangeProvider { constructor( private readonly engine: MarkdownEngine @@ -16,13 +18,13 @@ export default class MarkdownFoldingProvider implements vscode.FoldingProvider { public async provideFoldingRanges( document: vscode.TextDocument, - context: vscode.FoldingContext, + _: vscode.FoldingContext, _token: vscode.CancellationToken - ): Promise { + ): Promise { const tocProvider = new TableOfContentsProvider(this.engine, document); let toc = await tocProvider.getToc(); - if (context.maxRanges && toc.length > context.maxRanges) { - toc = toc.slice(0, context.maxRanges); + if (toc.length > rangeLimit) { + toc = toc.slice(0, rangeLimit); } const foldingRanges = toc.map((entry, startIndex) => { @@ -43,6 +45,6 @@ export default class MarkdownFoldingProvider implements vscode.FoldingProvider { }); - return new vscode.FoldingRangeList(foldingRanges); + return foldingRanges; } } \ No newline at end of file diff --git a/extensions/markdown-language-features/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts index 5095bcbbed0..44c570d64d4 100644 --- a/extensions/markdown-language-features/src/test/foldingProvider.test.ts +++ b/extensions/markdown-language-features/src/test/foldingProvider.test.ts @@ -16,7 +16,7 @@ const testFileName = vscode.Uri.parse('test.md'); suite('markdown.FoldingProvider', () => { test('Should not return anything for empty document', async () => { const folds = await getFoldsForDocument(``); - assert.strictEqual(folds.ranges.length, 0); + assert.strictEqual(folds.length, 0); }); test('Should not return anything for document without headers', async () => { @@ -24,7 +24,7 @@ suite('markdown.FoldingProvider', () => { **b** afas a#b a`); - assert.strictEqual(folds.ranges.length, 0); + assert.strictEqual(folds.length, 0); }); test('Should fold from header to end of document', async () => { @@ -32,10 +32,10 @@ a`); # b c d`); - assert.strictEqual(folds.ranges.length, 1); - const firstFold = folds.ranges[0]; - assert.strictEqual(firstFold.startLine, 1); - assert.strictEqual(firstFold.endLine, 3); + assert.strictEqual(folds.length, 1); + const firstFold = folds[0]; + assert.strictEqual(firstFold.start, 1); + assert.strictEqual(firstFold.end, 3); }); test('Should leave single newline before next header', async () => { @@ -45,10 +45,10 @@ x # b y`); - assert.strictEqual(folds.ranges.length, 2); - const firstFold = folds.ranges[0]; - assert.strictEqual(firstFold.startLine, 1); - assert.strictEqual(firstFold.endLine, 3); + assert.strictEqual(folds.length, 2); + const firstFold = folds[0]; + assert.strictEqual(firstFold.start, 1); + assert.strictEqual(firstFold.end, 3); }); test('Should collapse multuple newlines to single newline before next header', async () => { @@ -60,10 +60,10 @@ x # b y`); - assert.strictEqual(folds.ranges.length, 2); - const firstFold = folds.ranges[0]; - assert.strictEqual(firstFold.startLine, 1); - assert.strictEqual(firstFold.endLine, 5); + assert.strictEqual(folds.length, 2); + const firstFold = folds[0]; + assert.strictEqual(firstFold.start, 1); + assert.strictEqual(firstFold.end, 5); }); test('Should not collapse if there is no newline before next header', async () => { @@ -72,10 +72,10 @@ y`); x # b y`); - assert.strictEqual(folds.ranges.length, 2); - const firstFold = folds.ranges[0]; - assert.strictEqual(firstFold.startLine, 1); - assert.strictEqual(firstFold.endLine, 2); + assert.strictEqual(folds.length, 2); + const firstFold = folds[0]; + assert.strictEqual(firstFold.start, 1); + assert.strictEqual(firstFold.end, 2); }); }); diff --git a/extensions/typescript-language-features/src/features/foldingProvider.ts b/extensions/typescript-language-features/src/features/foldingProvider.ts index b5ad3d23199..20c1ec40647 100644 --- a/extensions/typescript-language-features/src/features/foldingProvider.ts +++ b/extensions/typescript-language-features/src/features/foldingProvider.ts @@ -9,7 +9,7 @@ import * as Proto from '../protocol'; import * as typeConverters from '../utils/typeConverters'; import { ITypeScriptServiceClient } from '../typescriptService'; -export default class TypeScriptFoldingProvider implements vscode.FoldingProvider { +export default class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider { public constructor( private readonly client: ITypeScriptServiceClient ) { } @@ -18,7 +18,7 @@ export default class TypeScriptFoldingProvider implements vscode.FoldingProvider document: vscode.TextDocument, _context: vscode.FoldingContext, token: vscode.CancellationToken - ): Promise { + ): Promise { if (!this.client.apiVersion.has280Features()) { return; } @@ -34,13 +34,13 @@ export default class TypeScriptFoldingProvider implements vscode.FoldingProvider return; } - return new vscode.FoldingRangeList(response.body.map(span => { + return response.body.map(span => { const range = typeConverters.Range.fromTextSpan(span.textSpan); // workaround for #47240 if (range.end.character > 0 && document.getText(new vscode.Range(range.end.translate(0, -1), range.end)) === '}') { return new vscode.FoldingRange(range.start.line, Math.max(range.end.line - 1, range.start.line)); } return new vscode.FoldingRange(range.start.line, range.end.line); - })); + }); } } diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index 5efb11d5a63..f23c7fab620 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -159,7 +159,7 @@ export default class LanguageProvider { let enable = workspace.getConfiguration().get(foldingSetting, false); if (enable && this.client.apiVersion.has280Features()) { if (!this.foldingProviderRegistration) { - this.foldingProviderRegistration = languages.registerFoldingProvider(this.documentSelector, new (await import('./features/foldingProvider')).default(this.client)); + this.foldingProviderRegistration = languages.registerFoldingRangeProvider(this.documentSelector, new (await import('./features/foldingProvider')).default(this.client)); } } else { if (this.foldingProviderRegistration) { diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 46e81803edc..76d62264ebc 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -835,7 +835,6 @@ export interface DocumentColorProvider { * @internal */ export interface FoldingContext { - maxRanges?: number; } /** @@ -844,59 +843,61 @@ export interface FoldingContext { /** * @internal */ -export interface FoldingProvider { +export interface FoldingRangeProvider { /** * Provides the color ranges for a specific model. */ - provideFoldingRanges(model: model.ITextModel, context: FoldingContext, token: CancellationToken): IFoldingRangeList | Thenable; + provideFoldingRanges(model: model.ITextModel, context: FoldingContext, token: CancellationToken): IFoldingRange[] | Thenable; } -/** - * @internal - */ -export interface IFoldingRangeList { - ranges: IFoldingRange[]; -} /** * @internal */ export interface IFoldingRange { /** - * The start line number + * The zero-based start line of the range to fold. The folded area starts after the line's last character. */ - startLineNumber: number; + start: number; /** - * The end line number + * The zero-based end line of the range to fold. The folded area ends with the line's last character. */ - endLineNumber: number; + end: number; /** - * The optional type of the folding range + * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or + * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands + * like 'Fold all comments'. See + * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. */ - type?: FoldingRangeType | string; - - // auto-collapse - // header span - + kind?: FoldingRangeKind; } /** * @internal */ -export enum FoldingRangeType { +export class FoldingRangeKind { /** - * Folding range for a comment + * Kind for folding range representing a comment. The value of the kind is 'comment'. */ - Comment = 'comment', + static readonly Comment = new FoldingRangeKind('comment'); /** - * Folding range for a imports or includes + * Kind for folding range representing a import. The value of the kind is 'imports'. */ - Imports = 'imports', + static readonly Imports = new FoldingRangeKind('imports'); /** - * Folding range for a region (e.g. `#region`) + * Kind for folding range representing regions (for example marked by `#region`, `#endregion`). + * The value of the kind is 'region'. */ - Region = 'region' + static readonly Region = new FoldingRangeKind('region'); + + /** + * Creates a new [FoldingRangeKind](#FoldingRangeKind). + * + * @param value of the kind. + */ + public constructor(public value: string) { + } } /** @@ -1047,7 +1048,7 @@ export const ColorProviderRegistry = new LanguageFeatureRegistry(); +export const FoldingRangeProviderRegistry = new LanguageFeatureRegistry(); /** * @internal diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index e4237e2afd6..4d54fef449f 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -28,7 +28,7 @@ import { IRange } from 'vs/editor/common/core/range'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { IndentRangeProvider } from 'vs/editor/contrib/folding/indentRangeProvider'; import { IPosition } from 'vs/editor/common/core/position'; -import { FoldingProviderRegistry, FoldingRangeType } from 'vs/editor/common/modes'; +import { FoldingRangeProviderRegistry, FoldingRangeKind } from 'vs/editor/common/modes'; import { SyntaxRangeProvider } from './syntaxRangeProvider'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -82,7 +82,7 @@ export class FoldingController implements IEditorContribution { this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; this.globalToDispose.push(this.editor.onDidChangeModel(() => this.onModelChanged())); - this.globalToDispose.push(FoldingProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged())); + this.globalToDispose.push(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged())); this.globalToDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { if (e.contribInfo) { @@ -205,7 +205,7 @@ export class FoldingController implements IEditorContribution { private getRangeProvider(): RangeProvider { if (!this.rangeProvider) { if (this._useFoldingProviders) { - let foldingProviders = FoldingProviderRegistry.ordered(this.foldingModel.textModel); + let foldingProviders = FoldingRangeProviderRegistry.ordered(this.foldingModel.textModel); this.rangeProvider = foldingProviders.length ? new SyntaxRangeProvider(foldingProviders) : new IndentRangeProvider(); } else { this.rangeProvider = new IndentRangeProvider(); @@ -584,7 +584,7 @@ class FoldAllBlockCommentsAction extends FoldingAction { invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void { if (foldingModel.regions.hasTypes()) { - setCollapseStateForType(foldingModel, FoldingRangeType.Comment, true); + setCollapseStateForType(foldingModel, FoldingRangeKind.Comment.value, true); } else { let comments = LanguageConfigurationRegistry.getComments(editor.getModel().getLanguageIdentifier().id); if (comments && comments.blockCommentStartToken) { @@ -612,7 +612,7 @@ class FoldAllRegionsAction extends FoldingAction { invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void { if (foldingModel.regions.hasTypes()) { - setCollapseStateForType(foldingModel, FoldingRangeType.Region, true); + setCollapseStateForType(foldingModel, FoldingRangeKind.Region.value, true); } else { let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id); if (foldingRules && foldingRules.markers && foldingRules.markers.start) { @@ -640,7 +640,7 @@ class UnfoldAllRegionsAction extends FoldingAction { invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void { if (foldingModel.regions.hasTypes()) { - setCollapseStateForType(foldingModel, FoldingRangeType.Region, false); + setCollapseStateForType(foldingModel, FoldingRangeKind.Region.value, false); } else { let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id); if (foldingRules && foldingRules.markers && foldingRules.markers.start) { diff --git a/src/vs/editor/contrib/folding/syntaxRangeProvider.ts b/src/vs/editor/contrib/folding/syntaxRangeProvider.ts index 7d5d7447929..7131c02d583 100644 --- a/src/vs/editor/contrib/folding/syntaxRangeProvider.ts +++ b/src/vs/editor/contrib/folding/syntaxRangeProvider.ts @@ -5,7 +5,7 @@ 'use strict'; -import { FoldingProvider, IFoldingRange, FoldingContext } from 'vs/editor/common/modes'; +import { FoldingRangeProvider, IFoldingRange, FoldingContext } from 'vs/editor/common/modes'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { toThenable } from 'vs/base/common/async'; import { ITextModel } from 'vs/editor/common/model'; @@ -26,7 +26,7 @@ const foldingContext: FoldingContext = { export class SyntaxRangeProvider implements RangeProvider { - constructor(private providers: FoldingProvider[]) { + constructor(private providers: FoldingRangeProvider[]) { } compute(model: ITextModel, cancellationToken: CancellationToken): Thenable { @@ -41,23 +41,23 @@ export class SyntaxRangeProvider implements RangeProvider { } -function collectSyntaxRanges(providers: FoldingProvider[], model: ITextModel, cancellationToken: CancellationToken): Thenable { +function collectSyntaxRanges(providers: FoldingRangeProvider[], model: ITextModel, cancellationToken: CancellationToken): Thenable { let promises = providers.map(provider => toThenable(provider.provideFoldingRanges(model, foldingContext, cancellationToken))); - return TPromise.join(promises).then(lists => { + return TPromise.join(promises).then(results => { let rangeData: IFoldingRangeData[] = null; if (cancellationToken.isCancellationRequested) { return null; } - for (let i = 0; i < lists.length; i++) { - let list = lists[i]; - if (list && Array.isArray(list.ranges)) { + for (let i = 0; i < results.length; i++) { + let ranges = results[i]; + if (Array.isArray(ranges)) { if (!Array.isArray(rangeData)) { rangeData = []; } let nLines = model.getLineCount(); - for (let r of list.ranges) { - if (r.startLineNumber > 0 && r.endLineNumber > r.startLineNumber && r.endLineNumber <= nLines) { - rangeData.push({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, rank: i, type: r.type }); + for (let r of ranges) { + if (r.start > 0 && r.end > r.start && r.end <= nLines) { + rangeData.push({ start: r.start, end: r.end, rank: i, kind: r.kind }); } } } @@ -145,7 +145,7 @@ export class RangesCollector { export function sanitizeRanges(rangeData: IFoldingRangeData[]): FoldingRegions { let sorted = rangeData.sort((d1, d2) => { - let diff = d1.startLineNumber - d2.startLineNumber; + let diff = d1.start - d2.start; if (diff === 0) { diff = d1.rank - d2.rank; } @@ -158,20 +158,20 @@ export function sanitizeRanges(rangeData: IFoldingRangeData[]): FoldingRegions { for (let entry of sorted) { if (!top) { top = entry; - collector.add(entry.startLineNumber, entry.endLineNumber, entry.type, previous.length); + collector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length); } else { - if (entry.startLineNumber > top.startLineNumber) { - if (entry.endLineNumber <= top.endLineNumber) { + if (entry.start > top.start) { + if (entry.end <= top.end) { previous.push(top); top = entry; - collector.add(entry.startLineNumber, entry.endLineNumber, entry.type, previous.length); - } else if (entry.startLineNumber > top.endLineNumber) { + collector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length); + } else if (entry.start > top.end) { do { top = previous.pop(); - } while (top && entry.startLineNumber > top.endLineNumber); + } while (top && entry.start > top.end); previous.push(top); top = entry; - collector.add(entry.startLineNumber, entry.endLineNumber, entry.type, previous.length); + collector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length); } } } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 704e11b1a6b..24c7142a6d9 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -13,88 +13,104 @@ declare module 'vscode' { //#region Aeschli: folding - export class FoldingRangeList { - - /** - * The folding ranges. - */ - ranges: FoldingRange[]; - - /** - * Creates new folding range list. - * - * @param ranges The folding ranges - */ - constructor(ranges: FoldingRange[]); - } - - export class FoldingRange { /** - * The start line number (zero-based) of the range to fold. The hidden area starts after the last character of that line. + * The zero-based start line of the range to fold. The folded area starts after the line's last character. */ - startLine: number; + start: number; /** - * The end line number (0-based) of the range to fold. The hidden area ends at the last character of that line. + * The zero-based end line of the range to fold. The folded area ends with the line's last character. */ - endLine: number; + end: number; /** - * The actual color value for this color range. + * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or + * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands + * like 'Fold all comments'. See + * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. */ - type?: FoldingRangeType | string; + kind?: FoldingRangeKind; /** * Creates a new folding range. * - * @param startLineNumber The first line of the fold - * @param type The last line of the fold + * @param start The start line of the folded range. + * @param end The end line of the folded range. + * @param kind The kind of the folding range. */ - constructor(startLineNumber: number, endLineNumber: number, type?: FoldingRangeType | string); + constructor(start: number, end: number, kind?: FoldingRangeKind); } - export enum FoldingRangeType { + export class FoldingRangeKind { /** - * Folding range for a comment + * Kind for folding range representing a comment. The value of the kind is 'comment'. */ - Comment = 'comment', + static readonly Comment: FoldingRangeKind; /** - * Folding range for a imports or includes + * Kind for folding range representing a import. The value of the kind is 'imports'. */ - Imports = 'imports', + static readonly Imports: FoldingRangeKind; /** - * Folding range for a region (e.g. `#region`) + * Kind for folding range representing regions (for example a folding range marked by `#region` and `#endregion`). + * The value of the kind is 'region'. */ - Region = 'region' + static readonly Region: FoldingRangeKind; + /** + * String value of the kind, e.g. `comment`. + */ + readonly value: string; + /** + * Creates a new [FoldingRangeKind](#FoldingRangeKind). + * + * @param value of the kind. + */ + public constructor(value: string); } export namespace languages { /** - * Register a folding provider. + * Register a folding range provider. * * Multiple folding can be registered for a language. In that case providers are sorted * by their [score](#languages.match) and the best-matching provider is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. - * @param provider A folding provider. + * @param provider A folding range provider. + * @param metadata Metadata about the kind of code actions the provider providers. * @return A [disposable](#Disposable) that unregisters this provider when being disposed. */ - export function registerFoldingProvider(selector: DocumentSelector, provider: FoldingProvider): Disposable; + export function registerFoldingRangeProvider(selector: DocumentSelector, provider: FoldingRangeProvider, metadata?: FoldingRangeProviderMetadata): Disposable; } - export interface FoldingContext { - maxRanges?: number; - } - - export interface FoldingProvider { + /** + * Metadata about the kind of folding ranges that a [FoldingRangeProvider](#FoldingRangeProvider) providers uses. + */ + export interface FoldingRangeProviderMetadata { /** - * Returns a list of folding ranges or null if the provider does not want to participate or was cancelled. + * [FoldingRangeKind](#FoldingRangeKind) that this provider may return. */ - provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken): ProviderResult; + readonly providedFoldingRangeKinds?: ReadonlyArray; + } + + /** + * Folding context (for future use) + */ + export interface FoldingContext { + } + + export interface FoldingRangeProvider { + /** + * Returns a list of folding ranges or null and undefined if the provider + * does not want to participate or was cancelled. + * @param document The document in which the command was invoked. + * @param context Additional context information (for future use) + * @param token A cancellation token. + */ + provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken): ProviderResult; } //#endregion diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index edebb1a5bd2..34fb61eea6a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -349,9 +349,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- folding - $registerFoldingProvider(handle: number, selector: ISerializedDocumentFilter[]): void { + $registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void { const proxy = this._proxy; - this._registrations[handle] = modes.FoldingProviderRegistry.register(toLanguageSelector(selector), { + this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(toLanguageSelector(selector), { provideFoldingRanges: (model, context, token) => { return wireCancellationToken(token, proxy.$provideFoldingRanges(handle, model.uri, context)); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 02fe0073cfe..2790ad78549 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -328,8 +328,8 @@ export function createApiFactory( registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable { return extHostLanguageFeatures.registerColorProvider(checkSelector(selector), provider); }, - registerFoldingProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.FoldingProvider): vscode.Disposable => { - return extHostLanguageFeatures.registerFoldingProvider(checkSelector(selector), provider); + registerFoldingRangeProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable => { + return extHostLanguageFeatures.registerFoldingRangeProvider(checkSelector(selector), provider); }), setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => { return extHostLanguageFeatures.setLanguageConfiguration(language, configuration); @@ -714,9 +714,8 @@ export function createApiFactory( FileType2: extHostTypes.FileType2, FileOpenFlags: files.FileOpenFlags, FileError: files.FileError, - FoldingRangeList: extHostTypes.FoldingRangeList, FoldingRange: extHostTypes.FoldingRange, - FoldingRangeType: extHostTypes.FoldingRangeType + FoldingRangeKind: extHostTypes.FoldingRangeKind }; }; } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 42ef9f86a07..c21323c8c04 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -283,7 +283,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], triggerCharacter: string[]): void; $registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void; $registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void; - $registerFoldingProvider(handle: number, selector: ISerializedDocumentFilter[]): void; + $registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void; $setLanguageConfiguration(handle: number, languageId: string, configuration: ISerializedLanguageConfiguration): void; } @@ -723,7 +723,7 @@ export interface ExtHostLanguageFeaturesShape { $resolveDocumentLink(handle: number, link: modes.ILink): TPromise; $provideDocumentColors(handle: number, resource: UriComponents): TPromise; $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise; - $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext): TPromise; + $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext): TPromise; } export interface ExtHostQuickOpenShape { diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 8e0753d3df4..3d5e2fe57ad 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -817,16 +817,16 @@ class FoldingProviderAdapter { constructor( private _documents: ExtHostDocuments, - private _provider: vscode.FoldingProvider + private _provider: vscode.FoldingRangeProvider ) { } - provideFoldingRanges(resource: URI, context: modes.FoldingContext): TPromise { + provideFoldingRanges(resource: URI, context: modes.FoldingContext): TPromise { const doc = this._documents.getDocumentData(resource).document; - return asWinJsPromise(token => this._provider.provideFoldingRanges(doc, context, token)).then(list => { - if (!Array.isArray(list.ranges)) { + return asWinJsPromise(token => this._provider.provideFoldingRanges(doc, context, token)).then(ranges => { + if (!Array.isArray(ranges)) { return void 0; } - return TypeConverters.FoldingRangeList.from(list); + return ranges.map(TypeConverters.FoldingRange.from); }); } } @@ -1178,13 +1178,13 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo)); } - registerFoldingProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingProvider): vscode.Disposable { + registerFoldingRangeProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable { const handle = this._addNewAdapter(new FoldingProviderAdapter(this._documents, provider)); - this._proxy.$registerFoldingProvider(handle, this._transformDocumentSelector(selector)); + this._proxy.$registerFoldingRangeProvider(handle, this._transformDocumentSelector(selector)); return this._createDisposable(handle); } - $provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext): TPromise { + $provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext): TPromise { return this._withAdapter(handle, FoldingProviderAdapter, adapter => adapter.provideFoldingRanges(URI.revive(resource), context)); } diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 0f412156674..b77f77279db 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -623,11 +623,9 @@ export namespace ProgressLocation { } } -export namespace FoldingRangeList { - export function from(rangeList: vscode.FoldingRangeList): modes.IFoldingRangeList { - return { - ranges: rangeList.ranges.map(r => ({ startLineNumber: r.startLine + 1, endLineNumber: r.endLine + 1, type: r.type })) - }; +export namespace FoldingRange { + export function from(r: vscode.FoldingRange): modes.IFoldingRange { + return { start: r.start + 1, end: r.end + 1, kind: r.kind }; } } diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index d988a15447d..d4da587fb9e 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1841,43 +1841,43 @@ export enum FileType2 { //#region folding api -export class FoldingRangeList { - - ranges: FoldingRange[]; - - constructor(ranges: FoldingRange[]) { - this.ranges = ranges; - } -} - export class FoldingRange { - startLine: number; + start: number; - endLine: number; + end: number; - type?: FoldingRangeType | string; + kind?: FoldingRangeKind; - constructor(startLine: number, endLine: number, type?: FoldingRangeType | string) { - this.startLine = startLine; - this.endLine = endLine; - this.type = type; + constructor(start: number, end: number, kind?: FoldingRangeKind) { + this.start = start; + this.end = end; + this.kind = kind; } } -export enum FoldingRangeType { +export class FoldingRangeKind { /** - * Folding range for a comment + * Kind for folding range representing a comment. The value of the kind is 'comment'. */ - Comment = 'comment', + static readonly Comment = new FoldingRangeKind('comment'); /** - * Folding range for a imports or includes + * Kind for folding range representing a import. The value of the kind is 'imports'. */ - Imports = 'imports', + static readonly Imports = new FoldingRangeKind('imports'); /** - * Folding range for a region (e.g. `#region`) + * Kind for folding range representing regions (for example marked by `#region`, `#endregion`). + * The value of the kind is 'region'. */ - Region = 'region' + static readonly Region = new FoldingRangeKind('region'); + + /** + * Creates a new [FoldingRangeKind](#FoldingRangeKind). + * + * @param value of the kind. + */ + public constructor(public value: string) { + } } //#endregion