Path: blob/main/src/vs/workbench/contrib/browserView/electron-browser/browserViewActions.ts
5220 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize2 } from '../../../../nls.js';6import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';7import { Action2, registerAction2, MenuId } from '../../../../platform/actions/common/actions.js';8import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';9import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';10import { KeyMod, KeyCode } from '../../../../base/common/keyCodes.js';11import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from '../../../services/editor/common/editorService.js';12import { Codicon } from '../../../../base/common/codicons.js';13import { 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';14import { BrowserViewUri } from '../../../../platform/browserView/common/browserViewUri.js';15import { IBrowserViewWorkbenchService } from '../common/browserView.js';16import { BrowserViewStorageScope } from '../../../../platform/browserView/common/browserView.js';17import { ChatContextKeys } from '../../chat/common/actions/chatContextKeys.js';18import { IOpenerService } from '../../../../platform/opener/common/opener.js';19import { IPreferencesService } from '../../../services/preferences/common/preferences.js';20import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';21import { logBrowserOpen } from './browserViewTelemetry.js';2223// Context key expression to check if browser editor is active24const BROWSER_EDITOR_ACTIVE = ContextKeyExpr.equals('activeEditor', BrowserEditor.ID);2526const BrowserCategory = localize2('browserCategory', "Browser");27const ActionGroupTabs = '1_tabs';28const ActionGroupPage = '2_page';29const ActionGroupSettings = '3_settings';3031interface IOpenBrowserOptions {32url?: string;33openToSide?: boolean;34}3536class OpenIntegratedBrowserAction extends Action2 {37constructor() {38super({39id: 'workbench.action.browser.open',40title: localize2('browser.openAction', "Open Integrated Browser"),41category: BrowserCategory,42f1: true43});44}4546async run(accessor: ServicesAccessor, urlOrOptions?: string | IOpenBrowserOptions): Promise<void> {47const editorService = accessor.get(IEditorService);48const telemetryService = accessor.get(ITelemetryService);4950// Parse arguments51const options = typeof urlOrOptions === 'string' ? { url: urlOrOptions } : (urlOrOptions ?? {});52const resource = BrowserViewUri.forUrl(options.url);53const group = options.openToSide ? SIDE_GROUP : ACTIVE_GROUP;5455logBrowserOpen(telemetryService, options.url ? 'commandWithUrl' : 'commandWithoutUrl');5657await editorService.openEditor({ resource }, group);58}59}6061class NewTabAction extends Action2 {62constructor() {63super({64id: 'workbench.action.browser.newTab',65title: localize2('browser.newTabAction', "New Tab"),66category: BrowserCategory,67f1: true,68precondition: BROWSER_EDITOR_ACTIVE,69menu: {70id: MenuId.BrowserActionsToolbar,71group: ActionGroupTabs,72order: 1,73},74// When already in a browser, Ctrl/Cmd + T opens a new tab75keybinding: {76weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over search actions77primary: KeyMod.CtrlCmd | KeyCode.KeyT,78}79});80}8182async run(accessor: ServicesAccessor, _browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {83const editorService = accessor.get(IEditorService);84const telemetryService = accessor.get(ITelemetryService);85const resource = BrowserViewUri.forUrl(undefined);8687logBrowserOpen(telemetryService, 'newTabCommand');8889await editorService.openEditor({ resource });90}91}9293class GoBackAction extends Action2 {94static readonly ID = 'workbench.action.browser.goBack';9596constructor() {97super({98id: GoBackAction.ID,99title: localize2('browser.goBackAction', 'Go Back'),100category: BrowserCategory,101icon: Codicon.arrowLeft,102f1: true,103precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_CAN_GO_BACK),104menu: {105id: MenuId.BrowserNavigationToolbar,106group: 'navigation',107order: 1,108},109keybinding: {110weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over editor navigation111primary: KeyMod.Alt | KeyCode.LeftArrow,112secondary: [KeyCode.BrowserBack],113mac: { primary: KeyMod.CtrlCmd | KeyCode.BracketLeft, secondary: [KeyCode.BrowserBack, KeyMod.CtrlCmd | KeyCode.LeftArrow] }114}115});116}117118async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {119if (browserEditor instanceof BrowserEditor) {120await browserEditor.goBack();121}122}123}124125class GoForwardAction extends Action2 {126static readonly ID = 'workbench.action.browser.goForward';127128constructor() {129super({130id: GoForwardAction.ID,131title: localize2('browser.goForwardAction', 'Go Forward'),132category: BrowserCategory,133icon: Codicon.arrowRight,134f1: true,135precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_CAN_GO_FORWARD),136menu: {137id: MenuId.BrowserNavigationToolbar,138group: 'navigation',139order: 2,140},141keybinding: {142weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over editor navigation143primary: KeyMod.Alt | KeyCode.RightArrow,144secondary: [KeyCode.BrowserForward],145mac: { primary: KeyMod.CtrlCmd | KeyCode.BracketRight, secondary: [KeyCode.BrowserForward, KeyMod.CtrlCmd | KeyCode.RightArrow] }146}147});148}149150async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {151if (browserEditor instanceof BrowserEditor) {152await browserEditor.goForward();153}154}155}156157class ReloadAction extends Action2 {158static readonly ID = 'workbench.action.browser.reload';159160constructor() {161super({162id: ReloadAction.ID,163title: localize2('browser.reloadAction', 'Reload'),164category: BrowserCategory,165icon: Codicon.refresh,166f1: true,167precondition: BROWSER_EDITOR_ACTIVE,168menu: {169id: MenuId.BrowserNavigationToolbar,170group: 'navigation',171order: 3,172},173keybinding: {174when: CONTEXT_BROWSER_FOCUSED,175weight: KeybindingWeight.WorkbenchContrib + 75, // Priority over debug and reload workbench176primary: KeyMod.CtrlCmd | KeyCode.KeyR,177secondary: [KeyCode.F5],178mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyR, secondary: [] }179}180});181}182183async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {184if (browserEditor instanceof BrowserEditor) {185await browserEditor.reload();186}187}188}189190class FocusUrlInputAction extends Action2 {191static readonly ID = 'workbench.action.browser.focusUrlInput';192193constructor() {194super({195id: FocusUrlInputAction.ID,196title: localize2('browser.focusUrlInputAction', 'Focus URL Input'),197category: BrowserCategory,198f1: true,199precondition: BROWSER_EDITOR_ACTIVE,200keybinding: {201weight: KeybindingWeight.WorkbenchContrib,202primary: KeyMod.CtrlCmd | KeyCode.KeyL,203}204});205}206207async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {208if (browserEditor instanceof BrowserEditor) {209await browserEditor.focusUrlInput();210}211}212}213214class AddElementToChatAction extends Action2 {215static readonly ID = 'workbench.action.browser.addElementToChat';216217constructor() {218const enabled = ContextKeyExpr.and(ChatContextKeys.enabled, ContextKeyExpr.equals('config.chat.sendElementsToChat.enabled', true));219super({220id: AddElementToChatAction.ID,221title: localize2('browser.addElementToChatAction', 'Add Element to Chat'),222category: BrowserCategory,223icon: Codicon.inspect,224f1: true,225precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, enabled),226toggled: CONTEXT_BROWSER_ELEMENT_SELECTION_ACTIVE,227menu: {228id: MenuId.BrowserActionsToolbar,229group: 'actions',230order: 1,231when: enabled232},233keybinding: [{234weight: KeybindingWeight.WorkbenchContrib + 50, // Priority over terminal235primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyC,236}, {237when: CONTEXT_BROWSER_ELEMENT_SELECTION_ACTIVE,238weight: KeybindingWeight.WorkbenchContrib,239primary: KeyCode.Escape240}]241});242}243244async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {245if (browserEditor instanceof BrowserEditor) {246await browserEditor.addElementToChat();247}248}249}250251class ToggleDevToolsAction extends Action2 {252static readonly ID = 'workbench.action.browser.toggleDevTools';253254constructor() {255super({256id: ToggleDevToolsAction.ID,257title: localize2('browser.toggleDevToolsAction', 'Toggle Developer Tools'),258category: BrowserCategory,259icon: Codicon.terminal,260f1: true,261precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_HAS_URL),262toggled: ContextKeyExpr.equals(CONTEXT_BROWSER_DEVTOOLS_OPEN.key, true),263menu: {264id: MenuId.BrowserActionsToolbar,265group: 'actions',266order: 2,267},268keybinding: {269weight: KeybindingWeight.WorkbenchContrib,270primary: KeyCode.F12271}272});273}274275async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {276if (browserEditor instanceof BrowserEditor) {277await browserEditor.toggleDevTools();278}279}280}281282class OpenInExternalBrowserAction extends Action2 {283static readonly ID = 'workbench.action.browser.openExternal';284285constructor() {286super({287id: OpenInExternalBrowserAction.ID,288title: localize2('browser.openExternalAction', 'Open in External Browser'),289category: BrowserCategory,290icon: Codicon.linkExternal,291f1: true,292precondition: BROWSER_EDITOR_ACTIVE,293menu: {294id: MenuId.BrowserActionsToolbar,295group: ActionGroupPage,296order: 10297}298});299}300301async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {302if (browserEditor instanceof BrowserEditor) {303const url = browserEditor.getUrl();304if (url) {305const openerService = accessor.get(IOpenerService);306await openerService.open(url, { openExternal: true });307}308}309}310}311312class ClearGlobalBrowserStorageAction extends Action2 {313static readonly ID = 'workbench.action.browser.clearGlobalStorage';314315constructor() {316super({317id: ClearGlobalBrowserStorageAction.ID,318title: localize2('browser.clearGlobalStorageAction', 'Clear Storage (Global)'),319category: BrowserCategory,320icon: Codicon.clearAll,321f1: true,322menu: {323id: MenuId.BrowserActionsToolbar,324group: ActionGroupSettings,325order: 1,326when: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Global)327}328});329}330331async run(accessor: ServicesAccessor): Promise<void> {332const browserViewWorkbenchService = accessor.get(IBrowserViewWorkbenchService);333await browserViewWorkbenchService.clearGlobalStorage();334}335}336337class ClearWorkspaceBrowserStorageAction extends Action2 {338static readonly ID = 'workbench.action.browser.clearWorkspaceStorage';339340constructor() {341super({342id: ClearWorkspaceBrowserStorageAction.ID,343title: localize2('browser.clearWorkspaceStorageAction', 'Clear Storage (Workspace)'),344category: BrowserCategory,345icon: Codicon.clearAll,346f1: true,347menu: {348id: MenuId.BrowserActionsToolbar,349group: ActionGroupSettings,350order: 1,351when: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Workspace)352}353});354}355356async run(accessor: ServicesAccessor): Promise<void> {357const browserViewWorkbenchService = accessor.get(IBrowserViewWorkbenchService);358await browserViewWorkbenchService.clearWorkspaceStorage();359}360}361362class ClearEphemeralBrowserStorageAction extends Action2 {363static readonly ID = 'workbench.action.browser.clearEphemeralStorage';364365constructor() {366super({367id: ClearEphemeralBrowserStorageAction.ID,368title: localize2('browser.clearEphemeralStorageAction', 'Clear Storage (Ephemeral)'),369category: BrowserCategory,370icon: Codicon.clearAll,371f1: true,372precondition: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Ephemeral),373menu: {374id: MenuId.BrowserActionsToolbar,375group: '3_settings',376order: 1,377when: ContextKeyExpr.equals(CONTEXT_BROWSER_STORAGE_SCOPE.key, BrowserViewStorageScope.Ephemeral)378}379});380}381382async run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): Promise<void> {383if (browserEditor instanceof BrowserEditor) {384await browserEditor.clearStorage();385}386}387}388389class OpenBrowserSettingsAction extends Action2 {390static readonly ID = 'workbench.action.browser.openSettings';391392constructor() {393super({394id: OpenBrowserSettingsAction.ID,395title: localize2('browser.openSettingsAction', 'Open Browser Settings'),396category: BrowserCategory,397icon: Codicon.settingsGear,398f1: false,399menu: {400id: MenuId.BrowserActionsToolbar,401group: ActionGroupSettings,402order: 2403}404});405}406407async run(accessor: ServicesAccessor): Promise<void> {408const preferencesService = accessor.get(IPreferencesService);409await preferencesService.openSettings({ query: '@id:workbench.browser.*,chat.sendElementsToChat.*' });410}411}412413// Find actions414415class ShowBrowserFindAction extends Action2 {416static readonly ID = 'workbench.action.browser.showFind';417418constructor() {419super({420id: ShowBrowserFindAction.ID,421title: localize2('browser.showFindAction', 'Find in Page'),422category: BrowserCategory,423f1: true,424precondition: BROWSER_EDITOR_ACTIVE,425menu: {426id: MenuId.BrowserActionsToolbar,427group: ActionGroupPage,428order: 1,429},430keybinding: {431weight: KeybindingWeight.EditorContrib,432primary: KeyMod.CtrlCmd | KeyCode.KeyF433}434});435}436437run(accessor: ServicesAccessor, browserEditor = accessor.get(IEditorService).activeEditorPane): void {438if (browserEditor instanceof BrowserEditor) {439browserEditor.showFind();440}441}442}443444class HideBrowserFindAction extends Action2 {445static readonly ID = 'workbench.action.browser.hideFind';446447constructor() {448super({449id: HideBrowserFindAction.ID,450title: localize2('browser.hideFindAction', 'Close Find Widget'),451category: BrowserCategory,452f1: false,453precondition: ContextKeyExpr.and(BROWSER_EDITOR_ACTIVE, CONTEXT_BROWSER_FIND_WIDGET_VISIBLE),454keybinding: {455weight: KeybindingWeight.EditorContrib + 5,456primary: KeyCode.Escape457}458});459}460461run(accessor: ServicesAccessor): void {462const browserEditor = accessor.get(IEditorService).activeEditorPane;463if (browserEditor instanceof BrowserEditor) {464browserEditor.hideFind();465}466}467}468469class BrowserFindNextAction extends Action2 {470static readonly ID = 'workbench.action.browser.findNext';471472constructor() {473super({474id: BrowserFindNextAction.ID,475title: localize2('browser.findNextAction', 'Find Next'),476category: BrowserCategory,477f1: false,478precondition: BROWSER_EDITOR_ACTIVE,479keybinding: [{480when: CONTEXT_BROWSER_FIND_WIDGET_FOCUSED,481weight: KeybindingWeight.EditorContrib,482primary: KeyCode.Enter483}, {484when: CONTEXT_BROWSER_FIND_WIDGET_VISIBLE,485weight: KeybindingWeight.EditorContrib,486primary: KeyCode.F3,487mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyG }488}]489});490}491492run(accessor: ServicesAccessor): void {493const browserEditor = accessor.get(IEditorService).activeEditorPane;494if (browserEditor instanceof BrowserEditor) {495browserEditor.findNext();496}497}498}499500class BrowserFindPreviousAction extends Action2 {501static readonly ID = 'workbench.action.browser.findPrevious';502503constructor() {504super({505id: BrowserFindPreviousAction.ID,506title: localize2('browser.findPreviousAction', 'Find Previous'),507category: BrowserCategory,508f1: false,509precondition: BROWSER_EDITOR_ACTIVE,510keybinding: [{511when: CONTEXT_BROWSER_FIND_WIDGET_FOCUSED,512weight: KeybindingWeight.EditorContrib,513primary: KeyMod.Shift | KeyCode.Enter514}, {515when: CONTEXT_BROWSER_FIND_WIDGET_VISIBLE,516weight: KeybindingWeight.EditorContrib,517primary: KeyMod.Shift | KeyCode.F3,518mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyG }519}]520});521}522523run(accessor: ServicesAccessor): void {524const browserEditor = accessor.get(IEditorService).activeEditorPane;525if (browserEditor instanceof BrowserEditor) {526browserEditor.findPrevious();527}528}529}530531// Register actions532registerAction2(OpenIntegratedBrowserAction);533registerAction2(NewTabAction);534registerAction2(GoBackAction);535registerAction2(GoForwardAction);536registerAction2(ReloadAction);537registerAction2(FocusUrlInputAction);538registerAction2(AddElementToChatAction);539registerAction2(ToggleDevToolsAction);540registerAction2(OpenInExternalBrowserAction);541registerAction2(ClearGlobalBrowserStorageAction);542registerAction2(ClearWorkspaceBrowserStorageAction);543registerAction2(ClearEphemeralBrowserStorageAction);544registerAction2(OpenBrowserSettingsAction);545registerAction2(ShowBrowserFindAction);546registerAction2(HideBrowserFindAction);547registerAction2(BrowserFindNextAction);548registerAction2(BrowserFindPreviousAction);549550551