44 *--------------------------------------------------------------------------------------------*/
55
66import { addDisposableListener } from 'vs/base/browser/dom' ;
7+ import { coalesce } from 'vs/base/common/arrays' ;
78import { CancelablePromise , createCancelablePromise , raceCancellation } from 'vs/base/common/async' ;
89import { CancellationToken } from 'vs/base/common/cancellation' ;
910import { UriList , VSDataTransfer , createStringDataTransferItem } from 'vs/base/common/dataTransfer' ;
@@ -13,22 +14,27 @@ import { Schemas } from 'vs/base/common/network';
1314import { generateUuid } from 'vs/base/common/uuid' ;
1415import { toVSDataTransfer } from 'vs/editor/browser/dnd' ;
1516import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
16- import { IBulkEditService , ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService' ;
1717import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
1818import { IRange , Range } from 'vs/editor/common/core/range' ;
1919import { Selection } from 'vs/editor/common/core/selection' ;
2020import { Handler , IEditorContribution , PastePayload } from 'vs/editor/common/editorCommon' ;
21- import { DocumentPasteEdit , DocumentPasteEditProvider , WorkspaceEdit } from 'vs/editor/common/languages' ;
21+ import { DocumentPasteEdit , DocumentPasteEditProvider } from 'vs/editor/common/languages' ;
2222import { ITextModel } from 'vs/editor/common/model' ;
2323import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
24+ import { registerDefaultPasteProviders } from 'vs/editor/contrib/copyPaste/browser/defaultPasteProviders' ;
2425import { CodeEditorStateFlag , EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState' ;
2526import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress' ;
26- import { SnippetParser } from 'vs/editor/contrib/snippet /browser/snippetParser ' ;
27+ import { PostEditWidgetManager } from 'vs/editor/contrib/postEditWidget /browser/postEditWidget ' ;
2728import { localize } from 'vs/nls' ;
2829import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
2930import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
31+ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey' ;
3032import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
3133
34+ export const changePasteTypeCommandId = 'editor.changePasteType' ;
35+
36+ export const pasteWidgetVisibleCtx = new RawContextKey < boolean > ( 'pasteWidgetVisible' , false , localize ( 'pasteWidgetVisible' , "Whether the paste widget is showing" ) ) ;
37+
3238const vscodeClipboardMime = 'application/vnd.code.copyMetadata' ;
3339
3440interface CopyMetadata {
@@ -51,15 +57,14 @@ export class CopyPasteController extends Disposable implements IEditorContributi
5157 readonly dataTransferPromise : CancelablePromise < VSDataTransfer > ;
5258 } ;
5359
54- private operationIdPool = 0 ;
55- private _currentOperation ?: { readonly id : number ; readonly promise : CancelablePromise < void > } ;
60+ private _currentOperation ?: CancelablePromise < void > ;
5661
5762 private readonly _pasteProgressManager : InlineProgressManager ;
63+ private readonly _postPasteWidgetManager : PostEditWidgetManager ;
5864
5965 constructor (
6066 editor : ICodeEditor ,
6167 @IInstantiationService instantiationService : IInstantiationService ,
62- @IBulkEditService private readonly _bulkEditService : IBulkEditService ,
6368 @IClipboardService private readonly _clipboardService : IClipboardService ,
6469 @IConfigurationService private readonly _configurationService : IConfigurationService ,
6570 @ILanguageFeaturesService private readonly _languageFeaturesService : ILanguageFeaturesService ,
@@ -74,6 +79,18 @@ export class CopyPasteController extends Disposable implements IEditorContributi
7479 this . _register ( addDisposableListener ( container , 'paste' , e => this . handlePaste ( e ) , true ) ) ;
7580
7681 this . _pasteProgressManager = this . _register ( new InlineProgressManager ( 'pasteIntoEditor' , editor , instantiationService ) ) ;
82+
83+ this . _postPasteWidgetManager = this . _register ( instantiationService . createInstance ( PostEditWidgetManager , 'pasteIntoEditor' , editor , pasteWidgetVisibleCtx , { id : changePasteTypeCommandId , label : localize ( 'postPasteWidgetTitle' , "Show paste options..." ) } ) ) ;
84+
85+ registerDefaultPasteProviders ( _languageFeaturesService ) ;
86+ }
87+
88+ public changePasteType ( ) {
89+ this . _postPasteWidgetManager . tryShowSelector ( ) ;
90+ }
91+
92+ public clearWidgets ( ) {
93+ this . _postPasteWidgetManager . clear ( ) ;
7794 }
7895
7996 private arePasteActionsEnabled ( model : ITextModel ) : boolean {
@@ -152,9 +169,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
152169 return ;
153170 }
154171
155- const operationId = this . operationIdPool ++ ;
156- this . _currentOperation ?. promise . cancel ( ) ;
157- this . _pasteProgressManager . clear ( ) ;
172+ this . _currentOperation ?. cancel ( ) ;
158173
159174 const selections = this . _editor . getSelections ( ) ;
160175 if ( ! selections ?. length || ! this . _editor . hasModel ( ) ) {
@@ -180,7 +195,6 @@ export class CopyPasteController extends Disposable implements IEditorContributi
180195 e . preventDefault ( ) ;
181196 e . stopImmediatePropagation ( ) ;
182197
183-
184198 const p = createCancelablePromise ( async ( token ) => {
185199 const editor = this . _editor ;
186200 if ( ! editor . hasModel ( ) ) {
@@ -189,10 +203,6 @@ export class CopyPasteController extends Disposable implements IEditorContributi
189203
190204 const tokenSource = new EditorStateCancellationTokenSource ( editor , CodeEditorStateFlag . Value | CodeEditorStateFlag . Selection , undefined , token ) ;
191205 try {
192- this . _pasteProgressManager . setAtPosition ( selections [ 0 ] . getEndPosition ( ) , localize ( 'pasteIntoEditorProgress' , "Running paste handlers. Click to cancel" ) , {
193- cancel : ( ) => tokenSource . cancel ( )
194- } ) ;
195-
196206 const dataTransfer = toVSDataTransfer ( e . clipboardData ! ) ;
197207
198208 if ( metadata ?. id && this . _currentClipboardItem ?. handle === metadata . id ) {
@@ -219,58 +229,37 @@ export class CopyPasteController extends Disposable implements IEditorContributi
219229
220230 dataTransfer . delete ( vscodeClipboardMime ) ;
221231
222- const providerEdit = await this . getProviderPasteEdit ( providers , dataTransfer , model , selections , tokenSource . token ) ;
232+ const providerEdits = await this . getPasteEdits ( providers , dataTransfer , model , selections , tokenSource . token ) ;
223233 if ( tokenSource . token . isCancellationRequested ) {
224234 return ;
225235 }
226236
227- if ( providerEdit ) {
228- const snippet = typeof providerEdit . insertText === 'string' ? SnippetParser . escape ( providerEdit . insertText ) : providerEdit . insertText . snippet ;
229- const combinedWorkspaceEdit : WorkspaceEdit = {
230- edits : [
231- new ResourceTextEdit ( model . uri , {
232- range : Selection . liftSelection ( editor . getSelection ( ) ) ,
233- text : snippet ,
234- insertAsSnippet : true ,
235- } ) ,
236- ...( providerEdit . additionalEdit ?. edits ?? [ ] )
237- ]
238- } ;
239- await this . _bulkEditService . apply ( combinedWorkspaceEdit , { editor } ) ;
240- return ;
237+ if ( providerEdits . length ) {
238+ return this . _postPasteWidgetManager . applyEditAndShowIfNeeded ( selections [ 0 ] , { activeEditIndex : 0 , allEdits : providerEdits } , tokenSource . token ) ;
241239 }
242240
243241 await this . applyDefaultPasteHandler ( dataTransfer , metadata , tokenSource . token ) ;
244242 } finally {
245243 tokenSource . dispose ( ) ;
246- if ( this . _currentOperation ?. id === operationId ) {
247- this . _pasteProgressManager . clear ( ) ;
244+ if ( this . _currentOperation === p ) {
248245 this . _currentOperation = undefined ;
249246 }
250247 }
251248 } ) ;
252249
253- this . _currentOperation = { id : operationId , promise : p } ;
250+ this . _pasteProgressManager . showWhile ( selections [ 0 ] . getEndPosition ( ) , localize ( 'pasteIntoEditorProgress' , "Running paste handlers. Click to cancel" ) , p ) ;
251+ this . _currentOperation = p ;
254252 }
255253
256- private getProviderPasteEdit ( providers : DocumentPasteEditProvider [ ] , dataTransfer : VSDataTransfer , model : ITextModel , selections : Selection [ ] , token : CancellationToken ) : Promise < DocumentPasteEdit | undefined > {
257- return raceCancellation ( ( async ( ) => {
258- for ( const provider of providers ) {
259- if ( token . isCancellationRequested ) {
260- return ;
261- }
262-
263- if ( ! isSupportedProvider ( provider , dataTransfer ) ) {
264- continue ;
265- }
266-
267- const edit = await provider . provideDocumentPasteEdits ( model , selections , dataTransfer , token ) ;
268- if ( edit ) {
269- return edit ;
270- }
271- }
272- return undefined ;
273- } ) ( ) , token ) ;
254+ private async getPasteEdits ( providers : readonly DocumentPasteEditProvider [ ] , dataTransfer : VSDataTransfer , model : ITextModel , selections : Selection [ ] , token : CancellationToken ) : Promise < DocumentPasteEdit [ ] > {
255+ const result = await raceCancellation (
256+ Promise . all (
257+ providers
258+ . filter ( provider => isSupportedProvider ( provider , dataTransfer ) )
259+ . map ( provider => provider . provideDocumentPasteEdits ( model , selections , dataTransfer , token ) )
260+ ) . then ( coalesce ) ,
261+ token ) ;
262+ return result ?? [ ] ;
274263 }
275264
276265 private async applyDefaultPasteHandler ( dataTransfer : VSDataTransfer , metadata : CopyMetadata | undefined , token : CancellationToken ) {
0 commit comments