@@ -14,19 +14,23 @@ import * as platform from 'vs/base/common/platform';
14
14
import { generateUuid } from 'vs/base/common/uuid' ;
15
15
import { toExternalVSDataTransfer , toVSDataTransfer } from 'vs/editor/browser/dnd' ;
16
16
import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
17
+ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService' ;
17
18
import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
18
19
import { IRange , Range } from 'vs/editor/common/core/range' ;
19
20
import { Selection } from 'vs/editor/common/core/selection' ;
20
21
import { Handler , IEditorContribution , PastePayload } from 'vs/editor/common/editorCommon' ;
21
22
import { DocumentPasteEdit , DocumentPasteEditProvider } from 'vs/editor/common/languages' ;
22
23
import { ITextModel } from 'vs/editor/common/model' ;
23
24
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
25
+ import { createCombinedWorkspaceEdit } from 'vs/editor/contrib/dropOrPasteInto/browser/edit' ;
24
26
import { CodeEditorStateFlag , EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState' ;
25
27
import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress' ;
26
28
import { localize } from 'vs/nls' ;
27
29
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
28
30
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey' ;
29
31
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
32
+ import { IProgressService , ProgressLocation } from 'vs/platform/progress/common/progress' ;
33
+ import { IQuickInputService , IQuickPickItem } from 'vs/platform/quickinput/common/quickInput' ;
30
34
import { PostEditWidgetManager } from './postEditWidget' ;
31
35
32
36
export const changePasteTypeCommandId = 'editor.changePasteType' ;
@@ -58,15 +62,19 @@ export class CopyPasteController extends Disposable implements IEditorContributi
58
62
} ;
59
63
60
64
private _currentPasteOperation ?: CancelablePromise < void > ;
65
+ private _pasteAsActionContext ?: { readonly preferredId : string | undefined } ;
61
66
62
67
private readonly _pasteProgressManager : InlineProgressManager ;
63
68
private readonly _postPasteWidgetManager : PostEditWidgetManager ;
64
69
65
70
constructor (
66
71
editor : ICodeEditor ,
67
72
@IInstantiationService instantiationService : IInstantiationService ,
73
+ @IBulkEditService private readonly _bulkEditService : IBulkEditService ,
68
74
@IClipboardService private readonly _clipboardService : IClipboardService ,
69
75
@ILanguageFeaturesService private readonly _languageFeaturesService : ILanguageFeaturesService ,
76
+ @IQuickInputService private readonly _quickInputService : IQuickInputService ,
77
+ @IProgressService private readonly _progressService : IProgressService ,
70
78
) {
71
79
super ( ) ;
72
80
@@ -86,6 +94,16 @@ export class CopyPasteController extends Disposable implements IEditorContributi
86
94
this . _postPasteWidgetManager . tryShowSelector ( ) ;
87
95
}
88
96
97
+ public pasteAs ( preferredId ?: string ) {
98
+ this . _editor . focus ( ) ;
99
+ try {
100
+ this . _pasteAsActionContext = { preferredId } ;
101
+ document . execCommand ( 'paste' ) ;
102
+ } finally {
103
+ this . _pasteAsActionContext = undefined ;
104
+ }
105
+ }
106
+
89
107
public clearWidgets ( ) {
90
108
this . _postPasteWidgetManager . clear ( ) ;
91
109
}
@@ -208,11 +226,20 @@ export class CopyPasteController extends Disposable implements IEditorContributi
208
226
e . preventDefault ( ) ;
209
227
e . stopImmediatePropagation ( ) ;
210
228
229
+ if ( this . _pasteAsActionContext ) {
230
+ this . showPasteAsPick ( this . _pasteAsActionContext . preferredId , allProviders , selections , dataTransfer , metadata ) ;
231
+ } else {
232
+ this . doPasteInline ( allProviders , selections , dataTransfer , metadata ) ;
233
+ }
234
+ }
235
+
236
+ private doPasteInline ( allProviders : readonly DocumentPasteEditProvider [ ] , selections : readonly Selection [ ] , dataTransfer : VSDataTransfer , metadata : CopyMetadata | undefined ) : void {
211
237
const p = createCancelablePromise ( async ( token ) => {
212
238
const editor = this . _editor ;
213
239
if ( ! editor . hasModel ( ) ) {
214
240
return ;
215
241
}
242
+ const model = editor . getModel ( ) ;
216
243
217
244
const tokenSource = new EditorStateCancellationTokenSource ( editor , CodeEditorStateFlag . Value | CodeEditorStateFlag . Selection , undefined , token ) ;
218
245
try {
@@ -253,6 +280,71 @@ export class CopyPasteController extends Disposable implements IEditorContributi
253
280
this . _currentPasteOperation = p ;
254
281
}
255
282
283
+ private showPasteAsPick ( preferredId : string | undefined , allProviders : readonly DocumentPasteEditProvider [ ] , selections : readonly Selection [ ] , dataTransfer : VSDataTransfer , metadata : CopyMetadata | undefined ) : void {
284
+ const p = createCancelablePromise ( async ( token ) => {
285
+ const editor = this . _editor ;
286
+ if ( ! editor . hasModel ( ) ) {
287
+ return ;
288
+ }
289
+ const model = editor . getModel ( ) ;
290
+
291
+ const tokenSource = new EditorStateCancellationTokenSource ( editor , CodeEditorStateFlag . Value | CodeEditorStateFlag . Selection , undefined , token ) ;
292
+ try {
293
+ await this . mergeInDataFromCopy ( dataTransfer , metadata , tokenSource . token ) ;
294
+ if ( tokenSource . token . isCancellationRequested ) {
295
+ return ;
296
+ }
297
+
298
+ // Filter out any providers the don't match the full data transfer we will send them.
299
+ const supportedProviders = allProviders . filter ( provider => isSupportedProvider ( provider , dataTransfer ) ) ;
300
+
301
+ const providerEdits = await this . getPasteEdits ( supportedProviders , dataTransfer , model , selections , tokenSource . token ) ;
302
+ if ( tokenSource . token . isCancellationRequested ) {
303
+ return ;
304
+ }
305
+
306
+ if ( ! providerEdits . length ) {
307
+ return ;
308
+ }
309
+
310
+ let pickedEdit : DocumentPasteEdit | undefined ;
311
+ if ( typeof preferredId === 'string' ) {
312
+ // We are looking for a specific edit
313
+ pickedEdit = providerEdits . find ( edit => edit . id === preferredId ) ;
314
+ } else {
315
+ const selected = await this . _quickInputService . pick (
316
+ providerEdits . map ( ( edit ) : IQuickPickItem & { edit : DocumentPasteEdit } => ( {
317
+ label : edit . label ,
318
+ description : edit . id ,
319
+ detail : edit . detail ,
320
+ edit,
321
+ } ) ) , {
322
+ placeHolder : localize ( 'pasteAsPickerPlaceholder' , "Select Paste Action" ) ,
323
+ } ) ;
324
+ pickedEdit = selected ?. edit ;
325
+ }
326
+
327
+ if ( ! pickedEdit ) {
328
+ return ;
329
+ }
330
+
331
+ const combinedWorkspaceEdit = createCombinedWorkspaceEdit ( model . uri , selections , pickedEdit ) ;
332
+ await this . _bulkEditService . apply ( combinedWorkspaceEdit , { editor : this . _editor } ) ;
333
+ } finally {
334
+ tokenSource . dispose ( ) ;
335
+ if ( this . _currentPasteOperation === p ) {
336
+ this . _currentPasteOperation = undefined ;
337
+ }
338
+ }
339
+ } ) ;
340
+
341
+ this . _progressService . withProgress ( {
342
+ location : ProgressLocation . Window ,
343
+ title : localize ( 'pasteAsProgress' , "Running paste handlers" ) ,
344
+ } , ( ) => p ) ;
345
+ }
346
+
347
+
256
348
private setCopyMetadata ( dataTransfer : DataTransfer , metadata : CopyMetadata ) {
257
349
dataTransfer . setData ( vscodeClipboardMime , JSON . stringify ( metadata ) ) ;
258
350
}
@@ -293,7 +385,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
293
385
}
294
386
}
295
387
296
- private async getPasteEdits ( providers : readonly DocumentPasteEditProvider [ ] , dataTransfer : VSDataTransfer , model : ITextModel , selections : Selection [ ] , token : CancellationToken ) : Promise < DocumentPasteEdit [ ] > {
388
+ private async getPasteEdits ( providers : readonly DocumentPasteEditProvider [ ] , dataTransfer : VSDataTransfer , model : ITextModel , selections : readonly Selection [ ] , token : CancellationToken ) : Promise < DocumentPasteEdit [ ] > {
297
389
const result = await raceCancellation (
298
390
Promise . all (
299
391
providers . map ( provider => provider . provideDocumentPasteEdits ( model , selections , dataTransfer , token ) )
0 commit comments