Skip to content

Commit

Permalink
Also show refactor documentation in normal lightbulb menu if refactor…
Browse files Browse the repository at this point in the history
…ings are returned

For #86788
  • Loading branch information
mjbvz committed Jan 14, 2020
1 parent 441a586 commit 0fc545e
Show file tree
Hide file tree
Showing 15 changed files with 110 additions and 102 deletions.
11 changes: 8 additions & 3 deletions src/vs/editor/common/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,8 @@ export interface CodeAction {
/**
* @internal
*/
export const enum CodeActionTrigger {
Automatic = 1,
export const enum CodeActionTriggerType {
Auto = 1,
Manual = 2,
}

Expand All @@ -565,7 +565,7 @@ export const enum CodeActionTrigger {
*/
export interface CodeActionContext {
only?: string;
trigger: CodeActionTrigger;
trigger: CodeActionTriggerType;
}

export interface CodeActionList extends IDisposable {
Expand All @@ -587,6 +587,11 @@ export interface CodeActionProvider {
* Optional list of CodeActionKinds that this provider returns.
*/
providedCodeActionKinds?: ReadonlyArray<string>;

/**
* @internal
*/
_getAdditionalMenuItems?(context: CodeActionContext, actions: readonly CodeAction[]): Command[];
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/vs/editor/contrib/codeAction/codeAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { ITextModel } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { CodeActionFilter, CodeActionKind, CodeActionTrigger, CodeActionTriggerType, filtersAction, mayIncludeActionsOfKind } from './types';
import { CodeActionFilter, CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind } from './types';

export const codeActionCommandId = 'editor.action.codeAction';
export const refactorCommandId = 'editor.action.refactor';
Expand Down Expand Up @@ -70,7 +70,7 @@ export function getCodeActions(

const codeActionContext: modes.CodeActionContext = {
only: filter.include?.value,
trigger: trigger.type === CodeActionTriggerType.Manual ? modes.CodeActionTrigger.Manual : modes.CodeActionTrigger.Automatic
trigger: trigger.type,
};

const cts = new TextModelCancellationTokenSource(model, token);
Expand Down Expand Up @@ -149,7 +149,7 @@ registerLanguageCommand('_executeCodeActionProvider', async function (accessor,
const codeActionSet = await getCodeActions(
model,
validatedRangeOrSelection,
{ type: CodeActionTriggerType.Manual, filter: { includeSourceActions: true, include: kind && kind.value ? new CodeActionKind(kind.value) : undefined } },
{ type: modes.CodeActionTriggerType.Manual, filter: { includeSourceActions: true, include: kind && kind.value ? new CodeActionKind(kind.value) : undefined } },
CancellationToken.None);

setTimeout(() => codeActionSet.dispose(), 100);
Expand Down
8 changes: 4 additions & 4 deletions src/vs/editor/contrib/codeAction/codeActionCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { IPosition } from 'vs/editor/common/core/position';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { CodeAction } from 'vs/editor/common/modes';
import { CodeAction, CodeActionTriggerType } from 'vs/editor/common/modes';
import { codeActionCommandId, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
import { CodeActionUi } from 'vs/editor/contrib/codeAction/codeActionUi';
import { MessageController } from 'vs/editor/contrib/message/messageController';
Expand All @@ -29,7 +29,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CodeActionModel, CodeActionsState, SUPPORTED_CODE_ACTIONS } from './codeActionModel';
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionFilter, CodeActionKind, CodeActionTrigger, CodeActionTriggerType } from './types';
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './types';

function contextKeyForSupportedActions(kind: CodeActionKind) {
return ContextKeyExpr.regex(
Expand Down Expand Up @@ -109,8 +109,8 @@ export class QuickFixController extends Disposable implements IEditorContributio
this._ui.getValue().update(newState);
}

public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) {
return this._ui.getValue().showCodeActionList(actions, at, { includeDisabledActions: false });
public showCodeActions(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition) {
return this._ui.getValue().showCodeActionList(trigger, actions, at, { includeDisabledActions: false });
}

public manualTriggerAtCurrentPosition(
Expand Down
35 changes: 21 additions & 14 deletions src/vs/editor/contrib/codeAction/codeActionMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { ScrollType } from 'vs/editor/common/editorCommon';
import { CodeAction } from 'vs/editor/common/modes';
import { CodeAction, CodeActionProviderRegistry } from 'vs/editor/common/modes';
import { codeActionCommandId, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind } from 'vs/editor/contrib/codeAction/types';
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind, CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
Expand Down Expand Up @@ -68,7 +68,7 @@ export class CodeActionMenu extends Disposable {
return this._visible;
}

public async show(codeActions: CodeActionSet, at: IAnchor | IPosition, options: CodeActionShowOptions): Promise<void> {
public async show(trigger: CodeActionTrigger, codeActions: CodeActionSet, at: IAnchor | IPosition, options: CodeActionShowOptions): Promise<void> {
const actionsToShow = options.includeDisabledActions ? codeActions.allActions : codeActions.validActions;
if (!actionsToShow.length) {
this._visible = false;
Expand All @@ -84,7 +84,7 @@ export class CodeActionMenu extends Disposable {
this._visible = true;
this._showingActions.value = codeActions;

const menuActions = this.getMenuActions(actionsToShow);
const menuActions = this.getMenuActions(trigger, actionsToShow);

const anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };
const resolver = this._keybindingResolver.getResolver();
Expand All @@ -101,19 +101,26 @@ export class CodeActionMenu extends Disposable {
});
}

private getMenuActions(actionsToShow: readonly CodeAction[]): IAction[] {
const allActions = actionsToShow
.map(action => new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action)));
private getMenuActions(trigger: CodeActionTrigger, actionsToShow: readonly CodeAction[]): IAction[] {
const toCodeActionAction = (action: CodeAction): CodeActionAction => new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action));

// Treat documentation actions as special
const result: IAction[] = allActions
.filter(action => !action.action.kind || !CodeActionKind.RefactorDocumentation.contains(new CodeActionKind(action.action.kind)));
const result: IAction[] = actionsToShow
.map(toCodeActionAction);

const documentationActions = allActions
.filter(action => action.action.kind && CodeActionKind.RefactorDocumentation.contains(new CodeActionKind(action.action.kind)));

if (documentationActions.length) {
result.push(new Separator(), ...documentationActions);
const model = this._editor.getModel();
if (model && result.length) {
for (const provider of CodeActionProviderRegistry.all(model)) {
if (provider._getAdditionalMenuItems) {
const items = provider._getAdditionalMenuItems({ trigger: trigger.type, only: trigger.filter?.include?.value }, actionsToShow);
if (items.length) {
result.push(new Separator(), ...items.map(command => toCodeActionAction({
title: command.title,
command: command,
})));
}
}
}
}

return result;
Expand Down
4 changes: 2 additions & 2 deletions src/vs/editor/contrib/codeAction/codeActionModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { CodeActionProviderRegistry } from 'vs/editor/common/modes';
import { CodeActionProviderRegistry, CodeActionTriggerType } from 'vs/editor/common/modes';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { getCodeActions, CodeActionSet } from './codeAction';
import { CodeActionTrigger, CodeActionTriggerType } from './types';
import { CodeActionTrigger } from './types';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { isEqual } from 'vs/base/common/resources';

Expand Down
18 changes: 9 additions & 9 deletions src/vs/editor/contrib/codeAction/codeActionUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { Lazy } from 'vs/base/common/lazy';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IPosition } from 'vs/editor/common/core/position';
import { CodeAction } from 'vs/editor/common/modes';
import { CodeAction, CodeActionTriggerType } from 'vs/editor/common/modes';
import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';
import { MessageController } from 'vs/editor/contrib/message/messageController';
import { CodeActionsState } from './codeActionModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CodeActionMenu, CodeActionShowOptions } from './codeActionMenu';
import { CodeActionsState } from './codeActionModel';
import { LightBulbWidget } from './lightBulbWidget';
import { CodeActionAutoApply, CodeActionTrigger, CodeActionTriggerType } from './types';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CodeActionAutoApply, CodeActionTrigger } from './types';

export class CodeActionUi extends Disposable {

Expand Down Expand Up @@ -46,7 +46,7 @@ export class CodeActionUi extends Disposable {

this._lightBulbWidget = new Lazy(() => {
const widget = this._register(instantiationService.createInstance(LightBulbWidget, this._editor, quickFixActionId, preferredFixActionId));
this._register(widget.onClick(e => this.showCodeActionList(e.actions, e, { includeDisabledActions: false })));
this._register(widget.onClick(e => this.showCodeActionList(e.trigger, e.actions, e, { includeDisabledActions: false })));
return widget;
});
}
Expand All @@ -65,7 +65,7 @@ export class CodeActionUi extends Disposable {
return;
}

this._lightBulbWidget.getValue().update(actions, newState.position);
this._lightBulbWidget.getValue().update(actions, newState.trigger, newState.position);

if (newState.trigger.type === CodeActionTriggerType.Manual) {
if (newState.trigger.filter?.include) { // Triggered for specific scope
Expand Down Expand Up @@ -103,7 +103,7 @@ export class CodeActionUi extends Disposable {
}

this._activeCodeActions.value = actions;
this._codeActionWidget.getValue().show(actions, newState.position, { includeDisabledActions });
this._codeActionWidget.getValue().show(newState.trigger, actions, newState.position, { includeDisabledActions });
} else {
// auto magically triggered
if (this._codeActionWidget.getValue().isVisible) {
Expand Down Expand Up @@ -143,7 +143,7 @@ export class CodeActionUi extends Disposable {
return undefined;
}

public async showCodeActionList(actions: CodeActionSet, at: IAnchor | IPosition, options: CodeActionShowOptions): Promise<void> {
this._codeActionWidget.getValue().show(actions, at, options);
public async showCodeActionList(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition, options: CodeActionShowOptions): Promise<void> {
this._codeActionWidget.getValue().show(trigger, actions, at, options);
}
}
11 changes: 7 additions & 4 deletions src/vs/editor/contrib/codeAction/lightBulbWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { editorLightBulbForeground, editorLightBulbAutoFixForeground } from 'vs/platform/theme/common/colorRegistry';
import { Gesture } from 'vs/base/browser/touch';
import type { CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';

namespace LightBulbState {

Expand All @@ -33,6 +34,7 @@ namespace LightBulbState {

constructor(
public readonly actions: CodeActionSet,
public readonly trigger: CodeActionTrigger,
public readonly editorPosition: IPosition,
public readonly widgetPosition: IContentWidgetPosition,
) { }
Expand All @@ -48,7 +50,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {

private readonly _domNode: HTMLDivElement;

private readonly _onClick = this._register(new Emitter<{ x: number; y: number; actions: CodeActionSet; }>());
private readonly _onClick = this._register(new Emitter<{ x: number; y: number; actions: CodeActionSet; trigger: CodeActionTrigger }>());
public readonly onClick = this._onClick.event;

private _state: LightBulbState.State = LightBulbState.Hidden;
Expand Down Expand Up @@ -95,7 +97,8 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
this._onClick.fire({
x: e.posx,
y: top + height + pad,
actions: this.state.actions
actions: this.state.actions,
trigger: this.state.trigger,
});
}));
this._register(dom.addDisposableListener(this._domNode, 'mouseenter', (e: MouseEvent) => {
Expand Down Expand Up @@ -139,7 +142,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
return this._state.type === LightBulbState.Type.Showing ? this._state.widgetPosition : null;
}

public update(actions: CodeActionSet, atPosition: IPosition) {
public update(actions: CodeActionSet, trigger: CodeActionTrigger, atPosition: IPosition) {
if (actions.validActions.length <= 0) {
return this.hide();
}
Expand Down Expand Up @@ -177,7 +180,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
}
}

this.state = new LightBulbState.Showing(actions, atPosition, {
this.state = new LightBulbState.Showing(actions, trigger, atPosition, {
position: { lineNumber: effectiveLineNumber, column: 1 },
preference: LightBulbWidget._posPref
});
Expand Down
20 changes: 10 additions & 10 deletions src/vs/editor/contrib/codeAction/test/codeAction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Range } from 'vs/editor/common/core/range';
import { TextModel } from 'vs/editor/common/model/textModel';
import * as modes from 'vs/editor/common/modes';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { CodeActionKind, CodeActionTriggerType } from 'vs/editor/contrib/codeAction/types';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
import { CancellationToken } from 'vs/base/common/cancellation';

Expand Down Expand Up @@ -125,7 +125,7 @@ suite('CodeAction', () => {
testData.tsLint.abc
];

const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Manual }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Manual }, CancellationToken.None);
assert.equal(actions.length, 6);
assert.deepEqual(actions, expected);
});
Expand All @@ -140,20 +140,20 @@ suite('CodeAction', () => {
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider));

{
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a') } }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a') } }, CancellationToken.None);
assert.equal(actions.length, 2);
assert.strictEqual(actions[0].title, 'a');
assert.strictEqual(actions[1].title, 'a.b');
}

{
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a.b') } }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a.b') } }, CancellationToken.None);
assert.equal(actions.length, 1);
assert.strictEqual(actions[0].title, 'a.b');
}

{
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a.b.c') } }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a.b.c') } }, CancellationToken.None);
assert.equal(actions.length, 0);
}
});
Expand All @@ -172,7 +172,7 @@ suite('CodeAction', () => {

disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider));

