3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
+ import { isAncestorOfActiveElement } from '../../../../../base/browser/dom.js' ;
6
7
import { toAction , WorkbenchActionExecutedClassification , WorkbenchActionExecutedEvent } from '../../../../../base/common/actions.js' ;
7
8
import { coalesce } from '../../../../../base/common/arrays.js' ;
8
9
import { Codicon } from '../../../../../base/common/codicons.js' ;
@@ -21,7 +22,7 @@ import { SuggestController } from '../../../../../editor/contrib/suggest/browser
21
22
import { localize , localize2 } from '../../../../../nls.js' ;
22
23
import { IActionViewItemService } from '../../../../../platform/actions/browser/actionViewItemService.js' ;
23
24
import { DropdownWithPrimaryActionViewItem } from '../../../../../platform/actions/browser/dropdownWithPrimaryActionViewItem.js' ;
24
- import { Action2 , MenuId , MenuItemAction , MenuRegistry , registerAction2 , SubmenuItemAction } from '../../../../../platform/actions/common/actions.js' ;
25
+ import { Action2 , ICommandPaletteOptions , MenuId , MenuItemAction , MenuRegistry , registerAction2 , SubmenuItemAction } from '../../../../../platform/actions/common/actions.js' ;
25
26
import { ICommandService } from '../../../../../platform/commands/common/commands.js' ;
26
27
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js' ;
27
28
import { IsLinuxContext , IsWindowsContext } from '../../../../../platform/contextkey/common/contextkeys.js' ;
@@ -50,7 +51,7 @@ import { extractAgentAndCommand } from '../../common/chatParserTypes.js';
50
51
import { IChatDetail , IChatService } from '../../common/chatService.js' ;
51
52
import { IChatRequestViewModel , IChatResponseViewModel , isRequestVM } from '../../common/chatViewModel.js' ;
52
53
import { IChatWidgetHistoryService } from '../../common/chatWidgetHistoryService.js' ;
53
- import { ChatMode , validateChatMode } from '../../common/constants.js' ;
54
+ import { ChatConfiguration , ChatMode , modeToString , validateChatMode } from '../../common/constants.js' ;
54
55
import { CopilotUsageExtensionFeatureId } from '../../common/languageModelStats.js' ;
55
56
import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js' ;
56
57
import { ChatViewId , IChatWidget , IChatWidgetService , showChatView , showCopilotView } from '../chat.js' ;
@@ -100,88 +101,140 @@ export interface IChatViewOpenRequestEntry {
100
101
101
102
const OPEN_CHAT_QUOTA_EXCEEDED_DIALOG = 'workbench.action.chat.openQuotaExceededDialog' ;
102
103
103
- export function registerChatActions ( ) {
104
- registerAction2 ( class OpenChatGlobalAction extends Action2 {
104
+ abstract class OpenChatGlobalAction extends Action2 {
105
+ constructor ( overrides : Pick < ICommandPaletteOptions , 'keybinding' | 'title' | 'id' | 'menu' > , private readonly mode ?: ChatMode ) {
106
+ super ( {
107
+ ...overrides ,
108
+ icon : Codicon . copilot ,
109
+ f1 : true ,
110
+ category : CHAT_CATEGORY ,
111
+ precondition : ChatContextKeys . Setup . hidden . negate ( ) ,
112
+ } ) ;
113
+ }
105
114
106
- constructor ( ) {
107
- super ( {
108
- id : CHAT_OPEN_ACTION_ID ,
109
- title : localize2 ( 'openChat' , "Open Chat" ) ,
110
- icon : Codicon . copilot ,
111
- f1 : true ,
112
- category : CHAT_CATEGORY ,
113
- precondition : ChatContextKeys . Setup . hidden . negate ( ) ,
114
- keybinding : {
115
- weight : KeybindingWeight . WorkbenchContrib ,
116
- primary : KeyMod . CtrlCmd | KeyMod . Alt | KeyCode . KeyI ,
117
- mac : {
118
- primary : KeyMod . CtrlCmd | KeyMod . WinCtrl | KeyCode . KeyI
119
- }
120
- } ,
121
- menu : [ {
122
- id : MenuId . ChatTitleBarMenu ,
123
- group : 'a_open' ,
124
- order : 1
125
- } ]
126
- } ) ;
127
- }
115
+ override async run ( accessor : ServicesAccessor , opts ?: string | IChatViewOpenOptions ) : Promise < void > {
116
+ opts = typeof opts === 'string' ? { query : opts } : opts ;
128
117
129
- override async run ( accessor : ServicesAccessor , opts ?: string | IChatViewOpenOptions ) : Promise < void > {
130
- opts = typeof opts === 'string' ? { query : opts } : opts ;
118
+ const chatService = accessor . get ( IChatService ) ;
119
+ const widgetService = accessor . get ( IChatWidgetService ) ;
120
+ const toolsService = accessor . get ( ILanguageModelToolsService ) ;
121
+ const viewsService = accessor . get ( IViewsService ) ;
122
+ const hostService = accessor . get ( IHostService ) ;
131
123
132
- const chatService = accessor . get ( IChatService ) ;
133
- const toolsService = accessor . get ( ILanguageModelToolsService ) ;
134
- const viewsService = accessor . get ( IViewsService ) ;
135
- const hostService = accessor . get ( IHostService ) ;
136
124
137
- const chatWidget = await showChatView ( viewsService ) ;
138
- if ( ! chatWidget ) {
139
- return ;
125
+ let chatWidget = widgetService . lastFocusedWidget ;
126
+ // When this was invoked to switch to a mode via keybinding, and some chat widget is focused, use that one.
127
+ // Otherwise, open the view.
128
+ if ( ! this . mode || ! chatWidget || ! isAncestorOfActiveElement ( chatWidget . domNode ) ) {
129
+ chatWidget = await showChatView ( viewsService ) ;
130
+ }
131
+
132
+ if ( ! chatWidget ) {
133
+ return ;
134
+ }
135
+
136
+ const mode = opts ?. mode ?? this . mode ;
137
+ if ( mode && validateChatMode ( mode ) ) {
138
+ chatWidget . input . setChatMode ( mode ) ;
139
+ }
140
+ if ( opts ?. previousRequests ?. length && chatWidget . viewModel ) {
141
+ for ( const { request, response } of opts . previousRequests ) {
142
+ chatService . addCompleteRequest ( chatWidget . viewModel . sessionId , request , undefined , 0 , { message : response } ) ;
140
143
}
141
- if ( opts ?. mode && validateChatMode ( opts . mode ) ) {
142
- chatWidget . input . setChatMode ( opts . mode ) ;
144
+ }
145
+ if ( opts ?. attachScreenshot ) {
146
+ const screenshot = await hostService . getScreenshot ( ) ;
147
+ if ( screenshot ) {
148
+ chatWidget . attachmentModel . addContext ( convertBufferToScreenshotVariable ( screenshot ) ) ;
143
149
}
144
- if ( opts ?. previousRequests ?. length && chatWidget . viewModel ) {
145
- for ( const { request , response } of opts . previousRequests ) {
146
- chatService . addCompleteRequest ( chatWidget . viewModel . sessionId , request , undefined , 0 , { message : response } ) ;
147
- }
150
+ }
151
+ if ( opts ?. query ) {
152
+ if ( opts . query . startsWith ( '@' ) && ( chatWidget . input . currentMode === ChatMode . Agent || chatService . edits2Enabled ) ) {
153
+ chatWidget . input . setChatMode ( ChatMode . Ask ) ;
148
154
}
149
- if ( opts ?. attachScreenshot ) {
150
- const screenshot = await hostService . getScreenshot ( ) ;
151
- if ( screenshot ) {
152
- chatWidget . attachmentModel . addContext ( convertBufferToScreenshotVariable ( screenshot ) ) ;
153
- }
155
+ if ( opts . isPartialQuery ) {
156
+ chatWidget . setInput ( opts . query ) ;
157
+ } else {
158
+ await chatWidget . waitForReady ( ) ;
159
+ chatWidget . acceptInput ( opts . query ) ;
154
160
}
155
- if ( opts ?. query ) {
156
- if ( opts . query . startsWith ( '@' ) && ( chatWidget . input . currentMode === ChatMode . Agent || chatService . edits2Enabled ) ) {
157
- chatWidget . input . setChatMode ( ChatMode . Ask ) ;
158
- }
159
- if ( opts . isPartialQuery ) {
160
- chatWidget . setInput ( opts . query ) ;
161
- } else {
162
- await chatWidget . waitForReady ( ) ;
163
- chatWidget . acceptInput ( opts . query ) ;
161
+ }
162
+ if ( opts ?. toolIds && opts . toolIds . length > 0 ) {
163
+ for ( const toolId of opts . toolIds ) {
164
+ const tool = toolsService . getTool ( toolId ) ;
165
+ if ( tool ) {
166
+ chatWidget . attachmentModel . addContext ( {
167
+ id : tool . id ,
168
+ name : tool . displayName ,
169
+ fullName : tool . displayName ,
170
+ value : undefined ,
171
+ icon : ThemeIcon . isThemeIcon ( tool . icon ) ? tool . icon : undefined ,
172
+ kind : 'tool'
173
+ } ) ;
164
174
}
165
175
}
166
- if ( opts ?. toolIds && opts . toolIds . length > 0 ) {
167
- for ( const toolId of opts . toolIds ) {
168
- const tool = toolsService . getTool ( toolId ) ;
169
- if ( tool ) {
170
- chatWidget . attachmentModel . addContext ( {
171
- id : tool . id ,
172
- name : tool . displayName ,
173
- fullName : tool . displayName ,
174
- value : undefined ,
175
- icon : ThemeIcon . isThemeIcon ( tool . icon ) ? tool . icon : undefined ,
176
- kind : 'tool'
177
- } ) ;
178
- }
176
+ }
177
+
178
+ chatWidget . focusInput ( ) ;
179
+ }
180
+ }
181
+
182
+ class PrimaryOpenChatGlobalAction extends OpenChatGlobalAction {
183
+ constructor ( ) {
184
+ super ( {
185
+ id : CHAT_OPEN_ACTION_ID ,
186
+ title : localize2 ( 'openChat' , "Open Chat" ) ,
187
+ keybinding : {
188
+ weight : KeybindingWeight . WorkbenchContrib ,
189
+ primary : KeyMod . CtrlCmd | KeyMod . Alt | KeyCode . KeyI ,
190
+ mac : {
191
+ primary : KeyMod . CtrlCmd | KeyMod . WinCtrl | KeyCode . KeyI
179
192
}
180
- }
193
+ } ,
194
+ menu : [ {
195
+ id : MenuId . ChatTitleBarMenu ,
196
+ group : 'a_open' ,
197
+ order : 1
198
+ } ]
199
+ } ) ;
200
+ }
201
+ }
202
+
203
+ export function getOpenChatActionIdForMode ( mode : ChatMode ) : string {
204
+ const modeStr = modeToString ( mode ) ;
205
+ return `workbench.action.chat.open${ modeStr } ` ;
206
+ }
207
+
208
+ abstract class ModeOpenChatGlobalAction extends OpenChatGlobalAction {
209
+ constructor ( mode : ChatMode , keybinding ?: ICommandPaletteOptions [ 'keybinding' ] ) {
210
+ super ( {
211
+ id : getOpenChatActionIdForMode ( mode ) ,
212
+ title : localize2 ( 'openChatMode' , "Open Chat ({0})" , modeToString ( mode ) ) ,
213
+ keybinding
214
+ } , mode ) ;
215
+ }
216
+ }
181
217
182
- chatWidget . focusInput ( ) ;
218
+ export function registerChatActions ( ) {
219
+ registerAction2 ( PrimaryOpenChatGlobalAction ) ;
220
+ registerAction2 ( class extends ModeOpenChatGlobalAction {
221
+ constructor ( ) { super ( ChatMode . Ask ) ; }
222
+ } ) ;
223
+ registerAction2 ( class extends ModeOpenChatGlobalAction {
224
+ constructor ( ) {
225
+ super ( ChatMode . Agent , {
226
+ when : ContextKeyExpr . has ( `config.${ ChatConfiguration . AgentEnabled } ` ) ,
227
+ weight : KeybindingWeight . WorkbenchContrib ,
228
+ primary : KeyMod . CtrlCmd | KeyMod . Shift | KeyCode . KeyI ,
229
+ linux : {
230
+ primary : KeyMod . CtrlCmd | KeyMod . Alt | KeyMod . Shift | KeyCode . KeyI
231
+ }
232
+ } , ) ;
183
233
}
184
234
} ) ;
235
+ registerAction2 ( class extends ModeOpenChatGlobalAction {
236
+ constructor ( ) { super ( ChatMode . Edit ) ; }
237
+ } ) ;
185
238
186
239
registerAction2 ( class ToggleChatAction extends Action2 {
187
240
constructor ( ) {
0 commit comments