From 497605c406bbc658b0f6c94775fa10021e39a8a4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Jun 2018 14:05:42 +0200 Subject: [PATCH] select suggestions based on select property, #35551 --- src/vs/editor/common/modes.ts | 1 + .../editor/contrib/suggest/suggestMemory.ts | 41 ++++++++++++------ .../suggest/test/suggestMemory.test.ts | 42 ++++++++++++++++++- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 2aa69522f6bdc..76d49745eff73 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -293,6 +293,7 @@ export interface ISuggestion { documentation?: string | IMarkdownString; filterText?: string; sortText?: string; + autoSelect?: boolean; noAutoAccept?: boolean; commitCharacters?: string[]; overwriteBefore?: number; diff --git a/src/vs/editor/contrib/suggest/suggestMemory.ts b/src/vs/editor/contrib/suggest/suggestMemory.ts index 29c6afc906dab..62eccf9ab0408 100644 --- a/src/vs/editor/contrib/suggest/suggestMemory.ts +++ b/src/vs/editor/contrib/suggest/suggestMemory.ts @@ -13,9 +13,26 @@ import { RunOnceScheduler } from 'vs/base/common/async'; export abstract class Memory { - abstract memorize(model: ITextModel, pos: IPosition, item: ICompletionItem): void; + select(model: ITextModel, pos: IPosition, items: ICompletionItem[]): number { + if (items.length === 0) { + return 0; + } + let topScore = items[0].score; + for (let i = 1; i < items.length; i++) { + const { score, suggestion } = items[i]; + if (score !== topScore) { + // stop when leaving the group of top matches + break; + } + if (suggestion.autoSelect) { + // stop when seeing an auto-select-item + return i; + } + } + return 0; + } - abstract select(model: ITextModel, pos: IPosition, items: ICompletionItem[]): number; + abstract memorize(model: ITextModel, pos: IPosition, item: ICompletionItem): void; abstract toJSON(): object; @@ -28,10 +45,6 @@ export class NoMemory extends Memory { // no-op } - select(model: ITextModel, pos: IPosition, items: ICompletionItem[]): number { - return 0; - } - toJSON() { return undefined; } @@ -67,15 +80,15 @@ export class LRUMemory extends Memory { // that has been used in the past let { word } = model.getWordUntilPosition(pos); if (word.length !== 0) { - return 0; + return super.select(model, pos, items); } let lineSuffix = model.getLineContent(pos.lineNumber).substr(pos.column - 10, pos.column - 1); if (/\s$/.test(lineSuffix)) { - return 0; + return super.select(model, pos, items); } - let res = 0; + let res = -1; let seq = -1; for (let i = 0; i < items.length; i++) { const { suggestion } = items[i]; @@ -86,7 +99,11 @@ export class LRUMemory extends Memory { res = i; } } - return res; + if (res === -1) { + return super.select(model, pos, items); + } else { + return res; + } } toJSON(): object { @@ -127,7 +144,7 @@ export class PrefixMemory extends Memory { select(model: ITextModel, pos: IPosition, items: ICompletionItem[]): number { let { word } = model.getWordUntilPosition(pos); if (!word) { - return 0; + return super.select(model, pos, items); } let key = `${model.getLanguageIdentifier().language}/${word}`; let item = this._trie.get(key); @@ -142,7 +159,7 @@ export class PrefixMemory extends Memory { } } } - return 0; + return super.select(model, pos, items); } toJSON(): object { diff --git a/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts b/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts index 4025fcd221efe..1ab9368e28683 100644 --- a/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts +++ b/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import { LRUMemory, NoMemory, PrefixMemory } from 'vs/editor/contrib/suggest/suggestMemory'; +import { LRUMemory, NoMemory, PrefixMemory, Memory } from 'vs/editor/contrib/suggest/suggestMemory'; import { ITextModel } from 'vs/editor/common/model'; import { TextModel } from 'vs/editor/common/model/textModel'; import { ICompletionItem } from 'vs/editor/contrib/suggest/completionModel'; @@ -28,6 +28,46 @@ suite('SuggestMemories', function () { ]; }); + test('AbstractMemory, select', function () { + + const mem = new class extends Memory { + memorize(model: ITextModel, pos: IPosition, item: ICompletionItem): void { + throw new Error('Method not implemented.'); + } toJSON(): object { + throw new Error('Method not implemented.'); + } + fromJSON(data: object): void { + throw new Error('Method not implemented.'); + } + }; + + let item1 = createSuggestItem('fazz', 0); + let item2 = createSuggestItem('bazz', 0); + let item3 = createSuggestItem('bazz', 0); + let item4 = createSuggestItem('bazz', 0); + item1.suggestion.autoSelect = false; + item2.suggestion.autoSelect = true; + item3.suggestion.autoSelect = true; + + assert.equal(mem.select(buffer, pos, [item1, item2, item3, item4]), 1); + }); + + test('[No|Prefix|LRU]Memory honor selection boost', function () { + let item1 = createSuggestItem('fazz', 0); + let item2 = createSuggestItem('bazz', 0); + let item3 = createSuggestItem('bazz', 0); + let item4 = createSuggestItem('bazz', 0); + item1.suggestion.autoSelect = false; + item2.suggestion.autoSelect = true; + item3.suggestion.autoSelect = true; + let items = [item1, item2, item3, item4]; + + + assert.equal(new NoMemory().select(buffer, pos, items), 1); + assert.equal(new LRUMemory().select(buffer, pos, items), 1); + assert.equal(new PrefixMemory().select(buffer, pos, items), 1); + }); + test('NoMemory', function () { const mem = new NoMemory();