quickFixCommands.ts 6.0 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 { bulkEdit } from 'vs/editor/browser/services/bulkEdit';
26 27
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
28
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
29 30 31

export class QuickFixController implements IEditorContribution {

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

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

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

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

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

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

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

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

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

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

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

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

	private async _onApplyCodeAction(action: CodeAction): TPromise<void> {
115
		if (action.edit) {
116 117 118 119 120
			await bulkEdit(this._textModelService, this._editor, action.edit.edits, this._fileService, {
				createdResources: action.edit.createdResources.map(create => ({ uri: URI.revive(create.uri), contents: create.contents })),
				renamedResources: action.edit.renamedResources.map(rename => ({ from: URI.revive(rename.from), to: URI.revive(rename.to) })),
				deletedResources: action.edit.deletedResources.map(URI.revive)
			});
121 122 123 124 125 126
		}

		if (action.command) {
			await this._commandService.executeCommand(action.command.id, ...action.command.arguments);
		}
	}
J
Johannes Rieken 已提交
127 128 129 130
}

export class QuickFixAction extends EditorAction {

131
	static readonly Id = 'editor.action.quickFix';
J
Johannes Rieken 已提交
132 133 134 135 136 137

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

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

154
registerEditorContribution(QuickFixController);
155
registerEditorAction(QuickFixAction);