4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
6
import { addDisposableListener } from 'vs/base/browser/dom' ;
7
+ import { coalesce } from 'vs/base/common/arrays' ;
7
8
import { CancelablePromise , createCancelablePromise , raceCancellation } from 'vs/base/common/async' ;
8
9
import { CancellationToken } from 'vs/base/common/cancellation' ;
9
10
import { UriList , VSDataTransfer , createStringDataTransferItem } from 'vs/base/common/dataTransfer' ;
@@ -13,22 +14,27 @@ import { Schemas } from 'vs/base/common/network';
13
14
import { generateUuid } from 'vs/base/common/uuid' ;
14
15
import { toVSDataTransfer } from 'vs/editor/browser/dnd' ;
15
16
import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
16
- import { IBulkEditService , ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService' ;
17
17
import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
18
18
import { IRange , Range } from 'vs/editor/common/core/range' ;
19
19
import { Selection } from 'vs/editor/common/core/selection' ;
20
20
import { 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' ;
22
22
import { ITextModel } from 'vs/editor/common/model' ;
23
23
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
24
+ import { registerDefaultPasteProviders } from 'vs/editor/contrib/copyPaste/browser/defaultPasteProviders' ;
24
25
import { CodeEditorStateFlag , EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState' ;
25
26
import { 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 ' ;
27
28
import { localize } from 'vs/nls' ;
28
29
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
29
30
import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
31
+ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey' ;
30
32
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
31
33
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
+
32
38
const vscodeClipboardMime = 'application/vnd.code.copyMetadata' ;
33
39
34
40
interface CopyMetadata {
@@ -51,15 +57,14 @@ export class CopyPasteController extends Disposable implements IEditorContributi
51
57
readonly dataTransferPromise : CancelablePromise < VSDataTransfer > ;
52
58
} ;
53
59
54
- private operationIdPool = 0 ;
55
- private _currentOperation ?: { readonly id : number ; readonly promise : CancelablePromise < void > } ;
60
+ private _currentOperation ?: CancelablePromise < void > ;
56
61
57
62
private readonly _pasteProgressManager : InlineProgressManager ;
63
+ private readonly _postPasteWidgetManager : PostEditWidgetManager ;
58
64
59
65
constructor (
60
66
editor : ICodeEditor ,
61
67
@IInstantiationService instantiationService : IInstantiationService ,
62
- @IBulkEditService private readonly _bulkEditService : IBulkEditService ,
63
68
@IClipboardService private readonly _clipboardService : IClipboardService ,
64
69
@IConfigurationService private readonly _configurationService : IConfigurationService ,
65
70
@ILanguageFeaturesService private readonly _languageFeaturesService : ILanguageFeaturesService ,
@@ -74,6 +79,18 @@ export class CopyPasteController extends Disposable implements IEditorContributi
74
79
this . _register ( addDisposableListener ( container , 'paste' , e => this . handlePaste ( e ) , true ) ) ;
75
80
76
81
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 ( ) ;
77
94
}
78
95
79
96
private arePasteActionsEnabled ( model : ITextModel ) : boolean {
@@ -152,9 +169,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
152
169
return ;
153
170
}
154
171
155
- const operationId = this . operationIdPool ++ ;
156
- this . _currentOperation ?. promise . cancel ( ) ;
157
- this . _pasteProgressManager . clear ( ) ;
172
+ this . _currentOperation ?. cancel ( ) ;
158
173
159
174
const selections = this . _editor . getSelections ( ) ;
160
175
if ( ! selections ?. length || ! this . _editor . hasModel ( ) ) {
@@ -180,7 +195,6 @@ export class CopyPasteController extends Disposable implements IEditorContributi
180
195
e . preventDefault ( ) ;
181
196
e . stopImmediatePropagation ( ) ;
182
197
183
-
184
198
const p = createCancelablePromise ( async ( token ) => {
185
199
const editor = this . _editor ;
186
200
if ( ! editor . hasModel ( ) ) {
@@ -189,10 +203,6 @@ export class CopyPasteController extends Disposable implements IEditorContributi
189
203
190
204
const tokenSource = new EditorStateCancellationTokenSource ( editor , CodeEditorStateFlag . Value | CodeEditorStateFlag . Selection , undefined , token ) ;
191
205
try {
192
- this . _pasteProgressManager . setAtPosition ( selections [ 0 ] . getEndPosition ( ) , localize ( 'pasteIntoEditorProgress' , "Running paste handlers. Click to cancel" ) , {
193
- cancel : ( ) => tokenSource . cancel ( )
194
- } ) ;
195
-
196
206
const dataTransfer = toVSDataTransfer ( e . clipboardData ! ) ;
197
207
198
208
if ( metadata ?. id && this . _currentClipboardItem ?. handle === metadata . id ) {
@@ -219,58 +229,37 @@ export class CopyPasteController extends Disposable implements IEditorContributi
219
229
220
230
dataTransfer . delete ( vscodeClipboardMime ) ;
221
231
222
- const providerEdit = await this . getProviderPasteEdit ( providers , dataTransfer , model , selections , tokenSource . token ) ;
232
+ const providerEdits = await this . getPasteEdits ( providers , dataTransfer , model , selections , tokenSource . token ) ;
223
233
if ( tokenSource . token . isCancellationRequested ) {
224
234
return ;
225
235
}
226
236
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 ) ;
241
239
}
242
240
243
241
await this . applyDefaultPasteHandler ( dataTransfer , metadata , tokenSource . token ) ;
244
242
} finally {
245
243
tokenSource . dispose ( ) ;
246
- if ( this . _currentOperation ?. id === operationId ) {
247
- this . _pasteProgressManager . clear ( ) ;
244
+ if ( this . _currentOperation === p ) {
248
245
this . _currentOperation = undefined ;
249
246
}
250
247
}
251
248
} ) ;
252
249
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 ;
254
252
}
255
253
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 ?? [ ] ;
274
263
}
275
264
276
265
private async applyDefaultPasteHandler ( dataTransfer : VSDataTransfer , metadata : CopyMetadata | undefined , token : CancellationToken ) {
0 commit comments