add executeFoldingRangeProvider command (#172968)

* add executeFoldingRangeProvider command

* add jsdoc for FoldingRangeKind.fromValue
This commit is contained in:
Martin Aeschlimann
2023-02-01 01:03:02 -08:00
committed by GitHub
parent d9ad2139a6
commit 7dff9e992b
6 changed files with 159 additions and 4 deletions
@@ -191,4 +191,47 @@ suite('vscode API - languages', () => {
assert.ok(result!.items.some(i => i.label === 'foo'), 'Results do not include "foo"');
});
test('folding command', async function () {
const content = `[
/**
* This is a comment with indentation issues
*/
{
"name": "bag of items",
"items": [
"foo", "bar"
]
}
]`;
const uri = await createRandomFile(content, undefined, '.jsonc');
await vscode.workspace.openTextDocument(uri);
const jsonExtension = await vscode.extensions.getExtension('vscode.json-language-features');
assert.ok(jsonExtension);
await jsonExtension.activate();
const result1 = await vscode.commands.executeCommand<vscode.FoldingRange[]>('vscode.executeFoldingRangeProvider', uri);
assert.deepEqual(result1, [
{ start: 0, end: 9 },
{ start: 1, end: 3, kind: vscode.FoldingRangeKind.Comment },
{ start: 4, end: 8 },
{ start: 6, end: 7 },
]);
await vscode.workspace.getConfiguration('editor').update('foldingStrategy', 'indentation');
try {
const result2 = await vscode.commands.executeCommand<vscode.FoldingRange[]>('vscode.executeFoldingRangeProvider', uri);
assert.deepEqual(result2, [
{ start: 0, end: 10 },
{ start: 1, end: 2 },
{ start: 3, end: 9 },
{ start: 4, end: 8 },
{ start: 6, end: 7 },
]);
await vscode.workspace.getConfiguration('editor').update('folding', false);
const result3 = await vscode.commands.executeCommand<vscode.FoldingRange[]>('vscode.executeFoldingRangeProvider', uri);
assert.deepEqual(result3, []);
} finally {
await vscode.workspace.getConfiguration('editor').update('foldingStrategy', undefined);
await vscode.workspace.getConfiguration('editor').update('folding', undefined);
}
});
});
+14
View File
@@ -1394,6 +1394,20 @@ export class FoldingRangeKind {
*/
static readonly Region = new FoldingRangeKind('region');
/**
* Returns a {@link FoldingRangeKind} for the given value.
*
* @param value of the kind.
*/
static fromValue(value: string) {
switch (value) {
case 'comment': return FoldingRangeKind.Comment;
case 'imports': return FoldingRangeKind.Imports;
case 'region': return FoldingRangeKind.Region;
}
return new FoldingRangeKind(value);
}
/**
* Creates a new {@link FoldingRangeKind}.
*
@@ -5,7 +5,7 @@
import { CancelablePromise, createCancelablePromise, Delayer, RunOnceScheduler } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { onUnexpectedError } from 'vs/base/common/errors';
import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { escapeRegExpCharacters } from 'vs/base/common/strings';
@@ -21,7 +21,7 @@ import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ITextModel } from 'vs/editor/common/model';
import { IModelContentChangedEvent } from 'vs/editor/common/textModelEvents';
import { FoldingRangeKind, FoldingRangeProvider } from 'vs/editor/common/languages';
import { FoldingRange, FoldingRangeKind, FoldingRangeProvider } from 'vs/editor/common/languages';
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
import { CollapseMemento, FoldingModel, getNextFoldLine, getParentFoldLine as getParentFoldLine, getPreviousFoldLine, setCollapseStateAtLevel, setCollapseStateForMatchingLines, setCollapseStateForRest, setCollapseStateForType, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateUp, toggleCollapseState } from 'vs/editor/contrib/folding/browser/foldingModel';
import { HiddenRangeModel } from 'vs/editor/contrib/folding/browser/hiddenRangeModel';
@@ -37,6 +37,10 @@ import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from 'vs
import { StopWatch } from 'vs/base/common/stopwatch';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { Emitter, Event } from 'vs/base/common/event';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { URI } from 'vs/base/common/uri';
import { IModelService } from 'vs/editor/common/services/model';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
const CONTEXT_FOLDING_ENABLED = new RawContextKey<boolean>('foldingEnabled', false);
@@ -75,6 +79,11 @@ export class FoldingController extends Disposable implements IEditorContribution
private static _foldingRangeSelector: FoldingRangeProviderSelector | undefined;
public static getFoldingRangeProviders(languageFeaturesService: ILanguageFeaturesService, model: ITextModel): FoldingRangeProvider[] {
const foldingRangeProviders = languageFeaturesService.foldingRangeProvider.ordered(model);
return (FoldingController._foldingRangeSelector?.(foldingRangeProviders, model)) ?? foldingRangeProviders;
}
public static setFoldingRangeProviderSelector(foldingRangeSelector: FoldingRangeProviderSelector): IDisposable {
FoldingController._foldingRangeSelector = foldingRangeSelector;
return { dispose: () => { FoldingController._foldingRangeSelector = undefined; } };
@@ -289,8 +298,7 @@ export class FoldingController extends Disposable implements IEditorContribution
const indentRangeProvider = new IndentRangeProvider(editorModel, this.languageConfigurationService, this._foldingLimitReporter);
this.rangeProvider = indentRangeProvider; // fallback
if (this._useFoldingProviders && this.foldingModel) {
const foldingProviders = this.languageFeaturesService.foldingRangeProvider.ordered(this.foldingModel.textModel);
const selectedProviders = (FoldingController._foldingRangeSelector?.(foldingProviders, editorModel)) ?? foldingProviders;
const selectedProviders = FoldingController.getFoldingRangeProviders(this.languageFeaturesService, editorModel);
if (selectedProviders.length > 0) {
this.rangeProvider = new SyntaxRangeProvider(editorModel, selectedProviders, () => this.triggerFoldingModelChanged(), this._foldingLimitReporter, indentRangeProvider);
}
@@ -1198,3 +1206,55 @@ for (let i = 1; i <= 7; i++) {
})
);
}
CommandsRegistry.registerCommand('_executeFoldingRangeProvider', async function (accessor, ...args) {
const [resource] = args;
if (!(resource instanceof URI)) {
throw illegalArgument();
}
const languageFeaturesService = accessor.get(ILanguageFeaturesService);
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument();
}
const configurationService = accessor.get(IConfigurationService);
if (!configurationService.getValue('editor.folding', { resource })) {
return [];
}
const languageConfigurationService = accessor.get(ILanguageConfigurationService);
const strategy = configurationService.getValue('editor.foldingStrategy', { resource });
const foldingLimitReporter = {
get limit() {
return <number>configurationService.getValue('editor.foldingMaximumRegions', { resource });
},
report: (info: FoldingLimitInfo) => { }
};
const indentRangeProvider = new IndentRangeProvider(model, languageConfigurationService, foldingLimitReporter);
let rangeProvider: RangeProvider = indentRangeProvider;
if (strategy !== 'indentation') {
const providers = FoldingController.getFoldingRangeProviders(languageFeaturesService, model);
if (providers.length) {
rangeProvider = new SyntaxRangeProvider(model, providers, () => { }, foldingLimitReporter, indentRangeProvider);
}
}
const ranges = await rangeProvider.compute(CancellationToken.None);
const result: FoldingRange[] = [];
try {
if (ranges) {
for (let i = 0; i < ranges.length; i++) {
const type = ranges.getType(i);
result.push({ start: ranges.getStartLineNumber(i), end: ranges.getEndLineNumber(i), kind: type ? FoldingRangeKind.fromValue(type) : undefined });
}
}
return result;
} finally {
rangeProvider.dispose();
}
});
+6
View File
@@ -7313,6 +7313,12 @@ declare namespace monaco.languages {
* The value of the kind is 'region'.
*/
static readonly Region: FoldingRangeKind;
/**
* Returns a {@link FoldingRangeKind} for the given value.
*
* @param value of the kind.
*/
static fromValue(value: string): FoldingRangeKind;
/**
* Creates a new {@link FoldingRangeKind}.
*
@@ -338,6 +338,18 @@ const newCommands: ApiCommand[] = [
return result.map(typeConverters.InlayHint.to.bind(undefined, converter));
})
),
// --- folding
new ApiCommand(
'vscode.executeFoldingRangeProvider', '_executeFoldingRangeProvider', 'Execute folding range provider',
[ApiCommandArgument.Uri],
new ApiCommandResult<languages.FoldingRange[] | undefined, vscode.FoldingRange[] | undefined>('A promise that resolves to an array of FoldingRange objects', (result, args) => {
if (result) {
return result.map(typeConverters.FoldingRange.to);
}
return undefined;
})
),
// --- notebooks
new ApiCommand(
'vscode.resolveNotebookContentProviders', '_resolveNotebookContentProvider', 'Resolve Notebook Content Providers',
@@ -1382,6 +1382,13 @@ export namespace FoldingRange {
}
return range;
}
export function to(r: languages.FoldingRange): vscode.FoldingRange {
const range: vscode.FoldingRange = { start: r.start - 1, end: r.end - 1 };
if (r.kind) {
range.kind = FoldingRangeKind.to(r.kind);
}
return range;
}
}
export namespace FoldingRangeKind {
@@ -1398,6 +1405,19 @@ export namespace FoldingRangeKind {
}
return undefined;
}
export function to(kind: languages.FoldingRangeKind | undefined): vscode.FoldingRangeKind | undefined {
if (kind) {
switch (kind.value) {
case languages.FoldingRangeKind.Comment.value:
return types.FoldingRangeKind.Comment;
case languages.FoldingRangeKind.Imports.value:
return types.FoldingRangeKind.Imports;
case languages.FoldingRangeKind.Region.value:
return types.FoldingRangeKind.Region;
}
}
return undefined;
}
}
export interface TextEditorOpenOptions extends vscode.TextDocumentShowOptions {