types.ts 4.8 KB
Newer Older
M
Matt Bierner 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { startsWith } from 'vs/base/common/strings';
7
import { CodeAction } from 'vs/editor/common/modes';
8
import { Position } from 'vs/editor/common/core/position';
M
Matt Bierner 已提交
9 10 11 12

export class CodeActionKind {
	private static readonly sep = '.';

13
	public static readonly None = new CodeActionKind('@@none@@'); // Special code action that contains nothing
M
Matt Bierner 已提交
14
	public static readonly Empty = new CodeActionKind('');
S
Sandeep Somavarapu 已提交
15
	public static readonly QuickFix = new CodeActionKind('quickfix');
M
Matt Bierner 已提交
16
	public static readonly Refactor = new CodeActionKind('refactor');
M
Matt Bierner 已提交
17
	public static readonly Source = new CodeActionKind('source');
18 19
	public static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports');
	public static readonly SourceFixAll = CodeActionKind.Source.append('fixAll');
M
Matt Bierner 已提交
20 21 22 23 24

	constructor(
		public readonly value: string
	) { }

25 26 27 28
	public equals(other: CodeActionKind): boolean {
		return this.value === other.value;
	}

29
	public contains(other: CodeActionKind): boolean {
30
		return this.equals(other) || this.value === '' || startsWith(other.value, this.value + CodeActionKind.sep);
31 32 33 34
	}

	public intersects(other: CodeActionKind): boolean {
		return this.contains(other) || other.contains(this);
M
Matt Bierner 已提交
35
	}
36 37 38 39

	public append(part: string): CodeActionKind {
		return new CodeActionKind(this.value + CodeActionKind.sep + part);
	}
M
Matt Bierner 已提交
40 41
}

42
export const enum CodeActionAutoApply {
43 44 45
	IfSingle = 'ifSingle',
	First = 'first',
	Never = 'never',
M
Matt Bierner 已提交
46 47
}

M
Matt Bierner 已提交
48
export interface CodeActionFilter {
49 50
	readonly include?: CodeActionKind;
	readonly excludes?: readonly CodeActionKind[];
M
Matt Bierner 已提交
51
	readonly includeSourceActions?: boolean;
52
	readonly onlyIncludePreferredActions?: boolean;
M
Matt Bierner 已提交
53 54
}

55 56
export function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: CodeActionKind): boolean {
	// A provided kind may be a subset or superset of our filtered kind.
57
	if (filter.include && !filter.include.intersects(providedKind)) {
58 59 60 61
		return false;
	}

	// Don't return source actions unless they are explicitly requested
62
	if (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) {
63 64 65 66 67 68 69 70 71 72
		return false;
	}

	return true;
}

export function filtersAction(filter: CodeActionFilter, action: CodeAction): boolean {
	const actionKind = action.kind ? new CodeActionKind(action.kind) : undefined;

	// Filter out actions by kind
73 74 75 76 77 78 79 80 81 82 83
	if (filter.include) {
		if (!actionKind || !filter.include.contains(actionKind)) {
			return false;
		}
	}

	if (filter.excludes) {
		if (actionKind && filter.excludes.some(exclude => {
			// Excludes are overwritten by includes
			return exclude.contains(actionKind) && (!filter.include || !filter.include.contains(actionKind));
		})) {
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
			return false;
		}
	}

	// Don't return source actions unless they are explicitly requested
	if (!filter.includeSourceActions) {
		if (actionKind && CodeActionKind.Source.contains(actionKind)) {
			return false;
		}
	}

	if (filter.onlyIncludePreferredActions) {
		if (!action.isPreferred) {
			return false;
		}
	}

	return true;
}

M
Matt Bierner 已提交
104
export interface CodeActionTrigger {
M
Matt Bierner 已提交
105 106 107
	readonly type: 'auto' | 'manual';
	readonly filter?: CodeActionFilter;
	readonly autoApply?: CodeActionAutoApply;
108 109 110 111
	readonly context?: {
		readonly notAvailableMessage: string;
		readonly position: Position;
	};
112
}
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

export class CodeActionCommandArgs {
	public static fromUser(arg: any, defaults: { kind: CodeActionKind, apply: CodeActionAutoApply }): CodeActionCommandArgs {
		if (!arg || typeof arg !== 'object') {
			return new CodeActionCommandArgs(defaults.kind, defaults.apply, false);
		}
		return new CodeActionCommandArgs(
			CodeActionCommandArgs.getKindFromUser(arg, defaults.kind),
			CodeActionCommandArgs.getApplyFromUser(arg, defaults.apply),
			CodeActionCommandArgs.getPreferredUser(arg));
	}

	private static getApplyFromUser(arg: any, defaultAutoApply: CodeActionAutoApply) {
		switch (typeof arg.apply === 'string' ? arg.apply.toLowerCase() : '') {
			case 'first': return CodeActionAutoApply.First;
			case 'never': return CodeActionAutoApply.Never;
			case 'ifsingle': return CodeActionAutoApply.IfSingle;
			default: return defaultAutoApply;
		}
	}

	private static getKindFromUser(arg: any, defaultKind: CodeActionKind) {
		return typeof arg.kind === 'string'
			? new CodeActionKind(arg.kind)
			: defaultKind;
	}

	private static getPreferredUser(arg: any): boolean {
		return typeof arg.preferred === 'boolean'
			? arg.preferred
			: false;
	}

	private constructor(
		public readonly kind: CodeActionKind,
		public readonly apply: CodeActionAutoApply,
		public readonly preferred: boolean,
	) { }
}