diff --git a/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts index 78326608824..382ac4727e7 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -281,7 +281,7 @@ abstract class EditorOrNativeTextInputCommand { constructor(target: MultiCommand) { // 1. handle case when focus is in editor. - target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => { + target.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: any) => { // Only if editor text focus (i.e. not if editor has widget focus). const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); if (focusedEditor && focusedEditor.hasTextFocus()) { @@ -291,7 +291,7 @@ abstract class EditorOrNativeTextInputCommand { }); // 2. handle case when focus is in some other `input` / `textarea`. - target.addImplementation(1000, (accessor: ServicesAccessor, args: any) => { + target.addImplementation(1000, 'generic-dom-input-textarea', (accessor: ServicesAccessor, args: any) => { // Only if focused on an element that allows for entering text const activeElement = document.activeElement; if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { @@ -302,7 +302,7 @@ abstract class EditorOrNativeTextInputCommand { }); // 3. (default) handle case when focus is somewhere else. - target.addImplementation(0, (accessor: ServicesAccessor, args: any) => { + target.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: any) => { // Redirecting to active editor const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor(); if (activeEditor) { diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index b0ff5985cd0..0ba2633acc4 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -23,6 +23,7 @@ import { withNullAsUndefined, assertType } from 'vs/base/common/types'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; +import { ILogService } from 'vs/platform/log/common/log'; export type ServicesAccessor = InstantiationServicesAccessor; @@ -149,20 +150,26 @@ export abstract class Command { */ export type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean | Promise; +interface ICommandImplementationRegistration { + priority: number; + name: string; + implementation: CommandImplementation; +} + export class MultiCommand extends Command { - private readonly _implementations: [number, CommandImplementation][] = []; + private readonly _implementations: ICommandImplementationRegistration[] = []; /** * A higher priority gets to be looked at first */ - public addImplementation(priority: number, implementation: CommandImplementation): IDisposable { - this._implementations.push([priority, implementation]); - this._implementations.sort((a, b) => b[0] - a[0]); + public addImplementation(priority: number, name: string, implementation: CommandImplementation): IDisposable { + this._implementations.push({ priority, name, implementation }); + this._implementations.sort((a, b) => b.priority - a.priority); return { dispose: () => { for (let i = 0; i < this._implementations.length; i++) { - if (this._implementations[i][1] === implementation) { + if (this._implementations[i].implementation === implementation) { this._implementations.splice(i, 1); return; } @@ -172,9 +179,11 @@ export class MultiCommand extends Command { } public runCommand(accessor: ServicesAccessor, args: any): void | Promise { + const logService = accessor.get(ILogService); for (const impl of this._implementations) { - const result = impl[1](accessor, args); + const result = impl.implementation(accessor, args); if (result) { + logService.trace(`Command '${this.id}' was handled by '${impl.name}'.`); if (typeof result === 'boolean') { return; } diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index 4b26bc013c8..fa3e3679894 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -169,7 +169,7 @@ function registerExecCommandImpl(target: MultiCommand | undefined, browserComman } // 1. handle case when focus is in editor. - target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => { + target.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: any) => { // Only if editor text focus (i.e. not if editor has widget focus). const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); if (focusedEditor && focusedEditor.hasTextFocus()) { @@ -186,7 +186,7 @@ function registerExecCommandImpl(target: MultiCommand | undefined, browserComman }); // 2. (default) handle case when focus is somewhere else. - target.addImplementation(0, (accessor: ServicesAccessor, args: any) => { + target.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: any) => { document.execCommand(browserCommand); return true; }); @@ -197,7 +197,7 @@ registerExecCommandImpl(CopyAction, 'copy'); if (PasteAction) { // 1. Paste: handle case when focus is in editor. - PasteAction.addImplementation(10000, (accessor: ServicesAccessor, args: any) => { + PasteAction.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: any) => { const codeEditorService = accessor.get(ICodeEditorService); const clipboardService = accessor.get(IClipboardService); @@ -235,7 +235,7 @@ if (PasteAction) { }); // 2. Paste: (default) handle case when focus is somewhere else. - PasteAction.addImplementation(0, (accessor: ServicesAccessor, args: any) => { + PasteAction.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: any) => { document.execCommand('paste'); return true; }); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index df09c1a4441..5e5d247017f 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -83,10 +83,10 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ })); const PRIORITY = 105; - this._register(UndoCommand.addImplementation(PRIORITY, () => { + this._register(UndoCommand.addImplementation(PRIORITY, 'custom-editor', () => { return this.withActiveCustomEditor(editor => editor.undo()); })); - this._register(RedoCommand.addImplementation(PRIORITY, () => { + this._register(RedoCommand.addImplementation(PRIORITY, 'custom-editor', () => { return this.withActiveCustomEditor(editor => editor.redo()); })); diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 953846bf84f..89976ac0fb3 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -286,7 +286,7 @@ CommandsRegistry.registerCommand({ }); function overrideActionForActiveExtensionEditorWebview(command: MultiCommand | undefined, f: (webview: Webview) => void) { - command?.addImplementation(105, (accessor) => { + command?.addImplementation(105, 'extensions-editor', (accessor) => { const editorService = accessor.get(IEditorService); const editor = editorService.activeEditorPane; if (editor instanceof ExtensionEditor) { diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index ece80b58309..0bd5f9917be 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -389,7 +389,7 @@ configurationRegistry.registerConfiguration({ } }); -UndoCommand.addImplementation(110, (accessor: ServicesAccessor) => { +UndoCommand.addImplementation(110, 'explorer', (accessor: ServicesAccessor) => { const undoRedoService = accessor.get(IUndoRedoService); const explorerService = accessor.get(IExplorerService); if (explorerService.hasViewFocus() && undoRedoService.canUndo(UNDO_REDO_SOURCE)) { @@ -400,7 +400,7 @@ UndoCommand.addImplementation(110, (accessor: ServicesAccessor) => { return false; }); -RedoCommand.addImplementation(110, (accessor: ServicesAccessor) => { +RedoCommand.addImplementation(110, 'explorer', (accessor: ServicesAccessor) => { const undoRedoService = accessor.get(IUndoRedoService); const explorerService = accessor.get(IExplorerService); if (explorerService.hasViewFocus() && undoRedoService.canRedo(UNDO_REDO_SOURCE)) { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts index 03db8421ef2..456d28de988 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts @@ -43,7 +43,7 @@ class NotebookClipboardContribution extends Disposable { const PRIORITY = 105; if (CopyAction) { - this._register(CopyAction.addImplementation(PRIORITY, accessor => { + this._register(CopyAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => { const activeElement = document.activeElement; if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { return false; @@ -80,7 +80,7 @@ class NotebookClipboardContribution extends Disposable { } if (PasteAction) { - PasteAction.addImplementation(PRIORITY, accessor => { + PasteAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => { const activeElement = document.activeElement; if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { return false; @@ -137,7 +137,7 @@ class NotebookClipboardContribution extends Disposable { } if (CutAction) { - CutAction.addImplementation(PRIORITY, accessor => { + CutAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => { const activeElement = document.activeElement; if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { return false; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts index 2187040c60e..d22364d963b 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts @@ -18,7 +18,7 @@ class NotebookUndoRedoContribution extends Disposable { super(); const PRIORITY = 105; - this._register(UndoCommand.addImplementation(PRIORITY, () => { + this._register(UndoCommand.addImplementation(PRIORITY, 'notebook-undo-redo', () => { const editor = getNotebookEditorFromEditorPane(this._editorService.activeEditorPane); if (editor?.viewModel) { return editor.viewModel.undo().then(cellResources => { @@ -37,7 +37,7 @@ class NotebookUndoRedoContribution extends Disposable { return false; })); - this._register(RedoCommand.addImplementation(PRIORITY, () => { + this._register(RedoCommand.addImplementation(PRIORITY, 'notebook-undo-redo', () => { const editor = getNotebookEditorFromEditorPane(this._editorService.activeEditorPane); if (editor?.viewModel) { return editor.viewModel.redo().then(cellResources => { diff --git a/src/vs/workbench/contrib/notebook/electron-browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/electron-browser/notebook.contribution.ts index 7499926090b..1a7bd0df795 100644 --- a/src/vs/workbench/contrib/notebook/electron-browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/electron-browser/notebook.contribution.ts @@ -39,23 +39,23 @@ function withWebview(accessor: ServicesAccessor, f: (webviewe: ElectronWebviewBa const PRIORITY = 105; -UndoCommand.addImplementation(PRIORITY, accessor => { +UndoCommand.addImplementation(PRIORITY, 'notebook-webview', accessor => { return withWebview(accessor, webview => webview.undo()); }); -RedoCommand.addImplementation(PRIORITY, accessor => { +RedoCommand.addImplementation(PRIORITY, 'notebook-webview', accessor => { return withWebview(accessor, webview => webview.redo()); }); -CopyAction?.addImplementation(PRIORITY, accessor => { +CopyAction?.addImplementation(PRIORITY, 'notebook-webview', accessor => { return withWebview(accessor, webview => webview.copy()); }); -PasteAction?.addImplementation(PRIORITY, accessor => { +PasteAction?.addImplementation(PRIORITY, 'notebook-webview', accessor => { return withWebview(accessor, webview => webview.paste()); }); -CutAction?.addImplementation(PRIORITY, accessor => { +CutAction?.addImplementation(PRIORITY, 'notebook-webview', accessor => { return withWebview(accessor, webview => webview.cut()); }); diff --git a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts index 97625d7d229..04790597ff5 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts @@ -11,7 +11,7 @@ import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/browser/w const PRIORITY = 100; function overrideCommandForWebview(command: MultiCommand | undefined, f: (webview: Webview) => void) { - command?.addImplementation(PRIORITY, accessor => { + command?.addImplementation(PRIORITY, 'webiew', accessor => { const webviewService = accessor.get(IWebviewService); const webview = webviewService.activeWebview; if (webview?.isFocused) {