Skip to content

Commit 9ab7b14

Browse files
authored
Merge pull request #163190 from c-claeys/multirange-formatting
Add support for multiRange formatting
2 parents d4d0d2a + f6d3226 commit 9ab7b14

File tree

9 files changed

+88
-12
lines changed

9 files changed

+88
-12
lines changed

src/vs/editor/common/languages.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,10 @@ export interface FormattingOptions {
11821182
* Prefer spaces over tabs.
11831183
*/
11841184
insertSpaces: boolean;
1185+
/**
1186+
* The list of multiple ranges to format at once, if the provider supports it.
1187+
*/
1188+
ranges?: Range[];
11851189
}
11861190
/**
11871191
* The document formatting provider interface defines the contract between extensions and
@@ -1213,6 +1217,8 @@ export interface DocumentRangeFormattingEditProvider {
12131217

12141218
readonly displayName?: string;
12151219

1220+
readonly canFormatMultipleRanges: boolean;
1221+
12161222
/**
12171223
* Provide formatting edits for a range in a document.
12181224
*

src/vs/editor/contrib/format/browser/format.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,23 @@ export async function formatDocumentRangesWithProvider(
217217
const allEdits: TextEdit[] = [];
218218
const rawEditsList: TextEdit[][] = [];
219219
try {
220-
for (const range of ranges) {
221-
if (cts.token.isCancellationRequested) {
222-
return true;
220+
if (provider.canFormatMultipleRanges) {
221+
logService.trace(`[format][provideDocumentRangeFormattingEdits] (request)`, provider.extensionId?.value, ranges);
222+
const result = (await provider.provideDocumentRangeFormattingEdits(
223+
model,
224+
ranges[0],
225+
{ ...model.getFormattingOptions(), ranges },
226+
cts.token
227+
)) || [];
228+
logService.trace(`[format][provideDocumentRangeFormattingEdits] (response)`, provider.extensionId?.value, result);
229+
rawEditsList.push(result);
230+
} else {
231+
for (const range of ranges) {
232+
if (cts.token.isCancellationRequested) {
233+
return true;
234+
}
235+
rawEditsList.push(await computeEdits(range));
223236
}
224-
rawEditsList.push(await computeEdits(range));
225237
}
226238

227239
for (let i = 0; i < ranges.length; ++i) {

src/vs/monaco.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7174,6 +7174,10 @@ declare namespace monaco.languages {
71747174
* Prefer spaces over tabs.
71757175
*/
71767176
insertSpaces: boolean;
7177+
/**
7178+
* The list of multiple ranges to format at once, if the provider supports it.
7179+
*/
7180+
ranges?: Range[];
71777181
}
71787182

