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

debt - replace CompletionItem#overwriteBefore/After with CompletionItem#range

上级 504ab3bb
......@@ -36,6 +36,30 @@ export class Position {
this.column = column;
}
/**
* Create a new postion from this position.
*
* @param newLineNumber new line number
* @param newColumn new column
*/
with(newLineNumber: number = this.lineNumber, newColumn: number = this.column): Position {
if (newLineNumber === this.lineNumber && newColumn === this.column) {
return this;
} else {
return new Position(newLineNumber, newColumn);
}
}
/**
* Derive a new position from this position.
*
* @param deltaLineNumber line number delta
* @param deltaColumn column delta
*/
delta(deltaLineNumber: number = 0, deltaColumn: number = 0): Position {
return this.with(this.lineNumber + deltaLineNumber, this.column + deltaColumn);
}
/**
* Test if this position equals other position
*/
......
......@@ -366,21 +366,20 @@ export let completionKindFromLegacyString = (function () {
*/
export interface CompletionItem {
label: string;
insertText: string;
insertTextIsSnippet?: boolean;
kind: CompletionKind;
detail?: string;
documentation?: string | IMarkdownString;
filterText?: string;
sortText?: string;
filterText?: string;
preselect?: boolean;
insertText: string;
insertTextIsSnippet?: boolean;
noWhitespaceAdjust?: boolean;
range?: IRange;
noAutoAccept?: boolean;
commitCharacters?: string[];
overwriteBefore?: number;
overwriteAfter?: number;
additionalTextEdits?: model.ISingleEditOperation[];
command?: Command;
noWhitespaceAdjust?: boolean;
}
/**
......
......@@ -462,10 +462,10 @@ export abstract class BaseEditorSimpleWorker {
if (model) {
const suggestions: CompletionItem[] = [];
const wordDefRegExp = new RegExp(wordDef, wordDefFlags);
const currentWord = model.getWordUntilPosition(position, wordDefRegExp).word;
const currentWord = model.getWordUntilPosition(position, wordDefRegExp);
const seen: Record<string, boolean> = Object.create(null);
seen[currentWord] = true;
seen[currentWord.word] = true;
for (
let iter = model.createWordIterator(wordDefRegExp), e = iter.next();
......@@ -486,7 +486,7 @@ export abstract class BaseEditorSimpleWorker {
label: word,
insertText: word,
noAutoAccept: true,
overwriteBefore: currentWord.length
range: { startLineNumber: position.lineNumber, startColumn: currentWord.startColumn, endLineNumber: position.lineNumber, endColumn: currentWord.endColumn }
});
}
......
......@@ -175,7 +175,8 @@ export class CompletionModel {
// 'word' is that remainder of the current line that we
// filter and score against. In theory each suggestion uses a
// different word, but in practice not - that's why we cache
const wordLen = suggestion.overwriteBefore + characterCountDelta - (item.position.column - this._column);
const overwriteBefore = item.position.column - suggestion.range.startColumn;
const wordLen = overwriteBefore + characterCountDelta - (item.position.column - this._column);
if (word.length !== wordLen) {
word = wordLen === 0 ? '' : leadingLineContent.slice(-wordLen);
}
......@@ -198,7 +199,7 @@ export class CompletionModel {
// if it matches we check with the label to compute highlights
// and if that doesn't yield a result we have no highlights,
// despite having the match
let match = scoreFn(word, suggestion.filterText, suggestion.overwriteBefore);
let match = scoreFn(word, suggestion.filterText, overwriteBefore);
if (!match) {
continue;
}
......@@ -207,7 +208,7 @@ export class CompletionModel {
} else {
// by default match `word` against the `label`
let match = scoreFn(word, suggestion.label, suggestion.overwriteBefore);
let match = scoreFn(word, suggestion.label, overwriteBefore);
if (match) {
item.score = match[0];
item.matches = match[1];
......
......@@ -16,6 +16,7 @@ import { Position, IPosition } from 'vs/editor/common/core/position';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Range } from 'vs/editor/common/core/range';
export const Context = {
Visible: new RawContextKey<boolean>('suggestWidgetVisible', false),
......@@ -59,6 +60,9 @@ export function provideSuggestionItems(
const allSuggestions: ISuggestionItem[] = [];
const acceptSuggestion = createSuggesionFilter(snippetConfig);
const wordUntil = model.getWordUntilPosition(position);
const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn);
position = position.clone();
// get provider groups, always add snippet suggestion provider
......@@ -90,7 +94,9 @@ export function provideSuggestionItems(
for (let suggestion of container.suggestions) {
if (acceptSuggestion(suggestion)) {
fixOverwriteBeforeAfter(suggestion, container);
if (!suggestion.range) {
suggestion.range = defaultRange;
}
allSuggestions.push({
position,
......@@ -131,15 +137,6 @@ export function provideSuggestionItems(
return result;
}
function fixOverwriteBeforeAfter(suggestion: CompletionItem, container: CompletionList): void {
if (typeof suggestion.overwriteBefore !== 'number') {
suggestion.overwriteBefore = 0;
}
if (typeof suggestion.overwriteAfter !== 'number' || suggestion.overwriteAfter < 0) {
suggestion.overwriteAfter = 0;
}
}
function createSuggestionResolver(provider: CompletionItemProvider, suggestion: CompletionItem, model: ITextModel, position: Position): (token: CancellationToken) => Promise<void> {
return (token) => {
if (typeof provider.resolveCompletionItem === 'function') {
......
......@@ -165,7 +165,7 @@ export class SuggestController implements IEditorContribution {
this._toDispose.push(this._widget.onDidFocus(({ item }) => {
const position = this._editor.getPosition();
const startColumn = item.position.column - item.suggestion.overwriteBefore;
const startColumn = item.suggestion.range.startColumn;
const endColumn = position.column;
let value = true;
if (
......@@ -236,10 +236,13 @@ export class SuggestController implements IEditorContribution {
insertText = SnippetParser.escape(insertText);
}
const overwriteBefore = position.column - suggestion.range.startColumn;
const overwriteAfter = suggestion.range.endColumn - position.column;
SnippetController2.get(this._editor).insert(
insertText,
suggestion.overwriteBefore + columnDelta,
suggestion.overwriteAfter,
overwriteBefore + columnDelta,
overwriteAfter,
false, false,
!suggestion.noWhitespaceAdjust
);
......@@ -310,7 +313,7 @@ export class SuggestController implements IEditorContribution {
return true;
}
const position = this._editor.getPosition();
const startColumn = item.position.column - item.suggestion.overwriteBefore;
const startColumn = item.suggestion.range.startColumn;
const endColumn = position.column;
if (endColumn - startColumn !== item.suggestion.insertText.length) {
// unequal lengths -> makes edit
......
......@@ -19,7 +19,7 @@ export function createSuggestItem(label: string, overwriteBefore: number, kind =
suggestion: CompletionItem = {
label,
overwriteBefore,
range: { startLineNumber: position.lineNumber, startColumn: position.column - overwriteBefore, endLineNumber: position.lineNumber, endColumn: position.column },
insertText: label,
kind
};
......
......@@ -356,7 +356,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'foo.bar',
kind: CompletionKind.Property,
insertText: 'foo.bar',
overwriteBefore: pos.column - 1
range: Range.fromPositions(pos.with(undefined, 1), pos)
}]
};
}
......@@ -371,7 +371,10 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'boom',
kind: CompletionKind.Property,
insertText: 'boom',
overwriteBefore: doc.getLineContent(pos.lineNumber)[pos.column - 2] === '.' ? 0 : pos.column - 1
range: Range.fromPositions(
pos.delta(0, doc.getLineContent(pos.lineNumber)[pos.column - 2] === '.' ? 0 : -1),
pos
)
}]
};
}
......@@ -465,7 +468,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'foo',
kind: CompletionKind.Property,
insertText: 'foo',
overwriteBefore: pos.column - 1
range: Range.fromPositions(pos.with(undefined, 1), pos)
}]
};
}
......@@ -502,7 +505,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'foo;',
kind: CompletionKind.Property,
insertText: 'foo',
overwriteBefore: pos.column - 1
range: Range.fromPositions(pos.with(undefined, 1), pos)
}]
};
}
......@@ -549,7 +552,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'foo.bar',
kind: CompletionKind.Property,
insertText: 'foo.bar',
overwriteBefore: pos.column - 1
range: Range.fromPositions(pos.with(undefined, 1), pos)
}
]
};
......@@ -578,12 +581,12 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'abc',
kind: CompletionKind.Property,
insertText: 'abc',
overwriteBefore: pos.column - 1
range: Range.fromPositions(pos.with(undefined, 1), pos)
}, {
label: 'äbc',
kind: CompletionKind.Property,
insertText: 'äbc',
overwriteBefore: pos.column - 1
range: Range.fromPositions(pos.with(undefined, 1), pos)
}]
};
}
......@@ -650,7 +653,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
label: 'bar',
kind: CompletionKind.Property,
insertText: 'bar',
overwriteBefore: 2,
range: Range.fromPositions(pos.delta(0, -2), pos),
additionalTextEdits: [{
text: ', bar',
range: { startLineNumber: 1, endLineNumber: 1, startColumn: 17, endColumn: 17 }
......
......@@ -759,11 +759,9 @@ class SuggestAdapter {
// insert the text of the edit and create a dedicated
// suggestion-container with overwrite[Before|After]
suggestion.overwriteBefore = position.column - editRange.startColumn;
suggestion.overwriteAfter = editRange.endColumn - position.column;
suggestion.range = editRange;
} else {
suggestion.overwriteBefore = position.column - wordStartPos.column;
suggestion.overwriteAfter = 0;
suggestion.range = { startLineNumber: position.lineNumber, startColumn: wordStartPos.column, endLineNumber: position.lineNumber, endColumn: position.column };
}
if (item.textEdit) {
suggestion.insertText = item.textEdit.text;
......
......@@ -468,6 +468,20 @@ declare namespace monaco {
*/
readonly column: number;
constructor(lineNumber: number, column: number);
/**
* Create a new postion from this position.
*
* @param newLineNumber new line number
* @param newColumn new column
*/
with(newLineNumber?: number, newColumn?: number): Position;
/**
* Derive a new position from this position.
*
* @param deltaLineNumber line number delta
* @param deltaColumn column delta
*/
delta(deltaLineNumber?: number, deltaColumn?: number): Position;
/**
* Test if this position equals other position
*/
......
......@@ -378,7 +378,7 @@ export class ExtHostApiCommands {
};
return this._commands.executeCommand<modes.CompletionList>('_executeCompletionItemProvider', args).then(result => {
if (result) {
const items = result.suggestions.map(suggestion => typeConverters.Suggest.to(position, suggestion));
const items = result.suggestions.map(suggestion => typeConverters.Suggest.to(suggestion));
return new types.CompletionList(items, result.incomplete);
}
return undefined;
......
......@@ -671,6 +671,7 @@ class SuggestAdapter {
sortText: item.sortText,
preselect: item.preselect,
//
range: undefined,
insertText: undefined,
additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
command: this._commands.toInternal(item.command),
......@@ -704,8 +705,7 @@ class SuggestAdapter {
} else {
range = defaultRange;
}
result.overwriteBefore = position.character - range.start.character;
result.overwriteAfter = range.end.character - position.character;
result.range = typeConvert.Range.from(range);
if (!range.isSingleLine || range.start.line !== position.line) {
console.warn('INVALID text edit -> must be single line and on the same line');
......
......@@ -544,7 +544,7 @@ export const CompletionItemKind = {
export namespace Suggest {
export function to(position: types.Position, suggestion: modes.CompletionItem): types.CompletionItem {
export function to(suggestion: modes.CompletionItem): types.CompletionItem {
const result = new types.CompletionItem(suggestion.label);
result.insertText = suggestion.insertText;
result.kind = CompletionItemKind.to(suggestion.kind);
......@@ -554,15 +554,7 @@ export namespace Suggest {
result.filterText = suggestion.filterText;
result.preselect = suggestion.preselect;
result.commitCharacters = suggestion.commitCharacters;
// 'overwrite[Before|After]'-logic
let overwriteBefore = (typeof suggestion.overwriteBefore === 'number') ? suggestion.overwriteBefore : 0;
let startPosition = new types.Position(position.line, Math.max(0, position.character - overwriteBefore));
let endPosition = position;
if (typeof suggestion.overwriteAfter === 'number') {
endPosition = new types.Position(position.line, position.character + suggestion.overwriteAfter);
}
result.range = new types.Range(startPosition, endPosition);
result.range = Range.to(suggestion.range);
// 'inserText'-logic
if (suggestion.insertTextIsSnippet) {
......
......@@ -34,6 +34,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { getSimpleCodeEditorWidgetOptions } from 'vs/workbench/parts/codeEditor/electron-browser/simpleEditorOptions';
import { getSimpleEditorOptions } from 'vs/workbench/parts/codeEditor/browser/simpleEditorOptions';
import { Range } from 'vs/editor/common/core/range';
const $ = dom.$;
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakopintWidgetService');
......@@ -234,8 +235,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
return {
suggestions: suggestions.map(s => {
s.suggestion.overwriteAfter = 0;
s.suggestion.overwriteBefore = overwriteBefore;
s.suggestion.range = Range.fromPositions(position.delta(0, -overwriteBefore), position);
return s.suggestion;
})
};
......
......@@ -27,6 +27,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { IOutputService } from 'vs/workbench/parts/output/common/output';
import { Range } from 'vs/editor/common/core/range';
export class DebugSession implements IDebugSession {
......@@ -463,7 +464,7 @@ export class DebugSession implements IDebugSession {
insertText: item.text || item.label,
kind: completionKindFromLegacyString(item.type),
filterText: item.start && item.length && text.substr(item.start, item.length).concat(item.label),
overwriteBefore: item.length || overwriteBefore
range: Range.fromPositions(position.delta(0, -(item.length || overwriteBefore)), position)
});
}
});
......
......@@ -30,6 +30,7 @@ import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/e
import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService';
import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IRange, Range } from 'vs/editor/common/core/range';
namespace schema {
......@@ -345,7 +346,7 @@ export class SnippetSuggestion implements CompletionItem {
detail: string;
insertText: string;
documentation: MarkdownString;
overwriteBefore: number;
range: IRange;
sortText: string;
noAutoAccept: boolean;
kind: CompletionKind;
......@@ -353,12 +354,12 @@ export class SnippetSuggestion implements CompletionItem {
constructor(
readonly snippet: Snippet,
overwriteBefore: number
range: IRange
) {
this.label = snippet.prefix;
this.detail = localize('detail.snippet', "{0} ({1})", snippet.description || snippet.name, snippet.source);
this.insertText = snippet.body;
this.overwriteBefore = overwriteBefore;
this.range = range;
this.sortText = `${snippet.snippetSource === SnippetSource.Extension ? 'z' : 'a'}-${snippet.prefix}`;
this.noAutoAccept = true;
this.kind = CompletionKind.Snippet;
......@@ -420,7 +421,7 @@ export class SnippetSuggestProvider implements CompletionItemProvider {
if (lineOffsets.length === 0) {
// no interesting spans found -> pick all snippets
suggestions = snippets.map(snippet => new SnippetSuggestion(snippet, 0));
suggestions = snippets.map(snippet => new SnippetSuggestion(snippet, Range.fromPositions(position)));
} else {
let consumed = new Set<Snippet>();
......@@ -429,7 +430,7 @@ export class SnippetSuggestProvider implements CompletionItemProvider {
start -= shift;
for (const snippet of snippets) {
if (!consumed.has(snippet) && matches(linePrefixLow, start, snippet.prefixLow, 0)) {
suggestions.push(new SnippetSuggestion(snippet, linePrefixLow.length - start));
suggestions.push(new SnippetSuggestion(snippet, Range.fromPositions(position.delta(0, -(linePrefixLow.length - start)), position)));
consumed.add(snippet);
}
}
......
......@@ -127,7 +127,11 @@ export class TabCompletionController implements editorCommon.IEditorContribution
} else if (this._activeSnippets.length > 1) {
// two or more -> show IntelliSense box
showSimpleSuggestions(this._editor, this._activeSnippets.map(snippet => new SnippetSuggestion(snippet, snippet.prefix.length)));
showSimpleSuggestions(this._editor, this._activeSnippets.map(snippet => {
const position = this._editor.getPosition();
const range = Range.fromPositions(position.delta(0, -snippet.prefix.length), position);
return new SnippetSuggestion(snippet, range);
}));
}
}
}
......
......@@ -85,7 +85,7 @@ suite('SnippetsService', function () {
assert.equal(result.incomplete, undefined);
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].label, 'bar');
assert.equal(result.suggestions[0].overwriteBefore, 3);
assert.equal(result.suggestions[0].range.startColumn, 1);
assert.equal(result.suggestions[0].insertText, 'barCodeSnippet');
});
});
......@@ -118,10 +118,10 @@ suite('SnippetsService', function () {
assert.equal(result.suggestions.length, 2);
assert.equal(result.suggestions[0].label, 'bar');
assert.equal(result.suggestions[0].insertText, 's1');
assert.equal(result.suggestions[0].overwriteBefore, 2);
assert.equal(result.suggestions[0].range.startColumn, 1);
assert.equal(result.suggestions[1].label, 'bar-bar');
assert.equal(result.suggestions[1].insertText, 's2');
assert.equal(result.suggestions[1].overwriteBefore, 2);
assert.equal(result.suggestions[1].range.startColumn, 1);
});
await provider.provideCompletionItems(model, new Position(1, 5), suggestContext).then(result => {
......@@ -129,7 +129,7 @@ suite('SnippetsService', function () {
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].label, 'bar-bar');
assert.equal(result.suggestions[0].insertText, 's2');
assert.equal(result.suggestions[0].overwriteBefore, 4);
assert.equal(result.suggestions[0].range.startColumn, 1);
});
await provider.provideCompletionItems(model, new Position(1, 6), suggestContext).then(result => {
......@@ -137,10 +137,10 @@ suite('SnippetsService', function () {
assert.equal(result.suggestions.length, 2);
assert.equal(result.suggestions[0].label, 'bar');
assert.equal(result.suggestions[0].insertText, 's1');
assert.equal(result.suggestions[0].overwriteBefore, 1);
assert.equal(result.suggestions[0].range.startColumn, 5);
assert.equal(result.suggestions[1].label, 'bar-bar');
assert.equal(result.suggestions[1].insertText, 's2');
assert.equal(result.suggestions[1].overwriteBefore, 5);
assert.equal(result.suggestions[1].range.startColumn, 1);
});
});
......@@ -166,14 +166,14 @@ suite('SnippetsService', function () {
return provider.provideCompletionItems(model, new Position(1, 4), suggestContext);
}).then(result => {
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].overwriteBefore, 2);
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);
}).then(result => {
assert.equal(result.suggestions.length, 1);
assert.equal(result.suggestions[0].overwriteBefore, 2);
assert.equal(result.suggestions[0].range.startColumn, 2);
model.dispose();
});
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册