mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-20 20:10:11 -04:00
Vscode merge (#4582)
* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd * fix issues with merges * bump node version in azpipe * replace license headers * remove duplicate launch task * fix build errors * fix build errors * fix tslint issues * working through package and linux build issues * more work * wip * fix packaged builds * working through linux build errors * wip * wip * wip * fix mac and linux file limits * iterate linux pipeline * disable editor typing * revert series to parallel * remove optimize vscode from linux * fix linting issues * revert testing change * add work round for new node * readd packaging for extensions * fix issue with angular not resolving decorator dependencies
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { flatten, isNonEmptyArray, mergeSort } from 'vs/base/common/arrays';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { equals, flatten, isNonEmptyArray, mergeSort } from 'vs/base/common/arrays';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { illegalArgument, isPromiseCanceledError, onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
|
||||
@@ -13,14 +13,41 @@ import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { CodeAction, CodeActionContext, CodeActionProviderRegistry, CodeActionTrigger as CodeActionTriggerKind } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind, CodeActionFilter } from './codeActionTrigger';
|
||||
import { CodeActionFilter, CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind } from './codeActionTrigger';
|
||||
|
||||
export class CodeActionSet {
|
||||
|
||||
private static codeActionsComparator(a: CodeAction, b: CodeAction): number {
|
||||
if (isNonEmptyArray(a.diagnostics)) {
|
||||
if (isNonEmptyArray(b.diagnostics)) {
|
||||
return a.diagnostics[0].message.localeCompare(b.diagnostics[0].message);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (isNonEmptyArray(b.diagnostics)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0; // both have no diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
public readonly actions: ReadonlyArray<CodeAction>;
|
||||
|
||||
public constructor(actions: CodeAction[]) {
|
||||
this.actions = mergeSort(actions, CodeActionSet.codeActionsComparator);
|
||||
}
|
||||
|
||||
public get hasAutoFix() {
|
||||
return this.actions.some(fix => !!fix.kind && CodeActionKind.QuickFix.contains(new CodeActionKind(fix.kind)) && !!fix.isPreferred);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCodeActions(
|
||||
model: ITextModel,
|
||||
rangeOrSelection: Range | Selection,
|
||||
trigger: CodeActionTrigger,
|
||||
token: CancellationToken
|
||||
): Promise<CodeAction[]> {
|
||||
): Promise<CodeActionSet> {
|
||||
const filter = trigger.filter || {};
|
||||
|
||||
const codeActionContext: CodeActionContext = {
|
||||
@@ -28,12 +55,13 @@ export function getCodeActions(
|
||||
trigger: trigger.type === 'manual' ? CodeActionTriggerKind.Manual : CodeActionTriggerKind.Automatic
|
||||
};
|
||||
|
||||
if (filter.kind && CodeActionKind.Source.contains(filter.kind) && rangeOrSelection.isEmpty()) {
|
||||
rangeOrSelection = model.getFullModelRange();
|
||||
}
|
||||
const chainedCancellation = new CancellationTokenSource();
|
||||
token.onCancellationRequested(() => chainedCancellation.cancel());
|
||||
|
||||
const promises = getCodeActionProviders(model, filter).map(provider => {
|
||||
return Promise.resolve(provider.provideCodeActions(model, rangeOrSelection, codeActionContext, token)).then(providedCodeActions => {
|
||||
const providers = getCodeActionProviders(model, filter);
|
||||
|
||||
const promises = providers.map(provider => {
|
||||
return Promise.resolve(provider.provideCodeActions(model, rangeOrSelection, codeActionContext, chainedCancellation.token)).then(providedCodeActions => {
|
||||
if (!Array.isArray(providedCodeActions)) {
|
||||
return [];
|
||||
}
|
||||
@@ -48,9 +76,19 @@ export function getCodeActions(
|
||||
});
|
||||
});
|
||||
|
||||
const listener = CodeActionProviderRegistry.onDidChange(() => {
|
||||
const newProviders = CodeActionProviderRegistry.all(model);
|
||||
if (!equals(newProviders, providers)) {
|
||||
chainedCancellation.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(flatten)
|
||||
.then(allCodeActions => mergeSort(allCodeActions, codeActionsComparator));
|
||||
.then(actions => new CodeActionSet(actions))
|
||||
.finally(() => {
|
||||
listener.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
function getCodeActionProviders(
|
||||
@@ -68,22 +106,8 @@ function getCodeActionProviders(
|
||||
});
|
||||
}
|
||||
|
||||
function codeActionsComparator(a: CodeAction, b: CodeAction): number {
|
||||
if (isNonEmptyArray(a.diagnostics)) {
|
||||
if (isNonEmptyArray(b.diagnostics)) {
|
||||
return a.diagnostics[0].message.localeCompare(b.diagnostics[0].message);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (isNonEmptyArray(b.diagnostics)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0; // both have no diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
registerLanguageCommand('_executeCodeActionProvider', function (accessor, args) {
|
||||
const { resource, range } = args;
|
||||
registerLanguageCommand('_executeCodeActionProvider', function (accessor, args): Promise<ReadonlyArray<CodeAction>> {
|
||||
const { resource, range, kind } = args;
|
||||
if (!(resource instanceof URI) || !Range.isIRange(range)) {
|
||||
throw illegalArgument();
|
||||
}
|
||||
@@ -96,6 +120,6 @@ registerLanguageCommand('_executeCodeActionProvider', function (accessor, args)
|
||||
return getCodeActions(
|
||||
model,
|
||||
model.validateRange(range),
|
||||
{ type: 'manual', filter: { includeSourceActions: true } },
|
||||
CancellationToken.None);
|
||||
{ type: 'manual', filter: { includeSourceActions: true, kind: kind && kind.value ? new CodeActionKind(kind.value) : undefined } },
|
||||
CancellationToken.None).then(actions => actions.actions);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { CancelablePromise } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
@@ -27,6 +27,7 @@ import { CodeActionContextMenu } from './codeActionWidget';
|
||||
import { LightBulbWidget } from './lightBulbWidget';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
|
||||
function contextKeyForSupportedActions(kind: CodeActionKind) {
|
||||
return ContextKeyExpr.regex(
|
||||
@@ -34,7 +35,7 @@ function contextKeyForSupportedActions(kind: CodeActionKind) {
|
||||
new RegExp('(\\s|^)' + escapeRegExpCharacters(kind.value) + '\\b'));
|
||||
}
|
||||
|
||||
export class QuickFixController implements IEditorContribution {
|
||||
export class QuickFixController extends Disposable implements IEditorContribution {
|
||||
|
||||
private static readonly ID = 'editor.contrib.quickFixController';
|
||||
|
||||
@@ -42,15 +43,15 @@ export class QuickFixController implements IEditorContribution {
|
||||
return editor.getContribution<QuickFixController>(QuickFixController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _model: CodeActionModel;
|
||||
private _codeActionContextMenu: CodeActionContextMenu;
|
||||
private _lightBulbWidget: LightBulbWidget;
|
||||
private _disposables: IDisposable[] = [];
|
||||
private readonly _editor: ICodeEditor;
|
||||
private readonly _model: CodeActionModel;
|
||||
private readonly _codeActionContextMenu: CodeActionContextMenu;
|
||||
private readonly _lightBulbWidget: LightBulbWidget;
|
||||
|
||||
private _activeRequest: CancelablePromise<CodeAction[]> | undefined;
|
||||
private _activeRequest: CancelablePromise<CodeActionSet> | undefined;
|
||||
|
||||
constructor(editor: ICodeEditor,
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IMarkerService markerService: IMarkerService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@@ -59,24 +60,24 @@ export class QuickFixController implements IEditorContribution {
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._editor = editor;
|
||||
this._model = new CodeActionModel(this._editor, markerService, contextKeyService, progressService);
|
||||
this._codeActionContextMenu = new CodeActionContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action));
|
||||
this._lightBulbWidget = new LightBulbWidget(editor);
|
||||
this._lightBulbWidget = this._register(new LightBulbWidget(editor));
|
||||
|
||||
this._updateLightBulbTitle();
|
||||
|
||||
this._disposables.push(
|
||||
this._codeActionContextMenu.onDidExecuteCodeAction(_ => this._model.trigger({ type: 'auto', filter: {} })),
|
||||
this._lightBulbWidget.onClick(this._handleLightBulbSelect, this),
|
||||
this._model.onDidChangeState(e => this._onDidChangeCodeActionsState(e)),
|
||||
this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)
|
||||
);
|
||||
this._register(this._codeActionContextMenu.onDidExecuteCodeAction(_ => this._model.trigger({ type: 'auto', filter: {} })));
|
||||
this._register(this._lightBulbWidget.onClick(this._handleLightBulbSelect, this));
|
||||
this._register(this._model.onDidChangeState(e => this._onDidChangeCodeActionsState(e)));
|
||||
this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
this._model.dispose();
|
||||
dispose(this._disposables);
|
||||
}
|
||||
|
||||
private _onDidChangeCodeActionsState(newState: CodeActionsState.State): void {
|
||||
@@ -91,10 +92,10 @@ export class QuickFixController implements IEditorContribution {
|
||||
if (newState.trigger.filter && newState.trigger.filter.kind) {
|
||||
// Triggered for specific scope
|
||||
newState.actions.then(fixes => {
|
||||
if (fixes.length > 0) {
|
||||
if (fixes.actions.length > 0) {
|
||||
// Apply if we only have one action or requested autoApply
|
||||
if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && fixes.length === 1)) {
|
||||
this._onApplyCodeAction(fixes[0]);
|
||||
if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && fixes.actions.length === 1)) {
|
||||
this._onApplyCodeAction(fixes.actions[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +127,7 @@ export class QuickFixController implements IEditorContribution {
|
||||
this._codeActionContextMenu.show(e.state.actions, e);
|
||||
}
|
||||
|
||||
public triggerFromEditorSelection(filter?: CodeActionFilter, autoApply?: CodeActionAutoApply): Promise<CodeAction[] | undefined> {
|
||||
public triggerFromEditorSelection(filter?: CodeActionFilter, autoApply?: CodeActionAutoApply): Promise<CodeActionSet | undefined> {
|
||||
return this._model.trigger({ type: 'manual', filter, autoApply });
|
||||
}
|
||||
|
||||
@@ -177,7 +178,7 @@ function showCodeActionsForEditorSelection(
|
||||
|
||||
const pos = editor.getPosition();
|
||||
controller.triggerFromEditorSelection(filter, autoApply).then(codeActions => {
|
||||
if (!codeActions || !codeActions.length) {
|
||||
if (!codeActions || !codeActions.actions.length) {
|
||||
MessageController.get(editor).showMessage(notAvailableMessage, pos);
|
||||
}
|
||||
});
|
||||
@@ -253,7 +254,27 @@ export class CodeActionCommand extends EditorCommand {
|
||||
constructor() {
|
||||
super({
|
||||
id: CodeActionCommand.Id,
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider)
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
|
||||
description: {
|
||||
description: `Trigger a code action`,
|
||||
args: [{
|
||||
name: 'args',
|
||||
schema: {
|
||||
'type': 'object',
|
||||
'required': ['kind'],
|
||||
'properties': {
|
||||
'kind': {
|
||||
'type': 'string'
|
||||
},
|
||||
'apply': {
|
||||
'type': 'string',
|
||||
'default': 'ifSingle',
|
||||
'enum': ['first', 'ifSingle', 'never']
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -297,6 +318,25 @@ export class RefactorAction extends EditorAction {
|
||||
when: ContextKeyExpr.and(
|
||||
EditorContextKeys.writable,
|
||||
contextKeyForSupportedActions(CodeActionKind.Refactor)),
|
||||
},
|
||||
description: {
|
||||
description: 'Refactor...',
|
||||
args: [{
|
||||
name: 'args',
|
||||
schema: {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'kind': {
|
||||
'type': 'string'
|
||||
},
|
||||
'apply': {
|
||||
'type': 'string',
|
||||
'default': 'never',
|
||||
'enum': ['first', 'ifSingle', 'never']
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -333,6 +373,25 @@ export class SourceAction extends EditorAction {
|
||||
when: ContextKeyExpr.and(
|
||||
EditorContextKeys.writable,
|
||||
contextKeyForSupportedActions(CodeActionKind.Source)),
|
||||
},
|
||||
description: {
|
||||
description: 'Source Action...',
|
||||
args: [{
|
||||
name: 'args',
|
||||
schema: {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'kind': {
|
||||
'type': 'string'
|
||||
},
|
||||
'apply': {
|
||||
'type': 'string',
|
||||
'default': 'never',
|
||||
'enum': ['first', 'ifSingle', 'never']
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -381,6 +440,29 @@ export class OrganizeImportsAction extends EditorAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class FixAllAction extends EditorAction {
|
||||
|
||||
static readonly Id = 'editor.action.fixAll';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: FixAllAction.Id,
|
||||
label: nls.localize('fixAll.label', "Fix All"),
|
||||
alias: 'Fix All',
|
||||
precondition: ContextKeyExpr.and(
|
||||
EditorContextKeys.writable,
|
||||
contextKeyForSupportedActions(CodeActionKind.SourceFixAll))
|
||||
});
|
||||
}
|
||||
|
||||
public run(_accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
return showCodeActionsForEditorSelection(editor,
|
||||
nls.localize('fixAll.noneMessage', "No fix all action available"),
|
||||
{ kind: CodeActionKind.SourceFixAll, includeSourceActions: true },
|
||||
CodeActionAutoApply.IfSingle);
|
||||
}
|
||||
}
|
||||
|
||||
export class AutoFixAction extends EditorAction {
|
||||
|
||||
static readonly Id = 'editor.action.autoFix';
|
||||
|
||||
@@ -11,11 +11,11 @@ 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 { CodeAction, CodeActionProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { CodeActionProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { getCodeActions } from './codeAction';
|
||||
import { getCodeActions, CodeActionSet } from './codeAction';
|
||||
import { CodeActionTrigger } from './codeActionTrigger';
|
||||
|
||||
export const SUPPORTED_CODE_ACTIONS = new RawContextKey<string>('supportedCodeAction', '');
|
||||
@@ -26,9 +26,9 @@ export class CodeActionOracle {
|
||||
private readonly _autoTriggerTimer = new TimeoutTimer();
|
||||
|
||||
constructor(
|
||||
private _editor: ICodeEditor,
|
||||
private readonly _editor: ICodeEditor,
|
||||
private readonly _markerService: IMarkerService,
|
||||
private _signalChange: (newState: CodeActionsState.State) => void,
|
||||
private readonly _signalChange: (newState: CodeActionsState.State) => void,
|
||||
private readonly _delay: number = 250,
|
||||
private readonly _progressService?: IProgressService,
|
||||
) {
|
||||
@@ -112,7 +112,7 @@ export class CodeActionOracle {
|
||||
return selection ? selection : undefined;
|
||||
}
|
||||
|
||||
private _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): Promise<CodeAction[] | undefined> {
|
||||
private _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): Promise<CodeActionSet | undefined> {
|
||||
if (!selection) {
|
||||
// cancel
|
||||
this._signalChange(CodeActionsState.Empty);
|
||||
@@ -160,7 +160,7 @@ export namespace CodeActionsState {
|
||||
public readonly trigger: CodeActionTrigger,
|
||||
public readonly rangeOrSelection: Range | Selection,
|
||||
public readonly position: Position,
|
||||
public readonly actions: CancelablePromise<CodeAction[]>,
|
||||
public readonly actions: CancelablePromise<CodeActionSet>,
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -169,18 +169,18 @@ export namespace CodeActionsState {
|
||||
|
||||
export class CodeActionModel {
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _markerService: IMarkerService;
|
||||
private _codeActionOracle?: CodeActionOracle;
|
||||
private _state: CodeActionsState.State = CodeActionsState.Empty;
|
||||
private _onDidChangeState = new Emitter<CodeActionsState.State>();
|
||||
private _disposables: IDisposable[] = [];
|
||||
private readonly _supportedCodeActions: IContextKey<string>;
|
||||
|
||||
constructor(editor: ICodeEditor, markerService: IMarkerService, contextKeyService: IContextKeyService, private readonly _progressService: IProgressService) {
|
||||
this._editor = editor;
|
||||
this._markerService = markerService;
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
private readonly _markerService: IMarkerService,
|
||||
contextKeyService: IContextKeyService,
|
||||
private readonly _progressService: IProgressService
|
||||
) {
|
||||
this._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService);
|
||||
|
||||
this._disposables.push(this._editor.onDidChangeModel(() => this._update()));
|
||||
@@ -206,7 +206,7 @@ export class CodeActionModel {
|
||||
}
|
||||
|
||||
if (this._state.type === CodeActionsState.Type.Triggered) {
|
||||
// this._state.actions.cancel();
|
||||
this._state.actions.cancel();
|
||||
}
|
||||
this.setState(CodeActionsState.Empty);
|
||||
|
||||
@@ -231,7 +231,7 @@ export class CodeActionModel {
|
||||
}
|
||||
}
|
||||
|
||||
public trigger(trigger: CodeActionTrigger): Promise<CodeAction[] | undefined> {
|
||||
public trigger(trigger: CodeActionTrigger): Promise<CodeActionSet | undefined> {
|
||||
if (this._codeActionOracle) {
|
||||
return this._codeActionOracle.trigger(trigger);
|
||||
}
|
||||
|
||||
@@ -12,13 +12,14 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { CodeAction } from 'vs/editor/common/modes';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
|
||||
export class CodeActionContextMenu {
|
||||
|
||||
private _visible: boolean;
|
||||
private _onDidExecuteCodeAction = new Emitter<void>();
|
||||
|
||||
readonly onDidExecuteCodeAction: Event<void> = this._onDidExecuteCodeAction.event;
|
||||
private readonly _onDidExecuteCodeAction = new Emitter<void>();
|
||||
public readonly onDidExecuteCodeAction: Event<void> = this._onDidExecuteCodeAction.event;
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
@@ -26,13 +27,14 @@ export class CodeActionContextMenu {
|
||||
private readonly _onApplyCodeAction: (action: CodeAction) => Promise<any>
|
||||
) { }
|
||||
|
||||
async show(actionsToShow: Promise<CodeAction[]>, at?: { x: number; y: number } | Position): Promise<void> {
|
||||
async show(actionsToShow: Promise<CodeActionSet>, at?: { x: number; y: number } | Position): Promise<void> {
|
||||
const codeActions = await actionsToShow;
|
||||
if (!this._editor.getDomNode()) {
|
||||
// cancel when editor went off-dom
|
||||
return Promise.reject(canceled());
|
||||
}
|
||||
const actions = codeActions.map(action => this.codeActionToAction(action));
|
||||
this._visible = true;
|
||||
const actions = codeActions.actions.map(action => this.codeActionToAction(action));
|
||||
this._contextMenuService.showContextMenu({
|
||||
getAnchor: () => {
|
||||
if (Position.isIPosition(at)) {
|
||||
@@ -51,7 +53,7 @@ export class CodeActionContextMenu {
|
||||
|
||||
private codeActionToAction(action: CodeAction): Action {
|
||||
const id = action.command ? action.command.id : action.title;
|
||||
const title = action.isPreferred ? `${action.title} ★` : action.title;
|
||||
const title = action.title;
|
||||
return new Action(id, title, undefined, true, () =>
|
||||
this._onApplyCodeAction(action)
|
||||
.finally(() => this._onDidExecuteCodeAction.fire(undefined)));
|
||||
@@ -69,7 +71,7 @@ export class CodeActionContextMenu {
|
||||
this._editor.render();
|
||||
|
||||
// Translate to absolute editor position
|
||||
const cursorCoords = this._editor.getScrolledVisiblePosition(this._editor.getPosition());
|
||||
const cursorCoords = this._editor.getScrolledVisiblePosition(position);
|
||||
const editorCoords = getDomNodePagePosition(this._editor.getDomNode());
|
||||
const x = editorCoords.left + cursorCoords.left;
|
||||
const y = editorCoords.top + cursorCoords.top + cursorCoords.height;
|
||||
|
||||
@@ -21,7 +21,16 @@
|
||||
background: url('lightbulb.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs .lightbulb-glyph.autofixable {
|
||||
background: url('lightbulb-autofix.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .lightbulb-glyph,
|
||||
.monaco-editor.hc-black .lightbulb-glyph {
|
||||
background: url('lightbulb-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .lightbulb-glyph.autofixable,
|
||||
.monaco-editor.hc-black .lightbulb-glyph.autofixable {
|
||||
background: url('lightbulb-autofix-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import 'vs/css!./lightBulbWidget';
|
||||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { CodeActionsState } from './codeActionModel';
|
||||
|
||||
export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
@@ -126,8 +127,8 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
|
||||
const selection = this._state.rangeOrSelection;
|
||||
this._state.actions.then(fixes => {
|
||||
if (!token.isCancellationRequested && fixes && fixes.length > 0 && selection) {
|
||||
this._show();
|
||||
if (!token.isCancellationRequested && fixes.actions.length > 0 && selection) {
|
||||
this._show(fixes);
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
@@ -144,7 +145,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
return this._domNode.title;
|
||||
}
|
||||
|
||||
private _show(): void {
|
||||
private _show(codeActions: CodeActionSet): void {
|
||||
const config = this._editor.getConfiguration();
|
||||
if (!config.contribInfo.lightbulbEnabled) {
|
||||
return;
|
||||
@@ -184,6 +185,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
|
||||
position: { lineNumber: effectiveLineNumber, column: 1 },
|
||||
preference: LightBulbWidget._posPref
|
||||
};
|
||||
dom.toggleClass(this._domNode, 'autofixable', codeActions.hasAutoFix);
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
|
||||
10
src/vs/editor/contrib/codeAction/lightbulb-autofix-dark.svg
Normal file
10
src/vs/editor/contrib/codeAction/lightbulb-autofix-dark.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.001 4.2C12.601 2.1 10.301 0 8.801 0H6.201C5.801 0 5.601 0.2 5.601 0.2C3.501 0.8 2.001 2.7 2.001 4.9C2.001 5.4 1.901 7.2 3.701 8.7C4.201 9.2 4.901 10.7 5.001 11.1V14.4L6.601 16H8.601L10.101 14.4V11C10.201 10.6 10.901 9.1 11.401 8.7C12.501 7.8 12.901 6.8 13.001 6V4.2Z" fill="#1E1E1E"/>
|
||||
<path d="M6.00098 12H9.00098V13H6.00098V12ZM7.00098 15H8.10098L9.00098 14H6.00098L7.00098 15Z" fill="#C5C5C5"/>
|
||||
<path d="M12.1011 4.9999C12.1011 2.6999 10.3011 0.899902 8.00107 0.899902C7.90107 0.899902 6.60107 0.999902 6.60107 0.999902C4.50107 1.2999 2.90107 2.9999 2.90107 4.9999C2.90107 5.0999 2.70107 6.5999 4.30107 7.9999C5.00107 8.6999 5.80107 10.3999 5.90107 10.8999L6.00107 10.9999H9.00107L9.10107 10.7999C9.20107 10.2999 10.0011 8.5999 10.7011 7.8999C12.3011 6.5999 12.1011 5.0999 12.1011 4.9999V4.9999ZM9.10107 5.9999L8.60107 8.9999H8.00107V5.9999C9.10107 5.9999 8.90107 4.9999 8.90107 4.9999H6.00107V5.0999C6.00107 5.2999 6.10107 5.9999 7.00107 5.9999V8.9999H6.50107L6.30107 8.2999L6.00107 5.9999C5.30107 5.9999 5.10107 5.5999 5.00107 5.2999V4.8999C5.00107 4.0999 5.90107 3.9999 5.90107 3.9999H9.00107C9.00107 3.9999 10.0011 4.0999 10.0011 4.9999C10.0011 4.9999 10.1011 5.9999 9.10107 5.9999Z" fill="#DDB204"/>
|
||||
<path d="M10.001 5C10.001 4.1 9.00098 4 9.00098 4H5.90098C5.90098 4 5.00098 4.1 5.00098 4.9V5.3C5.00098 5.6 5.30098 6 5.90098 6L6.30098 8.3L6.50098 9H7.00098V6C6.00098 6 6.00098 5.3 6.00098 5.1V5H9.00098C9.00098 5 9.10098 6 8.10098 6V9H8.70098L9.20098 6C10.101 6 10.001 5 10.001 5Z" fill="#252526"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 12C8 9.77386 9.77386 8 12 8C14.2261 8 16 9.77386 16 12C16 14.2261 14.2261 16 12 16C9.77386 16 8 14.2261 8 12Z" fill="#1E1E1E"/>
|
||||
<path d="M12.3192 12.3031L13.3495 13.3334L13.3334 13.3495L12.3031 12.3192L12 12.0162L11.697 12.3192L10.6667 13.3495L10.6506 13.3334L11.6809 12.3031L11.9839 12L11.6809 11.697L10.6506 10.6667L10.6667 10.6506L11.697 11.6809L12 11.9839L12.3031 11.6809L13.3334 10.6506L13.3495 10.6667L12.3192 11.697L12.0162 12L12.3192 12.3031ZM12 8.46034C10.03 8.46034 8.46034 10.03 8.46034 12C8.46034 13.9701 10.03 15.5397 12 15.5397C13.9701 15.5397 15.5397 13.9701 15.5397 12C15.5397 10.03 13.9701 8.46034 12 8.46034Z" fill="#007ACC" stroke="#1E1E1E" stroke-width="0.857143"/>
|
||||
<path d="M12.6225 12.0002L13.9558 13.3336L13.3336 13.9558L12.0002 12.6225L10.6669 13.9558L10.0447 13.3336L11.378 12.0002L10.0447 10.6669L10.6669 10.0447L12.0002 11.378L13.3336 10.0447L13.9558 10.6669L12.6225 12.0002Z" fill="#007ACC"/>
|
||||
<path d="M10.704 14L11.2028 12.4712L10 11.6394H11.4732L12 10L12.5361 11.6394H14L12.7972 12.4712L13.3054 14L12 13.024L10.704 14Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
10
src/vs/editor/contrib/codeAction/lightbulb-autofix.svg
Normal file
10
src/vs/editor/contrib/codeAction/lightbulb-autofix.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.001 4.2C12.601 2.1 10.301 0 8.801 0H6.201C5.801 0 5.601 0.2 5.601 0.2C3.501 0.8 2.001 2.7 2.001 4.9C2.001 5.4 1.901 7.2 3.701 8.7C4.201 9.2 4.901 10.7 5.001 11.1V14.4L6.601 16H8.601L10.101 14.4V11C10.201 10.6 10.901 9.1 11.401 8.7C12.501 7.8 12.901 6.8 13.001 6V4.2Z" fill="#F6F6F6"/>
|
||||
<path d="M6.00098 12H9.00098V13H6.00098V12ZM7.00098 15H8.10098L9.00098 14H6.00098L7.00098 15Z" fill="#848484"/>
|
||||
<path d="M12.1011 4.9999C12.1011 2.6999 10.3011 0.899902 8.00107 0.899902C7.90107 0.899902 6.60107 0.999902 6.60107 0.999902C4.50107 1.2999 2.90107 2.9999 2.90107 4.9999C2.90107 5.0999 2.70107 6.5999 4.30107 7.9999C5.00107 8.6999 5.80107 10.3999 5.90107 10.8999L6.00107 10.9999H9.00107L9.10107 10.7999C9.20107 10.2999 10.0011 8.5999 10.7011 7.8999C12.3011 6.5999 12.1011 5.0999 12.1011 4.9999V4.9999ZM9.10107 5.9999L8.60107 8.9999H8.00107V5.9999C9.10107 5.9999 8.90107 4.9999 8.90107 4.9999H6.00107V5.0999C6.00107 5.2999 6.10107 5.9999 7.00107 5.9999V8.9999H6.50107L6.30107 8.2999L6.00107 5.9999C5.30107 5.9999 5.10107 5.5999 5.00107 5.2999V4.8999C5.00107 4.0999 5.90107 3.9999 5.90107 3.9999H9.00107C9.00107 3.9999 10.0011 4.0999 10.0011 4.9999C10.0011 4.9999 10.1011 5.9999 9.10107 5.9999Z" fill="#FFCC00"/>
|
||||
<path d="M10.001 5C10.001 4.1 9.00098 4 9.00098 4H5.90098C5.90098 4 5.00098 4.1 5.00098 4.9V5.3C5.00098 5.6 5.30098 6 5.90098 6L6.30098 8.3L6.50098 9H7.00098V6C6.00098 6 6.00098 5.3 6.00098 5.1V5H9.00098C9.00098 5 9.10098 6 8.10098 6V9H8.70098L9.20098 6C10.101 6 10.001 5 10.001 5Z" fill="#F0EFF1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 12C8 9.77386 9.77386 8 12 8C14.2261 8 16 9.77386 16 12C16 14.2261 14.2261 16 12 16C9.77386 16 8 14.2261 8 12Z" fill="#F6F6F6"/>
|
||||
<path d="M12.3192 12.3031L13.3495 13.3334L13.3334 13.3495L12.3031 12.3192L12 12.0162L11.697 12.3192L10.6667 13.3495L10.6506 13.3334L11.6809 12.3031L11.9839 12L11.6809 11.697L10.6506 10.6667L10.6667 10.6506L11.697 11.6809L12 11.9839L12.3031 11.6809L13.3334 10.6506L13.3495 10.6667L12.3192 11.697L12.0162 12L12.3192 12.3031ZM12 8.46034C10.03 8.46034 8.46034 10.03 8.46034 12C8.46034 13.9701 10.03 15.5397 12 15.5397C13.9701 15.5397 15.5397 13.9701 15.5397 12C15.5397 10.03 13.9701 8.46034 12 8.46034Z" fill="#007ACC" stroke="#F6F6F6" stroke-width="0.857143"/>
|
||||
<path d="M12.6225 12.0002L13.9558 13.3336L13.3336 13.9558L12.0002 12.6225L10.6669 13.9558L10.0447 13.3336L11.378 12.0002L10.0447 10.6669L10.6669 10.0447L12.0002 11.378L13.3336 10.0447L13.9558 10.6669L12.6225 12.0002Z" fill="#007ACC"/>
|
||||
<path d="M10.704 14L11.2028 12.4712L10 11.6394H11.4732L12 10L12.5361 11.6394H14L12.7972 12.4712L13.3054 14L12 13.024L10.704 14Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -12,7 +12,6 @@ import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
|
||||
import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
|
||||
suite('CodeAction', () => {
|
||||
|
||||
@@ -117,7 +116,7 @@ suite('CodeAction', () => {
|
||||
testData.tsLint.abc
|
||||
];
|
||||
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'manual' }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'manual' }, CancellationToken.None);
|
||||
assert.equal(actions.length, 6);
|
||||
assert.deepEqual(actions, expected);
|
||||
});
|
||||
@@ -136,20 +135,20 @@ suite('CodeAction', () => {
|
||||
disposables.push(CodeActionProviderRegistry.register('fooLang', provider));
|
||||
|
||||
{
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None);
|
||||
assert.equal(actions.length, 2);
|
||||
assert.strictEqual(actions[0].title, 'a');
|
||||
assert.strictEqual(actions[1].title, 'a.b');
|
||||
}
|
||||
|
||||
{
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a.b') } }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a.b') } }, CancellationToken.None);
|
||||
assert.equal(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, 'a.b');
|
||||
}
|
||||
|
||||
{
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a.b.c') } }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a.b.c') } }, CancellationToken.None);
|
||||
assert.equal(actions.length, 0);
|
||||
}
|
||||
});
|
||||
@@ -165,7 +164,7 @@ suite('CodeAction', () => {
|
||||
|
||||
disposables.push(CodeActionProviderRegistry.register('fooLang', provider));
|
||||
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None);
|
||||
assert.equal(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, 'a');
|
||||
});
|
||||
@@ -183,13 +182,13 @@ suite('CodeAction', () => {
|
||||
disposables.push(CodeActionProviderRegistry.register('fooLang', provider));
|
||||
|
||||
{
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto' }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto' }, CancellationToken.None);
|
||||
assert.equal(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, 'b');
|
||||
}
|
||||
|
||||
{
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: CodeActionKind.Source, includeSourceActions: true } }, CancellationToken.None);
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: CodeActionKind.Source, includeSourceActions: true } }, CancellationToken.None);
|
||||
assert.equal(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, 'a');
|
||||
}
|
||||
@@ -208,7 +207,7 @@ suite('CodeAction', () => {
|
||||
|
||||
disposables.push(CodeActionProviderRegistry.register('fooLang', provider));
|
||||
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 2, 1), {
|
||||
const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), {
|
||||
type: 'auto',
|
||||
filter: {
|
||||
kind: CodeActionKind.QuickFix
|
||||
@@ -217,49 +216,5 @@ suite('CodeAction', () => {
|
||||
assert.strictEqual(actions.length, 0);
|
||||
assert.strictEqual(wasInvoked, false);
|
||||
});
|
||||
|
||||
test('getCodeActions requests for source actions should expand source actions range to entire document #53525', async function () {
|
||||
const provider = new class implements CodeActionProvider {
|
||||
provideCodeActions(model: ITextModel, range: Range): CodeAction[] {
|
||||
return [{
|
||||
title: rangeToString(range),
|
||||
kind: CodeActionKind.Source.value,
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
disposables.push(CodeActionProviderRegistry.register('fooLang', provider));
|
||||
|
||||
{
|
||||
const actions = await getCodeActions(model, new Range(1, 1, 1, 1), {
|
||||
type: 'manual',
|
||||
filter: {
|
||||
kind: CodeActionKind.Source,
|
||||
includeSourceActions: true,
|
||||
}
|
||||
}, CancellationToken.None);
|
||||
assert.strictEqual(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, rangeToString(model.getFullModelRange()));
|
||||
}
|
||||
|
||||
{
|
||||
const range = new Range(1, 1, 1, 2);
|
||||
|
||||
// But we should not expand for non-empty selections
|
||||
const actions = await getCodeActions(model, range, {
|
||||
type: 'manual',
|
||||
filter: {
|
||||
kind: CodeActionKind.Source,
|
||||
includeSourceActions: true,
|
||||
}
|
||||
}, CancellationToken.None);
|
||||
assert.strictEqual(actions.length, 1);
|
||||
assert.strictEqual(actions[0].title, rangeToString(range));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function rangeToString(range: Range): string {
|
||||
return `${range.startLineNumber},${range.startColumn} ${range.endLineNumber},${range.endColumn} `;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ suite('CodeAction', () => {
|
||||
assert.equal(e.trigger.type, 'auto');
|
||||
assert.ok(e.actions);
|
||||
|
||||
e.actions!.then(fixes => {
|
||||
e.actions.then(fixes => {
|
||||
oracle.dispose();
|
||||
assert.equal(fixes.length, 1);
|
||||
assert.equal(fixes.actions.length, 1);
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
@@ -88,9 +88,9 @@ suite('CodeAction', () => {
|
||||
const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => {
|
||||
assert.equal(e.trigger.type, 'auto');
|
||||
assert.ok(e.actions);
|
||||
e.actions!.then(fixes => {
|
||||
e.actions.then(fixes => {
|
||||
oracle.dispose();
|
||||
assert.equal(fixes.length, 1);
|
||||
assert.equal(fixes.actions.length, 1);
|
||||
resolve(undefined);
|
||||
}, reject);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user