提交 883936de 编写于 作者: J Johannes Rieken

modernize vscode.executeCompletionItemProvider-command

上级 4e4f02f6
......@@ -6,7 +6,6 @@
import { onUnexpectedExternalError, canceled, isPromiseCanceledError } from 'vs/base/common/errors';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions';
import * as modes from 'vs/editor/common/modes';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
......@@ -18,6 +17,10 @@ import { isDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifec
import { MenuId } from 'vs/platform/actions/common/actions';
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
import { StopWatch } from 'vs/base/common/stopwatch';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { assertType } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
export const Context = {
Visible: new RawContextKey<boolean>('suggestWidgetVisible', false),
......@@ -341,31 +344,42 @@ export function getSuggestionComparator(snippetConfig: SnippetSortOrder): (a: Co
return _snippetComparators.get(snippetConfig)!;
}
registerDefaultLanguageCommand('_executeCompletionItemProvider', async (model, position, args) => {
CommandsRegistry.registerCommand('_executeCompletionItemProvider', async (accessor, ...args: [URI, IPosition, string?, number?]) => {
const [uri, position, triggerCharacter, maxItemsToResolve] = args;
assertType(URI.isUri(uri));
assertType(Position.isIPosition(position));
assertType(typeof triggerCharacter === 'string' || !triggerCharacter);
assertType(typeof maxItemsToResolve === 'number' || !maxItemsToResolve);
const result: modes.CompletionList = {
incomplete: false,
suggestions: []
};
const ref = await accessor.get(ITextModelService).createModelReference(uri);
try {
const resolving: Promise<any>[] = [];
const maxItemsToResolve = args['maxItemsToResolve'] || 0;
const result: modes.CompletionList = {
incomplete: false,
suggestions: []
};
const completions = await provideSuggestionItems(model, position);
for (const item of completions.items) {
if (resolving.length < maxItemsToResolve) {
resolving.push(item.resolve(CancellationToken.None));
const resolving: Promise<any>[] = [];
const completions = await provideSuggestionItems(ref.object.textEditorModel, Position.lift(position), undefined, { triggerCharacter, triggerKind: triggerCharacter ? modes.CompletionTriggerKind.TriggerCharacter : modes.CompletionTriggerKind.Invoke });
for (const item of completions.items) {
if (resolving.length < (maxItemsToResolve ?? 0)) {
resolving.push(item.resolve(CancellationToken.None));
}
result.incomplete = result.incomplete || item.container.incomplete;
result.suggestions.push(item.completion);
}
try {
await Promise.all(resolving);
return result;
} finally {
setTimeout(() => completions.disposable.dispose(), 100);
}
result.incomplete = result.incomplete || item.container.incomplete;
result.suggestions.push(item.completion);
}
try {
await Promise.all(resolving);
return result;
} finally {
setTimeout(() => completions.disposable.dispose(), 100);
ref.dispose();
}
});
interface SuggestController extends IEditorContribution {
......
......@@ -12,7 +12,7 @@ import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto, IIncomingCallD
import * as modes from 'vs/editor/common/modes';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter, OpenIssueReporterArgs } from './apiCommands';
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
......@@ -43,7 +43,7 @@ export class ApiCommandResult<V, O = V> {
constructor(
readonly description: string,
readonly convert: (v: V, apiArgs: any[]) => O
readonly convert: (v: V, apiArgs: any[], cmdConverter: CommandsConverter) => O
) { }
}
......@@ -69,7 +69,7 @@ export class ApiCommand {
});
const internalResult = await commands.executeCommand(this.internalId, ...internalArgs);
return this.result.convert(internalResult, apiArgs);
return this.result.convert(internalResult, apiArgs, commands.converter);
}, undefined, this._getCommandHandlerDesc());
}
......@@ -235,6 +235,23 @@ const newCommands: ApiCommand[] = [
'vscode.executeLinkProvider', '_executeLinkProvider', 'Execute document link provider.',
[ApiCommandArgument.Uri, new ApiCommandArgument('linkResolveCount', '(optional) Number of links that should be resolved, only when links are unresolved.', v => typeof v === 'number' || typeof v === 'undefined', v => v)],
new ApiCommandResult<modes.ILink[], vscode.DocumentLink[]>('A promise that resolves to an array of DocumentLink-instances.', value => value.map(typeConverters.DocumentLink.to))
),
// --- completions
new ApiCommand(
'vscode.executeCompletionItemProvider', '_executeCompletionItemProvider', 'Execute completion item provider.',
[
ApiCommandArgument.Uri,
ApiCommandArgument.Position,
new ApiCommandArgument('triggerCharacter', '(optional) Trigger completion when the user types the character, like `,` or `(`', v => typeof v === 'string' || typeof v === 'undefined', v => v),
new ApiCommandArgument('itemResolveCount', '(optional) Number of completions to resolve (too large numbers slow down completions)', v => typeof v === 'number' || typeof v === 'undefined', v => v)
],
new ApiCommandResult<modes.CompletionList, vscode.CompletionList>('A promise that resolves to a CompletionList-instance.', (value, _args, converter) => {
if (!value) {
return new types.CompletionList([]);
}
const items = value.suggestions.map(suggestion => typeConverters.CompletionItem.to(suggestion, converter));
return new types.CompletionList(items, value.incomplete);
})
)
];
......@@ -267,16 +284,7 @@ export class ExtHostApiCommands {
],
returns: 'A promise that resolves to SignatureHelp.'
});
this._register('vscode.executeCompletionItemProvider', this._executeCompletionItemProvider, {
description: 'Execute completion item provider.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
{ name: 'triggerCharacter', description: '(optional) Trigger completion when the user types the character, like `,` or `(`', constraint: (value: any) => value === undefined || typeof value === 'string' },
{ name: 'itemResolveCount', description: '(optional) Number of completions to resolve (too large numbers slow down completions)', constraint: (value: any) => value === undefined || typeof value === 'number' }
],
returns: 'A promise that resolves to a CompletionList-instance.'
});
this._register('vscode.executeCodeActionProvider', this._executeCodeActionProvider, {
description: 'Execute code action provider.',
args: [
......@@ -402,22 +410,6 @@ export class ExtHostApiCommands {
});
}
private _executeCompletionItemProvider(resource: URI, position: types.Position, triggerCharacter: string, maxItemsToResolve: number): Promise<types.CompletionList | undefined> {
const args = {
resource,
position: position && typeConverters.Position.from(position),
triggerCharacter,
maxItemsToResolve
};
return this._commands.executeCommand<modes.CompletionList>('_executeCompletionItemProvider', args).then(result => {
if (result) {
const items = result.suggestions.map(suggestion => typeConverters.CompletionItem.to(suggestion, this._commands.converter));
return new types.CompletionList(items, result.incomplete);
}
return undefined;
});
}
private _executeDocumentColorProvider(resource: URI): Promise<types.ColorInformation[]> {
const args = {
resource
......
......@@ -28,7 +28,7 @@ import 'vs/workbench/contrib/search/browser/search.contribution';
import { NullLogService } from 'vs/platform/log/common/log';
import { ITextModel } from 'vs/editor/common/model';
import { nullExtensionDescription, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { dispose } from 'vs/base/common/lifecycle';
import { dispose, ImmortalReference } from 'vs/base/common/lifecycle';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { mock } from 'vs/base/test/common/mock';
import { NullApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
......@@ -48,6 +48,7 @@ import 'vs/editor/contrib/parameterHints/provideSignatureHelp';
import 'vs/editor/contrib/smartSelect/smartSelect';
import 'vs/editor/contrib/suggest/suggest';
import 'vs/editor/contrib/rename/rename';
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
const defaultSelector = { scheme: 'far' };
const model: ITextModel = createTextModel(
......@@ -108,6 +109,13 @@ suite('ExtHostLanguageFeatureCommands', function () {
services.set(IModelService, new class extends mock<IModelService>() {
getModel() { return model; }
});
services.set(ITextModelService, new class extends mock<ITextModelService>() {
async createModelReference() {
return new ImmortalReference<IResolvedTextEditorModel>(new class extends mock<IResolvedTextEditorModel>() {
textEditorModel = model;
});
}
});
services.set(IEditorWorkerService, new class extends mock<IEditorWorkerService>() {
async computeMoreMinimalEdits(_uri: any, edits: any) {
return edits || undefined;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册