From 2bc4681760511f113c663305e8d1a3d85a46d300 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Aug 2016 10:45:22 +0200 Subject: [PATCH] debt - move scoring into completion model, honor the text range of each completion item --- .../contrib/suggest/browser/suggestWidget.ts | 34 ++----------- .../contrib/suggest/common/completionModel.ts | 51 ++++++++++++++++--- 2 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 852926035f8..160c19db7ae 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -166,23 +166,6 @@ class Delegate implements IDelegate { } } -function computeScore(suggestion: string, currentWord: string, currentWordLowerCase: string): number { - const suggestionLowerCase = suggestion.toLowerCase(); - let score = 0; - - for (let i = 0; i < currentWord.length && i < suggestion.length; i++) { - if (currentWord[i] === suggestion[i]) { - score += 2; - } else if (currentWordLowerCase[i] === suggestionLowerCase[i]) { - score += 1; - } else { - break; - } - } - - return score; -} - enum State { Hidden, Loading, @@ -592,21 +575,10 @@ export class SuggestWidget implements IContentWidget, IDisposable { this.completionModel = null; } else { - const currentWord = e.currentWord; - const currentWordLowerCase = currentWord.toLowerCase(); + // TODO@joao,joh move this to a better place let snippetCount = 0; let textCount = 0; - let bestSuggestionIndex = -1; - let bestScore = -1; - this.completionModel.items.forEach((item, index) => { - const score = computeScore(item.suggestion.label, currentWord, currentWordLowerCase); - - if (score > bestScore) { - bestScore = score; - bestSuggestionIndex = index; - } - switch (item.suggestion.type) { case 'snippet': snippetCount++; break; case 'text': textCount++; break; @@ -614,8 +586,8 @@ export class SuggestWidget implements IContentWidget, IDisposable { }); this.list.splice(0, this.list.length, ...this.completionModel.items); - this.list.setFocus(bestSuggestionIndex); - this.list.reveal(bestSuggestionIndex, 0); + this.list.setFocus(this.completionModel.topScoreIdx); + this.list.reveal(this.completionModel.topScoreIdx, 0); this.setState(State.Open); diff --git a/src/vs/editor/contrib/suggest/common/completionModel.ts b/src/vs/editor/contrib/suggest/common/completionModel.ts index 0d766e3f6b1..aeaf67650b2 100644 --- a/src/vs/editor/contrib/suggest/common/completionModel.ts +++ b/src/vs/editor/contrib/suggest/common/completionModel.ts @@ -38,7 +38,9 @@ export class CompletionModel { private _lineContext: LineContext; private _items: CompletionItem[] = []; + private _filteredItems: CompletionItem[] = undefined; + private _topScoreIdx: number; constructor(raw: ISuggestionItem[], leadingLineContent: string) { this.raw = raw; @@ -61,21 +63,31 @@ export class CompletionModel { get items(): CompletionItem[] { if (!this._filteredItems) { - this._filter(); + this._filterAndScore(); } return this._filteredItems; } + get topScoreIdx(): number { + if (!this._filteredItems) { + this._filterAndScore(); + } + return this._topScoreIdx; + } - private _filter(): void { + private _filterAndScore(): void { this._filteredItems = []; + this._topScoreIdx = -1; + let topScore = -1; const {leadingLineContent, characterCountDelta} = this._lineContext; - for (let item of this._items) { + + //TODO@joh - sort by 'overwriteBefore' such that we can 'reuse' the word (wordLowerCase) + for (const item of this._items) { const start = leadingLineContent.length - (item.suggestion.overwriteBefore + characterCountDelta); const word = leadingLineContent.substr(start); - const {filter, suggestion} = item; + let match = false; // compute highlights based on 'label' @@ -87,9 +99,36 @@ export class CompletionModel { match = !isFalsyOrEmpty(filter(word, suggestion.filterText)); } - if (match) { - this._filteredItems.push(item); + if (!match) { + continue; + } + + this._filteredItems.push(item); + + // compute score against word + const wordLowerCase = word.toLowerCase(); + const score = CompletionModel._score(suggestion.label, word, wordLowerCase); + if (score > topScore) { + topScore = score; + this._topScoreIdx = this._filteredItems.length - 1; } } } + + private static _score(suggestion: string, currentWord: string, currentWordLowerCase: string): number { + const suggestionLowerCase = suggestion.toLowerCase(); + let score = 0; + + for (let i = 0, len = Math.min(currentWord.length, suggestion.length); i < len; i++) { + if (currentWord[i] === suggestion[i]) { + score += 2; + } else if (currentWordLowerCase[i] === suggestionLowerCase[i]) { + score += 1; + } else { + break; + } + } + + return score; + } }