提交 19bc6c27 编写于 作者: R Rob Lourens

Implement ./ and absolute path searching per #27226

上级 457fa64f
......@@ -115,7 +115,6 @@ export class PatternInputWidget extends Widget {
let searchPaths: string[];
if (isGlobPattern) {
const segments = splitGlobAware(pattern, ',')
.map(s => strings.ltrim(s.trim(), './'))
.filter(s => !!s.length);
const groups = this.groupByPathsAndExprSegments(segments);
......@@ -123,7 +122,6 @@ export class PatternInputWidget extends Widget {
exprSegments = groups.exprSegments;
} else {
const segments = pattern.split(',')
.map(s => strings.ltrim(s.trim(), './'))
.filter(s => !!s.length);
const groups = this.groupByPathsAndExprSegments(segments);
......@@ -144,15 +142,14 @@ export class PatternInputWidget extends Widget {
private groupByPathsAndExprSegments(segments: string[]) {
const isSearchPath = (segment: string) => {
// An segment is a search path if it is an absolute path and doesn't contain any glob characters
return paths.isAbsolute(segment) && !segment.match(/[\*\{\}\(\)\[\]\?]/);
// A segment is a search path if it is an absolute path or starts with ./
return paths.isAbsolute(segment) || strings.startsWith(segment, './');
};
const groups = collections.groupBy(segments,
segment => isSearchPath(segment) ? 'searchPaths' : 'exprSegments');
groups.searchPaths = groups.searchPaths || [];
groups.exprSegments = (groups.exprSegments || [])
.map(segment => strings.trim(segment, '/'));
groups.exprSegments = groups.exprSegments || [];
return groups;
}
......
......@@ -17,6 +17,7 @@ import env = require('vs/base/common/platform');
import { Delayer } from 'vs/base/common/async';
import URI from 'vs/base/common/uri';
import strings = require('vs/base/common/strings');
import * as paths from 'vs/base/common/paths';
import dom = require('vs/base/browser/dom');
import { IAction, Action } from 'vs/base/common/actions';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
......@@ -897,13 +898,24 @@ export class SearchViewlet extends Viewlet {
const workspace = this.contextService.getWorkspace();
if (workspace) {
if (workspace.roots.length === 1) {
// Fallback to old way for single root workspace
folderPath = this.contextService.toWorkspaceRelativePath(resource);
// Show relative path from the root for single-root mode
folderPath = paths.relative(workspace.roots[0].fsPath, resource.fsPath);
if (folderPath && folderPath !== '.') {
folderPath = './' + folderPath;
}
} else {
folderPath = resource.fsPath;
const owningRoot = this.contextService.getRoot(resource);
if (owningRoot) {
const owningRootBasename = paths.basename(owningRoot.fsPath);
// If this root is the only one with its basename, use a relative ./ path. If there is another, use an absolute path
const isUniqueRoot = workspace.roots.filter(root => paths.basename(root.fsPath) === owningRootBasename).length === 1;
if (isUniqueRoot) {
folderPath = `./${owningRootBasename}/${paths.relative(owningRoot.fsPath, resource.fsPath)}`;
} else {
folderPath = resource.fsPath;
}
}
}
}
......@@ -977,7 +989,14 @@ export class SearchViewlet extends Viewlet {
};
const folderResources = this.contextService.hasWorkspace() ? this.contextService.getWorkspace().roots : [];
this.onQueryTriggered(this.queryBuilder.text(content, folderResources, options), excludePatternText, includePatternText);
let query: ISearchQuery;
// try {
query = this.queryBuilder.text(content, folderResources, options);
// } catch (e) {
// // TODO@roblou show error popup
// }
this.onQueryTriggered(query, excludePatternText, includePatternText);
if (!preserveFocus) {
this.searchWidget.focus(false); // focus back to input field
......
......@@ -4,15 +4,20 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import { IExpression } from 'vs/base/common/glob';
import { mixin } from 'vs/base/common/objects';
import * as objects from 'vs/base/common/objects';
import * as paths from 'vs/base/common/paths';
import uri from 'vs/base/common/uri';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IPatternInfo, IQueryOptions, IFolderQueryOptions, ISearchQuery, QueryType, ISearchConfiguration, getExcludes } from 'vs/platform/search/common/search';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class QueryBuilder {
constructor( @IConfigurationService private configurationService: IConfigurationService) {
constructor(
@IConfigurationService private configurationService: IConfigurationService,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService) {
}
public text(contentPattern: IPatternInfo, folderResources?: uri[], options?: IQueryOptions): ISearchQuery {
......@@ -38,6 +43,8 @@ export class QueryBuilder {
return folderConfig.search.useRipgrep;
});
const searchPaths = this.getSearchPaths(options).searchPaths;
return {
type,
folderQueries,
......@@ -52,7 +59,7 @@ export class QueryBuilder {
useRipgrep,
disregardIgnoreFiles: options.disregardIgnoreFiles,
disregardExcludeSettings: options.disregardExcludeSettings,
searchPaths: options.searchPaths
searchPaths
};
}
......@@ -62,9 +69,64 @@ export class QueryBuilder {
if (options.disregardExcludeSettings) {
return null;
} else if (options.excludePattern) {
return mixin(options.excludePattern, settingsExcludePattern, false /* no overwrite */);
return objects.mixin(options.excludePattern, settingsExcludePattern, false /* no overwrite */);
} else {
return settingsExcludePattern;
}
}
private getSearchPaths(options: IQueryOptions): { searchPaths: string[], additionalIncludePatterns: string[] } {
if (!this.workspaceContextService.hasWorkspace() || !options.searchPaths) {
// No workspace => ignore search paths
return {
searchPaths: [],
additionalIncludePatterns: []
};
}
const workspace = this.workspaceContextService.getWorkspace();
if (workspace.roots.length < 2) {
// 1 open folder => just resolve the search paths to absolute paths
const searchPaths = options.searchPaths.map(searchPath => {
const relativeSearchPathMatch = searchPath.match(/\.\/(.+)/);
if (relativeSearchPathMatch) {
return paths.join(workspace.roots[0].fsPath, relativeSearchPathMatch[1]);
} else {
return null;
}
});
return {
searchPaths,
additionalIncludePatterns: []
};
}
// Is a multiroot workspace
const searchPaths: string[] = [];
const additionalIncludePatterns: string[] = [];
// Resolve searchPaths, relative or absolute, against roots
for (const searchPath of options.searchPaths) {
if (paths.isAbsolute(searchPath)) {
searchPaths.push(searchPath); // later, pull out globs
} else {
const relativeSearchPathMatch = searchPath.match(/\.\/(.+)\/(.+)/);
if (relativeSearchPathMatch) {
const searchPathRoot = relativeSearchPathMatch[1];
const matchingRoots = workspace.roots.filter(root => paths.basename(root.fsPath) === searchPathRoot);
if (!matchingRoots.length) {
throw new Error(nls.localize('search.invalidRootFolder', 'No root folder named {}', searchPathRoot));
}
searchPaths.push(...matchingRoots.map(root => paths.join(root.fsPath, relativeSearchPathMatch[2])));
} else {
// Malformed ./ search path
throw new Error(nls.localize('search.invalidRelativeInclude', 'Invalid folder include pattern: {}', searchPath));
}
}
}
return { searchPaths, additionalIncludePatterns };
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册