提交 2924e2b1 编写于 作者: B Benjamin Pasero

Enable to search on the full path when parts of the query contain path separators

上级 0a7c9f72
......@@ -8,6 +8,7 @@ import {Registry} from 'vs/platform/platform';
import filters = require('vs/base/common/filters');
import strings = require('vs/base/common/strings');
import types = require('vs/base/common/types');
import paths = require('vs/base/common/paths');
import URI from 'vs/base/common/uri';
import {EventType} from 'vs/base/common/events';
import comparers = require('vs/base/common/comparers');
......@@ -31,7 +32,8 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry {
editorService: IWorkbenchEditorService,
private contextService: IWorkspaceContextService,
input: EditorInput,
highlights: IHighlight[],
labelHighlights: IHighlight[],
descriptionHighlights: IHighlight[],
model: EditorHistoryModel
) {
super(editorService);
......@@ -49,11 +51,11 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry {
}
}
this.setHighlights(highlights);
this.setHighlights(labelHighlights, descriptionHighlights);
}
public clone(highlights: IHighlight[]): EditorHistoryEntry {
return new EditorHistoryEntry(this.editorService, this.contextService, this.input, highlights, this.model);
public clone(labelHighlights: IHighlight[], descriptionHighlights?: IHighlight[]): EditorHistoryEntry {
return new EditorHistoryEntry(this.editorService, this.contextService, this.input, labelHighlights, descriptionHighlights, this.model);
}
public getLabel(): string {
......@@ -130,7 +132,7 @@ export class EditorHistoryModel extends QuickOpenModel {
// Remove any existing entry and add to the beginning
this.remove(entry);
this.entries.unshift(new EditorHistoryEntry(this.editorService, this.contextService, entry, null, this));
this.entries.unshift(new EditorHistoryEntry(this.editorService, this.contextService, entry, null, null, this));
// Respect max entries setting
if (this.entries.length > MAX_ENTRIES) {
......@@ -207,14 +209,35 @@ export class EditorHistoryModel extends QuickOpenModel {
let results: QuickOpenEntry[] = [];
for (let i = 0; i < this.entries.length; i++) {
let entry = this.entries[i];
let entry = <EditorHistoryEntry>this.entries[i];
if (!entry.getResource()) {
continue; //For now, only support to match on inputs that provide resource information
}
let highlights = filters.matchesFuzzy(searchValue, (<EditorHistoryEntry>entry).getInput().getName());
if (highlights) {
results.push((<EditorHistoryEntry>entry).clone(highlights));
let label = entry.getInput().getName();
let description = entry.getInput().getDescription();
let labelHighlights: IHighlight[] = [];
let descriptionHighlights: IHighlight[] = [];
// Search inside filename
if (searchValue.indexOf(paths.nativeSep) < 0) {
labelHighlights = filters.matchesFuzzy(searchValue, label);
}
// Search in full path
else {
descriptionHighlights = filters.matchesFuzzy(strings.trim(searchValue, paths.nativeSep), description);
// If we have no highlights, assume that the match is split among name and parent folder
if (!descriptionHighlights || !descriptionHighlights.length) {
labelHighlights = filters.matchesFuzzy(paths.basename(searchValue), label);
descriptionHighlights = filters.matchesFuzzy(strings.trim(paths.dirname(searchValue), paths.nativeSep), description);
}
}
if ((labelHighlights && labelHighlights.length) || (descriptionHighlights && descriptionHighlights.length)) {
results.push(entry.clone(labelHighlights, descriptionHighlights));
}
}
......@@ -222,7 +245,20 @@ export class EditorHistoryModel extends QuickOpenModel {
if (searchValue) {
let normalizedSearchValue = strings.stripWildcards(searchValue.toLowerCase());
return results.sort((elementA:EditorHistoryEntry, elementB:EditorHistoryEntry) => {
return results.sort((elementA: EditorHistoryEntry, elementB: EditorHistoryEntry) => {
// Give matches with label highlights higher priority over
// those with only description highlights
const labelHighlightsA = elementA.getHighlights()[0] || [];
const labelHighlightsB = elementB.getHighlights()[0] || [];
if (labelHighlightsA.length && !labelHighlightsB.length) {
return -1;
} else if (!labelHighlightsA.length && labelHighlightsB.length) {
return 1;
}
// Sort by name/path
let nameA = elementA.getInput().getName();
let nameB = elementB.getInput().getName();
......
......@@ -10,6 +10,7 @@ import nls = require('vs/nls');
import {ThrottledDelayer} from 'vs/base/common/async';
import types = require('vs/base/common/types');
import strings = require('vs/base/common/strings');
import paths = require('vs/base/common/paths');
import filters = require('vs/base/common/filters');
import {IRange} from 'vs/editor/common/editorCommon';
import {compareAnything} from 'vs/base/common/comparers';
......@@ -210,6 +211,9 @@ export class OpenAnythingHandler extends QuickOpenHandler {
}
public getResultsFromCache(searchValue: string, range: IRange = null): QuickOpenEntry[] {
if (searchValue.indexOf(paths.nativeSep) >= 0) {
return null; // TODO@Ben implement caching for path search
}
// Find cache entries by prefix of search value
let cachedEntries: QuickOpenEntry[];
......@@ -257,6 +261,19 @@ export class OpenAnythingHandler extends QuickOpenHandler {
}
private compareResults(elementA:QuickOpenEntry, elementB:QuickOpenEntry, searchValue: string): number {
// Give matches with label highlights higher priority over
// those with only description highlights
const labelHighlightsA = elementA.getHighlights()[0] || [];
const labelHighlightsB = elementB.getHighlights()[0] || [];
if (labelHighlightsA.length && !labelHighlightsB.length) {
return -1;
} else if (!labelHighlightsA.length && labelHighlightsB.length) {
return 1;
}
// Sort by name/path
let nameA = elementA.getLabel();
let nameB = elementB.getLabel();
......
......@@ -34,7 +34,12 @@ export class FileEntry extends EditorQuickOpenEntry {
private resource: URI;
private range: IRange;
constructor(name: string, resource: URI, highlights: IHighlight[],
constructor(
name: string,
description: string,
resource: URI,
labelHighlights: IHighlight[],
descriptionHighlights: IHighlight[],
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkspaceContextService contextService: IWorkspaceContextService
......@@ -43,8 +48,8 @@ export class FileEntry extends EditorQuickOpenEntry {
this.resource = resource;
this.name = name;
this.description = labels.getPathLabel(paths.dirname(this.resource.fsPath), contextService);
this.setHighlights(highlights);
this.description = description;
this.setHighlights(labelHighlights, descriptionHighlights);
}
public getLabel(): string {
......@@ -149,9 +154,28 @@ export class OpenFileHandler extends QuickOpenHandler {
let results: QuickOpenEntry[] = [];
for (let i = 0; i < matches.length; i++) {
let fileMatch = matches[i];
let highlights = filters.matchesFuzzy(searchValue, fileMatch.name());
let description = labels.getPathLabel(paths.dirname(fileMatch.resource().fsPath), this.contextService);
let labelHighlights: IHighlight[] = [];
let descriptionHighlights: IHighlight[] = [];
// Search inside filename
if (searchValue.indexOf(paths.nativeSep) < 0) {
labelHighlights = filters.matchesFuzzy(searchValue, fileMatch.name());
}
// Search in full path
else {
descriptionHighlights = filters.matchesFuzzy(strings.trim(searchValue, paths.nativeSep), description);
// If we have no highlights, assume that the match is split among name and parent folder
if (!descriptionHighlights || !descriptionHighlights.length) {
labelHighlights = filters.matchesFuzzy(paths.basename(searchValue), fileMatch.name());
descriptionHighlights = filters.matchesFuzzy(strings.trim(paths.dirname(searchValue), paths.nativeSep), description);
}
}
results.push(this.instantiationService.createInstance(FileEntry, fileMatch.name(), fileMatch.resource(), highlights));
results.push(this.instantiationService.createInstance(FileEntry, fileMatch.name(), description, fileMatch.resource(), labelHighlights, descriptionHighlights));
}
return results;
......
......@@ -31,6 +31,7 @@ export class FileWalker {
private isLimitHit: boolean;
private resultCount: number;
private isCanceled: boolean;
private searchInPath: boolean;
private walkedPaths: { [path: string]: boolean; };
......@@ -41,6 +42,7 @@ export class FileWalker {
this.includePattern = config.includePattern;
this.maxResults = config.maxResults || null;
this.walkedPaths = Object.create(null);
this.searchInPath = this.filePattern && this.filePattern.indexOf(paths.sep) >= 0;
}
private resetState(): void {
......@@ -81,7 +83,7 @@ export class FileWalker {
}
// Check for match on file pattern and include pattern
if (this.isFilePatternMatch(paths.basename(absolutePath)) && (!this.includePattern || glob.match(this.includePattern, absolutePath))) {
if (this.isFilePatternMatch(paths.basename(absolutePath), absolutePath) && (!this.includePattern || glob.match(this.includePattern, absolutePath))) {
this.resultCount++;
if (this.maxResults && this.resultCount > this.maxResults) {
......@@ -156,7 +158,7 @@ export class FileWalker {
if ((<any>error).code === FileWalker.ENOTDIR && !this.isCanceled && !this.isLimitHit) {
// Check for match on file pattern and include pattern
if (this.isFilePatternMatch(file) && (!this.includePattern || glob.match(this.includePattern, relativeFilePath, children))) {
if (this.isFilePatternMatch(file, relativeFilePath) && (!this.includePattern || glob.match(this.includePattern, relativeFilePath, children))) {
this.resultCount++;
if (this.maxResults && this.resultCount > this.maxResults) {
......@@ -183,11 +185,11 @@ export class FileWalker {
});
}
private isFilePatternMatch(path: string): boolean {
private isFilePatternMatch(name: string, path: string): boolean {
// Check for search pattern
if (this.filePattern) {
const res = filters.matchesFuzzy(this.filePattern, path);
const res = filters.matchesFuzzy(this.filePattern, this.searchInPath ? path : name);
return !!res && res.length > 0;
}
......
......@@ -47,6 +47,24 @@ suite('Search', () => {
});
});
test('Files: examples/com*', function(done: () => void) {
let engine = new FileSearchEngine({
rootPaths: [require.toUrl('./fixtures')],
filePattern: 'examples' + path.sep + 'com*'
});
let count = 0;
engine.search((result) => {
if (result) {
count++;
}
}, () => { }, (error) => {
assert.ok(!error);
assert.equal(count, 1);
done();
});
});
test('Files: *.js (Files as roots)', function(done: () => void) {
let engine = new FileSearchEngine({
rootPaths: [require.toUrl('./fixtures/examples/company.js'), require.toUrl('./fixtures/examples/small.js')],
......
......@@ -43,7 +43,7 @@ suite('Workbench QuickOpen', () => {
let model = new EditorHistoryModel(editorService, null, contextService);
let input1 = inst.createInstance(StringEditorInput, "name1", 'description', "value1", "text/plain", false);
let entry1 = new EditorHistoryEntry(editorService, contextService, input1, null, model);
let entry1 = new EditorHistoryEntry(editorService, contextService, input1, null, null, model);
assert.equal(input1.getName(), entry1.getLabel());
assert.equal(input1.getDescription(), entry1.getDescription());
......@@ -63,7 +63,7 @@ suite('Workbench QuickOpen', () => {
let input2 = inst.createInstance(StringEditorInput, "name2", 'description', "value2", "text/plain", false);
(<any>input2).getResource = () => "path";
let entry2 = new EditorHistoryEntry(editorService, contextService, input2, null, model);
let entry2 = new EditorHistoryEntry(editorService, contextService, input2, null, null, model);
assert.equal(entry2.getResource(), "path");
assert(!entry1.matches(entry2.getInput()));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册