Skip to content

Commit 379bfe6

Browse files
committed
support array of ranges in formatDocumentRangesWithProvider and formatDocumentRangesWithSelectedProvider, microsoft#103745
1 parent f56e95e commit 379bfe6

3 files changed

Lines changed: 44 additions & 30 deletions

File tree

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

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { alert } from 'vs/base/browser/ui/aria/aria';
7-
import { isNonEmptyArray } from 'vs/base/common/arrays';
7+
import { asArray, isNonEmptyArray } from 'vs/base/common/arrays';
88
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
99
import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
1010
import { URI } from 'vs/base/common/uri';
@@ -120,10 +120,10 @@ export abstract class FormattingConflicts {
120120
}
121121
}
122122

123-
export async function formatDocumentRangeWithSelectedProvider(
123+
export async function formatDocumentRangesWithSelectedProvider(
124124
accessor: ServicesAccessor,
125125
editorOrModel: ITextModel | IActiveCodeEditor,
126-
range: Range,
126+
rangeOrRanges: Range | Range[],
127127
mode: FormattingMode,
128128
token: CancellationToken
129129
): Promise<void> {
@@ -133,15 +133,15 @@ export async function formatDocumentRangeWithSelectedProvider(
133133
const provider = DocumentRangeFormattingEditProviderRegistry.ordered(model);
134134
const selected = await FormattingConflicts.select(provider, model, mode);
135135
if (selected) {
136-
await instaService.invokeFunction(formatDocumentRangeWithProvider, selected, editorOrModel, range, token);
136+
await instaService.invokeFunction(formatDocumentRangesWithProvider, selected, editorOrModel, rangeOrRanges, token);
137137
}
138138
}
139139

140-
export async function formatDocumentRangeWithProvider(
140+
export async function formatDocumentRangesWithProvider(
141141
accessor: ServicesAccessor,
142142
provider: DocumentRangeFormattingEditProvider,
143143
editorOrModel: ITextModel | IActiveCodeEditor,
144-
range: Range,
144+
rangeOrRanges: Range | Range[],
145145
token: CancellationToken
146146
): Promise<boolean> {
147147
const workerService = accessor.get(IEditorWorkerService);
@@ -156,39 +156,53 @@ export async function formatDocumentRangeWithProvider(
156156
cts = new TextModelCancellationTokenSource(editorOrModel, token);
157157
}
158158

159-
let edits: TextEdit[] | undefined;
160-
try {
161-
const rawEdits = await provider.provideDocumentRangeFormattingEdits(
162-
model,
163-
range,
164-
model.getFormattingOptions(),
165-
cts.token
166-
);
167-
edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
168-
169-
if (cts.token.isCancellationRequested) {
170-
return true;
159+
// make sure that ranges don't overlap nor touch each other
160+
let ranges: Range[] = [];
161+
let len = 0;
162+
for (let range of asArray(rangeOrRanges).sort(Range.compareRangesUsingStarts)) {
163+
if (len > 0 && Range.areIntersectingOrTouching(ranges[len - 1], range)) {
164+
ranges[len - 1] = Range.fromPositions(ranges[len - 1].getStartPosition(), range.getEndPosition());
165+
} else {
166+
len = ranges.push(range);
171167
}
168+
}
172169

173-
} finally {
174-
cts.dispose();
170+
const allEdits: TextEdit[] = [];
171+
for (let range of ranges) {
172+
try {
173+
const rawEdits = await provider.provideDocumentRangeFormattingEdits(
174+
model,
175+
range,
176+
model.getFormattingOptions(),
177+
cts.token
178+
);
179+
const minEdits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
180+
if (minEdits) {
181+
allEdits.push(...minEdits);
182+
}
183+
if (cts.token.isCancellationRequested) {
184+
return true;
185+
}
186+
} finally {
187+
cts.dispose();
188+
}
175189
}
176190

177-
if (!edits || edits.length === 0) {
191+
if (allEdits.length === 0) {
178192
return false;
179193
}
180194

181195
if (isCodeEditor(editorOrModel)) {
182196
// use editor to apply edits
183-
FormattingEdit.execute(editorOrModel, edits, true);
184-
alertFormattingEdits(edits);
197+
FormattingEdit.execute(editorOrModel, allEdits, true);
198+
alertFormattingEdits(allEdits);
185199
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate);
186200

187201
} else {
188202
// use model to apply edits
189-
const [{ range }] = edits;
203+
const [{ range }] = allEdits;
190204
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
191-
model.pushEditOperations([initialSelection], edits.map(edit => {
205+
model.pushEditOperations([initialSelection], allEdits.map(edit => {
192206
return {
193207
text: edit.text,
194208
range: Range.lift(edit.range),

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon';
1616
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
1717
import { DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
1818
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
19-
import { getOnTypeFormattingEdits, alertFormattingEdits, formatDocumentRangeWithSelectedProvider, formatDocumentWithSelectedProvider, FormattingMode } from 'vs/editor/contrib/format/format';
19+
import { getOnTypeFormattingEdits, alertFormattingEdits, formatDocumentRangesWithSelectedProvider, formatDocumentWithSelectedProvider, FormattingMode } from 'vs/editor/contrib/format/format';
2020
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
2121
import * as nls from 'vs/nls';
2222
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
@@ -202,7 +202,7 @@ class FormatOnPaste implements IEditorContribution {
202202
if (this.editor.getSelections().length > 1) {
203203
return;
204204
}
205-
this._instantiationService.invokeFunction(formatDocumentRangeWithSelectedProvider, this.editor, range, FormattingMode.Silent, CancellationToken.None).catch(onUnexpectedError);
205+
this._instantiationService.invokeFunction(formatDocumentRangesWithSelectedProvider, this.editor, range, FormattingMode.Silent, CancellationToken.None).catch(onUnexpectedError);
206206
}
207207
}
208208

@@ -274,7 +274,7 @@ class FormatSelectionAction extends EditorAction {
274274

275275
const progressService = accessor.get(IEditorProgressService);
276276
await progressService.showWhile(
277-
instaService.invokeFunction(formatDocumentRangeWithSelectedProvider, editor, range, FormattingMode.Explicit, CancellationToken.None),
277+
instaService.invokeFunction(formatDocumentRangesWithSelectedProvider, editor, range, FormattingMode.Explicit, CancellationToken.None),
278278
250
279279
);
280280
}

src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
1212
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
1313
import { CancellationToken } from 'vs/base/common/cancellation';
1414
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
15-
import { formatDocumentRangeWithProvider, formatDocumentWithProvider, getRealAndSyntheticDocumentFormattersOrdered, FormattingConflicts, FormattingMode } from 'vs/editor/contrib/format/format';
15+
import { formatDocumentRangesWithProvider, formatDocumentWithProvider, getRealAndSyntheticDocumentFormattersOrdered, FormattingConflicts, FormattingMode } from 'vs/editor/contrib/format/format';
1616
import { Range } from 'vs/editor/common/core/range';
1717
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1818
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@@ -308,7 +308,7 @@ registerEditorAction(class FormatSelectionMultipleAction extends EditorAction {
308308
const provider = DocumentRangeFormattingEditProviderRegistry.ordered(model);
309309
const pick = await instaService.invokeFunction(showFormatterPick, model, provider);
310310
if (typeof pick === 'number') {
311-
await instaService.invokeFunction(formatDocumentRangeWithProvider, provider[pick], editor, range, CancellationToken.None);
311+
await instaService.invokeFunction(formatDocumentRangesWithProvider, provider[pick], editor, range, CancellationToken.None);
312312
}
313313

314314
logFormatterTelemetry(telemetryService, 'range', provider, typeof pick === 'number' && provider[pick] || undefined);

0 commit comments

Comments
 (0)