提交 66c13c81 编写于 作者: J Johannes Rieken

expose `command` and `additionalTextEdits` in API, wire it up, #6874

上级 63c8b7a7
......@@ -367,7 +367,7 @@ export interface ISuggestion {
noAutoAccept?: boolean;
overwriteBefore?: number;
overwriteAfter?: number;
extraEdits?: editorCommon.ISingleEditOperation[];
additionalTextEdits?: editorCommon.ISingleEditOperation[];
command?: Command;
}
......
......@@ -65,22 +65,22 @@ export class SuggestController implements IEditorContribution {
private onDidSelectItem(item: CompletionItem): void {
if (item) {
const {insertText, overwriteBefore, overwriteAfter, extraEdits, command} = item.suggestion;
const {insertText, overwriteBefore, overwriteAfter, additionalTextEdits, command} = item.suggestion;
const columnDelta = this.editor.getPosition().column - this.model.getTriggerPosition().column;
// todo@joh
// * order of stuff command/extraEdit/actual edit
// * failure of command?
// * wait for command to execute?
// todo@joh
// * order of stuff command/extraEdit/actual edit
// * failure of command?
// * wait for command to execute?
if (command) {
this.commandService.executeCommand(command.id, ...command.arguments).then(undefined, err => {
console.error(err);
});
}
if (Array.isArray(extraEdits)) {
if (Array.isArray(additionalTextEdits)) {
this.editor.pushUndoStop();
this.editor.executeEdits('suggestController.extraEdits', extraEdits.map(edit => EditOperation.replace(edit.range, edit.text)));
this.editor.executeEdits('suggestController.additionalTextEdits', additionalTextEdits.map(edit => EditOperation.replace(edit.range, edit.text)));
this.editor.pushUndoStop();
}
......
......@@ -2228,14 +2228,16 @@ declare namespace vscode {
}
/**
* A completion item represents a text snippet that is
* proposed to complete text that is being typed.
* A completion item represents a text snippet that is proposed to complete text that is being typed.
*
* It is suffient to create a completion item from just
* a [label](#CompletionItem.label). In that case the completion
* item will replace the [word](#TextDocument.getWordRangeAtPosition)
* until the cursor with the given label.
* It is suffient to create a completion item from just a [label](#CompletionItem.label). In that
* case the completion item will replace the [word](#TextDocument.getWordRangeAtPosition)
* until the cursor with the given label or [insertText](#CompletionItem.insertText). Otherwise the
* the given [edit](#CompletionItem.textEdit) is used.
*
* When selecting a completion item in the editor its defined or synthesized text edit will be applied
* to *all* cursors/selections whereas [additionalTextEdits](CompletionItem.additionalTextEdits) will be
* applied as provided.
*
* @see [CompletionItemProvider.provideCompletionItems](#CompletionItemProvider.provideCompletionItems)
* @see [CompletionItemProvider.resolveCompletionItem](#CompletionItemProvider.resolveCompletionItem)
......@@ -2292,11 +2294,25 @@ declare namespace vscode {
* 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 one the same
* line completions where [requested](#CompletionItemProvider.provideCompletionItems) at.
* The [range](#Range) of the edit must be single-line and on the same
* line completions were [requested](#CompletionItemProvider.provideCompletionItems) at.
*/
textEdit: TextEdit;
/**
* An optional array of additional [text edits](#TextEdit) that are applied when
* selecting this completion. Edits must not overlap with the main [edit](#CompletionItem.textEdit)
* nor with themselves.
*/
additionalTextEdits: TextEdit[];
/**
* An optional [command](#Command) that is executed when selecting this completion. *Note* that additional
* modifications to the current document should be described with the
* [additionalTextEdits](#CompletionItem.additionalTextEdits)-property.
*/
command: Command;
/**
* Creates a new completion item.
*
......
......@@ -496,7 +496,7 @@ class SuggestAdapter {
private _documents: ExtHostDocuments;
private _provider: vscode.CompletionItemProvider;
private _cache: { [key: string]: CompletionList } = Object.create(null);
private _cache: { [key: string]: { list: CompletionList; disposables: IDisposable[]; } } = Object.create(null);
constructor(documents: ExtHostDocuments, provider: vscode.CompletionItemProvider) {
this._documents = documents;
......@@ -509,7 +509,10 @@ class SuggestAdapter {
const pos = TypeConverters.toPosition(position);
const key = resource.toString();
delete this._cache[key];
if (this._cache[key]) {
dispose(this._cache[key].disposables);
delete this._cache[key];
}
return asWinJsPromise<vscode.CompletionItem[]|vscode.CompletionList>(token => this._provider.provideCompletionItems(doc, pos, token)).then(value => {
......@@ -522,6 +525,7 @@ class SuggestAdapter {
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
.with({ end: pos });
const disposables: IDisposable[] = [];
let list: CompletionList;
if (Array.isArray(value)) {
list = new CompletionList(value);
......@@ -540,7 +544,7 @@ class SuggestAdapter {
for (let i = 0; i < list.items.length; i++) {
const item = list.items[i];
const suggestion = <ISuggestion2> TypeConverters.Suggest.from(item);
const suggestion = <ISuggestion2> TypeConverters.Suggest.from(item, disposables);
if (item.textEdit) {
......@@ -572,26 +576,24 @@ class SuggestAdapter {
}
// cache for details call
this._cache[key] = list;
this._cache[key] = { list, disposables };
return result;
});
}
resolveCompletionItem(resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
if (typeof this._provider.resolveCompletionItem !== 'function') {
return TPromise.as(suggestion);
}
let list = this._cache[resource.toString()];
if (!list) {
if (typeof this._provider.resolveCompletionItem !== 'function' || !this._cache[resource.toString()]) {
return TPromise.as(suggestion);
}
let item = list.items[Number((<ISuggestion2> suggestion).id)];
const {list, disposables} = this._cache[resource.toString()];
const item = list.items[Number((<ISuggestion2> suggestion).id)];
if (!item) {
return TPromise.as(suggestion);
}
return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
return TypeConverters.Suggest.from(resolvedItem || item);
return TypeConverters.Suggest.from(resolvedItem || item, disposables);
});
}
}
......
......@@ -311,7 +311,7 @@ export const CompletionItemKind = {
export const Suggest = {
from(item: vscode.CompletionItem): modes.ISuggestion {
from(item: vscode.CompletionItem, disposables: IDisposable[]): modes.ISuggestion {
const suggestion: modes.ISuggestion = {
label: item.label,
insertText: item.insertText || item.label,
......@@ -319,7 +319,9 @@ export const Suggest = {
detail: item.detail,
documentation: item.documentation,
sortText: item.sortText,
filterText: item.filterText
filterText: item.filterText,
command: Command.from(item.command, disposables),
additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TextEdit.from)
};
return suggestion;
},
......
......@@ -775,6 +775,8 @@ export class CompletionItem {
filterText: string;
insertText: string;
textEdit: TextEdit;
additionalTextEdits: TextEdit[];
command: vscode.Command;
constructor(label: string, kind?: CompletionItemKind) {
this.label = label;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册