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
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
14
import { optional } from 'vs/platform/instantiation/common/instantiation';
J
Johannes Rieken 已提交
15
import { IMarkerService } from 'vs/platform/markers/common/markers';
16
import { IEditorContribution } from 'vs/editor/common/editorCommon';
17
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
18
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction } from 'vs/editor/browser/editorExtensions';
J
Johannes Rieken 已提交
19 20 21 22
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { QuickFixContextMenu } from './quickFixWidget';
import { LightBulbWidget } from './lightBulbWidget';
import { QuickFixModel, QuickFixComputeEvent } from './quickFixModel';
23 24
import { TPromise } from 'vs/base/common/winjs.base';
import { CodeAction } from 'vs/editor/common/modes';
25
import { createBulkEdit } from 'vs/editor/browser/services/bulkEdit';
26 27
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
28 29 30

export class QuickFixController implements IEditorContribution {

31
	private static readonly ID = 'editor.contrib.quickFixController';
J
Johannes Rieken 已提交
32

33
	public static get(editor: ICodeEditor): QuickFixController {
J
Johannes Rieken 已提交
34 35 36 37 38
		return editor.getContribution<QuickFixController>(QuickFixController.ID);
	}

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

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

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

		this._disposables.push(
60 61 62 63
			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 已提交
64 65 66 67 68 69 70 71 72 73
		);
	}

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

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

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

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

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

	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");
		}
110
		this._lightBulbWidget.title = title;
J
Johannes Rieken 已提交
111
	}
112 113

	private async _onApplyCodeAction(action: CodeAction): TPromise<void> {
114
		if (action.edit) {
115
			const edit = createBulkEdit(this._textModelService, this._editor, this._fileService);
116
			edit.add(action.edit.edits);
117 118 119 120 121 122 123
			await edit.finish();
		}

		if (action.command) {
			await this._commandService.executeCommand(action.command.id, ...action.command.arguments);
		}
	}
J
Johannes Rieken 已提交
124 125 126 127
}

export class QuickFixAction extends EditorAction {

128
	static readonly Id = 'editor.action.quickFix';
J
Johannes Rieken 已提交
129 130 131 132 133 134

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

143
	public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
J
Johannes Rieken 已提交
144 145 146 147 148 149
		let controller = QuickFixController.get(editor);
		if (controller) {
			controller.triggerFromEditorSelection();
		}
	}
}
150

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