55
66import { equals } from '../../../../base/common/arrays.js' ;
77import { Codicon } from '../../../../base/common/codicons.js' ;
8+ import { KeyCode } from '../../../../base/common/keyCodes.js' ;
89import { Disposable } from '../../../../base/common/lifecycle.js' ;
910import { autorun , derivedOpts , IObservable } from '../../../../base/common/observable.js' ;
1011import { localize , localize2 } from '../../../../nls.js' ;
1112import { MenuId , registerAction2 , Action2 , MenuRegistry } from '../../../../platform/actions/common/actions.js' ;
1213import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js' ;
14+ import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js' ;
15+ import { KeybindingsRegistry , KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js' ;
1316import { IQuickInputService , IQuickPickItem , IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js' ;
1417import { IWorkbenchContribution } from '../../../../workbench/common/contributions.js' ;
1518import { SessionsCategories } from '../../../common/categories.js' ;
@@ -26,6 +29,7 @@ export const RunScriptDropdownMenuId = MenuId.for('AgentSessionsRunScriptDropdow
2629
2730// Action IDs
2831const RUN_SCRIPT_ACTION_ID = 'workbench.action.agentSessions.runScript' ;
32+ const RUN_SCRIPT_ACTION_PRIMARY_ID = 'workbench.action.agentSessions.runScriptPrimary' ;
2933const CONFIGURE_DEFAULT_RUN_ACTION_ID = 'workbench.action.agentSessions.configureDefaultRunAction' ;
3034
3135function getTaskDisplayLabel ( task : ITaskEntry ) : string {
@@ -62,6 +66,7 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
6266
6367 constructor (
6468 @ISessionsManagementService private readonly _activeSessionService : ISessionsManagementService ,
69+ @IKeybindingService private readonly _keybindingService : IKeybindingService ,
6570 @IQuickInputService private readonly _quickInputService : IQuickInputService ,
6671 @ISessionsConfigurationService private readonly _sessionsConfigService : ISessionsConfigurationService ,
6772 ) {
@@ -94,6 +99,40 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
9499 private _registerActions ( ) : void {
95100 const that = this ;
96101
102+ this . _register ( registerAction2 ( class extends Action2 {
103+ constructor ( ) {
104+ super ( {
105+ id : RUN_SCRIPT_ACTION_PRIMARY_ID ,
106+ title : { value : localize ( 'runPrimaryScript' , 'Run Primary Script' ) , original : 'Run Primary Script' } ,
107+ icon : Codicon . play ,
108+ category : SessionsCategories . Sessions ,
109+ f1 : true ,
110+ } ) ;
111+ }
112+
113+ async run ( ) : Promise < void > {
114+ const activeState = that . _activeRunState . get ( ) ;
115+ if ( ! activeState ) {
116+ return ;
117+ }
118+
119+ const { tasks, session, lastRunTaskLabel } = activeState ;
120+ if ( tasks . length === 0 ) {
121+ const task = await that . _showConfigureQuickPick ( session ) ;
122+ if ( task ) {
123+ await that . _sessionsConfigService . runTask ( task , session ) ;
124+ }
125+ return ;
126+ }
127+
128+ const mruIndex = lastRunTaskLabel !== undefined
129+ ? tasks . findIndex ( t => t . label === lastRunTaskLabel )
130+ : - 1 ;
131+ const primaryTask = tasks [ mruIndex >= 0 ? mruIndex : 0 ] ;
132+ await that . _sessionsConfigService . runTask ( primaryTask , session ) ;
133+ }
134+ } ) ) ;
135+
97136 this . _register ( autorun ( reader => {
98137 const activeState = this . _activeRunState . read ( reader ) ;
99138 if ( ! activeState ) {
@@ -112,13 +151,15 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
112151 for ( let i = 0 ; i < tasks . length ; i ++ ) {
113152 const task = tasks [ i ] ;
114153 const actionId = `${ RUN_SCRIPT_ACTION_ID } .${ i } ` ;
154+ const isPrimary = i === ( mruIndex >= 0 ? mruIndex : 0 ) ;
115155
116156 reader . store . add ( registerAction2 ( class extends Action2 {
117157 constructor ( ) {
118158 super ( {
119159 id : actionId ,
120160 title : getTaskDisplayLabel ( task ) ,
121- tooltip : localize ( 'runActionTooltip' , "Run '{0}' in terminal" , getTaskDisplayLabel ( task ) ) ,
161+ tooltip : ! isPrimary ? localize ( 'runActionTooltip' , "Run '{0}' in terminal" , getTaskDisplayLabel ( task ) )
162+ : localize ( 'runActionTooltipKeybinding' , "Run '{0}' in terminal ({1})" , getTaskDisplayLabel ( task ) , that . _keybindingService . lookupKeybinding ( RUN_SCRIPT_ACTION_PRIMARY_ID ) ?. getLabel ( ) ?? '' ) ,
122163 icon : Codicon . play ,
123164 category : SessionsCategories . Sessions ,
124165 menu : [ {
@@ -154,18 +195,20 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
154195 }
155196
156197 async run ( ) : Promise < void > {
157- await that . _showConfigureQuickPick ( session ) ;
198+ const task = await that . _showConfigureQuickPick ( session ) ;
199+ if ( task ) {
200+ await that . _sessionsConfigService . runTask ( task , session ) ;
201+ }
158202 }
159203 } ) ) ;
160204 } ) ) ;
161205 }
162206
163- private async _showConfigureQuickPick ( session : IActiveSessionItem ) : Promise < void > {
207+ private async _showConfigureQuickPick ( session : IActiveSessionItem ) : Promise < ITaskEntry | undefined > {
164208 const nonSessionTasks = await this . _sessionsConfigService . getNonSessionTasks ( session ) ;
165209 if ( nonSessionTasks . length === 0 ) {
166210 // No existing tasks, go straight to custom command input
167- await this . _showCustomCommandInput ( session ) ;
168- return ;
211+ return this . _showCustomCommandInput ( session ) ;
169212 }
170213
171214 interface ITaskPickItem extends IQuickPickItem {
@@ -198,38 +241,36 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
198241 } ) ;
199242
200243 if ( ! picked ) {
201- return ;
244+ return undefined ;
202245 }
203246
204247 const pickedItem = picked as ITaskPickItem ;
205248 if ( pickedItem . task ) {
206249 // Existing task — set inSessions: true
207250 await this . _sessionsConfigService . addTaskToSessions ( pickedItem . task , session , pickedItem . source ?? 'workspace' ) ;
251+ return pickedItem . task ;
208252 } else {
209253 // Custom command path
210- await this . _showCustomCommandInput ( session ) ;
254+ return this . _showCustomCommandInput ( session ) ;
211255 }
212256 }
213257
214- private async _showCustomCommandInput ( session : IActiveSessionItem ) : Promise < void > {
258+ private async _showCustomCommandInput ( session : IActiveSessionItem ) : Promise < ITaskEntry | undefined > {
215259 const command = await this . _quickInputService . input ( {
216260 placeHolder : localize ( 'enterCommandPlaceholder' , "Enter command (e.g., npm run dev)" ) ,
217261 prompt : localize ( 'enterCommandPrompt' , "This command will be run as a task in the integrated terminal" )
218262 } ) ;
219263
220264 if ( ! command ) {
221- return ;
265+ return undefined ;
222266 }
223267
224268 const target = await this . _pickStorageTarget ( session ) ;
225269 if ( ! target ) {
226- return ;
270+ return undefined ;
227271 }
228272
229- const newTask = await this . _sessionsConfigService . createAndAddTask ( command , session , target ) ;
230- if ( newTask ) {
231- await this . _sessionsConfigService . runTask ( newTask , session ) ;
232- }
273+ return this . _sessionsConfigService . createAndAddTask ( command , session , target ) ;
233274 }
234275
235276 private async _pickStorageTarget ( session : IActiveSessionItem ) : Promise < TaskStorageTarget | undefined > {
@@ -317,3 +358,13 @@ class RunScriptNotAvailableAction extends Action2 {
317358}
318359
319360registerAction2 ( RunScriptNotAvailableAction ) ;
361+
362+ // Register F5 keybinding at module level to ensure it's in the registry
363+ // before the keybinding resolver is cached. The command handler is
364+ // registered later by RunScriptContribution.
365+ KeybindingsRegistry . registerKeybindingRule ( {
366+ id : RUN_SCRIPT_ACTION_PRIMARY_ID ,
367+ primary : KeyCode . F5 ,
368+ weight : KeybindingWeight . WorkbenchContrib + 100 ,
369+ when : IsAuxiliaryWindowContext . toNegated ( )
370+ } ) ;
0 commit comments