From fff9302b367acf12ef7e183fe8b03708b5476e2e Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 19 Oct 2020 15:59:47 +0200 Subject: [PATCH] folding: provider event to signal that folding ranges have changed. Fixes #99914 --- src/vs/editor/common/modes.ts | 6 +++++ src/vs/editor/contrib/folding/folding.ts | 2 +- .../contrib/folding/syntaxRangeProvider.ts | 15 ++++++++++-- .../contrib/folding/test/syntaxFold.test.ts | 2 +- src/vs/monaco.d.ts | 4 ++++ src/vs/vscode.proposed.d.ts | 11 +++++++++ .../api/browser/mainThreadLanguageFeatures.ts | 24 +++++++++++++++---- .../workbench/api/common/extHost.protocol.ts | 3 ++- .../api/common/extHostLanguageFeatures.ts | 18 ++++++++++---- 9 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index faad9ab6da5..34f041ea626 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1293,6 +1293,12 @@ export interface FoldingContext { * A provider of folding ranges for editor models. */ export interface FoldingRangeProvider { + + /** + * An optional event to signal that the folding ranges from this provider have changed. + */ + onDidChange?: Event; + /** * Provides the folding ranges for a specific model. */ diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index 251f7aa1607..0bfa5f68166 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -264,7 +264,7 @@ export class FoldingController extends Disposable implements IEditorContribution }, 30000); return rangeProvider; // keep memento in case there are still no foldingProviders on the next request. } else if (foldingProviders.length > 0) { - this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders); + this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders, () => this.onModelContentChanged()); } } this.foldingStateMemento = null; diff --git a/src/vs/editor/contrib/folding/syntaxRangeProvider.ts b/src/vs/editor/contrib/folding/syntaxRangeProvider.ts index 4e66801be36..898694bb2f8 100644 --- a/src/vs/editor/contrib/folding/syntaxRangeProvider.ts +++ b/src/vs/editor/contrib/folding/syntaxRangeProvider.ts @@ -9,6 +9,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { RangeProvider } from './folding'; import { MAX_LINE_NUMBER, FoldingRegions } from './foldingRanges'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { DisposableStore } from 'vs/base/common/lifecycle'; const MAX_FOLDING_REGIONS = 5000; @@ -25,7 +26,17 @@ export class SyntaxRangeProvider implements RangeProvider { readonly id = ID_SYNTAX_PROVIDER; - constructor(private readonly editorModel: ITextModel, private providers: FoldingRangeProvider[], private limit = MAX_FOLDING_REGIONS) { + readonly disposables: DisposableStore | undefined; + + constructor(private readonly editorModel: ITextModel, private providers: FoldingRangeProvider[], handleFoldingRangesChange: () => void, private limit = MAX_FOLDING_REGIONS) { + for (const provider of providers) { + if (typeof provider.onDidChange === 'function') { + if (!this.disposables) { + this.disposables = new DisposableStore(); + } + this.disposables.add(provider.onDidChange(handleFoldingRangesChange)); + } + } } compute(cancellationToken: CancellationToken): Promise { @@ -39,8 +50,8 @@ export class SyntaxRangeProvider implements RangeProvider { } dispose() { + this.disposables?.dispose(); } - } function collectSyntaxRanges(providers: FoldingRangeProvider[], model: ITextModel, cancellationToken: CancellationToken): Promise { diff --git a/src/vs/editor/contrib/folding/test/syntaxFold.test.ts b/src/vs/editor/contrib/folding/test/syntaxFold.test.ts index 86a4280259e..915ba173661 100644 --- a/src/vs/editor/contrib/folding/test/syntaxFold.test.ts +++ b/src/vs/editor/contrib/folding/test/syntaxFold.test.ts @@ -74,7 +74,7 @@ suite('Syntax folding', () => { let providers = [new TestFoldingRangeProvider(model, ranges)]; async function assertLimit(maxEntries: number, expectedRanges: IndentRange[], message: string) { - let indentRanges = await new SyntaxRangeProvider(model, providers, maxEntries).compute(CancellationToken.None); + let indentRanges = await new SyntaxRangeProvider(model, providers, () => { }, maxEntries).compute(CancellationToken.None); let actual: IndentRange[] = []; if (indentRanges) { for (let i = 0; i < indentRanges.length; i++) { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index a44cb3bb307..1cd72bf8512 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6137,6 +6137,10 @@ declare namespace monaco.languages { * A provider of folding ranges for editor models. */ export interface FoldingRangeProvider { + /** + * An optional event to signal that the folding ranges from this provider have changed. + */ + onDidChange?: IEvent; /** * Provides the folding ranges for a specific model. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 5a3de044162..63712708d62 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2190,4 +2190,15 @@ declare module 'vscode' { canReply: boolean; } //#endregion + + //#region https://github.com/microsoft/vscode/issues/108929 FoldingRangeProvider.onDidChangeFoldingRanges @aeschli + export interface FoldingRangeProvider2 extends FoldingRangeProvider { + + /** + * An optional event to signal that the folding ranges from this provider have changed. + */ + onDidChangeFoldingRanges?: Event; + + } + //#endregion } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 635730ba75b..9cbb21d567f 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -571,13 +571,27 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- folding - $registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void { - const proxy = this._proxy; - this._registrations.set(handle, modes.FoldingRangeProviderRegistry.register(selector, { + $registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void { + const provider = { provideFoldingRanges: (model, context, token) => { - return proxy.$provideFoldingRanges(handle, model.uri, context, token); + return this._proxy.$provideFoldingRanges(handle, model.uri, context, token); } - })); + }; + + if (typeof eventHandle === 'number') { + const emitter = new Emitter(); + this._registrations.set(eventHandle, emitter); + provider.onDidChange = emitter.event; + } + + this._registrations.set(handle, modes.FoldingRangeProviderRegistry.register(selector, provider)); + } + + $emitFoldingRangeEvent(eventHandle: number, event?: any): void { + const obj = this._registrations.get(eventHandle); + if (obj instanceof Emitter) { + obj.fire(event); + } } // -- smart select diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index ddca6becf25..dd64b66a1ac 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -398,7 +398,8 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void; $registerDocumentLinkProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean): void; $registerDocumentColorProvider(handle: number, selector: IDocumentFilterDto[]): void; - $registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void; + $registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void; + $emitFoldingRangeEvent(eventHandle: number, event?: any): void; $registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void; $setLanguageConfiguration(handle: number, languageId: string, configuration: ILanguageConfigurationDto): void; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index ef49bb42954..8e65422a946 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1810,10 +1810,20 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token), undefined); } - registerFoldingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable { - const handle = this._addNewAdapter(new FoldingProviderAdapter(this._documents, provider), extension); - this._proxy.$registerFoldingRangeProvider(handle, this._transformDocumentSelector(selector)); - return this._createDisposable(handle); + registerFoldingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider2): vscode.Disposable { + const handle = this._nextHandle(); + const eventHandle = typeof provider.onDidChangeFoldingRanges === 'function' ? this._nextHandle() : undefined; + + this._adapter.set(handle, new AdapterData(new FoldingProviderAdapter(this._documents, provider), extension)); + this._proxy.$registerFoldingRangeProvider(handle, this._transformDocumentSelector(selector), eventHandle); + let result = this._createDisposable(handle); + + if (eventHandle !== undefined) { + const subscription = provider.onDidChangeFoldingRanges!(_ => this._proxy.$emitFoldingRangeEvent(eventHandle)); + result = Disposable.from(result, subscription); + } + + return result; } $provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext, token: CancellationToken): Promise { -- GitLab