diff --git a/src/vs/editor/contrib/suggest/suggestMemory.ts b/src/vs/editor/contrib/suggest/suggestMemory.ts index f8997401fdec0021cbeac7272c4f572a9d8073d4..d08685206be40a783284de537c27cc16241ab381 100644 --- a/src/vs/editor/contrib/suggest/suggestMemory.ts +++ b/src/vs/editor/contrib/suggest/suggestMemory.ts @@ -22,10 +22,10 @@ export abstract class Memory { if (items.length === 0) { return 0; } - let topScore = items[0].score; + let topScore = items[0].score[0]; for (let i = 1; i < items.length; i++) { const { score, completion: suggestion } = items[i]; - if (score !== topScore) { + if (score[0] !== topScore) { // stop when leaving the group of top matches break; } @@ -81,33 +81,42 @@ export class LRUMemory extends Memory { } select(model: ITextModel, pos: IPosition, items: CompletionItem[]): number { - // in order of completions, select the first - // that has been used in the past - let { word } = model.getWordUntilPosition(pos); - if (word.length !== 0) { - return super.select(model, pos, items); + + if (items.length === 0) { + return 0; } - let lineSuffix = model.getLineContent(pos.lineNumber).substr(pos.column - 10, pos.column - 1); + const lineSuffix = model.getLineContent(pos.lineNumber).substr(pos.column - 10, pos.column - 1); if (/\s$/.test(lineSuffix)) { return super.select(model, pos, items); } - let res = -1; + let topScore = items[0].score[0]; + let indexPreselect = -1; + let indexRecency = -1; let seq = -1; for (let i = 0; i < items.length; i++) { - const { completion: suggestion } = items[i]; - const key = `${model.getLanguageIdentifier().language}/${suggestion.label}`; - const item = this._cache.get(key); - if (item && item.touch > seq && item.type === suggestion.kind && item.insertText === suggestion.insertText) { + if (items[i].score[0] !== topScore) { + // consider only top items + break; + } + const key = `${model.getLanguageIdentifier().language}/${items[i].completion.label}`; + const item = this._cache.peek(key); + if (item && item.touch > seq && item.type === items[i].completion.kind && item.insertText === items[i].completion.insertText) { seq = item.touch; - res = i; + indexRecency = i; + } + if (items[i].completion.preselect && indexPreselect === -1) { + // stop when seeing an auto-select-item + return indexPreselect = i; } } - if (res === -1) { - return super.select(model, pos, items); + if (indexRecency !== -1) { + return indexRecency; + } else if (indexPreselect !== -1) { + return indexPreselect; } else { - return res; + return 0; } } diff --git a/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts b/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts index 3dda6f9f6fb5e11a13cc3e4f5326033b2f407743..fd2ee8ec49cf0fee237c6289989758624ae182c8 100644 --- a/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts +++ b/src/vs/editor/contrib/suggest/test/suggestMemory.test.ts @@ -101,6 +101,29 @@ suite('SuggestMemories', function () { ]), 0); }); + test('`"editor.suggestSelection": "recentlyUsed"` should be a little more sticky #78571', function () { + + let item1 = createSuggestItem('gamma', 0); + let item2 = createSuggestItem('game', 0); + items = [item1, item2]; + + let mem = new LRUMemory(); + buffer.setValue(' foo.'); + mem.memorize(buffer, { lineNumber: 1, column: 1 }, item2); + + assert.equal(mem.select(buffer, { lineNumber: 1, column: 2 }, items), 0); // leading whitespace -> ignore recent items + + mem.memorize(buffer, { lineNumber: 1, column: 9 }, item2); + assert.equal(mem.select(buffer, { lineNumber: 1, column: 9 }, items), 1); // foo. + + buffer.setValue(' foo.g'); + assert.equal(mem.select(buffer, { lineNumber: 1, column: 10 }, items), 1); // foo.g, 'gamma' and 'game' have the same score + + item1.score = [10, 0, 0]; + assert.equal(mem.select(buffer, { lineNumber: 1, column: 10 }, items), 0); // foo.g, 'gamma' has higher score + + }); + test('intellisense is not showing top options first #43429', function () { // ensure we don't memorize for whitespace prefixes