From e22ef32f659b99e3fccbd703d864b5d754c485b4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 28 Jun 2019 12:56:52 +0200 Subject: [PATCH 1/3] add editor.suggest._explain-setting which replaces suggest details with score, distance, index information --- .../editor/contrib/suggest/suggestWidget.ts | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 7dabc8b16a5..3ea9a62625e 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -37,6 +37,8 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { FileKind } from 'vs/platform/files/common/files'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const expandSuggestionDocsByDefault = false; @@ -247,7 +249,8 @@ class SuggestionDetails { private readonly widget: SuggestWidget, private readonly editor: ICodeEditor, private readonly markdownRenderer: MarkdownRenderer, - private readonly triggerKeybindingLabel: string + private readonly triggerKeybindingLabel: string, + @IConfigurationService private readonly _configService: IConfigurationService, ) { this.disposables = []; @@ -289,7 +292,20 @@ class SuggestionDetails { renderItem(item: CompletionItem): void { this.renderDisposeable = dispose(this.renderDisposeable); - if (!item || !canExpandCompletionItem(item)) { + let { documentation, detail } = item.completion; + const shouldExplain = this._configService.getValue('editor.suggest._explain'); + // --- documentation + + if (shouldExplain) { + let md = ''; + md += `score: ${item.score[0]}${item.word ? `, compared '${item.completion.filterText && (item.completion.filterText + ' (filterText)') || item.completion.label}' with '${item.word}'` : ' (no prefix)'}\n`; + md += `distance: ${item.distance}, see localityBonus-setting\n`; + md += `index: ${item.idx}, ${item.completion.sortText && (`'${item.completion.sortText}' (sortText)`) || 'extension order'}\n`; + documentation = new MarkdownString().appendCodeblock('empty', md); + detail = undefined; + } + + if (!shouldExplain && !canExpandCompletionItem(item)) { this.type.textContent = ''; this.docs.textContent = ''; addClass(this.el, 'no-docs'); @@ -297,19 +313,20 @@ class SuggestionDetails { return; } removeClass(this.el, 'no-docs'); - if (typeof item.completion.documentation === 'string') { + if (typeof documentation === 'string') { removeClass(this.docs, 'markdown-docs'); - this.docs.textContent = item.completion.documentation; + this.docs.textContent = documentation; } else { addClass(this.docs, 'markdown-docs'); this.docs.innerHTML = ''; - const renderedContents = this.markdownRenderer.render(item.completion.documentation); + const renderedContents = this.markdownRenderer.render(documentation); this.renderDisposeable = renderedContents; this.docs.appendChild(renderedContents.element); } - if (item.completion.detail) { - this.type.innerText = item.completion.detail; + // --- details + if (detail) { + this.type.innerText = detail; show(this.type); } else { this.type.innerText = ''; @@ -333,8 +350,8 @@ class SuggestionDetails { this.ariaLabel = strings.format( '{0}{1}', - item.completion.detail || '', - item.completion.documentation ? (typeof item.completion.documentation === 'string' ? item.completion.documentation : item.completion.documentation.value) : ''); + detail || '', + documentation ? (typeof documentation === 'string' ? documentation : documentation.value) : ''); } getAriaLabel() { @@ -479,7 +496,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate toggleClass(this.element, 'no-icons', !this.editor.getConfiguration().contribInfo.suggest.showIcons); applyIconStyle(); From 5f406230c9d60bd0bf9ae5c67f506597013e18c1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 1 Jul 2019 09:43:41 +0200 Subject: [PATCH 2/3] use keybinding instead of setting, show provider name (iff possible) --- src/vs/editor/common/modes.ts | 5 ++++ .../services/editorWorkerServiceImpl.ts | 2 ++ .../editor/contrib/suggest/suggestWidget.ts | 23 ++++++++++++++----- .../api/browser/mainThreadLanguageFeatures.ts | 3 ++- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostLanguageFeatures.ts | 2 +- .../browser/snippetCompletionProvider.ts | 2 ++ 7 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index da61c64e070..0616ed0e7a6 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -510,6 +510,11 @@ export interface CompletionContext { */ export interface CompletionItemProvider { + /** + * @internal + */ + _debugDisplayName?: string; + triggerCharacters?: string[]; /** * Provide completion items for the given position and document. diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index d42a7f7782e..6cefce59c2c 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -133,6 +133,8 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { private readonly _configurationService: ITextResourceConfigurationService; private readonly _modelService: IModelService; + readonly _debugDisplayName = 'wordbasedCompletions'; + constructor( workerManager: WorkerManager, configurationService: ITextResourceConfigurationService, diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 3ea9a62625e..17ffa84b03a 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -38,7 +38,8 @@ import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { FileKind } from 'vs/platform/files/common/files'; import { MarkdownString } from 'vs/base/common/htmlContent'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; const expandSuggestionDocsByDefault = false; @@ -230,6 +231,18 @@ const enum State { Details } + +let _explainMode = false; +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'suggest.toggleExplainMode', + handler() { + _explainMode = !_explainMode; + }, + when: SuggestContext.Visible, + weight: KeybindingWeight.EditorContrib, + primary: KeyMod.CtrlCmd | KeyCode.US_SLASH, +}); + class SuggestionDetails { private el: HTMLElement; @@ -250,7 +263,6 @@ class SuggestionDetails { private readonly editor: ICodeEditor, private readonly markdownRenderer: MarkdownRenderer, private readonly triggerKeybindingLabel: string, - @IConfigurationService private readonly _configService: IConfigurationService, ) { this.disposables = []; @@ -293,19 +305,18 @@ class SuggestionDetails { this.renderDisposeable = dispose(this.renderDisposeable); let { documentation, detail } = item.completion; - const shouldExplain = this._configService.getValue('editor.suggest._explain'); // --- documentation - if (shouldExplain) { + if (_explainMode) { let md = ''; md += `score: ${item.score[0]}${item.word ? `, compared '${item.completion.filterText && (item.completion.filterText + ' (filterText)') || item.completion.label}' with '${item.word}'` : ' (no prefix)'}\n`; md += `distance: ${item.distance}, see localityBonus-setting\n`; md += `index: ${item.idx}, ${item.completion.sortText && (`'${item.completion.sortText}' (sortText)`) || 'extension order'}\n`; documentation = new MarkdownString().appendCodeblock('empty', md); - detail = undefined; + detail = `Provider: ${item.provider._debugDisplayName}`; } - if (!shouldExplain && !canExpandCompletionItem(item)) { + if (!_explainMode && !canExpandCompletionItem(item)) { this.type.textContent = ''; this.docs.textContent = ''; addClass(this.el, 'no-docs'); diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 1b55da3d731..d54e01d9a9b 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -346,9 +346,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha }; } - $registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void { + $registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void { const provider: modes.CompletionItemProvider = { triggerCharacters, + _debugDisplayName: extensionId.value, provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise => { return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => { if (!result) { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 2f51c54ee7c..f9f60f7dde7 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -348,7 +348,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void; $registerNavigateTypeSupport(handle: number): void; $registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportsResolveInitialValues: boolean): void; - $registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void; + $registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void; $registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void; $registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[], supportsResolve: boolean): void; $registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 4aefb1cc5d6..84e28939bb3 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1380,7 +1380,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerCompletionItemProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable { const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider), extension); - this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider)); + this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider), extension.identifier); return this._createDisposable(handle); } diff --git a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts index 106ca8be945..87ca39e297c 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts @@ -64,6 +64,8 @@ export class SnippetCompletionProvider implements CompletionItemProvider { private static readonly _maxPrefix = 10000; + readonly _debugDisplayName = 'snippetCompletions'; + constructor( @IModeService private readonly _modeService: IModeService, From 162c502a36a4be66818db142dda48172a99f53fb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 1 Jul 2019 09:52:35 +0200 Subject: [PATCH 3/3] better wording for sort text --- src/vs/editor/contrib/suggest/suggestWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 17ffa84b03a..fd6c81d0fac 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -311,7 +311,7 @@ class SuggestionDetails { let md = ''; md += `score: ${item.score[0]}${item.word ? `, compared '${item.completion.filterText && (item.completion.filterText + ' (filterText)') || item.completion.label}' with '${item.word}'` : ' (no prefix)'}\n`; md += `distance: ${item.distance}, see localityBonus-setting\n`; - md += `index: ${item.idx}, ${item.completion.sortText && (`'${item.completion.sortText}' (sortText)`) || 'extension order'}\n`; + md += `index: ${item.idx}, based on ${item.completion.sortText && `sortText: "${item.completion.sortText}"` || 'label'}\n`; documentation = new MarkdownString().appendCodeblock('empty', md); detail = `Provider: ${item.provider._debugDisplayName}`; }