提交 53321de6 编写于 作者: J Johannes Rieken

fix #60247

上级 099c23fe
......@@ -13,7 +13,7 @@ import { compare, endsWith, isFalsyOrWhitespace } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { Position } from 'vs/editor/common/core/position';
import { ITextModel } from 'vs/editor/common/model';
import { CompletionItem, CompletionList, CompletionItemProvider, LanguageId, CompletionContext, CompletionItemKind } from 'vs/editor/common/modes';
import { CompletionItem, CompletionList, CompletionItemProvider, LanguageId, CompletionItemKind } from 'vs/editor/common/modes';
import { IModeService } from 'vs/editor/common/services/modeService';
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
import { setSnippetSuggestSupport } from 'vs/editor/contrib/suggest/suggest';
......@@ -365,53 +365,35 @@ export class SnippetSuggestProvider implements CompletionItemProvider {
//
}
provideCompletionItems(model: ITextModel, position: Position, context: CompletionContext): Promise<CompletionList> {
provideCompletionItems(model: ITextModel, pos: Position): Promise<CompletionList> {
const languageId = this._getLanguageIdAtPosition(model, position);
const languageId = this._getLanguageIdAtPosition(model, pos);
return this._snippets.getSnippets(languageId).then(snippets => {
let suggestions: SnippetSuggestion[];
let shift = Math.max(0, position.column - 100);
let pos = { lineNumber: position.lineNumber, column: Math.max(1, position.column - 100) };
let lineOffsets: number[] = [];
let linePrefixLow = model.getLineContent(position.lineNumber).substr(Math.max(0, position.column - 100), position.column - 1).toLowerCase();
while (pos.column < position.column) {
let word = model.getWordAtPosition(pos);
if (word) {
// at a word
lineOffsets.push(word.startColumn - 1);
pos.column = word.endColumn + 1;
if (word.endColumn - 1 < linePrefixLow.length && !/\s/.test(linePrefixLow[word.endColumn - 1])) {
lineOffsets.push(word.endColumn - 1);
}
let suggestions: SnippetSuggestion[] = [];
let atWord = Boolean(model.getWordAtPosition(pos));
let lineLow = model.getLineContent(pos.lineNumber).substring(0, pos.column - 1).toLowerCase();
} else if (!/\s/.test(linePrefixLow[pos.column - 1])) {
// at a none-whitespace character
lineOffsets.push(pos.column - 1);
pos.column += 1;
} else {
// always advance!
pos.column += 1;
}
}
for (const snippet of snippets) {
if (lineOffsets.length === 0) {
// no interesting spans found -> pick all snippets
suggestions = snippets.map(snippet => new SnippetSuggestion(snippet, Range.fromPositions(position)));
} else {
let consumed = new Set<Snippet>();
suggestions = [];
for (let start of lineOffsets) {
start -= shift;
for (const snippet of snippets) {
if (!consumed.has(snippet) && matches(linePrefixLow, start, snippet.prefixLow, 0)) {
suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(position.delta(0, -(linePrefixLow.length - start)), position)));
consumed.add(snippet);
}
let prefixLow = snippet.prefix;
let prefixPos = prefixLow.length - 1;
let linePos = lineLow.length - 1;
let linePosStart = linePos;
while (linePos >= 0 && prefixPos >= 0) {
if (lineLow[linePos] === prefixLow[prefixPos]) {
linePos -= 1;
}
prefixPos -= 1;
}
if (linePos !== linePosStart) {
// some overlap
suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(pos.delta(0, linePos - linePosStart), pos)));
} else if (!atWord) {
// no overlap but not at a word
suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(pos)));
}
}
......@@ -451,16 +433,6 @@ export class SnippetSuggestProvider implements CompletionItemProvider {
}
}
function matches(pattern: string, patternStart: number, word: string, wordStart: number): boolean {
while (patternStart < pattern.length && wordStart < word.length) {
if (pattern[patternStart] === word[wordStart]) {
patternStart += 1;
}
wordStart += 1;
}
return patternStart === pattern.length;
}
export function getNonWhitespacePrefix(model: ISimpleModel, position: Position): string {
/**
* Do not analyze more characters
......
......@@ -11,7 +11,6 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
import { TextModel } from 'vs/editor/common/model/textModel';
import { ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution';
import { Snippet, SnippetSource } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile';
import { CompletionContext, CompletionTriggerKind } from 'vs/editor/common/modes';
class SimpleSnippetService implements ISnippetsService {
_serviceBrand: any;
......@@ -39,7 +38,6 @@ suite('SnippetsService', function () {
let modeService: ModeServiceImpl;
let snippetService: ISnippetsService;
let suggestContext: CompletionContext = { triggerKind: CompletionTriggerKind.Invoke };
setup(function () {
modeService = new ModeServiceImpl();
......@@ -68,7 +66,7 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
const model = TextModel.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 1), suggestContext).then(result => {
return provider.provideCompletionItems(model, new Position(1, 1)).then(result => {
assert.equal(result.incomplete, undefined);
assert.equal(result.suggestions.length, 2);
});
......@@ -79,7 +77,7 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
const model = TextModel.createFromString('bar', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 4), suggestContext).then(result => {
return provider.provideCompletionItems(model, new Position(1, 4)).then(result => {
assert.equal(result.incomplete, undefined);
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].label, 'bar');
......@@ -111,7 +109,7 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
const model = TextModel.createFromString('bar-bar', undefined, modeService.getLanguageIdentifier('fooLang'));
await provider.provideCompletionItems(model, new Position(1, 3), suggestContext).then(result => {
await provider.provideCompletionItems(model, new Position(1, 3)).then(result => {
assert.equal(result.incomplete, undefined);
assert.equal(result.suggestions.length, 2);
assert.equal(result.suggestions[0].label, 'bar');
......@@ -122,7 +120,7 @@ suite('SnippetsService', function () {
assert.equal(result.suggestions[1].range.startColumn, 1);
});
await provider.provideCompletionItems(model, new Position(1, 5), suggestContext).then(result => {
await provider.provideCompletionItems(model, new Position(1, 5)).then(result => {
assert.equal(result.incomplete, undefined);
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].label, 'bar-bar');
......@@ -130,7 +128,7 @@ suite('SnippetsService', function () {
assert.equal(result.suggestions[0].range.startColumn, 1);
});
await provider.provideCompletionItems(model, new Position(1, 6), suggestContext).then(result => {
await provider.provideCompletionItems(model, new Position(1, 6)).then(result => {
assert.equal(result.incomplete, undefined);
assert.equal(result.suggestions.length, 2);
assert.equal(result.suggestions[0].label, 'bar');
......@@ -156,19 +154,19 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
let model = TextModel.createFromString('\t<?php', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 7), suggestContext).then(result => {
return provider.provideCompletionItems(model, new Position(1, 7)).then(result => {
assert.equal(result.suggestions.length, 1);
model.dispose();
model = TextModel.createFromString('\t<?', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 4), suggestContext);
return provider.provideCompletionItems(model, new Position(1, 4));
}).then(result => {
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].range.startColumn, 2);
model.dispose();
model = TextModel.createFromString('a<?', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 4), suggestContext);
return provider.provideCompletionItems(model, new Position(1, 4));
}).then(result => {
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].range.startColumn, 2);
......@@ -191,9 +189,9 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
let model = TextModel.createFromString('<head>\n\t\n>/head>', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 1), suggestContext).then(result => {
return provider.provideCompletionItems(model, new Position(1, 1)).then(result => {
assert.equal(result.suggestions.length, 1);
return provider.provideCompletionItems(model, new Position(2, 2), suggestContext);
return provider.provideCompletionItems(model, new Position(2, 2));
}).then(result => {
assert.equal(result.suggestions.length, 1);
});
......@@ -221,7 +219,7 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
let model = TextModel.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang'));
return provider.provideCompletionItems(model, new Position(1, 1), suggestContext).then(result => {
return provider.provideCompletionItems(model, new Position(1, 1)).then(result => {
assert.equal(result.suggestions.length, 2);
let [first, second] = result.suggestions;
assert.equal(first.label, 'first');
......@@ -243,13 +241,13 @@ suite('SnippetsService', function () {
let model = TextModel.createFromString('p-', undefined, modeService.getLanguageIdentifier('fooLang'));
let result = await provider.provideCompletionItems(model, new Position(1, 2), suggestContext);
let result = await provider.provideCompletionItems(model, new Position(1, 2));
assert.equal(result.suggestions.length, 1);
result = await provider.provideCompletionItems(model, new Position(1, 3), suggestContext);
result = await provider.provideCompletionItems(model, new Position(1, 3));
assert.equal(result.suggestions.length, 1);
result = await provider.provideCompletionItems(model, new Position(1, 3), { triggerCharacter: '-', triggerKind: CompletionTriggerKind.TriggerCharacter });
result = await provider.provideCompletionItems(model, new Position(1, 3));
assert.equal(result.suggestions.length, 1);
});
......@@ -267,7 +265,26 @@ suite('SnippetsService', function () {
const provider = new SnippetSuggestProvider(modeService, snippetService);
let model = TextModel.createFromString('Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea b', undefined, modeService.getLanguageIdentifier('fooLang'));
let result = await provider.provideCompletionItems(model, new Position(1, 158), suggestContext);
let result = await provider.provideCompletionItems(model, new Position(1, 158));
assert.equal(result.suggestions.length, 1);
});
test('No snippets suggestion beyond character 100 if not at end of line #60247', async function () {
snippetService = new SimpleSnippetService([new Snippet(
['fooLang'],
'bug',
'bug',
'',
'second',
'',
SnippetSource.User
)]);
const provider = new SnippetSuggestProvider(modeService, snippetService);
let model = TextModel.createFromString('Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea Thisisaverylonglinegoingwithmore100bcharactersandthismakesintellisensebecomea b text_after_b', undefined, modeService.getLanguageIdentifier('fooLang'));
let result = await provider.provideCompletionItems(model, new Position(1, 158));
assert.equal(result.suggestions.length, 1);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册