From a6058fbd9de04fefd4cbea2ea15766a5f86f9bbe Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 27 Apr 2017 11:47:40 +0200 Subject: [PATCH] fix #25495 --- .../suggest/browser/completionModel.ts | 43 ++++++++++-- .../contrib/suggest/browser/suggestModel.ts | 2 +- .../test/browser/completionModel.test.ts | 66 +++++++++++++++++-- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/completionModel.ts b/src/vs/editor/contrib/suggest/browser/completionModel.ts index 98ab5727ff2..dd84990104e 100644 --- a/src/vs/editor/contrib/suggest/browser/completionModel.ts +++ b/src/vs/editor/contrib/suggest/browser/completionModel.ts @@ -7,7 +7,7 @@ import { fuzzyScore } from 'vs/base/common/filters'; import { ISuggestSupport } from 'vs/editor/common/modes'; -import { ISuggestionItem } from './suggest'; +import { ISuggestionItem, SnippetConfig } from './suggest'; export interface ICompletionItem extends ISuggestionItem { matches?: number[]; @@ -29,18 +29,25 @@ export class LineContext { export class CompletionModel { - private _lineContext: LineContext; - private _column: number; - private _items: ISuggestionItem[]; + private readonly _column: number; + private readonly _items: ISuggestionItem[]; + private readonly _snippetCompareFn = CompletionModel._compareCompletionItems; + private _lineContext: LineContext; private _filteredItems: ICompletionItem[]; private _isIncomplete: boolean; private _stats: ICompletionStats; - constructor(items: ISuggestionItem[], column: number, lineContext: LineContext) { + constructor(items: ISuggestionItem[], column: number, lineContext: LineContext, snippetConfig?: SnippetConfig) { this._items = items; this._column = column; this._lineContext = lineContext; + + if (snippetConfig === 'top') { + this._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsUp; + } else if (snippetConfig === 'bottom') { + this._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsDown; + } } get lineContext(): LineContext { @@ -143,10 +150,10 @@ export class CompletionModel { } } - this._filteredItems.sort(CompletionModel._compareCompletionItems); + this._filteredItems.sort(this._snippetCompareFn); } - private static _compareCompletionItems(a: ICompletionItem, b: ICompletionItem) { + private static _compareCompletionItems(a: ICompletionItem, b: ICompletionItem): number { if (a.score > b.score) { return -1; } else if (a.score < b.score) { @@ -159,4 +166,26 @@ export class CompletionModel { return 0; } } + + private static _compareCompletionItemsSnippetsDown(a: ICompletionItem, b: ICompletionItem): number { + if (a.suggestion.type !== b.suggestion.type) { + if (a.suggestion.type === 'snippet') { + return 1; + } else if (b.suggestion.type === 'snippet') { + return -1; + } + } + return CompletionModel._compareCompletionItems(a, b); + } + + private static _compareCompletionItemsSnippetsUp(a: ICompletionItem, b: ICompletionItem): number { + if (a.suggestion.type !== b.suggestion.type) { + if (a.suggestion.type === 'snippet') { + return -1; + } else if (b.suggestion.type === 'snippet') { + return 1; + } + } + return CompletionModel._compareCompletionItems(a, b); + } } diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index 96d9642fc1c..1bb4c209b18 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -362,7 +362,7 @@ export class SuggestModel implements IDisposable { this.completionModel = new CompletionModel(items, this.context.column, { leadingLineContent: ctx.leadingLineContent, characterCountDelta: this.context ? ctx.column - this.context.column : 0 - }); + }, this.editor.getConfiguration().contribInfo.snippetSuggestions); this.onNewContext(ctx); }).then(null, onUnexpectedError); diff --git a/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts index dfa3422e627..c5f80a483cb 100644 --- a/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts @@ -5,14 +5,14 @@ 'use strict'; import * as assert from 'assert'; -import { ISuggestion, ISuggestResult, ISuggestSupport } from 'vs/editor/common/modes'; +import { ISuggestion, ISuggestResult, ISuggestSupport, SuggestionType } from 'vs/editor/common/modes'; import { ISuggestionItem } from 'vs/editor/contrib/suggest/browser/suggest'; import { CompletionModel } from 'vs/editor/contrib/suggest/browser/completionModel'; import { IPosition } from 'vs/editor/common/core/position'; suite('CompletionModel', function () { - function createSuggestItem(label: string, overwriteBefore: number, incomplete: boolean = false, position: IPosition = { lineNumber: 1, column: 1 }): ISuggestionItem { + function createSuggestItem(label: string, overwriteBefore: number, type: SuggestionType = 'property', incomplete: boolean = false, position: IPosition = { lineNumber: 1, column: 1 }): ISuggestionItem { return new class implements ISuggestionItem { @@ -22,7 +22,7 @@ suite('CompletionModel', function () { label, overwriteBefore, insertText: label, - type: 'property' + type }; container: ISuggestResult = { @@ -79,7 +79,7 @@ suite('CompletionModel', function () { assert.equal(model.incomplete, false); let incompleteModel = new CompletionModel([ - createSuggestItem('foo', 3, true), + createSuggestItem('foo', 3, undefined, true), createSuggestItem('foo', 2), ], 1, { leadingLineContent: 'foo', @@ -90,8 +90,8 @@ suite('CompletionModel', function () { test('replaceIncomplete', function () { - const completeItem = createSuggestItem('foobar', 1, false, { lineNumber: 1, column: 2 }); - const incompleteItem = createSuggestItem('foofoo', 1, true, { lineNumber: 1, column: 2 }); + const completeItem = createSuggestItem('foobar', 1, undefined, false, { lineNumber: 1, column: 2 }); + const incompleteItem = createSuggestItem('foofoo', 1, undefined, true, { lineNumber: 1, column: 2 }); const model = new CompletionModel([completeItem, incompleteItem], 2, { leadingLineContent: '', characterCountDelta: 0 }); assert.equal(model.incomplete, true); @@ -127,4 +127,58 @@ suite('CompletionModel', function () { assert.equal(d.suggestion.label, 'p'); }); + test('keep snippet sorting with prefix: top, #25495', function () { + + model = new CompletionModel([ + createSuggestItem('Snippet1', 1, 'snippet'), + createSuggestItem('tnippet2', 1, 'snippet'), + createSuggestItem('semver', 1, 'property'), + ], 1, { + leadingLineContent: 's', + characterCountDelta: 0 + }, 'top'); + + assert.equal(model.items.length, 2); + const [a, b] = model.items; + assert.equal(a.suggestion.label, 'Snippet1'); + assert.equal(b.suggestion.label, 'semver'); + assert.ok(a.score < b.score); // snippet really promoted + + }); + + test('keep snippet sorting with prefix: bottom, #25495', function () { + + model = new CompletionModel([ + createSuggestItem('snippet1', 1, 'snippet'), + createSuggestItem('tnippet2', 1, 'snippet'), + createSuggestItem('Semver', 1, 'property'), + ], 1, { + leadingLineContent: 's', + characterCountDelta: 0 + }, 'bottom'); + + assert.equal(model.items.length, 2); + const [a, b] = model.items; + assert.equal(a.suggestion.label, 'Semver'); + assert.equal(b.suggestion.label, 'snippet1'); + assert.ok(a.score < b.score); // snippet really demoted + }); + + test('keep snippet sorting with prefix: inline, #25495', function () { + + model = new CompletionModel([ + createSuggestItem('snippet1', 1, 'snippet'), + createSuggestItem('tnippet2', 1, 'snippet'), + createSuggestItem('Semver', 1, 'property'), + ], 1, { + leadingLineContent: 's', + characterCountDelta: 0 + }, 'inline'); + + assert.equal(model.items.length, 2); + const [a, b] = model.items; + assert.equal(a.suggestion.label, 'snippet1'); + assert.equal(b.suggestion.label, 'Semver'); + assert.ok(a.score > b.score); // snippet really demoted + }); });