const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a') } }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Auto, filter: { include: new CodeActionKind('a') } }, CancellationToken.None);
assert.equal(actions.length, 1);
assert.strictEqual(actions[0].title, 'a');
});
Expand All @@ -186,13 +186,13 @@ suite('CodeAction', () => {
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider));

{
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Auto }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Auto }, CancellationToken.None);
assert.equal(actions.length, 1);
assert.strictEqual(actions[0].title, 'b');
}

{
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: CodeActionTriggerType.Auto, filter: { include: CodeActionKind.Source, includeSourceActions: true } }, CancellationToken.None);
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: modes.CodeActionTriggerType.Auto, filter: { include: CodeActionKind.Source, includeSourceActions: true } }, CancellationToken.None);
assert.equal(actions.length, 1);
assert.strictEqual(actions[0].title, 'a');
}
Expand All @@ -209,7 +209,7 @@ suite('CodeAction', () => {

{
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), {
type: CodeActionTriggerType.Auto, filter: {
type: modes.CodeActionTriggerType.Auto, filter: {
include: CodeActionKind.Source.append('test'),
excludes: [CodeActionKind.Source],
includeSourceActions: true,
Expand All @@ -234,7 +234,7 @@ suite('CodeAction', () => {
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider));

const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), {
type: CodeActionTriggerType.Auto,
type: modes.CodeActionTriggerType.Auto,
filter: {
include: CodeActionKind.QuickFix
}
Expand Down
Loading

0 comments on commit 0fc545e

Please sign in to comment.