3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
- import { localize } from 'vs/nls' ;
7
6
import { Codicon } from 'vs/base/common/codicons' ;
7
+ import { KeyCode , KeyMod } from 'vs/base/common/keyCodes' ;
8
8
import { ICodeEditor , isCodeEditor , isDiffEditor } from 'vs/editor/browser/editorBrowser' ;
9
- import { ServicesAccessor } from 'vs/editor/browser/editorExtensions' ;
9
+ import { EditorAction2 , ServicesAccessor } from 'vs/editor/browser/editorExtensions' ;
10
10
import { IBulkEditService , ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService' ;
11
+ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService' ;
11
12
import { Range } from 'vs/editor/common/core/range' ;
12
13
import { ILanguageService } from 'vs/editor/common/languages/language' ;
13
14
import { ITextModel } from 'vs/editor/common/model' ;
15
+ import { CopyAction } from 'vs/editor/contrib/clipboard/browser/clipboard' ;
16
+ import { localize } from 'vs/nls' ;
14
17
import { Action2 , MenuId , registerAction2 } from 'vs/platform/actions/common/actions' ;
15
18
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
19
+ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry' ;
16
20
import { TerminalLocation } from 'vs/platform/terminal/common/terminal' ;
17
21
import { IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor' ;
18
22
import { INTERACTIVE_SESSION_CATEGORY } from 'vs/workbench/contrib/interactiveSession/browser/actions/interactiveSessionActions' ;
23
+ import { codeBlockInfoByModelUri } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer' ;
19
24
import { IInteractiveSessionCopyAction , IInteractiveSessionService , IInteractiveSessionUserActionEvent , InteractiveSessionCopyKind } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService' ;
20
25
import { IInteractiveResponseViewModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionViewModel' ;
26
+ import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations' ;
27
+ import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser' ;
28
+ import { CellKind , NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon' ;
21
29
import { ITerminalEditorService , ITerminalGroupService , ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal' ;
22
30
import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
23
31
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles' ;
24
- import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser' ;
25
- import { CellKind , NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon' ;
26
- import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations' ;
27
32
28
33
export interface IInteractiveSessionCodeBlockActionContext {
29
34
code : string ;
@@ -80,15 +85,64 @@ export function registerInteractiveSessionCodeBlockActions() {
80
85
}
81
86
} ) ;
82
87
83
- registerAction2 ( class InsertCodeBlockAction extends Action2 {
88
+ CopyAction ?. addImplementation ( 50000 , 'interactiveSession-codeblock' , ( accessor ) => {
89
+ // get active code editor
90
+ const editor = accessor . get ( ICodeEditorService ) . getFocusedCodeEditor ( ) ;
91
+ if ( ! editor ) {
92
+ return false ;
93
+ }
94
+
95
+ const editorModel = editor . getModel ( ) ;
96
+ if ( ! editorModel ) {
97
+ return false ;
98
+ }
99
+
100
+ const context = getContextFromEditor ( editor ) ;
101
+ if ( ! context ) {
102
+ return false ;
103
+ }
104
+
105
+ const noSelection = editor . getSelections ( ) ?. length === 1 && editor . getSelection ( ) ?. isEmpty ( ) ;
106
+ const copiedText = noSelection ?
107
+ editorModel . getValue ( ) :
108
+ editor . getSelections ( ) ?. reduce ( ( acc , selection ) => acc + editorModel . getValueInRange ( selection ) , '' ) ?? '' ;
109
+ const totalCharacters = editorModel . getValueLength ( ) ;
110
+
111
+ // Report copy to extensions
112
+ if ( context . element . providerResponseId ) {
113
+ const interactiveSessionService = accessor . get ( IInteractiveSessionService ) ;
114
+ interactiveSessionService . notifyUserAction ( {
115
+ providerId : context . element . providerId ,
116
+ action : {
117
+ kind : 'copy' ,
118
+ codeBlockIndex : context . codeBlockIndex ,
119
+ responseId : context . element . providerResponseId ,
120
+ copyType : InteractiveSessionCopyKind . Action ,
121
+ copiedText,
122
+ copiedCharacters : copiedText . length ,
123
+ totalCharacters,
124
+ }
125
+ } ) ;
126
+ }
127
+
128
+ // Copy full cell if no selection, otherwise fall back on normal editor implementation
129
+ if ( noSelection ) {
130
+ accessor . get ( IClipboardService ) . writeText ( context . code ) ;
131
+ return true ;
132
+ }
133
+
134
+ return false ;
135
+ } ) ;
136
+
137
+ registerAction2 ( class InsertCodeBlockAction extends EditorAction2 {
84
138
constructor ( ) {
85
139
super ( {
86
140
id : 'workbench.action.interactiveSession.insertCodeBlock' ,
87
141
title : {
88
142
value : localize ( 'interactive.insertCodeBlock.label' , "Insert at Cursor" ) ,
89
143
original : 'Insert at Cursor'
90
144
} ,
91
- f1 : false ,
145
+ f1 : true ,
92
146
category : INTERACTIVE_SESSION_CATEGORY ,
93
147
icon : Codicon . insert ,
94
148
menu : {
@@ -98,10 +152,13 @@ export function registerInteractiveSessionCodeBlockActions() {
98
152
} ) ;
99
153
}
100
154
101
- async run ( accessor : ServicesAccessor , ...args : any [ ] ) {
102
- const context = args [ 0 ] ;
155
+ override async runEditorCommand ( accessor : ServicesAccessor , editor : ICodeEditor , ...args : any [ ] ) {
156
+ let context = args [ 0 ] ;
103
157
if ( ! isCodeBlockActionContext ( context ) ) {
104
- return ;
158
+ context = getContextFromEditor ( editor ) ;
159
+ if ( ! isCodeBlockActionContext ( context ) ) {
160
+ return ;
161
+ }
105
162
}
106
163
107
164
const editorService = accessor . get ( IEditorService ) ;
@@ -160,15 +217,14 @@ export function registerInteractiveSessionCodeBlockActions() {
160
217
}
161
218
162
219
private async handleTextEditor ( accessor : ServicesAccessor , codeEditor : ICodeEditor , activeModel : ITextModel , context : IInteractiveSessionCodeBlockActionContext ) {
220
+ this . notifyUserAction ( accessor , context ) ;
163
221
const bulkEditService = accessor . get ( IBulkEditService ) ;
164
222
165
223
const activeSelection = codeEditor . getSelection ( ) ?? new Range ( activeModel . getLineCount ( ) , 1 , activeModel . getLineCount ( ) , 1 ) ;
166
224
await bulkEditService . apply ( [ new ResourceTextEdit ( activeModel . uri , {
167
225
range : activeSelection ,
168
226
text : context . code ,
169
227
} ) ] ) ;
170
-
171
- this . notifyUserAction ( accessor , context ) ;
172
228
}
173
229
174
230
private notifyUserAction ( accessor : ServicesAccessor , context : IInteractiveSessionCodeBlockActionContext ) {
@@ -186,15 +242,15 @@ export function registerInteractiveSessionCodeBlockActions() {
186
242
187
243
} ) ;
188
244
189
- registerAction2 ( class InsertIntoNewFileAction extends Action2 {
245
+ registerAction2 ( class InsertIntoNewFileAction extends EditorAction2 {
190
246
constructor ( ) {
191
247
super ( {
192
248
id : 'workbench.action.interactiveSession.insertIntoNewFile' ,
193
249
title : {
194
250
value : localize ( 'interactive.insertIntoNewFile.label' , "Insert Into New File" ) ,
195
251
original : 'Insert Into New File'
196
252
} ,
197
- f1 : false ,
253
+ f1 : true ,
198
254
category : INTERACTIVE_SESSION_CATEGORY ,
199
255
icon : Codicon . newFile ,
200
256
menu : {
@@ -205,10 +261,13 @@ export function registerInteractiveSessionCodeBlockActions() {
205
261
} ) ;
206
262
}
207
263
208
- async run ( accessor : ServicesAccessor , ...args : any [ ] ) {
209
- const context = args [ 0 ] ;
264
+ override async runEditorCommand ( accessor : ServicesAccessor , editor : ICodeEditor , ...args : any [ ] ) {
265
+ let context = args [ 0 ] ;
210
266
if ( ! isCodeBlockActionContext ( context ) ) {
211
- return ;
267
+ context = getContextFromEditor ( editor ) ;
268
+ if ( ! isCodeBlockActionContext ( context ) ) {
269
+ return ;
270
+ }
212
271
}
213
272
214
273
const editorService = accessor . get ( IEditorService ) ;
@@ -228,29 +287,39 @@ export function registerInteractiveSessionCodeBlockActions() {
228
287
}
229
288
} ) ;
230
289
231
- registerAction2 ( class RunInTerminalAction extends Action2 {
290
+ registerAction2 ( class RunInTerminalAction extends EditorAction2 {
232
291
constructor ( ) {
233
292
super ( {
234
293
id : 'workbench.action.interactiveSession.runInTerminal' ,
235
294
title : {
236
295
value : localize ( 'interactive.runInTerminal.label' , "Run in Terminal" ) ,
237
296
original : 'Run in Terminal'
238
297
} ,
239
- f1 : false ,
298
+ f1 : true ,
240
299
category : INTERACTIVE_SESSION_CATEGORY ,
241
300
icon : Codicon . terminal ,
242
301
menu : {
243
302
id : MenuId . InteractiveSessionCodeBlock ,
244
303
group : 'navigation' ,
245
304
isHiddenByDefault : true ,
305
+ } ,
306
+ keybinding : {
307
+ primary : KeyMod . WinCtrl | KeyCode . Enter ,
308
+ win : {
309
+ primary : KeyMod . CtrlCmd | KeyMod . Alt | KeyCode . Enter
310
+ } ,
311
+ weight : KeybindingWeight . EditorContrib
246
312
}
247
313
} ) ;
248
314
}
249
315
250
- async run ( accessor : ServicesAccessor , ...args : any [ ] ) {
251
- const context = args [ 0 ] ;
316
+ override async runEditorCommand ( accessor : ServicesAccessor , editor : ICodeEditor , ...args : any [ ] ) {
317
+ let context = args [ 0 ] ;
252
318
if ( ! isCodeBlockActionContext ( context ) ) {
253
- return ;
319
+ context = getContextFromEditor ( editor ) ;
320
+ if ( ! isCodeBlockActionContext ( context ) ) {
321
+ return ;
322
+ }
254
323
}
255
324
256
325
const interactiveSessionService = accessor . get ( IInteractiveSessionService ) ;
@@ -275,7 +344,7 @@ export function registerInteractiveSessionCodeBlockActions() {
275
344
terminalGroupService . showPanel ( true ) ;
276
345
}
277
346
278
- terminal . sendText ( context . code , false ) ;
347
+ terminal . sendText ( context . code , false , true ) ;
279
348
280
349
interactiveSessionService . notifyUserAction ( < IInteractiveSessionUserActionEvent > {
281
350
providerId : context . element . providerId ,
@@ -289,3 +358,22 @@ export function registerInteractiveSessionCodeBlockActions() {
289
358
}
290
359
} ) ;
291
360
}
361
+
362
+ function getContextFromEditor ( editor : ICodeEditor ) : IInteractiveSessionCodeBlockActionContext | undefined {
363
+ const model = editor . getModel ( ) ;
364
+ if ( ! model ) {
365
+ return ;
366
+ }
367
+
368
+ const codeBlockInfo = codeBlockInfoByModelUri . get ( model . uri ) ;
369
+ if ( ! codeBlockInfo ) {
370
+ return ;
371
+ }
372
+
373
+ return {
374
+ element : codeBlockInfo . element ,
375
+ codeBlockIndex : codeBlockInfo . codeBlockIndex ,
376
+ code : editor . getValue ( ) ,
377
+ languageId : editor . getModel ( ) ! . getLanguageId ( ) ,
378
+ } ;
379
+ }
0 commit comments