71797183
/**
@@ -7194,6 +7198,7 @@ declare namespace monaco.languages {
71947198
*/
71957199
export interface DocumentRangeFormattingEditProvider {
71967200
readonly displayName?: string;
7201+
readonly canFormatMultipleRanges: boolean;
71977202
/**
71987203
* Provide formatting edits for a range in a document.
71997204
*

src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'
3232
import * as search from 'vs/workbench/contrib/search/common/search';
3333
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
3434
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
35-
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape } from '../common/extHost.protocol';
35+
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, IRangeFormattingProviderMetadataDto } from '../common/extHost.protocol';
3636

3737
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
3838
export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {
@@ -401,10 +401,11 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
401401
}));
402402
}
403403

404-
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void {
404+
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string, metadata: IRangeFormattingProviderMetadataDto): void {
405405
this._registrations.set(handle, this._languageFeaturesService.documentRangeFormattingEditProvider.register(selector, <languages.DocumentRangeFormattingEditProvider>{
406406
extensionId,
407407
displayName,
408+
canFormatMultipleRanges: metadata.canFormatMultipleRanges,
408409
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
409410
return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);
410411
}

src/vs/workbench/api/common/extHost.api.impl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
536536
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
537537
return extHostLanguageFeatures.registerDocumentFormattingEditProvider(extension, checkSelector(selector), provider);
538538
},
539-
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
540-
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(extension, checkSelector(selector), provider);
539+
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider, metadata?: vscode.DocumentRangeFormattingEditProviderMetadata): vscode.Disposable {
540+
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(extension, checkSelector(selector), provider, metadata);
541541
},
542542
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacters: string[]): vscode.Disposable {
543543
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(extension, checkSelector(selector), provider, [firstTriggerCharacter].concat(moreTriggerCharacters));

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@ export interface IDocumentFilterDto {
356356
notebookType?: string;
357357
}
358358

359+
export interface IRangeFormattingProviderMetadataDto {
360+
readonly canFormatMultipleRanges?: boolean;
361+
}
362+
359363
export interface ISignatureHelpProviderMetadataDto {
360364
readonly triggerCharacters: readonly string[];
361365
readonly retriggerCharacters: readonly string[];
@@ -388,7 +392,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
388392
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void;
389393
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void;
390394
$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
391-
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
395+
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string, metadata: IRangeFormattingProviderMetadataDto): void;
392396
$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
393397
$registerNavigateTypeSupport(handle: number, supportsResolve: boolean): void;
394398
$registerRenameSupport(handle: number, selector: IDocumentFilterDto[], supportsResolveInitialValues: boolean): void;

src/vs/workbench/api/common/extHostLanguageFeatures.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { Cache } from './cache';
3333
import { StopWatch } from 'vs/base/common/stopwatch';
3434
import { isCancellationError, NotImplementedError } from 'vs/base/common/errors';
3535
import { raceCancellationError } from 'vs/base/common/async';
36-
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
36+
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
3737
import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry';
3838

3939
// --- adapter
@@ -2055,9 +2055,13 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
20552055
return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options, token), undefined, token);
20562056
}
20572057

2058-
registerDocumentRangeFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
2058+
registerDocumentRangeFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider, metadata?: vscode.DocumentRangeFormattingEditProviderMetadata): vscode.Disposable {
2059+
const canFormatMultipleRanges = metadata?.canFormatMultipleRanges ?? false;
2060+
if (canFormatMultipleRanges) {
2061+
checkProposedApiEnabled(extension, 'formatMultipleRanges');
2062+
}
20592063
const handle = this._addNewAdapter(new RangeFormattingAdapter(this._documents, provider), extension);
2060-
this._proxy.$registerRangeFormattingSupport(handle, this._transformDocumentSelector(selector), extension.identifier, extension.displayName || extension.name);
2064+
this._proxy.$registerRangeFormattingSupport(handle, this._transformDocumentSelector(selector), extension.identifier, extension.displayName || extension.name, metadata ?? { canFormatMultipleRanges: false });
20612065
return this._createDisposable(handle);
20622066
}
20632067

src/vs/workbench/services/extensions/common/extensionsApiProposals.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const allApiProposals = Object.freeze({
3737
fileComments: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fileComments.d.ts',
3838
fileSearchProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fileSearchProvider.d.ts',
3939
findTextInFiles: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles.d.ts',
40+
formatMultipleRanges: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.formatMultipleRanges.d.ts',
4041
fsChunks: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fsChunks.d.ts',
4142
getSessions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.getSessions.d.ts',
4243
idToken: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.idToken.d.ts',
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
declare module 'vscode' {
7+
8+
// https://github.com/microsoft/vscode/issues/158776
9+
10+
/**
11+
* Metadata about a registered {@linkcode DocumentRangeFormattingEditProvider}.
12+
*/
13+
export interface DocumentRangeFormattingEditProviderMetadata {
14+
/**
15+
* `true` if the range formatting provider supports formatting multiple ranges at once.
16+
*/
17+
readonly canFormatMultipleRanges?: boolean;
18+
}
19+
20+
export interface FormattingOptions2 {
21+
22+
/**
23+
* The list of multiple ranges to format at once, if the provider supports it.
24+
*/
25+
// TODO@API should this all ranges or all except for the first range?
26+
// TODO@API needs a name that is more descriptive
27+
ranges?: Range[];
28+
29+
[key: string]: boolean | number | string | undefined | object;
30+
}
31+
32+
export interface DocumentRangeFormattingEditProvider {
33+
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions & FormattingOptions2, token: CancellationToken): ProviderResult<TextEdit[]>;
34+
}
35+
36+
export namespace languages {
37+
/**
38+
*
39+
* @param metadata Metadata about the provider.
40+
*/
41+
export function registerDocumentRangeFormattingEditProvider(selector: DocumentSelector, provider: DocumentRangeFormattingEditProvider, metadata?: DocumentRangeFormattingEditProviderMetadata): Disposable;
42+
}
43+
}

0 commit comments

Comments
 (0)