quickFixCommands.ts 5.6 KB
Newer Older
J
Johannes Rieken 已提交
1 2 3 4 5 6 7 8 9 10 11
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import * as nls from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
12
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
J
Johannes Rieken 已提交
13 14
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IMarkerService } from 'vs/platform/markers/common/markers';
J
Johannes Rieken 已提交
15
import { ICommonCodeEditor, IEditorContribution } from 'vs/editor/common/editorCommon';
16
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
17
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction } from 'vs/editor/browser/editorExtensions';
J
Johannes Rieken 已提交
18 19 20 21
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { QuickFixContextMenu } from './quickFixWidget';
import { LightBulbWidget } from './lightBulbWidget';
import { QuickFixModel, QuickFixComputeEvent } from './quickFixModel';
22 23 24 25 26
import { TPromise } from 'vs/base/common/winjs.base';
import { CodeAction } from 'vs/editor/common/modes';
import { createBulkEdit } from 'vs/editor/common/services/bulkEdit';
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
27 28 29 30 31 32 33 34 35 36 37

export class QuickFixController implements IEditorContribution {

	private static ID = 'editor.contrib.quickFixController';

	public static get(editor: ICommonCodeEditor): QuickFixController {
		return editor.getContribution<QuickFixController>(QuickFixController.ID);
	}

	private _editor: ICodeEditor;
	private _model: QuickFixModel;
38 39
	private _quickFixContextMenu: QuickFixContextMenu;
	private _lightBulbWidget: LightBulbWidget;
J
Johannes Rieken 已提交
40 41
	private _disposables: IDisposable[] = [];

42
	constructor(editor: ICodeEditor,
J
Johannes Rieken 已提交
43
		@IMarkerService markerService: IMarkerService,
44
		@IContextKeyService contextKeyService: IContextKeyService,
45
		@ICommandService private readonly _commandService: ICommandService,
46
		@IContextMenuService contextMenuService: IContextMenuService,
47 48 49
		@IKeybindingService private readonly _keybindingService: IKeybindingService,
		@ITextModelService private readonly _textModelService: ITextModelService,
		@IFileService private _fileService: IFileService
J
Johannes Rieken 已提交
50 51 52
	) {
		this._editor = editor;
		this._model = new QuickFixModel(this._editor, markerService);
53
		this._quickFixContextMenu = new QuickFixContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action));
54 55 56
		this._lightBulbWidget = new LightBulbWidget(editor);

		this._updateLightBulbTitle();
J
Johannes Rieken 已提交
57 58

		this._disposables.push(
59 60 61 62
			this._quickFixContextMenu.onDidExecuteCodeAction(_ => this._model.trigger('auto')),
			this._lightBulbWidget.onClick(this._handleLightBulbSelect, this),
			this._model.onDidChangeFixes(e => this._onQuickFixEvent(e)),
			this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)
J
Johannes Rieken 已提交
63 64 65 66 67 68 69 70 71 72
		);
	}

	public dispose(): void {
		this._model.dispose();
		dispose(this._disposables);
	}

	private _onQuickFixEvent(e: QuickFixComputeEvent): void {
		if (e && e.type === 'manual') {
73 74
			this._quickFixContextMenu.show(e.fixes, e.position);

J
Johannes Rieken 已提交
75 76 77 78
		} else if (e && e.fixes) {
			// auto magically triggered
			// * update an existing list of code actions
			// * manage light bulb
79 80
			if (this._quickFixContextMenu.isVisible) {
				this._quickFixContextMenu.show(e.fixes, e.position);
J
Johannes Rieken 已提交
81
			} else {
82
				this._lightBulbWidget.model = e;
J
Johannes Rieken 已提交
83 84
			}
		} else {
85
			this._lightBulbWidget.hide();
J
Johannes Rieken 已提交
86 87 88 89 90 91 92 93
		}
	}

	public getId(): string {
		return QuickFixController.ID;
	}

	private _handleLightBulbSelect(coords: { x: number, y: number }): void {
94
		this._quickFixContextMenu.show(this._lightBulbWidget.model.fixes, coords);
J
Johannes Rieken 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108
	}

	public triggerFromEditorSelection(): void {
		this._model.trigger('manual');
	}

	private _updateLightBulbTitle(): void {
		const kb = this._keybindingService.lookupKeybinding(QuickFixAction.Id);
		let title: string;
		if (kb) {
			title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel());
		} else {
			title = nls.localize('quickFix', "Show Fixes");
		}
109
		this._lightBulbWidget.title = title;
J
Johannes Rieken 已提交
110
	}
111 112 113 114 115 116 117 118 119 120 121 122

	private async _onApplyCodeAction(action: CodeAction): TPromise<void> {
		if (action.edits) {
			const edit = createBulkEdit(this._textModelService, this._editor, this._fileService);
			edit.add(action.edits.edits);
			await edit.finish();
		}

		if (action.command) {
			await this._commandService.executeCommand(action.command.id, ...action.command.arguments);
		}
	}
J
Johannes Rieken 已提交
123 124 125 126 127 128 129 130 131 132 133
}

export class QuickFixAction extends EditorAction {

	static Id = 'editor.action.quickFix';

	constructor() {
		super({
			id: QuickFixAction.Id,
			label: nls.localize('quickfix.trigger.label', "Quick Fix"),
			alias: 'Quick Fix',
134
			precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
J
Johannes Rieken 已提交
135
			kbOpts: {
136
				kbExpr: EditorContextKeys.textFocus,
J
Johannes Rieken 已提交
137 138 139 140 141 142 143 144 145 146 147 148
				primary: KeyMod.CtrlCmd | KeyCode.US_DOT
			}
		});
	}

	public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
		let controller = QuickFixController.get(editor);
		if (controller) {
			controller.triggerFromEditorSelection();
		}
	}
}
149

150
registerEditorContribution(QuickFixController);
151
registerEditorAction(QuickFixAction);