Path: blob/main/src/vs/workbench/browser/actions/textInputActions.ts
3296 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 { IAction, Separator, toAction } from '../../../base/common/actions.js';6import { localize } from '../../../nls.js';7import { IWorkbenchLayoutService } from '../../services/layout/browser/layoutService.js';8import { IContextMenuService } from '../../../platform/contextview/browser/contextView.js';9import { Disposable } from '../../../base/common/lifecycle.js';10import { EventHelper, addDisposableListener, getActiveDocument, getWindow, isHTMLInputElement, isHTMLTextAreaElement } from '../../../base/browser/dom.js';11import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../common/contributions.js';12import { IClipboardService } from '../../../platform/clipboard/common/clipboardService.js';13import { StandardMouseEvent } from '../../../base/browser/mouseEvent.js';14import { Event as BaseEvent } from '../../../base/common/event.js';15import { Lazy } from '../../../base/common/lazy.js';16import { ILogService } from '../../../platform/log/common/log.js';1718export function createTextInputActions(clipboardService: IClipboardService, logService: ILogService): IAction[] {19return [2021toAction({ id: 'undo', label: localize('undo', "Undo"), run: () => getActiveDocument().execCommand('undo') }),22toAction({ id: 'redo', label: localize('redo', "Redo"), run: () => getActiveDocument().execCommand('redo') }),23new Separator(),24toAction({25id: 'editor.action.clipboardCutAction', label: localize('cut', "Cut"), run: () => {26logService.trace('TextInputActionsProvider#cut');27getActiveDocument().execCommand('cut');28}29}),30toAction({31id: 'editor.action.clipboardCopyAction', label: localize('copy', "Copy"), run: () => {32logService.trace('TextInputActionsProvider#copy');33getActiveDocument().execCommand('copy');34}35}),36toAction({37id: 'editor.action.clipboardPasteAction',38label: localize('paste', "Paste"),39run: async (element: unknown) => {40logService.trace('TextInputActionsProvider#paste');41const clipboardText = await clipboardService.readText();42if (isHTMLTextAreaElement(element) || isHTMLInputElement(element)) {43const selectionStart = element.selectionStart || 0;44const selectionEnd = element.selectionEnd || 0;4546element.value = `${element.value.substring(0, selectionStart)}${clipboardText}${element.value.substring(selectionEnd, element.value.length)}`;47element.selectionStart = selectionStart + clipboardText.length;48element.selectionEnd = element.selectionStart;49element.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));50}51}52}),53new Separator(),54toAction({ id: 'editor.action.selectAll', label: localize('selectAll', "Select All"), run: () => getActiveDocument().execCommand('selectAll') })55];56}5758export class TextInputActionsProvider extends Disposable implements IWorkbenchContribution {5960static readonly ID = 'workbench.contrib.textInputActionsProvider';6162private readonly textInputActions = new Lazy<IAction[]>(() => createTextInputActions(this.clipboardService, this.logService));6364constructor(65@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,66@IContextMenuService private readonly contextMenuService: IContextMenuService,67@IClipboardService private readonly clipboardService: IClipboardService,68@ILogService private readonly logService: ILogService69) {70super();7172this.registerListeners();73}7475private registerListeners(): void {7677// Context menu support in input/textarea78this._register(BaseEvent.runAndSubscribe(this.layoutService.onDidAddContainer, ({ container, disposables }) => {79disposables.add(addDisposableListener(container, 'contextmenu', e => this.onContextMenu(getWindow(container), e)));80}, { container: this.layoutService.mainContainer, disposables: this._store }));81}8283private onContextMenu(targetWindow: Window, e: MouseEvent): void {84if (e.defaultPrevented) {85return; // make sure to not show these actions by accident if component indicated to prevent86}8788const target = e.target;89if (!isHTMLTextAreaElement(target) && !isHTMLInputElement(target)) {90return; // only for inputs or textareas91}9293EventHelper.stop(e, true);9495const event = new StandardMouseEvent(targetWindow, e);9697this.contextMenuService.showContextMenu({98getAnchor: () => event,99getActions: () => this.textInputActions.value,100getActionsContext: () => target,101});102}103}104105registerWorkbenchContribution2(106TextInputActionsProvider.ID,107TextInputActionsProvider,108WorkbenchPhase.BlockRestore // Block to allow right-click into input fields before restore finished109);110111112