44 *--------------------------------------------------------------------------------------------*/
55
66import { 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' ;
88import { CancellationToken , CancellationTokenSource } from 'vs/base/common/cancellation' ;
99import { illegalArgument , onUnexpectedExternalError } from 'vs/base/common/errors' ;
1010import { 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 ) ,
0 commit comments