diff --git a/src/vs/editor/browser/standalone/simpleServices.ts b/src/vs/editor/browser/standalone/simpleServices.ts index bc5801ffaeb6b4417194e0451e7443b7ebb7d0c3..c2525b82801e2edbb85212cd53615a1a27e3c8c2 100644 --- a/src/vs/editor/browser/standalone/simpleServices.ts +++ b/src/vs/editor/browser/standalone/simpleServices.ts @@ -24,7 +24,7 @@ import { getDefaultValues as getDefaultConfiguration } from 'vs/platform/configu import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { ITextModelResolverService, ITextModelContentProvider, ITextEditorModel } from 'vs/editor/common/services/resolverService'; -import { IDisposable, IReference, ImmortalReference } from 'vs/base/common/lifecycle'; +import { IDisposable, IReference, ImmortalReference, combinedDisposable } from 'vs/base/common/lifecycle'; import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -275,8 +275,13 @@ export class StandaloneCommandService implements ICommandService { this._dynamicCommands = Object.create(null); } - public addCommand(id: string, command: ICommand): void { + public addCommand(id: string, command: ICommand): IDisposable { this._dynamicCommands[id] = command; + return { + dispose: () => { + delete this._dynamicCommands[id]; + } + }; } public executeCommand(id: string, ...args: any[]): TPromise { @@ -320,11 +325,14 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { })); } - public addDynamicKeybinding(keybinding: number, handler: ICommandHandler, when: string, commandId: string = null): string { + public addDynamicKeybinding(keybinding: number, handler: ICommandHandler, when: string, commandId: string = null): [string, IDisposable] { + let toDispose: IDisposable[] = []; + if (commandId === null) { commandId = 'DYNAMIC_' + (++StandaloneKeybindingService.LAST_GENERATED_ID); } let parsedContext = IOSupport.readKeybindingWhen(when); + this._dynamicKeybindings.push({ keybinding: keybinding, command: commandId, @@ -333,16 +341,30 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { weight2: 0 }); + toDispose.push({ + dispose: () => { + for (let i = 0; i < this._dynamicKeybindings.length; i++) { + let kb = this._dynamicKeybindings[i]; + if (kb.command === commandId) { + this._dynamicKeybindings.splice(i, 1); + this.updateResolver({ source: KeybindingSource.Default }); + return; + } + } + } + }); + let commandService = this._commandService; if (commandService instanceof StandaloneCommandService) { - commandService.addCommand(commandId, { + toDispose.push(commandService.addCommand(commandId, { handler: handler - }); + })); } else { throw new Error('Unknown command service!'); } this.updateResolver({ source: KeybindingSource.Default }); - return commandId; + + return [commandId, combinedDisposable(toDispose)]; } private updateResolver(event: IKeybindingEvent): void { diff --git a/src/vs/editor/browser/standalone/standaloneCodeEditor.ts b/src/vs/editor/browser/standalone/standaloneCodeEditor.ts index 10f1807d026991708fc0744f4f600cb29480dec5..90f525f32979348d51a73c74fb1a17a33ee785f4 100644 --- a/src/vs/editor/browser/standalone/standaloneCodeEditor.ts +++ b/src/vs/editor/browser/standalone/standaloneCodeEditor.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands'; @@ -46,13 +46,13 @@ export interface IDiffEditorConstructionOptions extends IDiffEditorOptions { export interface IStandaloneCodeEditor extends ICodeEditor { addCommand(keybinding: number, handler: ICommandHandler, context: string): string; createContextKey(key: string, defaultValue: T): IContextKey; - addAction(descriptor: IActionDescriptor): void; + addAction(descriptor: IActionDescriptor): IDisposable; } export interface IStandaloneDiffEditor extends IDiffEditor { addCommand(keybinding: number, handler: ICommandHandler, context: string): string; createContextKey(key: string, defaultValue: T): IContextKey; - addAction(descriptor: IActionDescriptor): void; + addAction(descriptor: IActionDescriptor): IDisposable; } export class StandaloneEditor extends CodeEditor implements IStandaloneCodeEditor { @@ -130,7 +130,8 @@ export class StandaloneEditor extends CodeEditor implements IStandaloneCodeEdito console.warn('Cannot add command because the editor is configured with an unrecognized KeybindingService'); return null; } - return this._standaloneKeybindingService.addDynamicKeybinding(keybinding, handler, context); + let r = this._standaloneKeybindingService.addDynamicKeybinding(keybinding, handler, context); + return r[0]; } public createContextKey(key: string, defaultValue: T): IContextKey { @@ -141,8 +142,8 @@ export class StandaloneEditor extends CodeEditor implements IStandaloneCodeEdito return this._contextKeyService.createKey(key, defaultValue); } - public addAction(descriptor: IActionDescriptor): void { - super.addAction(descriptor); + public addAction(descriptor: IActionDescriptor): IDisposable { + let toDispose = [super.addAction(descriptor)]; if (!this._standaloneKeybindingService) { console.warn('Cannot add keybinding because the editor is configured with an unrecognized KeybindingService'); return null; @@ -151,10 +152,14 @@ export class StandaloneEditor extends CodeEditor implements IStandaloneCodeEdito let handler: ICommandHandler = (accessor) => { return this.trigger('keyboard', descriptor.id, null); }; - descriptor.keybindings.forEach((kb) => { - this._standaloneKeybindingService.addDynamicKeybinding(kb, handler, descriptor.keybindingContext, descriptor.id); - }); - } + toDispose = toDispose.concat( + descriptor.keybindings.map((kb) => { + let r = this._standaloneKeybindingService.addDynamicKeybinding(kb, handler, descriptor.keybindingContext, descriptor.id); + return r[1]; + }) + ); + } + return combinedDisposable(toDispose); } _attachModel(model: IModel): void { @@ -216,7 +221,8 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon console.warn('Cannot add command because the editor is configured with an unrecognized KeybindingService'); return null; } - return this._standaloneKeybindingService.addDynamicKeybinding(keybinding, handler, context); + let r = this._standaloneKeybindingService.addDynamicKeybinding(keybinding, handler, context); + return r[0]; } public createContextKey(key: string, defaultValue: T): IContextKey { @@ -227,8 +233,8 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon return this._contextKeyService.createKey(key, defaultValue); } - public addAction(descriptor: IActionDescriptor): void { - super.addAction(descriptor); + public addAction(descriptor: IActionDescriptor): IDisposable { + let toDispose = [super.addAction(descriptor)]; if (!this._standaloneKeybindingService) { console.warn('Cannot add keybinding because the editor is configured with an unrecognized KeybindingService'); return null; @@ -237,9 +243,13 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon let handler: ICommandHandler = (ctx) => { return this.trigger('keyboard', descriptor.id, null); }; - descriptor.keybindings.forEach((kb) => { - this._standaloneKeybindingService.addDynamicKeybinding(kb, handler, descriptor.keybindingContext, descriptor.id); - }); - } + toDispose = toDispose.concat( + descriptor.keybindings.map((kb) => { + let r = this._standaloneKeybindingService.addDynamicKeybinding(kb, handler, descriptor.keybindingContext, descriptor.id); + return r[1]; + }) + ); + } + return combinedDisposable(toDispose); } } diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index c71c84dbfb4f7f531c39af0e57508bb89728a17f..93c75caf1825b28e4445a1a6204d5499ad95df58 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -611,8 +611,8 @@ export class DiffEditorWidget extends EventEmitter implements editorBrowser.IDif this.modifiedEditor.revealRangeInCenterIfOutsideViewport(range); } - public addAction(descriptor: editorCommon.IActionDescriptor): void { - this.modifiedEditor.addAction(descriptor); + public addAction(descriptor: editorCommon.IActionDescriptor): IDisposable { + return this.modifiedEditor.addAction(descriptor); } public getActions(): editorCommon.IEditorAction[] { diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 3bdb7b417d209ced68393375cf93f5ecc7f60bbf..7e9ba5f6dacbcb0a2ad9c7b9aeea8cdba5da06f7 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -7,7 +7,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import Event, { fromEventEmitter } from 'vs/base/common/event'; import { EventEmitter, IEventEmitter } from 'vs/base/common/eventEmitter'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -510,7 +510,7 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom return (this._contributions[id] || null); } - public addAction(descriptor: editorCommon.IActionDescriptor): void { + public addAction(descriptor: editorCommon.IActionDescriptor): IDisposable { if ( (typeof descriptor.id !== 'string') || (typeof descriptor.label !== 'string') @@ -518,6 +518,7 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom ) { throw new Error('Invalid action descriptor, `id`, `label` and `run` are required properties!'); } + let toDispose: IDisposable[] = []; // Generate a unique id to allow the same descriptor.id across multiple editor instances let uniqueId = this.getId() + ':' + descriptor.id; @@ -525,7 +526,7 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom let action = new DynamicEditorAction(descriptor, this); // Register the command - CommandsRegistry.registerCommand(uniqueId, () => action.run()); + toDispose.push(CommandsRegistry.registerCommand(uniqueId, () => action.run())); if (descriptor.contextMenuGroupId) { let menuItem: IMenuItem = { @@ -539,10 +540,17 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom }; // Register the menu item - MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem); + toDispose.push(MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem)); } this._actions[action.id] = action; + toDispose.push({ + dispose: () => { + delete this._actions[action.id]; + } + }); + + return combinedDisposable(toDispose); } public getActions(): editorCommon.IEditorAction[] { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 3f82204c8decfa78b3936e1bfe10690b46d7df3e..f7adf7eec539c4463895a5aa6a2e6dfa6a07e119 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -3481,7 +3481,7 @@ export interface IEditor { /** * Add a new action to this editor. */ - addAction(descriptor: IActionDescriptor): void; + addAction(descriptor: IActionDescriptor): IDisposable; /** * Returns all actions associated with this editor. diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 5d30f79feb38d9bfac76e2f2aba15441cd76ee2f..a71dcb853b4749a6115181481ecd726bcbc3ce26 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -951,13 +951,13 @@ declare module monaco.editor { export interface IStandaloneCodeEditor extends ICodeEditor { addCommand(keybinding: number, handler: ICommandHandler, context: string): string; createContextKey(key: string, defaultValue: T): IContextKey; - addAction(descriptor: IActionDescriptor): void; + addAction(descriptor: IActionDescriptor): IDisposable; } export interface IStandaloneDiffEditor extends IDiffEditor { addCommand(keybinding: number, handler: ICommandHandler, context: string): string; createContextKey(key: string, defaultValue: T): IContextKey; - addAction(descriptor: IActionDescriptor): void; + addAction(descriptor: IActionDescriptor): IDisposable; } export interface ICommandHandler { (...args: any[]): void; @@ -2891,7 +2891,7 @@ declare module monaco.editor { /** * Add a new action to this editor. */ - addAction(descriptor: IActionDescriptor): void; + addAction(descriptor: IActionDescriptor): IDisposable; /** * Returns all actions associated with this editor. */