search.ts 6.4 KB
Newer Older
E
Erich Gamma 已提交
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.
 *--------------------------------------------------------------------------------------------*/
'use strict';

J
Johannes Rieken 已提交
7
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
E
Erich Gamma 已提交
8
import uri from 'vs/base/common/uri';
9
import * as objects from 'vs/base/common/objects';
10 11
import * as paths from 'vs/base/common/paths';
import * as glob from 'vs/base/common/glob';
J
Johannes Rieken 已提交
12 13
import { IFilesConfiguration } from 'vs/platform/files/common/files';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
14
import { IDisposable } from 'vs/base/common/lifecycle';
E
Erich Gamma 已提交
15

B
Benjamin Pasero 已提交
16
export const ID = 'searchService';
E
Erich Gamma 已提交
17

B
Benjamin Pasero 已提交
18
export const ISearchService = createDecorator<ISearchService>(ID);
B
Benjamin Pasero 已提交
19

E
Erich Gamma 已提交
20 21 22 23
/**
 * A service that enables to search for files or with in files.
 */
export interface ISearchService {
24
	_serviceBrand: any;
E
Erich Gamma 已提交
25
	search(query: ISearchQuery): PPromise<ISearchComplete, ISearchProgressItem>;
26
	extendQuery(query: ISearchQuery): void;
27
	clearCache(cacheKey: string): TPromise<void>;
28 29 30 31 32
	registerSearchResultProvider(provider: ISearchResultProvider): IDisposable;
}

export interface ISearchResultProvider {
	search(query: ISearchQuery): PPromise<ISearchComplete, ISearchProgressItem>;
E
Erich Gamma 已提交
33 34
}

35
export interface IFolderQuery {
R
Rob Lourens 已提交
36
	folder: uri;
37 38
	excludePattern?: glob.IExpression;
	includePattern?: glob.IExpression;
R
Rob Lourens 已提交
39
	fileEncoding?: string;
40
	disregardIgnoreFiles?: boolean;
R
Rob Lourens 已提交
41 42
}

R
Rob Lourens 已提交
43
export interface ICommonQueryOptions {
44
	extraFileResources?: uri[];
R
Rob Lourens 已提交
45
	filePattern?: string; // file search only
R
Rob Lourens 已提交
46
	fileEncoding?: string;
E
Erich Gamma 已提交
47
	maxResults?: number;
48 49 50 51 52 53
	/**
	 * If true no results will be returned. Instead `limitHit` will indicate if at least one result exists or not.
	 *
	 * Currently does not work with queries including a 'siblings clause'.
	 */
	exists?: boolean;
54 55
	sortByScore?: boolean;
	cacheKey?: string;
56
	useRipgrep?: boolean;
R
Rob Lourens 已提交
57 58
	disregardIgnoreFiles?: boolean;
	disregardExcludeSettings?: boolean;
59
	ignoreSymlinks?: boolean;
E
Erich Gamma 已提交
60 61
}

R
Rob Lourens 已提交
62 63 64 65 66 67
export interface IQueryOptions extends ICommonQueryOptions {
	excludePattern?: string;
	includePattern?: string;
}

export interface ISearchQuery extends ICommonQueryOptions {
E
Erich Gamma 已提交
68
	type: QueryType;
R
Rob Lourens 已提交
69

70 71
	excludePattern?: glob.IExpression;
	includePattern?: glob.IExpression;
E
Erich Gamma 已提交
72
	contentPattern?: IPatternInfo;
73
	folderQueries?: IFolderQuery[];
74
	usingSearchPaths?: boolean;
E
Erich Gamma 已提交
75 76 77 78 79 80
}

export enum QueryType {
	File = 1,
	Text = 2
}
K
kieferrm 已提交
81
/* __GDPR__FRAGMENT__
K
kieferrm 已提交
82 83 84 85 86 87 88 89 90
	"IPatternInfo" : {
		"pattern" : { "classification": "CustomerContent", "purpose": "FeatureInsight" },
		"isRegExp": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
		"isWordMatch": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
		"wordSeparators": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
		"isMultiline": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
		"isCaseSensitive": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
	}
*/
E
Erich Gamma 已提交
91 92 93 94
export interface IPatternInfo {
	pattern: string;
	isRegExp?: boolean;
	isWordMatch?: boolean;
95
	wordSeparators?: string;
S
Sandeep Somavarapu 已提交
96
	isMultiline?: boolean;
E
Erich Gamma 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	isCaseSensitive?: boolean;
}

