提交 7d5ae744 编写于 作者: M Martin Aeschlimann

Merge branch 'master' of https://github.com/Microsoft/vscode

......@@ -45,7 +45,7 @@ BEGIN THIRD PARTY
* Start of word/path bonus: 7
* Start of string bonus: 8
*/
export function _doScore(target: string, query: string): Score {
export function _doScore(target: string, query: string, inverse?: boolean): Score {
if (!target || !query) {
return NO_SCORE; // return early if target or query are undefined
}
......@@ -62,11 +62,25 @@ export function _doScore(target: string, query: string): Score {
const matchingPositions: number[] = [];
let index = 0;
let startAt = 0;
let index: number;
let startAt: number;
if (!inverse) {
index = 0;
startAt = 0;
} else {
index = queryLen - 1; // inverse: from end of query to beginning
startAt = target.length - 1; // inverse: from end of target to beginning
}
let score = 0;
while (index < queryLen) {
let indexOf = targetLower.indexOf(queryLower[index], startAt);
while (inverse ? index >= 0 : index < queryLen) {
let indexOf: number;
if (!inverse) {
indexOf = targetLower.indexOf(queryLower[index], startAt);
} else {
indexOf = targetLower.lastIndexOf(queryLower[index], startAt); // inverse: look from the end
}
if (indexOf < 0) {
// console.log(`Character not part of target ${query[index]}`);
......@@ -120,8 +134,18 @@ export function _doScore(target: string, query: string): Score {
// console.groupEnd();
startAt = indexOf + 1;
index++;
if (!inverse) {
startAt = indexOf + 1;
index++;
} else {
startAt = indexOf - 1; // inverse: go to begining from end
index--; // inverse: also for query index
}
}
// inverse: flip the matching positions so that they appear in order
if (inverse) {
matchingPositions.reverse();
}
const res: Score = (score > 0) ? [score, matchingPositions] : NO_SCORE;
......@@ -248,7 +272,18 @@ function doScoreItem<T>(label: string, description: string, path: string, query:
const descriptionPrefixLength = descriptionPrefix.length;
const descriptionAndLabel = `${descriptionPrefix}${label}`;
const [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query);
let [labelDescriptionScore, labelDescriptionPositions] = _doScore(descriptionAndLabel, query);
// Optimize for file paths: score from the back to the beginning to catch more specific folder
// names that match on the end of the file. This yields better results in most cases.
if (!!path) {
const [labelDescriptionScoreInverse, labelDescriptionPositionsInverse] = _doScore(descriptionAndLabel, query, true /* inverse */);
if (labelDescriptionScoreInverse && labelDescriptionScoreInverse > labelDescriptionScore) {
labelDescriptionScore = labelDescriptionScoreInverse;
labelDescriptionPositions = labelDescriptionPositionsInverse;
}
}
if (labelDescriptionScore) {
const labelDescriptionMatches = createMatches(labelDescriptionPositions);
const labelMatch: IMatch[] = [];
......
......@@ -79,7 +79,7 @@ suite('Scorer', () => {
assert.equal(positions[1], 6);
});
test('scoreFile - matches are proper', function () {
test('scoreItem - matches are proper', function () {
let res = scorer.scoreItem(null, 'something', ResourceAccessor, cache);
assert.ok(!res.score);
......@@ -151,7 +151,25 @@ suite('Scorer', () => {
assert.ok(pathRes.score > noRes.score);
});
test('compareFilesByScore - identity', function () {
test('scoreItem - optimize for file paths', function () {
const resource = URI.file('/xyz/others/spath/some/xsp/file123.txt');
// xsp is more relevant to the end of the file path even though it matches
// fuzzy also in the beginning. we verify the more relevant match at the
// end gets returned.
const pathRes = scorer.scoreItem(resource, 'xspfile123', ResourceAccessor, cache);
assert.ok(pathRes.score);
assert.ok(pathRes.descriptionMatch);
assert.ok(pathRes.labelMatch);
assert.equal(pathRes.labelMatch.length, 1);
assert.equal(pathRes.labelMatch[0].start, 0);
assert.equal(pathRes.labelMatch[0].end, 7);
assert.equal(pathRes.descriptionMatch.length, 1);
assert.equal(pathRes.descriptionMatch[0].start, 23);
assert.equal(pathRes.descriptionMatch[0].end, 26);
});
test('compareItemsByScore - identity', function () {
const resourceA = URI.file('/some/path/fileA.txt');
const resourceB = URI.file('/some/path/other/fileB.txt');
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
......
......@@ -17,7 +17,7 @@ import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/serv
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as minimist from 'minimist';
import * as path from 'path';
import { QuickOpenHandler, IQuickOpenRegistry, Extensions } from 'vs/workbench/browser/quickopen';
import { IQuickOpenRegistry, Extensions } from 'vs/workbench/browser/quickopen';
import { Registry } from 'vs/platform/registry/common/platform';
import { SearchService } from 'vs/workbench/services/search/node/searchService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
......@@ -58,7 +58,7 @@ suite('QuickOpen performance (integration)', () => {
test('Measure', () => {
if (process.env['VSCODE_PID']) {
return; // TODO@Christoph find out why test fails when run from within VS Code
return void 0; // TODO@Christoph find out why test fails when run from within VS Code
}
const n = 3;
......@@ -88,27 +88,25 @@ suite('QuickOpen performance (integration)', () => {
assert.ok(descriptor);
function measure() {
return instantiationService.createInstance(descriptor)
.then((handler: QuickOpenHandler) => {
handler.onOpen();
return handler.getResults('a').then(result => {
const uncachedEvent = popEvent();
assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache');
assert.strictEqual(uncachedEvent.data.files.fromCache, true, 'files.fromCache');
if (testWorkspaceArg) {
assert.ok(!!uncachedEvent.data.files.joined, 'files.joined');
}
return uncachedEvent;
}).then(uncachedEvent => {
return handler.getResults('ab').then(result => {
const cachedEvent = popEvent();
assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache');
assert.ok(cachedEvent.data.files.fromCache, 'filesFromCache');
handler.onClose(false);
return [uncachedEvent, cachedEvent];
});
});
const handler = descriptor.instantiate(instantiationService);
handler.onOpen();
return handler.getResults('a').then(result => {
const uncachedEvent = popEvent();
assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache');
assert.strictEqual(uncachedEvent.data.files.fromCache, true, 'files.fromCache');
if (testWorkspaceArg) {
assert.ok(!!uncachedEvent.data.files.joined, 'files.joined');
}
return uncachedEvent;
}).then(uncachedEvent => {
return handler.getResults('ab').then(result => {
const cachedEvent = popEvent();
assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache');
assert.ok(cachedEvent.data.files.fromCache, 'filesFromCache');
handler.onClose(false);
return [uncachedEvent, cachedEvent];
});
});
}
function popEvent() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册