6
6
import { DataTransfers } from 'vs/base/browser/dnd' ;
7
7
import { addDisposableListener } from 'vs/base/browser/dom' ;
8
8
import { CancelablePromise , createCancelablePromise } from 'vs/base/common/async' ;
9
- import { CancellationToken } from 'vs/base/common/cancellation' ;
10
9
import { createStringDataTransferItem , VSDataTransfer } from 'vs/base/common/dataTransfer' ;
11
10
import { Disposable } from 'vs/base/common/lifecycle' ;
12
11
import { Mimes } from 'vs/base/common/mime' ;
@@ -16,8 +15,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
16
15
import { IBulkEditService , ResourceEdit } from 'vs/editor/browser/services/bulkEditService' ;
17
16
import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
18
17
import { IRange , Range } from 'vs/editor/common/core/range' ;
19
- import { IEditorContribution } from 'vs/editor/common/editorCommon' ;
20
- import { DocumentPasteEdit , DocumentPasteEditProvider } from 'vs/editor/common/languages' ;
18
+ import { Handler , IEditorContribution , PastePayload } from 'vs/editor/common/editorCommon' ;
21
19
import { ITextModel } from 'vs/editor/common/model' ;
22
20
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
23
21
import { CodeEditorStateFlag , EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState' ;
@@ -26,21 +24,12 @@ import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
26
24
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
27
25
import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
28
26
29
- const vscodeClipboardMime = 'application/vnd.code.copyId ' ;
27
+ const vscodeClipboardMime = 'application/vnd.code.copyMetadata ' ;
30
28
31
- const defaultPasteEditProvider = new class implements DocumentPasteEditProvider {
32
- pasteMimeTypes = [ Mimes . text , 'text' ] ;
33
-
34
- async provideDocumentPasteEdits ( _model : ITextModel , _ranges : readonly IRange [ ] , dataTransfer : VSDataTransfer , _token : CancellationToken ) : Promise < DocumentPasteEdit | undefined > {
35
- const textDataTransfer = dataTransfer . get ( Mimes . text ) ?? dataTransfer . get ( 'text' ) ;
36
- if ( textDataTransfer ) {
37
- const text = await textDataTransfer . asString ( ) ;
38
- return { insertText : text } ;
39
- }
40
-
41
- return undefined ;
42
- }
43
- } ;
29
+ interface CopyMetadata {
30
+ readonly id ?: string ;
31
+ readonly wasFromEmptySelection : boolean ;
32
+ }
44
33
45
34
export class CopyPasteController extends Disposable implements IEditorContribution {
46
35
@@ -97,7 +86,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
97
86
98
87
const ranges : IRange [ ] = [ ...selections ] ;
99
88
const primarySelection = selections [ 0 ] ;
100
- if ( primarySelection . isEmpty ( ) ) {
89
+ const wasFromEmptySelection = primarySelection . isEmpty ( ) ;
90
+ if ( wasFromEmptySelection ) {
101
91
if ( ! this . _editor . getOption ( EditorOption . emptySelectionClipboard ) ) {
102
92
return ;
103
93
}
@@ -106,14 +96,18 @@ export class CopyPasteController extends Disposable implements IEditorContributi
106
96
107
97
const providers = this . _languageFeaturesService . documentPasteEditProvider . ordered ( model ) . filter ( x => ! ! x . prepareDocumentPaste ) ;
108
98
if ( ! providers . length ) {
99
+ this . setCopyMetadata ( e . clipboardData , { wasFromEmptySelection } ) ;
109
100
return ;
110
101
}
111
102
112
103
const dataTransfer = toVSDataTransfer ( e . clipboardData ) ;
113
104
114
105
// Save off a handle pointing to data that VS Code maintains.
115
106
const handle = generateUuid ( ) ;
116
- e . clipboardData . setData ( vscodeClipboardMime , handle ) ;
107
+ this . setCopyMetadata ( e . clipboardData , {
108
+ id : handle ,
109
+ wasFromEmptySelection,
110
+ } ) ;
117
111
118
112
const promise = createCancelablePromise ( async token => {
119
113
const results = await Promise . all ( providers . map ( provider => {
@@ -133,6 +127,10 @@ export class CopyPasteController extends Disposable implements IEditorContributi
133
127
this . _currentClipboardItem = { handle : handle , dataTransferPromise : promise } ;
134
128
}
135
129
130
+ private setCopyMetadata ( dataTransfer : DataTransfer , metadata : CopyMetadata ) {
131
+ dataTransfer . setData ( vscodeClipboardMime , JSON . stringify ( metadata ) ) ;
132
+ }
133
+
136
134
private async handlePaste ( e : ClipboardEvent ) {
137
135
if ( ! e . clipboardData || ! this . _editor . hasTextFocus ( ) ) {
138
136
return ;
@@ -148,9 +146,10 @@ export class CopyPasteController extends Disposable implements IEditorContributi
148
146
return ;
149
147
}
150
148
151
- const handle = e . clipboardData ?. getData ( vscodeClipboardMime ) ;
152
- if ( typeof handle !== 'string' ) {
153
- return ;
149
+ let metadata : CopyMetadata | undefined ;
150
+ const rawMetadata = e . clipboardData ?. getData ( vscodeClipboardMime ) ;
151
+ if ( rawMetadata && typeof rawMetadata === 'string' ) {
152
+ metadata = JSON . parse ( rawMetadata ) ;
154
153
}
155
154
156
155
const providers = this . _languageFeaturesService . documentPasteEditProvider . ordered ( model ) ;
@@ -167,7 +166,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
167
166
try {
168
167
const dataTransfer = toVSDataTransfer ( e . clipboardData ) ;
169
168
170
- if ( handle && this . _currentClipboardItem ?. handle === handle ) {
169
+ if ( metadata ?. id && this . _currentClipboardItem ?. handle === metadata . id ) {
171
170
const toMergeDataTransfer = await this . _currentClipboardItem . dataTransferPromise ;
172
171
toMergeDataTransfer . forEach ( ( value , key ) => {
173
172
dataTransfer . replace ( key , value ) ;
@@ -184,7 +183,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
184
183
185
184
dataTransfer . delete ( vscodeClipboardMime ) ;
186
185
187
- for ( const provider of [ ... providers , defaultPasteEditProvider ] ) {
186
+ for ( const provider of providers ) {
188
187
if ( ! provider . pasteMimeTypes . some ( type => {
189
188
if ( type . toLowerCase ( ) === DataTransfers . FILES . toLowerCase ( ) ) {
190
189
return [ ...dataTransfer . values ( ) ] . some ( item => item . asFile ( ) ) ;
@@ -208,6 +207,23 @@ export class CopyPasteController extends Disposable implements IEditorContributi
208
207
return ;
209
208
}
210
209
}
210
+
211
+ // Default handler
212
+ const textDataTransfer = dataTransfer . get ( Mimes . text ) ?? dataTransfer . get ( 'text' ) ;
213
+ if ( ! textDataTransfer ) {
214
+ return ;
215
+ }
216
+
217
+ const text = await textDataTransfer . asString ( ) ;
218
+ if ( originalDocVersion !== model . getVersionId ( ) ) {
219
+ return ;
220
+ }
221
+
222
+ this . _editor . trigger ( 'keyboard' , Handler . Paste , < PastePayload > {
223
+ text : text ,
224
+ pasteOnNewLine : metadata ?. wasFromEmptySelection ,
225
+ multicursorText : null
226
+ } ) ;
211
227
} finally {
212
228
tokenSource . dispose ( ) ;
213
229
}
0 commit comments