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

6
import { CodeAction, CodeActionTriggerType } from 'vs/editor/common/modes';
7
import { Position } from 'vs/editor/common/core/position';
M
Matt Bierner 已提交
8 9 10 11

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

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

	constructor(
		public readonly value: string
	) { }

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

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

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

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

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

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

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

60 61 62 63 64 65
	if (filter.excludes) {
		if (filter.excludes.some(exclude => excludesAction(providedKind, exclude, filter.include))) {
			return false;
		}
	}

66
	// Don't return source actions unless they are explicitly requested
67
	if (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) {
68 69 70 71 72 73 74 75 76 77
		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
78 79 80 81 82 83 84
	if (filter.include) {
		if (!actionKind || !filter.include.contains(actionKind)) {
			return false;
		}
	}

	if (filter.excludes) {
85
		if (actionKind && filter.excludes.some(exclude => excludesAction(actionKind, exclude, filter.include))) {
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
			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;
}

106 107 108 109 110 111 112 113 114 115 116
function excludesAction(providedKind: CodeActionKind, exclude: CodeActionKind, include: CodeActionKind | undefined): boolean {
	if (!exclude.contains(providedKind)) {
		return false;
	}
	if (include && exclude.contains(include)) {
		// The include is more specific, don't filter out
		return false;
	}
	return true;
}

M
Matt Bierner 已提交
117
export interface CodeActionTrigger {
118
	readonly type: CodeActionTriggerType;
M
Matt Bierner 已提交
119 120
	readonly filter?: CodeActionFilter;
	readonly autoApply?: CodeActionAutoApply;
121 122 123 124
	readonly context?: {
		readonly notAvailableMessage: string;
		readonly position: Position;
	};
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 152 153 154 155 156 157 158 159 160 161 162 163 164

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,
	) { }
}