mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 20:26:08 +00:00
SnippetString and improved CompletionItem.insertText, #3210
This commit is contained in:
@@ -12,7 +12,7 @@ import { XHRRequest } from 'request-light';
|
||||
|
||||
import {
|
||||
CompletionItem, CompletionItemProvider, CompletionList, TextDocument, Position, Hover, HoverProvider,
|
||||
CancellationToken, Range, TextEdit, MarkedString, DocumentSelector, languages, Disposable
|
||||
CancellationToken, Range, MarkedString, DocumentSelector, languages, Disposable
|
||||
} from 'vscode';
|
||||
|
||||
export interface ISuggestionsCollector {
|
||||
@@ -109,7 +109,7 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
|
||||
add: (suggestion: CompletionItem) => {
|
||||
if (!proposed[suggestion.label]) {
|
||||
proposed[suggestion.label] = true;
|
||||
suggestion.textEdit = TextEdit.replace(overwriteRange, suggestion.insertText);
|
||||
suggestion.range = overwriteRange;
|
||||
items.push(suggestion);
|
||||
}
|
||||
},
|
||||
@@ -160,4 +160,4 @@ export class JSONCompletionItemProvider implements CompletionItemProvider {
|
||||
}
|
||||
return nextToken === SyntaxKind.CloseBraceToken || nextToken === SyntaxKind.EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
src/vs/vscode.d.ts
vendored
46
src/vs/vscode.d.ts
vendored
@@ -2023,6 +2023,25 @@ declare module 'vscode' {
|
||||
entries(): [Uri, TextEdit[]][];
|
||||
}
|
||||
|
||||
/**
|
||||
* A snippet string is a template which allows to insert text
|
||||
* and to control the editor cursor when insertion happens.
|
||||
*
|
||||
* A snippet can define tab stops and placeholders with `$1`, `$2`
|
||||
* and `${3:foo}`. `$0` defines the final tab stop, it defaults to
|
||||
* the end of the snippet. Placeholders with equal identifiers are linked,
|
||||
* that is typing in one will update others too.
|
||||
*/
|
||||
export class SnippetString {
|
||||
|
||||
/**
|
||||
* The snippet string.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
constructor(value: string);
|
||||
}
|
||||
|
||||
/**
|
||||
* The rename provider interface defines the contract between extensions and
|
||||
* the [rename](https://code.visualstudio.com/docs/editor/editingevolved#_rename-symbol)-feature.
|
||||
@@ -2310,19 +2329,32 @@ declare module 'vscode' {
|
||||
filterText: string;
|
||||
|
||||
/**
|
||||
* A string that should be inserted in a document when selecting
|
||||
* A string or snippet that should be inserted in a document when selecting
|
||||
* this completion. When `falsy` the [label](#CompletionItem.label)
|
||||
* is used.
|
||||
*/
|
||||
insertText: string;
|
||||
insertText: string | SnippetString;
|
||||
|
||||
/**
|
||||
* An [edit](#TextEdit) which is applied to a document when selecting
|
||||
* this completion. When an edit is provided the value of
|
||||
* [insertText](#CompletionItem.insertText) is ignored.
|
||||
* A range of text that should be replaced by this completion item.
|
||||
*
|
||||
* The [range](#Range) of the edit must be single-line and on the same
|
||||
* line completions were [requested](#CompletionItemProvider.provideCompletionItems) at.
|
||||
* Defaults to a range from the start of the [current word](#TextDocument.getWordRangeAtPosition) to the
|
||||
* current position.
|
||||
*
|
||||
* *Note:* The range must be a [single line](#Range.isSingleLine) and it must
|
||||
* [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems).
|
||||
*/
|
||||
range: Range;
|
||||
|
||||
/**
|
||||
* @deprecated **Deprecated** in favor of `CompletionItem.insertText` and `CompletionItem.range`.
|
||||
*
|
||||
* ~~An [edit](#TextEdit) which is applied to a document when selecting
|
||||
* this completion. When an edit is provided the value of
|
||||
* [insertText](#CompletionItem.insertText) is ignored.~~
|
||||
*
|
||||
* ~~The [range](#Range) of the edit must be single-line and on the same
|
||||
* line completions were [requested](#CompletionItemProvider.provideCompletionItems) at.~~
|
||||
*/
|
||||
textEdit: TextEdit;
|
||||
|
||||
|
||||
@@ -368,41 +368,42 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ
|
||||
window,
|
||||
workspace,
|
||||
// types
|
||||
Uri: URI,
|
||||
Location: extHostTypes.Location,
|
||||
Diagnostic: extHostTypes.Diagnostic,
|
||||
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
|
||||
EventEmitter: Emitter,
|
||||
Disposable: extHostTypes.Disposable,
|
||||
TextEdit: extHostTypes.TextEdit,
|
||||
WorkspaceEdit: extHostTypes.WorkspaceEdit,
|
||||
Position: extHostTypes.Position,
|
||||
Range: extHostTypes.Range,
|
||||
Selection: extHostTypes.Selection,
|
||||
CancellationTokenSource: CancellationTokenSource,
|
||||
Hover: extHostTypes.Hover,
|
||||
SymbolKind: extHostTypes.SymbolKind,
|
||||
SymbolInformation: extHostTypes.SymbolInformation,
|
||||
DocumentHighlightKind: extHostTypes.DocumentHighlightKind,
|
||||
DocumentHighlight: extHostTypes.DocumentHighlight,
|
||||
CodeLens: extHostTypes.CodeLens,
|
||||
ParameterInformation: extHostTypes.ParameterInformation,
|
||||
SignatureInformation: extHostTypes.SignatureInformation,
|
||||
SignatureHelp: extHostTypes.SignatureHelp,
|
||||
CompletionItem: extHostTypes.CompletionItem,
|
||||
CompletionItemKind: extHostTypes.CompletionItemKind,
|
||||
CompletionList: extHostTypes.CompletionList,
|
||||
Diagnostic: extHostTypes.Diagnostic,
|
||||
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
|
||||
Disposable: extHostTypes.Disposable,
|
||||
DocumentHighlight: extHostTypes.DocumentHighlight,
|
||||
DocumentHighlightKind: extHostTypes.DocumentHighlightKind,
|
||||
DocumentLink: extHostTypes.DocumentLink,
|
||||
ViewColumn: extHostTypes.ViewColumn,
|
||||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
IndentAction: languageConfiguration.IndentAction,
|
||||
OverviewRulerLane: EditorCommon.OverviewRulerLane,
|
||||
TextEditorRevealType: extHostTypes.TextEditorRevealType,
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EventEmitter: Emitter,
|
||||
Hover: extHostTypes.Hover,
|
||||
IndentAction: languageConfiguration.IndentAction,
|
||||
Location: extHostTypes.Location,
|
||||
OverviewRulerLane: EditorCommon.OverviewRulerLane,
|
||||
ParameterInformation: extHostTypes.ParameterInformation,
|
||||
Position: extHostTypes.Position,
|
||||
Range: extHostTypes.Range,
|
||||
Selection: extHostTypes.Selection,
|
||||
SignatureHelp: extHostTypes.SignatureHelp,
|
||||
SignatureInformation: extHostTypes.SignatureInformation,
|
||||
SnippetString: extHostTypes.SnippetString,
|
||||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
SymbolInformation: extHostTypes.SymbolInformation,
|
||||
SymbolKind: extHostTypes.SymbolKind,
|
||||
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
|
||||
TextEdit: extHostTypes.TextEdit,
|
||||
TextEditorCursorStyle: EditorCommon.TextEditorCursorStyle,
|
||||
TextEditorLineNumbersStyle: extHostTypes.TextEditorLineNumbersStyle,
|
||||
TextEditorRevealType: extHostTypes.TextEditorRevealType,
|
||||
TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind,
|
||||
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
|
||||
Uri: URI,
|
||||
ViewColumn: extHostTypes.ViewColumn,
|
||||
WorkspaceEdit: extHostTypes.WorkspaceEdit,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||
import * as vscode from 'vscode';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, CompletionItem } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Range, Disposable, CompletionList, CompletionItem, SnippetString } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { IPosition, IRange, ISingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
@@ -21,7 +22,6 @@ import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier } from './extHost.protocol';
|
||||
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as semver from 'semver';
|
||||
|
||||
// --- adapter
|
||||
|
||||
@@ -415,7 +415,6 @@ class SuggestAdapter {
|
||||
private _heapService: ExtHostHeapService;
|
||||
private _provider: vscode.CompletionItemProvider;
|
||||
private _extension: IExtensionDescription;
|
||||
private _extensionIsBefore180: boolean;
|
||||
|
||||
constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider, extension?: IExtensionDescription) {
|
||||
this._documents = documents;
|
||||
@@ -423,18 +422,6 @@ class SuggestAdapter {
|
||||
this._heapService = heapService;
|
||||
this._provider = provider;
|
||||
this._extension = extension;
|
||||
this._extensionIsBefore180 = SuggestAdapter._isBefore180(extension);
|
||||
}
|
||||
|
||||
private static _isBefore180(extension: IExtensionDescription): boolean {
|
||||
if (extension && extension.engines) {
|
||||
let versionOrRange = extension.engines.vscode;
|
||||
if (semver.valid(versionOrRange)) {
|
||||
return semver.lt(versionOrRange, '1.8.0');
|
||||
} else if (semver.validRange(versionOrRange)) {
|
||||
return semver.gtr('1.8.0', versionOrRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provideCompletionItems(resource: URI, position: IPosition): TPromise<modes.ISuggestResult> {
|
||||
@@ -448,10 +435,6 @@ class SuggestAdapter {
|
||||
suggestions: [],
|
||||
};
|
||||
|
||||
// the default text edit range
|
||||
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
|
||||
.with({ end: pos });
|
||||
|
||||
let list: CompletionList;
|
||||
if (!value) {
|
||||
// undefined and null are valid results
|
||||
@@ -465,39 +448,21 @@ class SuggestAdapter {
|
||||
result.incomplete = list.isIncomplete;
|
||||
}
|
||||
|
||||
for (let i = 0; i < list.items.length; i++) {
|
||||
// the default text edit range
|
||||
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
|
||||
.with({ end: pos });
|
||||
|
||||
const item = list.items[i];
|
||||
const suggestion = TypeConverters.Suggest.from(item);
|
||||
suggestion.command = this._commands.toInternal(item.command);
|
||||
ObjectIdentifier.mixin(suggestion, this._heapService.keep(item));
|
||||
for (const item of list.items) {
|
||||
|
||||
if (item.textEdit) {
|
||||
const suggestion = this._convertCompletionItem(item, pos, wordRangeBeforePos);
|
||||
|
||||
const editRange = item.textEdit.range;
|
||||
|
||||
// invalid text edit
|
||||
if (!editRange.isSingleLine || editRange.start.line !== pos.line) {
|
||||
console.warn('INVALID text edit, must be single line and on the same line');
|
||||
continue;
|
||||
}
|
||||
|
||||
// insert the text of the edit and create a dedicated
|
||||
// suggestion-container with overwrite[Before|After]
|
||||
suggestion.insertText = item.textEdit.newText;
|
||||
suggestion.overwriteBefore = pos.character - editRange.start.character;
|
||||
suggestion.overwriteAfter = editRange.end.character - pos.character;
|
||||
|
||||
} else {
|
||||
// default text edit
|
||||
suggestion.overwriteBefore = pos.character - wordRangeBeforePos.start.character;
|
||||
suggestion.overwriteAfter = 0;
|
||||
// bad completion item
|
||||
if (!suggestion) {
|
||||
// converter did warn
|
||||
continue;
|
||||
}
|
||||
|
||||
suggestion._extensionId = this._extension && this._extension.id;
|
||||
suggestion.snippetType = 'internal';
|
||||
|
||||
// store suggestion
|
||||
ObjectIdentifier.mixin(suggestion, this._heapService.keep(item));
|
||||
result.suggestions.push(suggestion);
|
||||
}
|
||||
|
||||
@@ -516,13 +481,82 @@ class SuggestAdapter {
|
||||
if (!item) {
|
||||
return TPromise.as(suggestion);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
|
||||
resolvedItem = resolvedItem || item;
|
||||
const suggestion = TypeConverters.Suggest.from(resolvedItem);
|
||||
suggestion.command = this._commands.toInternal(resolvedItem.command);
|
||||
|
||||
if (!resolvedItem) {
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
const pos = TypeConverters.toPosition(position);
|
||||
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos)).with({ end: pos });
|
||||
const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos);
|
||||
if (newSuggestion) {
|
||||
mixin(suggestion, newSuggestion, true);
|
||||
}
|
||||
|
||||
return suggestion;
|
||||
});
|
||||
}
|
||||
|
||||
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range): modes.ISuggestion {
|
||||
if (!item.label) {
|
||||
console.warn('INVALID text edit -> must have at least a label');
|
||||
return;
|
||||
}
|
||||
|
||||
const result: modes.ISuggestion = {
|
||||
//
|
||||
label: item.label,
|
||||
type: TypeConverters.CompletionItemKind.from(item.kind),
|
||||
detail: item.detail,
|
||||
documentation: item.documentation,
|
||||
filterText: item.filterText,
|
||||
sortText: item.sortText,
|
||||
//
|
||||
insertText: undefined,
|
||||
additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TypeConverters.TextEdit.from),
|
||||
command: this._commands.toInternal(item.command)
|
||||
};
|
||||
|
||||
// 'insertText'-logic
|
||||
if (item.textEdit) {
|
||||
result.insertText = item.textEdit.newText;
|
||||
result.snippetType = 'internal';
|
||||
|
||||
} else if (typeof item.insertText === 'string') {
|
||||
result.insertText = item.insertText;
|
||||
result.snippetType = 'internal';
|
||||
|
||||
} else if (item.insertText instanceof SnippetString) {
|
||||
result.insertText = item.insertText.value;
|
||||
result.snippetType = 'textmate';
|
||||
|
||||
} else {
|
||||
result.insertText = item.label;
|
||||
result.snippetType = 'internal';
|
||||
}
|
||||
|
||||
// 'overwrite[Before|After]'-logic
|
||||
let range: vscode.Range;
|
||||
if (item.textEdit) {
|
||||
range = item.textEdit.range;
|
||||
} else if (item.range) {
|
||||
range = item.range;
|
||||
} else {
|
||||
range = defaultRange;
|
||||
}
|
||||
result.overwriteBefore = position.character - range.start.character;
|
||||
result.overwriteAfter = range.end.character - position.character;
|
||||
|
||||
if (!range.isSingleLine || range.start.line !== position.line) {
|
||||
console.warn('INVALID text edit -> must be single line and on the same line');
|
||||
return;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class SignatureHelpAdapter {
|
||||
|
||||
@@ -270,23 +270,9 @@ export const CompletionItemKind = {
|
||||
}
|
||||
};
|
||||
|
||||
export const Suggest = {
|
||||
export namespace Suggest {
|
||||
|
||||
from(item: vscode.CompletionItem): modes.ISuggestion {
|
||||
const suggestion: modes.ISuggestion = {
|
||||
label: item.label || '<missing label>',
|
||||
insertText: item.insertText || item.label,
|
||||
type: CompletionItemKind.from(item.kind),
|
||||
detail: item.detail,
|
||||
documentation: item.documentation,
|
||||
sortText: item.sortText,
|
||||
filterText: item.filterText,
|
||||
additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TextEdit.from)
|
||||
};
|
||||
return suggestion;
|
||||
},
|
||||
|
||||
to(position: types.Position, suggestion: modes.ISuggestion): types.CompletionItem {
|
||||
export function to(position: types.Position, suggestion: modes.ISuggestion): types.CompletionItem {
|
||||
const result = new types.CompletionItem(suggestion.label);
|
||||
result.insertText = suggestion.insertText;
|
||||
result.kind = CompletionItemKind.to(suggestion.type);
|
||||
@@ -295,14 +281,25 @@ export const Suggest = {
|
||||
result.sortText = suggestion.sortText;
|
||||
result.filterText = suggestion.filterText;
|
||||
|
||||
// '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);
|
||||
|
||||
// 'inserText'-logic
|
||||
if (suggestion.snippetType === 'textmate') {
|
||||
result.insertText = new types.SnippetString(suggestion.insertText);
|
||||
} else {
|
||||
result.insertText = suggestion.insertText;
|
||||
result.textEdit = new types.TextEdit(result.range, result.insertText);
|
||||
}
|
||||
|
||||
// TODO additionalEdits, command
|
||||
|
||||
result.textEdit = types.TextEdit.replace(new types.Range(startPosition, endPosition), suggestion.insertText);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -522,6 +522,15 @@ export class WorkspaceEdit {
|
||||
}
|
||||
}
|
||||
|
||||
export class SnippetString {
|
||||
|
||||
value: string;
|
||||
|
||||
constructor(value: string) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
export enum DiagnosticSeverity {
|
||||
Hint = 3,
|
||||
Information = 2,
|
||||
@@ -774,7 +783,8 @@ export class CompletionItem {
|
||||
documentation: string;
|
||||
sortText: string;
|
||||
filterText: string;
|
||||
insertText: string;
|
||||
insertText: string | SnippetString;
|
||||
range: Range;
|
||||
textEdit: TextEdit;
|
||||
additionalTextEdits: TextEdit[];
|
||||
command: vscode.Command;
|
||||
@@ -876,4 +886,4 @@ export class DocumentLink {
|
||||
this.range = range;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
|
||||
// --- suggest
|
||||
|
||||
test('Suggest, back and forth', function (done) {
|
||||
test('Suggest, back and forth', function () {
|
||||
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
|
||||
provideCompletionItems(doc, pos): any {
|
||||
let a = new types.CompletionItem('item1');
|
||||
@@ -296,53 +296,54 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
b.textEdit = types.TextEdit.replace(new types.Range(0, 4, 0, 8), 'foo'); // overwite after
|
||||
let c = new types.CompletionItem('item3');
|
||||
c.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 6), 'foobar'); // overwite before & after
|
||||
|
||||
// snippet string!
|
||||
let d = new types.CompletionItem('item4');
|
||||
d.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 4), ''); // overwite before
|
||||
d.range = new types.Range(0, 1, 0, 4);// overwite before
|
||||
d.insertText = new types.SnippetString('foo$0bar');
|
||||
return [a, b, c, d];
|
||||
}
|
||||
}, []));
|
||||
|
||||
threadService.sync().then(() => {
|
||||
commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4)).then(list => {
|
||||
try {
|
||||
assert.ok(list instanceof types.CompletionList);
|
||||
let values = list.items;
|
||||
assert.ok(Array.isArray(values));
|
||||
assert.equal(values.length, 4);
|
||||
let [first, second, third, forth] = values;
|
||||
assert.equal(first.label, 'item1');
|
||||
assert.equal(first.textEdit.newText, 'item1');
|
||||
assert.equal(first.textEdit.range.start.line, 0);
|
||||
assert.equal(first.textEdit.range.start.character, 0);
|
||||
assert.equal(first.textEdit.range.end.line, 0);
|
||||
assert.equal(first.textEdit.range.end.character, 4);
|
||||
return threadService.sync().then(() => {
|
||||
return commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4)).then(list => {
|
||||
|
||||
assert.equal(second.label, 'item2');
|
||||
assert.equal(second.textEdit.newText, 'foo');
|
||||
assert.equal(second.textEdit.range.start.line, 0);
|
||||
assert.equal(second.textEdit.range.start.character, 4);
|
||||
assert.equal(second.textEdit.range.end.line, 0);
|
||||
assert.equal(second.textEdit.range.end.character, 8);
|
||||
assert.ok(list instanceof types.CompletionList);
|
||||
let values = list.items;
|
||||
assert.ok(Array.isArray(values));
|
||||
assert.equal(values.length, 4);
|
||||
let [first, second, third, forth] = values;
|
||||
assert.equal(first.label, 'item1');
|
||||
assert.equal(first.textEdit.newText, 'item1');
|
||||
assert.equal(first.textEdit.range.start.line, 0);
|
||||
assert.equal(first.textEdit.range.start.character, 0);
|
||||
assert.equal(first.textEdit.range.end.line, 0);
|
||||
assert.equal(first.textEdit.range.end.character, 4);
|
||||
|
||||
assert.equal(third.label, 'item3');
|
||||
assert.equal(third.textEdit.newText, 'foobar');
|
||||
assert.equal(third.textEdit.range.start.line, 0);
|
||||
assert.equal(third.textEdit.range.start.character, 1);
|
||||
assert.equal(third.textEdit.range.end.line, 0);
|
||||
assert.equal(third.textEdit.range.end.character, 6);
|
||||
assert.equal(second.label, 'item2');
|
||||
assert.equal(second.textEdit.newText, 'foo');
|
||||
assert.equal(second.textEdit.range.start.line, 0);
|
||||
assert.equal(second.textEdit.range.start.character, 4);
|
||||
assert.equal(second.textEdit.range.end.line, 0);
|
||||
assert.equal(second.textEdit.range.end.character, 8);
|
||||
|
||||
assert.equal(forth.label, 'item4');
|
||||
assert.equal(forth.textEdit.newText, '');
|
||||
assert.equal(forth.textEdit.range.start.line, 0);
|
||||
assert.equal(forth.textEdit.range.start.character, 1);
|
||||
assert.equal(forth.textEdit.range.end.line, 0);
|
||||
assert.equal(forth.textEdit.range.end.character, 4);
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}, done);
|
||||
}, done);
|
||||
assert.equal(third.label, 'item3');
|
||||
assert.equal(third.textEdit.newText, 'foobar');
|
||||
assert.equal(third.textEdit.range.start.line, 0);
|
||||
assert.equal(third.textEdit.range.start.character, 1);
|
||||
assert.equal(third.textEdit.range.end.line, 0);
|
||||
assert.equal(third.textEdit.range.end.character, 6);
|
||||
|
||||
assert.equal(forth.label, 'item4');
|
||||
assert.equal(forth.textEdit, undefined);
|
||||
assert.equal(forth.range.start.line, 0);
|
||||
assert.equal(forth.range.start.character, 1);
|
||||
assert.equal(forth.range.end.line, 0);
|
||||
assert.equal(forth.range.end.character, 4);
|
||||
assert.ok(forth.insertText instanceof types.SnippetString);
|
||||
assert.equal((<types.SnippetString>forth.insertText).value, 'foo$0bar');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('Suggest, return CompletionList !array', function (done) {
|
||||
|
||||
Reference in New Issue
Block a user