提交 42561682 编写于 作者: J Johannes Rieken

validate on client (using faster ways), don't send repeated data, #95325

上级 8265dfec
......@@ -151,6 +151,10 @@ export class CompletionModel {
const item = source[i];
if (item.isInvalid) {
continue; // SKIP invalid items
}
// collect those supports that signaled having
// an incomplete result
if (item.container.incomplete) {
......
......@@ -53,6 +53,9 @@ export class CompletionItem {
readonly sortTextLow?: string;
readonly filterTextLow?: string;
// validation
readonly isInvalid: boolean = false;
// sorting, filtering
score: FuzzyScore = FuzzyScore.Default;
distance: number = 0;
......@@ -73,6 +76,9 @@ export class CompletionItem {
// ensure lower-variants (perf)
this.labelLow = this.textLabel.toLowerCase();
// validate label
this.isInvalid = !this.textLabel;
this.sortTextLow = completion.sortText && completion.sortText.toLowerCase();
this.filterTextLow = completion.filterText && completion.filterText.toLowerCase();
......@@ -81,10 +87,21 @@ export class CompletionItem {
this.editStart = new Position(completion.range.startLineNumber, completion.range.startColumn);
this.editInsertEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);
this.editReplaceEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);
// validate range
this.isInvalid = this.isInvalid
|| Range.spansMultipleLines(completion.range) || completion.range.startLineNumber !== position.lineNumber;
} else {
this.editStart = new Position(completion.range.insert.startLineNumber, completion.range.insert.startColumn);
this.editInsertEnd = new Position(completion.range.insert.endLineNumber, completion.range.insert.endColumn);
this.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn);
// validate ranges
this.isInvalid = this.isInvalid
|| Range.spansMultipleLines(completion.range.insert) || Range.spansMultipleLines(completion.range.replace)
|| completion.range.insert.startLineNumber !== position.lineNumber || completion.range.replace.startLineNumber !== position.lineNumber
|| Range.compareRangesUsingStarts(completion.range.insert, completion.range.replace) !== 0;
}
// create the suggestion resolver
......@@ -154,7 +171,7 @@ export function provideSuggestionItems(
context: modes.CompletionContext = { triggerKind: modes.CompletionTriggerKind.Invoke },
token: CancellationToken = CancellationToken.None
): Promise<CompletionItem[]> {
// const t1 = Date.now();
const word = model.getWordAtPosition(position);
const defaultReplaceRange = word ? new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : Range.fromPositions(position);
const defaultInsertRange = defaultReplaceRange.setEndPosition(position.lineNumber, position.column);
......@@ -227,6 +244,7 @@ export function provideSuggestionItems(
disposables.dispose();
return Promise.reject<any>(canceled());
}
// console.log(`${allSuggestions.length} items AFTER ${Date.now() - t1}ms`);
return allSuggestions.sort(getSuggestionComparator(options.snippetSortOrder));
});
......
......@@ -876,33 +876,30 @@ class SuggestAdapter {
for (let i = 0; i < list.items.length; i++) {
const item = list.items[i];
// check for bad completion item first
if (this._validateCompletionItem(item, pos)) {
const dto = this._convertCompletionItem(item, [pid, i], insertRange, replaceRange);
completions.push(dto);
}
const dto = this._convertCompletionItem(item, [pid, i], insertRange, replaceRange);
completions.push(dto);
}
return result;
}
async resolveCompletionItem(_resource: URI, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
async resolveCompletionItem(_resource: URI, _position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
if (typeof this._provider.resolveCompletionItem !== 'function') {
return Promise.resolve(undefined);
return undefined;
}
const item = this._cache.get(...id);
if (!item) {
return Promise.resolve(undefined);
return undefined;
}
const pos = typeConvert.Position.to(position);
const _mustNotChange = SuggestAdapter._mustNotChangeHash(item);
const _mayNotChange = SuggestAdapter._mayNotChangeHash(item);
const resolvedItem = await asPromise(() => this._provider.resolveCompletionItem!(item, token));
if (!resolvedItem || !this._validateCompletionItem(resolvedItem, pos)) {
if (!resolvedItem) {
return undefined;
}
......@@ -952,14 +949,14 @@ class SuggestAdapter {
//
x: id,
//
[extHostProtocol.ISuggestDataDtoField.label]: item.label,
[extHostProtocol.ISuggestDataDtoField.label]: item.label ?? '',
[extHostProtocol.ISuggestDataDtoField.label2]: item.label2,
[extHostProtocol.ISuggestDataDtoField.kind]: item.kind !== undefined ? typeConvert.CompletionItemKind.from(item.kind) : undefined,
[extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
[extHostProtocol.ISuggestDataDtoField.detail]: item.detail,
[extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
[extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText,
[extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText,
[extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText !== item.label ? item.sortText : undefined,
[extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText !== item.label ? item.filterText : undefined,
[extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect || undefined,
[extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
[extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters,
......@@ -1003,31 +1000,6 @@ class SuggestAdapter {
return result;
}
private _validateCompletionItem(item: vscode.CompletionItem, position: vscode.Position): boolean {
if (typeof item.label !== 'string' || item.label.length === 0) {
this._logService.warn('INVALID text edit -> must have at least a label');
return false;
}
if (Range.isRange(item.range)) {
if (!item.range.isSingleLine || item.range.start.line !== position.line) {
this._logService.trace('INVALID range -> must be single line and on the same line');
return false;
}
} else if (item.range) {
if (!item.range.inserting.isSingleLine || item.range.inserting.start.line !== position.line
|| !item.range.replacing.isSingleLine || item.range.replacing.start.line !== position.line
|| !item.range.inserting.start.isEqual(item.range.replacing.start)
|| !item.range.replacing.contains(item.range.inserting)
) {
this._logService.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range');
return false;
}
}
return true;
}
private static _mustNotChangeHash(item: vscode.CompletionItem) {
const res = JSON.stringify([item.label, item.sortText, item.filterText, item.insertText, item.range]);
return res;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册