Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/browserView/electron-browser/browserViewActions.ts
5220 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { localize2 } from '../../../../nls.js';
7
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
8
import { Action2, registerAction2, MenuId } from '../../../../platform/actions/common/actions.js';
9
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
10
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
11
import { KeyMod, KeyCode } from '../../../../base/common/keyCodes.js';
12
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from '../../../services/editor/common/editorService.js';
13
import { Codicon } from '../../../../base/common/codicons.js';
14
import { BrowserEditor, CONTEXT_BROWSER_CAN_GO_BACK, CONTEXT_BROWSER_CAN_GO_FORWARD, CONTEXT_BROWSER_DEVTOOLS_OPEN, CONTEXT_BROWSER_FOCUSED, CONTEXT_BROWSER_HAS_URL, CONTEXT_BROWSER_STORAGE_SCOPE, CONTEXT_BROWSER_ELEMENT_SELECTION_ACTIVE, CONTEXT_BROWSER_FIND_WIDGET_FOCUSED, CONTEXT_BROWSER_FIND_WIDGET_VISIBLE } from './browserEditor.js';
15
import { BrowserViewUri } from '../../../../platform/browserView/common/browserViewUri.js';
16
import { IBrowserViewWorkbenchService } from '../common/browserView.js';
17
import { BrowserViewStorageScope } from '../../../../platform/browserView/common/browserView.js';
18
import { ChatContextKeys } from '../../chat/common/actions/chatContextKeys.js';
19
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
20
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
21
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
22
import { logBrowserOpen } from './browserViewTelemetry.js';
23
24
// Context key expression to check if browser editor is active
25
const BROWSER_EDITOR_ACTIVE = ContextKeyExpr.equals('activeEditor', BrowserEditor.ID);
26
27
const BrowserCategory = localize2('browserCategory', "Browser");
28
const ActionGroupTabs = '1_tabs';
29
const ActionGroupPage = '2_page';
30
const ActionGroupSettings = '3_settings';
31
32
interface IOpenBrowserOptions {
33
url?: string;
34
openToSide?: boolean;
35
}
36
37
class OpenIntegratedBrowserAction extends Action2 {
38
constructor() {
39
super({
40
id: 'workbench.action.browser.open',
41
title: localize2('browser.openAction', "Open Integrated Browser"),
42
category: BrowserCategory,
43
f1: true
44
});
45
}
46
47
async run(accessor: ServicesAccessor, urlOrOptions?: string | IOpenBrowserOptions): Promise<void> {
48
const editorService = accessor.get(IEditorService);
49
const telemetryService = accessor.get(ITelemetryService);
50
51
// Parse arguments
52
const options = typeof urlOrOptions === 'string' ? { url: urlOrOptions } : (urlOrOptions ?? {});
53
const resource = BrowserViewUri.forUrl(options.url);
54
const group = options.openToSide ? SIDE_GROUP : ACTIVE_GROUP;
55
56
logBrowserOpen(telemetryService, options.url ? 'commandWithUrl' : 'commandWithoutUrl');
57
58
await editorService.openEditor({ resource }, group);
59
}
60
}
61
62
class NewTabAction extends Action2 {
63
constructor() {
64
super({
65
id: 'workbench.action.browser.newTab',
66
title: localize2('browser.newTabAction', "New Tab"),
67
category: BrowserCategory,
68
f1: true,
69
precondition: BROWSER_EDITOR_ACTIVE,
70
menu: {
71
id: MenuId.BrowserActionsToolbar,
72
group: ActionGroupTabs,
73
order: 1,
74
},
75
// When already in a browser, Ctrl/Cmd + T opens a new tab
76
keybinding: {
77
weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over search actions
78
primary: KeyMod.CtrlCmd | KeyCode.KeyT,
79
}
80
});
81
}
82
83
async run(accessor: ServicesAccessor, _browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
84
const editorService = accessor.get(IEditorService);
85
const telemetryService = accessor.get(ITelemetryService);
86
const resource = BrowserViewUri.forUrl(undefined);
87
88
logBrowserOpen(telemetryService, 'newTabCommand');
89
90
await editorService.openEditor({ resource });
91
}
92
}
93
94
class GoBackAction extends Action2 {
95
static readonly ID = 'workbench.action.browser.goBack';
96
97
constructor() {
98
super({
99
id: GoBackAction.ID,
100
title: localize2('browser.goBackAction', 'Go Back'),
101
category: BrowserCategory,
102
icon: Codicon.arrowLeft,
103
f1: true,
104
precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_CAN_GO_BACK),
105
menu: {
106
id: MenuId.BrowserNavigationToolbar,
107
group: 'navigation',
108
order: 1,
109
},
110
keybinding: {
111
weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over editor navigation
112
primary: KeyMod.Alt | KeyCode.LeftArrow,
113
secondary: [KeyCode.BrowserBack],
114
mac: { primary: KeyMod.CtrlCmd | KeyCode.BracketLeft, secondary: [KeyCode.BrowserBack, KeyMod.CtrlCmd | KeyCode.LeftArrow] }
115
}
116
});
117
}
118
119
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
120
if (browserEditor instanceof BrowserEditor) {
121
await browserEditor.goBack();
122
}
123
}
124
}
125
126
class GoForwardAction extends Action2 {
127
static readonly ID = 'workbench.action.browser.goForward';
128
129
constructor() {
130
super({
131
id: GoForwardAction.ID,
132
title: localize2('browser.goForwardAction', 'Go Forward'),
133
category: BrowserCategory,
134
icon: Codicon.arrowRight,
135
f1: true,
136
precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_CAN_GO_FORWARD),
137
menu: {
138
id: MenuId.BrowserNavigationToolbar,
139
group: 'navigation',
140
order: 2,
141
},
142
keybinding: {
143
weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over editor navigation
144
primary: KeyMod.Alt | KeyCode.RightArrow,
145
secondary: [KeyCode.BrowserForward],
146
mac: { primary: KeyMod.CtrlCmd | KeyCode.BracketRight, secondary: [KeyCode.BrowserForward, KeyMod.CtrlCmd | KeyCode.RightArrow] }
147
}
148
});
149
}
150
151
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
152
if (browserEditor instanceof BrowserEditor) {
153
await browserEditor.goForward();
154
}
155
}
156
}
157
158
class ReloadAction extends Action2 {
159
static readonly ID = 'workbench.action.browser.reload';
160
161
constructor() {
162
super({
163
id: ReloadAction.ID,
164
title: localize2('browser.reloadAction', 'Reload'),
165
category: BrowserCategory,
166
icon: Codicon.refresh,
167
f1: true,
168
precondition: BROWSER_EDITOR_ACTIVE,
169
menu: {
170
id: MenuId.BrowserNavigationToolbar,
171
group: 'navigation',
172
order: 3,
173
},
174
keybinding: {
175
when: CONTEXT_BROWSER_FOCUSED,
176
weight: KeybindingWeight.WorkbenchContrib + 75, // Priority over debug and reload workbench
177
primary: KeyMod.CtrlCmd | KeyCode.KeyR,
178
secondary: [KeyCode.F5],
179
mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyR, secondary: [] }
180
}
181
});
182
}
183
184
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
185
if (browserEditor instanceof BrowserEditor) {
186
await browserEditor.reload();
187
}
188
}
189
}
190
191
class FocusUrlInputAction extends Action2 {
192
static readonly ID = 'workbench.action.browser.focusUrlInput';
193
194
constructor() {
195
super({
196
id: FocusUrlInputAction.ID,
197
title: localize2('browser.focusUrlInputAction', 'Focus URL Input'),
198
category: BrowserCategory,
199
f1: true,
200
precondition: BROWSER_EDITOR_ACTIVE,
201
keybinding: {
202
weight: KeybindingWeight.WorkbenchContrib,
203
primary: KeyMod.CtrlCmd | KeyCode.KeyL,
204
}
205
});
206
}
207
208
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
209
if (browserEditor instanceof BrowserEditor) {
210
await browserEditor.focusUrlInput();
211
}
212
}
213
}
214
215
class AddElementToChatAction extends Action2 {
216
static readonly ID = 'workbench.action.browser.addElementToChat';
217
218
constructor() {
219
const enabled = ContextKeyExpr.and(ChatContextKeys.enabled, ContextKeyExpr.equals('config.chat.sendElementsToChat.enabled', true));
220
super({
221
id: AddElementToChatAction.ID,
222
title: localize2('browser.addElementToChatAction', 'Add Element to Chat'),
223
category: BrowserCategory,
224
icon: Codicon.inspect,
225
f1: true,
226
precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, enabled),
227
toggled: CONTEXT_BROWSER_ELEMENT_SELECTION_ACTIVE,
228
menu: {
229
id: MenuId.BrowserActionsToolbar,
230
group: 'actions',
231
order: 1,
232
when: enabled
233
},
234
keybinding: [{
235
weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over terminal
236
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyC,
237
}, {
238
when: CONTEXT_BROWSER_ELEMENT_SELECTION_ACTIVE,
239
weight: KeybindingWeight.WorkbenchContrib,
240
primary: KeyCode.Escape
241
}]
242
});
243
}
244
245
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
246
if (browserEditor instanceof BrowserEditor) {
247
await browserEditor.addElementToChat();
248
}
249
}
250
}
251
252
class ToggleDevToolsAction extends Action2 {
253
static readonly ID = 'workbench.action.browser.toggleDevTools';
254
255
constructor() {
256
super({
257
id: ToggleDevToolsAction.ID,
258
title: localize2('browser.toggleDevToolsAction', 'Toggle Developer Tools'),
259
category: BrowserCategory,
260
icon: Codicon.terminal,
261
f1: true,
262
precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_HAS_URL),
263
toggled: ContextKeyExpr.equals(CONTEXT_BROWSER_DEVTOOLS_OPEN.key, true),
264
menu: {
265
id: MenuId.BrowserActionsToolbar,
266
group: 'actions',
267
order: 2,
268
},
269
keybinding: {
270
weight: KeybindingWeight.WorkbenchContrib,
271
primary: KeyCode.F12
272
}
273
});
274
}
275
276
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
277
if (browserEditor instanceof BrowserEditor) {
278
await browserEditor.toggleDevTools();
279
}
280
}
281
}
282
283
class OpenInExternalBrowserAction extends Action2 {
284
static readonly ID = 'workbench.action.browser.openExternal';
285
286
constructor() {
287
super({
288
id: OpenInExternalBrowserAction.ID,
289
title: localize2('browser.openExternalAction', 'Open in External Browser'),
290
category: BrowserCategory,
291
icon: Codicon.linkExternal,
292
f1: true,
293
precondition: BROWSER_EDITOR_ACTIVE,
294
menu: {
295
id: MenuId.BrowserActionsToolbar,
296
group: ActionGroupPage,
297
order: 10
298
}
299
});
300
}
301
302
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
303
if (browserEditor instanceof BrowserEditor) {
304
const url = browserEditor.getUrl();
305
if (url) {
306
const openerService = accessor.get(IOpenerService);
307
await openerService.open(url, { openExternal: true });
308
}
309
}
310
}
311
}
312
313
class ClearGlobalBrowserStorageAction extends Action2 {
314
static readonly ID = 'workbench.action.browser.clearGlobalStorage';
315
316
constructor() {
317
super({
318
id: ClearGlobalBrowserStorageAction.ID,
319
title: localize2('browser.clearGlobalStorageAction', 'Clear Storage (Global)'),
320
category: BrowserCategory,
321
icon: Codicon.clearAll,
322
f1: true,
323
menu: {
324
id: MenuId.BrowserActionsToolbar,
325
group: ActionGroupSettings,
326
order: 1,
327
when: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Global)
328
}
329
});
330
}
331
332
async run(accessor: ServicesAccessor): Promise<void> {
333
const browserViewWorkbenchService = accessor.get(IBrowserViewWorkbenchService);
334
await browserViewWorkbenchService.clearGlobalStorage();
335
}
336
}
337
338
class ClearWorkspaceBrowserStorageAction extends Action2 {
339
static readonly ID = 'workbench.action.browser.clearWorkspaceStorage';
340
341
constructor() {
342
super({
343
id: ClearWorkspaceBrowserStorageAction.ID,
344
title: localize2('browser.clearWorkspaceStorageAction', 'Clear Storage (Workspace)'),
345
category: BrowserCategory,
346
icon: Codicon.clearAll,
347
f1: true,
348
menu: {
349
id: MenuId.BrowserActionsToolbar,
350
group: ActionGroupSettings,
351
order: 1,
352
when: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Workspace)
353
}
354
});
355
}
356
357
async run(accessor: ServicesAccessor): Promise<void> {
358
const browserViewWorkbenchService = accessor.get(IBrowserViewWorkbenchService);
359
await browserViewWorkbenchService.clearWorkspaceStorage();
360
}
361
}
362
363
class ClearEphemeralBrowserStorageAction extends Action2 {
364
static readonly ID = 'workbench.action.browser.clearEphemeralStorage';
365
366
constructor() {
367
super({
368
id: ClearEphemeralBrowserStorageAction.ID,
369
title: localize2('browser.clearEphemeralStorageAction', 'Clear Storage (Ephemeral)'),
370
category: BrowserCategory,
371
icon: Codicon.clearAll,
372
f1: true,
373
precondition: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Ephemeral),
374
menu: {
375
id: MenuId.BrowserActionsToolbar,
376
group: '3_settings',
377
order: 1,
378
when: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Ephemeral)
379
}
380
});
381
}
382
383
async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {
384
if (browserEditor instanceof BrowserEditor) {
385
await browserEditor.clearStorage();
386
}
387
}
388
}
389
390
class OpenBrowserSettingsAction extends Action2 {
391
static readonly ID = 'workbench.action.browser.openSettings';
392
393
constructor() {
394
super({
395
id: OpenBrowserSettingsAction.ID,
396
title: localize2('browser.openSettingsAction', 'Open Browser Settings'),
397
category: BrowserCategory,
398
icon: Codicon.settingsGear,
399
f1: false,
400
menu: {
401
id: MenuId.BrowserActionsToolbar,
402
group: ActionGroupSettings,
403
order: 2
404
}
405
});
406
}
407
408
async run(accessor: ServicesAccessor): Promise<void> {
409
const preferencesService = accessor.get(IPreferencesService);
410
await preferencesService.openSettings({ query: '@id:workbench.browser.*,chat.sendElementsToChat.*' });
411
}
412
}
413
414
// Find actions
415
416
class ShowBrowserFindAction extends Action2 {
417
static readonly ID = 'workbench.action.browser.showFind';
418
419
constructor() {
420
super({
421
id: ShowBrowserFindAction.ID,
422
title: localize2('browser.showFindAction', 'Find in Page'),
423
category: BrowserCategory,
424
f1: true,
425
precondition: BROWSER_EDITOR_ACTIVE,
426
menu: {
427
id: MenuId.BrowserActionsToolbar,
428
group: ActionGroupPage,
429
order: 1,
430
},
431
keybinding: {
432
weight: KeybindingWeight.EditorContrib,
433
primary: KeyMod.CtrlCmd | KeyCode.KeyF
434
}
435
});
436
}
437
438
run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): void {
439
if (browserEditor instanceof BrowserEditor) {
440
browserEditor.showFind();
441
}
442
}
443
}
444
445
class HideBrowserFindAction extends Action2 {
446
static readonly ID = 'workbench.action.browser.hideFind';
447
448
constructor() {
449
super({
450
id: HideBrowserFindAction.ID,
451
title: localize2('browser.hideFindAction', 'Close Find Widget'),
452
category: BrowserCategory,
453
f1: false,
454
precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_FIND_WIDGET_VISIBLE),
455
keybinding: {
456
weight: KeybindingWeight.EditorContrib + 5,
457
primary: KeyCode.Escape
458
}
459
});
460
}
461
462
run(accessor: ServicesAccessor): void {
463
const browserEditor = accessor.get(IEditorService).activeEditorPane;
464
if (browserEditor instanceof BrowserEditor) {
465
browserEditor.hideFind();
466
}
467
}
468
}
469
470
class BrowserFindNextAction extends Action2 {
471
static readonly ID = 'workbench.action.browser.findNext';
472
473
constructor() {
474
super({
475
id: BrowserFindNextAction.ID,
476
title: localize2('browser.findNextAction', 'Find Next'),
477
category: BrowserCategory,
478
f1: false,
479
precondition: BROWSER_EDITOR_ACTIVE,
480
keybinding: [{
481
when: CONTEXT_BROWSER_FIND_WIDGET_FOCUSED,
482
weight: KeybindingWeight.EditorContrib,
483
primary: KeyCode.Enter
484
}, {
485
when: CONTEXT_BROWSER_FIND_WIDGET_VISIBLE,
486
weight: KeybindingWeight.EditorContrib,
487
primary: KeyCode.F3,
488
mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyG }
489
}]
490
});
491
}
492
493
run(accessor: ServicesAccessor): void {
494
const browserEditor = accessor.get(IEditorService).activeEditorPane;
495
if (browserEditor instanceof BrowserEditor) {
496
browserEditor.findNext();
497
}
498
}
499
}
500
501
class BrowserFindPreviousAction extends Action2 {
502
static readonly ID = 'workbench.action.browser.findPrevious';
503
504
constructor() {
505
super({
506
id: BrowserFindPreviousAction.ID,
507
title: localize2('browser.findPreviousAction', 'Find Previous'),
508
category: BrowserCategory,
509
f1: false,
510
precondition: BROWSER_EDITOR_ACTIVE,
511
keybinding: [{
512
when: CONTEXT_BROWSER_FIND_WIDGET_FOCUSED,
513
weight: KeybindingWeight.EditorContrib,
514
primary: KeyMod.Shift | KeyCode.Enter
515
}, {
516
when: CONTEXT_BROWSER_FIND_WIDGET_VISIBLE,
517
weight: KeybindingWeight.EditorContrib,
518
primary: KeyMod.Shift | KeyCode.F3,
519
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyG }
520
}]
521
});
522
}
523
524
run(accessor: ServicesAccessor): void {
525
const browserEditor = accessor.get(IEditorService).activeEditorPane;
526
if (browserEditor instanceof BrowserEditor) {
527
browserEditor.findPrevious();
528
}
529
}
530
}
531
532
// Register actions
533
registerAction2(OpenIntegratedBrowserAction);
534
registerAction2(NewTabAction);
535
registerAction2(GoBackAction);
536
registerAction2(GoForwardAction);
537
registerAction2(ReloadAction);
538
registerAction2(FocusUrlInputAction);
539
registerAction2(AddElementToChatAction);
540
registerAction2(ToggleDevToolsAction);
541
registerAction2(OpenInExternalBrowserAction);
542
registerAction2(ClearGlobalBrowserStorageAction);
543
registerAction2(ClearWorkspaceBrowserStorageAction);
544
registerAction2(ClearEphemeralBrowserStorageAction);
545
registerAction2(OpenBrowserSettingsAction);
546
registerAction2(ShowBrowserFindAction);
547
registerAction2(HideBrowserFindAction);
548
registerAction2(BrowserFindNextAction);
549
registerAction2(BrowserFindPreviousAction);
550
551