提交 e027a8aa 编写于 作者: B Benjamin Pasero

push down compare by score

上级 b82b39af
......@@ -4,21 +4,22 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import WinJS = require('vs/base/common/winjs.base');
import Types = require('vs/base/common/types');
import {TPromise} from 'vs/base/common/winjs.base';
import types = require('vs/base/common/types');
import URI from 'vs/base/common/uri';
import Tree = require('vs/base/parts/tree/common/tree');
import Filters = require('vs/base/common/filters');
import Strings = require('vs/base/common/strings');
import Paths = require('vs/base/common/paths');
import {ITree, IElementCallback} from 'vs/base/parts/tree/common/tree';
import filters = require('vs/base/common/filters');
import strings = require('vs/base/common/strings');
import paths = require('vs/base/common/paths');
import {IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IRenderer, IRunner, Mode} from 'vs/base/parts/quickopen/common/quickOpen';
import ActionsRenderer = require('vs/base/parts/tree/browser/actionsRenderer');
import Actions = require('vs/base/common/actions');
import {compareAnything} from 'vs/base/common/comparers';
import ActionBar = require('vs/base/browser/ui/actionbar/actionbar');
import TreeDefaults = require('vs/base/parts/tree/browser/treeDefaults');
import HighlightedLabel = require('vs/base/browser/ui/highlightedlabel/highlightedLabel');
import {IActionProvider} from 'vs/base/parts/tree/browser/actionsRenderer';
import {Action, IAction, IActionRunner} from 'vs/base/common/actions';
import {compareAnything, compareByPrefix} from 'vs/base/common/comparers';
import {ActionBar, IActionItem} from 'vs/base/browser/ui/actionbar/actionbar';
import {LegacyRenderer, ILegacyTemplateData} from 'vs/base/parts/tree/browser/treeDefaults';
import {HighlightedLabel} from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import DOM = require('vs/base/browser/dom');
import scorer = require('vs/base/common/scorer');
export interface IContext {
event: any;
......@@ -149,7 +150,7 @@ export class QuickOpenEntry {
// Normalize
if (lookFor) {
lookFor = Strings.stripWildcards(lookFor).toLowerCase();
lookFor = strings.stripWildcards(lookFor).toLowerCase();
}
// Give matches with label highlights higher priority over
......@@ -178,6 +179,56 @@ export class QuickOpenEntry {
return compareAnything(nameA, nameB, lookFor);
}
public static compareByScore(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string, scorerCache: { [key: string]: number }): number {
const labelA = elementA.getLabel();
const labelB = elementB.getLabel();
// treat prefix matches highest in any case
const prefixCompare = compareByPrefix(labelA, labelB, lookFor);
if (prefixCompare) {
return prefixCompare;
}
// Give higher importance to label score
const labelAScore = scorer.score(labelA, lookFor, scorerCache);
const labelBScore = scorer.score(labelB, lookFor, scorerCache);
// Useful for understanding the scoring
// elementA.setPrefix(labelAScore + ' ');
// elementB.setPrefix(labelBScore + ' ');
if (labelAScore !== labelBScore) {
return labelAScore > labelBScore ? -1 : 1;
}
// Score on full resource path comes next (if available)
let resourceA = elementA.getResource();
let resourceB = elementB.getResource();
if (resourceA && resourceB) {
const resourceAScore = scorer.score(resourceA.fsPath, lookFor, scorerCache);
const resourceBScore = scorer.score(resourceB.fsPath, lookFor, scorerCache);
// Useful for understanding the scoring
// elementA.setPrefix(elementA.getPrefix() + ' ' + resourceAScore + ': ');
// elementB.setPrefix(elementB.getPrefix() + ' ' + resourceBScore + ': ');
if (resourceAScore !== resourceBScore) {
return resourceAScore > resourceBScore ? -1 : 1;
}
}
// At this place, the scores are identical so we check for string lengths and favor shorter ones
if (labelA.length !== labelB.length) {
return labelA.length < labelB.length ? -1 : 1;
}
if (resourceA && resourceB && resourceA.fsPath.length !== resourceB.fsPath.length) {
return resourceA.fsPath.length < resourceB.fsPath.length ? -1 : 1;
}
return QuickOpenEntry.compare(elementA, elementB, lookFor);
}
/**
* A good default highlight implementation for an entry with label and description.
*/
......@@ -198,15 +249,15 @@ export class QuickOpenEntry {
}
// Fuzzy/Full-Path: Highlight is special
else if (fuzzyHighlight || lookFor.indexOf(Paths.nativeSep) >= 0) {
let candidateLabelHighlights = Filters.matchesFuzzy(lookFor, label, fuzzyHighlight);
else if (fuzzyHighlight || lookFor.indexOf(paths.nativeSep) >= 0) {
let candidateLabelHighlights = filters.matchesFuzzy(lookFor, label, fuzzyHighlight);
if (!candidateLabelHighlights) {
const pathPrefix = description ? (description + Paths.nativeSep) : '';
const pathPrefix = description ? (description + paths.nativeSep) : '';
const pathPrefixLength = pathPrefix.length;
// If there are no highlights in the label, build a path out of description and highlight and match on both,
// then extract the individual label and description highlights back to the original positions
let pathHighlights = Filters.matchesFuzzy(lookFor, pathPrefix + label, fuzzyHighlight);
let pathHighlights = filters.matchesFuzzy(lookFor, pathPrefix + label, fuzzyHighlight);
if (pathHighlights) {
pathHighlights.forEach(h => {
......@@ -234,13 +285,13 @@ export class QuickOpenEntry {
// Highlight only inside label
else {
labelHighlights = Filters.matchesFuzzy(lookFor, label);
labelHighlights = filters.matchesFuzzy(lookFor, label);
}
}
// Highlight by label otherwise
else {
labelHighlights = Filters.matchesFuzzy(lookFor, label);
labelHighlights = filters.matchesFuzzy(lookFor, label);
}
return { labelHighlights, descriptionHighlights };
......@@ -259,7 +310,7 @@ export class QuickOpenEntryItem extends QuickOpenEntry {
/**
* Allows to present the quick open entry in a custom way inside the tree.
*/
public render(tree: Tree.ITree, container: HTMLElement, previousCleanupFn: Tree.IElementCallback): Tree.IElementCallback {
public render(tree: ITree, container: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback {
return null;
}
}
......@@ -352,13 +403,13 @@ const templateEntry = 'quickOpenEntry';
const templateEntryGroup = 'quickOpenEntryGroup';
const templateEntryItem = 'quickOpenEntryItem';
class EntryItemRenderer extends TreeDefaults.LegacyRenderer {
class EntryItemRenderer extends LegacyRenderer {
public getTemplateId(tree: Tree.ITree, element: any): string {
public getTemplateId(tree: ITree, element: any): string {
return templateEntryItem;
}
protected render(tree: Tree.ITree, element: any, container: HTMLElement, previousCleanupFn?: Tree.IElementCallback): Tree.IElementCallback {
protected render(tree: ITree, element: any, container: HTMLElement, previousCleanupFn?: IElementCallback): IElementCallback {
if (element instanceof QuickOpenEntryItem) {
return (<QuickOpenEntryItem>element).render(tree, container, previousCleanupFn);
}
......@@ -367,25 +418,25 @@ class EntryItemRenderer extends TreeDefaults.LegacyRenderer {
}
}
class NoActionProvider implements ActionsRenderer.IActionProvider {
class NoActionProvider implements IActionProvider {
public hasActions(tree: Tree.ITree, element: any): boolean {
public hasActions(tree: ITree, element: any): boolean {
return false;
}
public getActions(tree: Tree.ITree, element: any): WinJS.TPromise<Actions.IAction[]> {
return WinJS.Promise.as(null);
public getActions(tree: ITree, element: any): TPromise<IAction[]> {
return TPromise.as(null);
}
public hasSecondaryActions(tree: Tree.ITree, element: any): boolean {
public hasSecondaryActions(tree: ITree, element: any): boolean {
return false;
}
public getSecondaryActions(tree: Tree.ITree, element: any): WinJS.TPromise<Actions.IAction[]> {
return WinJS.Promise.as(null);
public getSecondaryActions(tree: ITree, element: any): TPromise<IAction[]> {
return TPromise.as(null);
}
public getActionItem(tree: Tree.ITree, element: any, action: Actions.Action): ActionBar.IActionItem {
public getActionItem(tree: ITree, element: any, action: Action): IActionItem {
return null;
}
}
......@@ -394,10 +445,10 @@ export interface IQuickOpenEntryTemplateData {
container: HTMLElement;
icon: HTMLSpanElement;
prefix: HTMLSpanElement;
label: HighlightedLabel.HighlightedLabel;
label: HighlightedLabel;
meta: HTMLSpanElement;
description: HighlightedLabel.HighlightedLabel;
actionBar: ActionBar.ActionBar;
description: HighlightedLabel;
actionBar: ActionBar;
}
export interface IQuickOpenEntryGroupTemplateData extends IQuickOpenEntryTemplateData {
......@@ -406,11 +457,11 @@ export interface IQuickOpenEntryGroupTemplateData extends IQuickOpenEntryTemplat
class Renderer implements IRenderer<QuickOpenEntry> {
private actionProvider: ActionsRenderer.IActionProvider;
private actionRunner: Actions.IActionRunner;
private actionProvider: IActionProvider;
private actionRunner: IActionRunner;
private entryItemRenderer: EntryItemRenderer;
constructor(actionProvider: ActionsRenderer.IActionProvider = new NoActionProvider(), actionRunner: Actions.IActionRunner = null) {
constructor(actionProvider: IActionProvider = new NoActionProvider(), actionRunner: IActionRunner = null) {
this.actionProvider = actionProvider;
this.actionRunner = actionRunner;
this.entryItemRenderer = new EntryItemRenderer();
......@@ -462,7 +513,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
DOM.addClass(actionBarContainer, 'primary-action-bar');
container.appendChild(actionBarContainer);
let actionBar = new ActionBar.ActionBar(actionBarContainer, {
let actionBar = new ActionBar(actionBarContainer, {
actionRunner: this.actionRunner
});
......@@ -480,7 +531,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
entry.appendChild(prefix);
// Label
let label = new HighlightedLabel.HighlightedLabel(entry);
let label = new HighlightedLabel(entry);
// Meta
let meta = document.createElement('span');
......@@ -491,7 +542,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
let descriptionContainer = document.createElement('span');
entry.appendChild(descriptionContainer);
DOM.addClass(descriptionContainer, 'quick-open-entry-description');
let description = new HighlightedLabel.HighlightedLabel(descriptionContainer);
let description = new HighlightedLabel(descriptionContainer);
return {
container: container,
......@@ -509,7 +560,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
// Entry Item
if (templateId === templateEntryItem) {
this.entryItemRenderer.renderElement(null, entry, templateId, <TreeDefaults.ILegacyTemplateData>templateData);
this.entryItemRenderer.renderElement(null, entry, templateId, <ILegacyTemplateData>templateData);
return;
}
......@@ -595,7 +646,7 @@ export class QuickOpenModel implements
private _filter: IFilter<QuickOpenEntry>;
private _runner: IRunner<QuickOpenEntry>;
constructor(entries: QuickOpenEntry[] = [], actionProvider: ActionsRenderer.IActionProvider = new NoActionProvider()) {
constructor(entries: QuickOpenEntry[] = [], actionProvider: IActionProvider = new NoActionProvider()) {
this._entries = entries;
this._dataSource = this;
this._renderer = new Renderer(actionProvider);
......@@ -617,7 +668,7 @@ export class QuickOpenModel implements
* Adds entries that should show up in the quick open viewer.
*/
public addEntries(entries: QuickOpenEntry[]): void {
if (Types.isArray(entries)) {
if (types.isArray(entries)) {
this._entries = this._entries.concat(entries);
}
}
......@@ -626,7 +677,7 @@ export class QuickOpenModel implements
* Set the entries that should show up in the quick open viewer.
*/
public setEntries(entries: QuickOpenEntry[]): void {
if (Types.isArray(entries)) {
if (types.isArray(entries)) {
this._entries = entries;
}
}
......
......@@ -158,7 +158,7 @@ export class OpenAnythingHandler extends QuickOpenHandler {
let result = [...results[0].entries, ...results[1].entries];
// Sort
result.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue));
result.sort((elementA, elementB) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, this.scorerCache));
// Apply Range
result.forEach((element) => {
......@@ -280,7 +280,7 @@ export class OpenAnythingHandler extends QuickOpenHandler {
}
// Sort
results.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue));
results.sort((elementA, elementB) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, this.scorerCache));
// Apply Range
results.forEach((element) => {
......@@ -295,56 +295,6 @@ export class OpenAnythingHandler extends QuickOpenHandler {
return viewResults;
}
private sort(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number {
const labelA = elementA.getLabel();
const labelB = elementB.getLabel();
// treat prefix matches highest in any case
const prefixCompare = compareByPrefix(labelA, labelB, lookFor);
if (prefixCompare) {
return prefixCompare;
}
// Give higher importance to label score
const labelAScore = scorer.score(labelA, lookFor, this.scorerCache);
const labelBScore = scorer.score(labelB, lookFor, this.scorerCache);
// Useful for understanding the scoring
// elementA.setPrefix(labelAScore + ' ');
// elementB.setPrefix(labelBScore + ' ');
if (labelAScore !== labelBScore) {
return labelAScore > labelBScore ? -1 : 1;
}
// Score on full resource path comes next (can be null for symbols!)
let resourceA = elementA.getResource();
let resourceB = elementB.getResource();
if (resourceA && resourceB) {
const resourceAScore = scorer.score(resourceA.fsPath, lookFor, this.scorerCache);
const resourceBScore = scorer.score(resourceB.fsPath, lookFor, this.scorerCache);
// Useful for understanding the scoring
// elementA.setPrefix(elementA.getPrefix() + ' ' + resourceAScore + ': ');
// elementB.setPrefix(elementB.getPrefix() + ' ' + resourceBScore + ': ');
if (resourceAScore !== resourceBScore) {
return resourceAScore > resourceBScore ? -1 : 1;
}
}
// At this place, the scores are identical so we check for string lengths and favor shorter ones
if (labelA.length !== labelB.length) {
return labelA.length < labelB.length ? -1 : 1;
}
if (resourceA && resourceB && resourceA.fsPath.length !== resourceB.fsPath.length) {
return resourceA.fsPath.length < resourceB.fsPath.length ? -1 : 1;
}
return QuickOpenEntry.compare(elementA, elementB, lookFor);
}
public getGroupLabel(): string {
return nls.localize('fileAndTypeResults', "file and symbol results");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册