export interface IFileMatch {
	resource?: uri;
	lineMatches?: ILineMatch[];
}

export interface ILineMatch {
	preview: string;
	lineNumber: number;
	offsetAndLengths: number[][];
}

export interface IProgress {
	total?: number;
	worked?: number;
}

116 117 118 119 120
export interface ISearchLog {
	message?: string;
}

export interface ISearchProgressItem extends IFileMatch, IProgress, ISearchLog {
E
Erich Gamma 已提交
121 122 123 124 125 126
	// Marker interface to indicate the possible values for progress calls from the engine
}

export interface ISearchComplete {
	limitHit?: boolean;
	results: IFileMatch[];
C
chrmarti 已提交
127 128 129 130
	stats: ISearchStats;
}

export interface ISearchStats {
131 132 133 134 135 136 137 138
	fromCache: boolean;
	resultCount: number;
	unsortedResultTime?: number;
	sortedResultTime?: number;
}

export interface ICachedSearchStats extends ISearchStats {
	cacheLookupStartTime: number;
139
	cacheFilterStartTime: number;
140 141
	cacheLookupResultTime: number;
	cacheEntryCount: number;
142
	joined?: ISearchStats;
143 144 145
}

export interface IUncachedSearchStats extends ISearchStats {
C
Christof Marti 已提交
146 147
	traversal: string;
	errors: string[];
C
chrmarti 已提交
148 149 150 151
	fileWalkStartTime: number;
	fileWalkResultTime: number;
	directoriesWalked: number;
	filesWalked: number;
C
Christof Marti 已提交
152 153 154
	cmdForkStartTime?: number;
	cmdForkResultTime?: number;
	cmdResultCount?: number;
E
Erich Gamma 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
}


// ---- very simple implementation of the search model --------------------

export class FileMatch implements IFileMatch {
	public lineMatches: LineMatch[] = [];
	constructor(public resource: uri) {
		// empty
	}
}

export class LineMatch implements ILineMatch {
	constructor(public preview: string, public lineNumber: number, public offsetAndLengths: number[][]) {
		// empty
	}
}

export interface ISearchConfiguration extends IFilesConfiguration {
	search: {
175
		exclude: glob.IExpression;
176
		useRipgrep: boolean;
177 178 179 180
		/**
		 * Use ignore file for file search.
		 */
		useIgnoreFiles: boolean;
181
		followSymlinks: boolean;
B
Benjamin Pasero 已提交
182
	};
183 184 185
	editor: {
		wordSeparators: string;
	};
B
Benjamin Pasero 已提交
186 187
}

188
export function getExcludes(configuration: ISearchConfiguration): glob.IExpression {
B
Benjamin Pasero 已提交
189 190 191 192
	const fileExcludes = configuration && configuration.files && configuration.files.exclude;
	const searchExcludes = configuration && configuration.search && configuration.search.exclude;

	if (!fileExcludes && !searchExcludes) {
R
Rob Lourens 已提交
193
		return undefined;
B
Benjamin Pasero 已提交
194 195 196 197 198 199
	}

	if (!fileExcludes || !searchExcludes) {
		return fileExcludes || searchExcludes;
	}

200
	let allExcludes: glob.IExpression = Object.create(null);
S
Sandeep Somavarapu 已提交
201 202 203
	// clone the config as it could be frozen
	allExcludes = objects.mixin(allExcludes, objects.clone(fileExcludes));
	allExcludes = objects.mixin(allExcludes, objects.clone(searchExcludes), true);
B
Benjamin Pasero 已提交
204 205

	return allExcludes;
206
}
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

export function pathIncludedInQuery(query: ISearchQuery, fsPath: string): boolean {
	if (query.excludePattern && glob.match(query.excludePattern, fsPath)) {
		return false;
	}

	if (query.includePattern && !glob.match(query.includePattern, fsPath)) {
		return false;
	}

	// If searchPaths are being used, the extra file must be in a subfolder and match the pattern, if present
	if (query.usingSearchPaths) {
		return query.folderQueries.every(fq => {
			const searchPath = fq.folder.fsPath;
			if (paths.isEqualOrParent(fsPath, searchPath)) {
				return !fq.includePattern || !!glob.match(fq.includePattern, fsPath);
			} else {
				return false;
			}
		});
	}

	return true;
}