This commit is contained in:
Johannes Rieken
2017-04-27 11:47:40 +02:00
parent bcf5eb2883
commit a6058fbd9d
3 changed files with 97 additions and 14 deletions
@@ -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);
}
}
@@ -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);
@@ -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
});
});