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

Implement ./ and absolute path searching per #27226

上级 457fa64f
...@@ -115,7 +115,6 @@ export class PatternInputWidget extends Widget { ...@@ -115,7 +115,6 @@ export class PatternInputWidget extends Widget {
let searchPaths: string[]; let searchPaths: string[];
if (isGlobPattern) { if (isGlobPattern) {
const segments = splitGlobAware(pattern, ',') const segments = splitGlobAware(pattern, ',')
.map(s => strings.ltrim(s.trim(), './'))
.filter(s => !!s.length); .filter(s => !!s.length);
const groups = this.groupByPathsAndExprSegments(segments); const groups = this.groupByPathsAndExprSegments(segments);
...@@ -123,7 +122,6 @@ export class PatternInputWidget extends Widget { ...@@ -123,7 +122,6 @@ export class PatternInputWidget extends Widget {
exprSegments = groups.exprSegments; exprSegments = groups.exprSegments;
} else { } else {
const segments = pattern.split(',') const segments = pattern.split(',')
.map(s => strings.ltrim(s.trim(), './'))
.filter(s => !!s.length); .filter(s => !!s.length);
const groups = this.groupByPathsAndExprSegments(segments); const groups = this.groupByPathsAndExprSegments(segments);
...@@ -144,15 +142,14 @@ export class PatternInputWidget extends Widget { ...@@ -144,15 +142,14 @@ export class PatternInputWidget extends Widget {
private groupByPathsAndExprSegments(segments: string[]) { private groupByPathsAndExprSegments(segments: string[]) {
const isSearchPath = (segment: string) => { const isSearchPath = (segment: string) => {
// An segment is a search path if it is an absolute path and doesn't contain any glob characters // A segment is a search path if it is an absolute path or starts with ./
return paths.isAbsolute(segment) && !segment.match(/[\*\{\}\(\)\[\]\?]/); return paths.isAbsolute(segment) || strings.startsWith(segment, './');
}; };
const groups = collections.groupBy(segments, const groups = collections.groupBy(segments,
segment => isSearchPath(segment) ? 'searchPaths' : 'exprSegments'); segment => isSearchPath(segment) ? 'searchPaths' : 'exprSegments');
groups.searchPaths = groups.searchPaths || []; groups.searchPaths = groups.searchPaths || [];
groups.exprSegments = (groups.exprSegments || []) groups.exprSegments = groups.exprSegments || [];
.map(segment => strings.trim(segment, '/'));
return groups; return groups;
} }
......
...@@ -17,6 +17,7 @@ import env = require('vs/base/common/platform'); ...@@ -17,6 +17,7 @@ import env = require('vs/base/common/platform');
import { Delayer } from 'vs/base/common/async'; import { Delayer } from 'vs/base/common/async';
import URI from 'vs/base/common/uri'; import URI from 'vs/base/common/uri';
import strings = require('vs/base/common/strings'); import strings = require('vs/base/common/strings');
import * as paths from 'vs/base/common/paths';
import dom = require('vs/base/browser/dom'); import dom = require('vs/base/browser/dom');
import { IAction, Action } from 'vs/base/common/actions'; import { IAction, Action } from 'vs/base/common/actions';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
...@@ -897,13 +898,24 @@ export class SearchViewlet extends Viewlet { ...@@ -897,13 +898,24 @@ export class SearchViewlet extends Viewlet {
const workspace = this.contextService.getWorkspace(); const workspace = this.contextService.getWorkspace();
if (workspace) { if (workspace) {
if (workspace.roots.length === 1) { if (workspace.roots.length === 1) {
// Fallback to old way for single root workspace // Show relative path from the root for single-root mode
folderPath = this.contextService.toWorkspaceRelativePath(resource); folderPath = paths.relative(workspace.roots[0].fsPath, resource.fsPath);
if (folderPath && folderPath !== '.') { if (folderPath && folderPath !== '.') {
folderPath = './' + folderPath; folderPath = './' + folderPath;
} }
} else { } 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 { ...@@ -977,7 +989,14 @@ export class SearchViewlet extends Viewlet {
}; };
const folderResources = this.contextService.hasWorkspace() ? this.contextService.getWorkspace().roots : []; 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) { if (!preserveFocus) {
this.searchWidget.focus(false); // focus back to input field this.searchWidget.focus(false); // focus back to input field
......
...@@ -4,15 +4,20 @@ ...@@ -4,15 +4,20 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import nls = require('vs/nls');
import { IExpression } from 'vs/base/common/glob'; 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 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 { IPatternInfo, IQueryOptions, IFolderQueryOptions, ISearchQuery, QueryType, ISearchConfiguration, getExcludes } from 'vs/platform/search/common/search';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class QueryBuilder { 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 { public text(contentPattern: IPatternInfo, folderResources?: uri[], options?: IQueryOptions): ISearchQuery {
...@@ -38,6 +43,8 @@ export class QueryBuilder { ...@@ -38,6 +43,8 @@ export class QueryBuilder {
return folderConfig.search.useRipgrep; return folderConfig.search.useRipgrep;
}); });
const searchPaths = this.getSearchPaths(options).searchPaths;
return { return {
type, type,
folderQueries, folderQueries,
...@@ -52,7 +59,7 @@ export class QueryBuilder { ...@@ -52,7 +59,7 @@ export class QueryBuilder {
useRipgrep, useRipgrep,
disregardIgnoreFiles: options.disregardIgnoreFiles, disregardIgnoreFiles: options.disregardIgnoreFiles,
disregardExcludeSettings: options.disregardExcludeSettings, disregardExcludeSettings: options.disregardExcludeSettings,
searchPaths: options.searchPaths searchPaths
}; };
} }
...@@ -62,9 +69,64 @@ export class QueryBuilder { ...@@ -62,9 +69,64 @@ export class QueryBuilder {
if (options.disregardExcludeSettings) { if (options.disregardExcludeSettings) {
return null; return null;
} else if (options.excludePattern) { } else if (options.excludePattern) {
return mixin(options.excludePattern, settingsExcludePattern, false /* no overwrite */); return objects.mixin(options.excludePattern, settingsExcludePattern, false /* no overwrite */);
} else { } else {
return settingsExcludePattern; 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.
先完成此消息的编辑!
想要评论请 注册