mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-20 20:10:11 -04:00
Merge from vscode 718331d6f3ebd1b571530ab499edb266ddd493d5
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/suggest';
|
||||
import 'vs/css!./media/suggestStatusBar';
|
||||
import 'vs/base/browser/ui/codiconLabel/codiconLabel'; // The codicon symbol styles are defined here and must be loaded
|
||||
import 'vs/editor/contrib/documentSymbols/outlineTree'; // The codicon symbol colors are defined here and must be loaded
|
||||
import * as nls from 'vs/nls';
|
||||
@@ -20,7 +21,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { Context as SuggestContext, CompletionItem } from './suggest';
|
||||
import { Context as SuggestContext, CompletionItem, suggestWidgetStatusbarMenu } from './suggest';
|
||||
import { CompletionModel } from './completionModel';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
@@ -39,8 +40,11 @@ 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 { flatten } from 'vs/base/common/arrays';
|
||||
import { flatten, isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
|
||||
const expandSuggestionDocsByDefault = false;
|
||||
|
||||
@@ -49,8 +53,8 @@ interface ISuggestionTemplateData {
|
||||
|
||||
/**
|
||||
* Flexbox
|
||||
* < ------- left ------- > < -------- right -------- >
|
||||
* <icon><label><signature> <qualifier><type><readmore>
|
||||
* < ------------- left ------------ > < --- right -- >
|
||||
* <icon><label><signature><qualifier> <type><readmore>
|
||||
*/
|
||||
left: HTMLElement;
|
||||
right: HTMLElement;
|
||||
@@ -301,7 +305,7 @@ class SuggestionDetails {
|
||||
private readonly widget: SuggestWidget,
|
||||
private readonly editor: ICodeEditor,
|
||||
private readonly markdownRenderer: MarkdownRenderer,
|
||||
private readonly triggerKeybindingLabel: string,
|
||||
private readonly kbToggleDetails: string,
|
||||
) {
|
||||
this.disposables = new DisposableStore();
|
||||
|
||||
@@ -316,7 +320,7 @@ class SuggestionDetails {
|
||||
|
||||
this.header = append(this.body, $('.header'));
|
||||
this.close = append(this.header, $('span.codicon.codicon-close'));
|
||||
this.close.title = nls.localize('readLess', "Read less...{0}", this.triggerKeybindingLabel);
|
||||
this.close.title = nls.localize('readLess', "Read less...{0}", this.kbToggleDetails);
|
||||
this.type = append(this.header, $('p.type'));
|
||||
|
||||
this.docs = append(this.body, $('p.docs'));
|
||||
@@ -340,7 +344,8 @@ class SuggestionDetails {
|
||||
}
|
||||
|
||||
renderItem(item: CompletionItem, explainMode: boolean): void {
|
||||
this.renderDisposeable = dispose(this.renderDisposeable);
|
||||
dispose(this.renderDisposeable);
|
||||
this.renderDisposeable = undefined;
|
||||
|
||||
let { documentation, detail } = item.completion;
|
||||
// --- documentation
|
||||
@@ -447,7 +452,8 @@ class SuggestionDetails {
|
||||
|
||||
dispose(): void {
|
||||
this.disposables.dispose();
|
||||
this.renderDisposeable = dispose(this.renderDisposeable);
|
||||
dispose(this.renderDisposeable);
|
||||
this.renderDisposeable = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,12 +485,14 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
private element: HTMLElement;
|
||||
private messageElement: HTMLElement;
|
||||
private listElement: HTMLElement;
|
||||
private statusBarElement: HTMLElement;
|
||||
private details: SuggestionDetails;
|
||||
private list: List<CompletionItem>;
|
||||
private listHeight?: number;
|
||||
|
||||
private readonly suggestWidgetVisible: IContextKey<boolean>;
|
||||
private readonly suggestWidgetMultipleSuggestions: IContextKey<boolean>;
|
||||
private readonly ctxSuggestWidgetVisible: IContextKey<boolean>;
|
||||
private readonly ctxSuggestWidgetDetailsVisible: IContextKey<boolean>;
|
||||
private readonly ctxSuggestWidgetMultipleSuggestions: IContextKey<boolean>;
|
||||
|
||||
private readonly showTimeout = new TimeoutTimer();
|
||||
private readonly toDispose = new DisposableStore();
|
||||
@@ -517,18 +525,19 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
constructor(
|
||||
private readonly editor: ICodeEditor,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
) {
|
||||
const kb = keybindingService.lookupKeybinding('editor.action.triggerSuggest');
|
||||
const triggerKeybindingLabel = !kb ? '' : ` (${kb.getLabel()})`;
|
||||
const markdownRenderer = this.toDispose.add(new MarkdownRenderer(editor, modeService, openerService));
|
||||
|
||||
const kbToggleDetails = keybindingService.lookupKeybinding('toggleSuggestionDetails')?.getLabel() ?? '';
|
||||
|
||||
this.isAuto = false;
|
||||
this.focusedItem = null;
|
||||
this.storageService = storageService;
|
||||
@@ -542,12 +551,55 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
|
||||
this.messageElement = append(this.element, $('.message'));
|
||||
this.listElement = append(this.element, $('.tree'));
|
||||
this.details = instantiationService.createInstance(SuggestionDetails, this.element, this, this.editor, markdownRenderer, triggerKeybindingLabel);
|
||||
|
||||
const applyStatusBarStyle = () => toggleClass(this.element, 'with-status-bar', !this.editor.getOption(EditorOption.suggest).hideStatusBar);
|
||||
applyStatusBarStyle();
|
||||
|
||||
this.statusBarElement = append(this.element, $('.suggest-status-bar'));
|
||||
const actionViewItemProvider = <IActionViewItemProvider>(action => {
|
||||
const kb = keybindingService.lookupKeybindings(action.id);
|
||||
return new class extends ActionViewItem {
|
||||
constructor() {
|
||||
super(undefined, action, { label: true, icon: false });
|
||||
}
|
||||
updateLabel() {
|
||||
if (isFalsyOrEmpty(kb) || !this.label) {
|
||||
return super.updateLabel();
|
||||
}
|
||||
const { label } = this.getAction();
|
||||
this.label.textContent = /{\d}/.test(label)
|
||||
? strings.format(this.getAction().label, kb[0].getLabel())
|
||||
: `${this.getAction().label} (${kb[0].getLabel()})`;
|
||||
}
|
||||
};
|
||||
});
|
||||
const leftActions = new ActionBar(this.statusBarElement, { actionViewItemProvider });
|
||||
const rightActions = new ActionBar(this.statusBarElement, { actionViewItemProvider });
|
||||
const menu = menuService.createMenu(suggestWidgetStatusbarMenu, contextKeyService);
|
||||
const renderMenu = () => {
|
||||
const left: IAction[] = [];
|
||||
const right: IAction[] = [];
|
||||
for (let [group, actions] of menu.getActions()) {
|
||||
if (group === 'left') {
|
||||
left.push(...actions);
|
||||
} else {
|
||||
right.push(...actions);
|
||||
}
|
||||
}
|
||||
leftActions.clear();
|
||||
leftActions.push(left);
|
||||
rightActions.clear();
|
||||
rightActions.push(right);
|
||||
};
|
||||
this.toDispose.add(menu.onDidChange(() => renderMenu()));
|
||||
this.toDispose.add(menu);
|
||||
|
||||
this.details = instantiationService.createInstance(SuggestionDetails, this.element, this, this.editor, markdownRenderer, kbToggleDetails);
|
||||
|
||||
const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons);
|
||||
applyIconStyle();
|
||||
|
||||
let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, triggerKeybindingLabel);
|
||||
let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, kbToggleDetails);
|
||||
|
||||
this.list = new List('SuggestWidget', this.listElement, this, [renderer], {
|
||||
useShadows: false,
|
||||
@@ -582,10 +634,16 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.toDispose.add(this.list.onSelectionChange(e => this.onListSelection(e)));
|
||||
this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e)));
|
||||
this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged()));
|
||||
this.toDispose.add(this.editor.onDidChangeConfiguration(e => { if (e.hasChanged(EditorOption.suggest)) { applyIconStyle(); } }));
|
||||
this.toDispose.add(this.editor.onDidChangeConfiguration(e => {
|
||||
if (e.hasChanged(EditorOption.suggest)) {
|
||||
applyStatusBarStyle();
|
||||
applyIconStyle();
|
||||
}
|
||||
}));
|
||||
|
||||
this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService);
|
||||
this.suggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService);
|
||||
this.ctxSuggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService);
|
||||
this.ctxSuggestWidgetDetailsVisible = SuggestContext.DetailsVisible.bindTo(contextKeyService);
|
||||
this.ctxSuggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService);
|
||||
|
||||
this.editor.addContentWidget(this);
|
||||
this.setState(State.Hidden);
|
||||
@@ -661,12 +719,14 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
const backgroundColor = theme.getColor(editorSuggestWidgetBackground);
|
||||
if (backgroundColor) {
|
||||
this.listElement.style.backgroundColor = backgroundColor.toString();
|
||||
this.statusBarElement.style.backgroundColor = backgroundColor.toString();
|
||||
this.details.element.style.backgroundColor = backgroundColor.toString();
|
||||
this.messageElement.style.backgroundColor = backgroundColor.toString();
|
||||
}
|
||||
const borderColor = theme.getColor(editorSuggestWidgetBorder);
|
||||
if (borderColor) {
|
||||
this.listElement.style.borderColor = borderColor.toString();
|
||||
this.statusBarElement.style.borderColor = borderColor.toString();
|
||||
this.details.element.style.borderColor = borderColor.toString();
|
||||
this.messageElement.style.borderColor = borderColor.toString();
|
||||
this.detailsBorderColor = borderColor.toString();
|
||||
@@ -704,7 +764,6 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.firstFocusInCurrentList = !this.focusedItem;
|
||||
if (item !== this.focusedItem) {
|
||||
|
||||
|
||||
if (this.currentSuggestionDetails) {
|
||||
this.currentSuggestionDetails.cancel();
|
||||
this.currentSuggestionDetails = null;
|
||||
@@ -759,7 +818,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
|
||||
switch (state) {
|
||||
case State.Hidden:
|
||||
hide(this.messageElement, this.details.element, this.listElement);
|
||||
hide(this.messageElement, this.details.element, this.listElement, this.statusBarElement);
|
||||
this.hide();
|
||||
this.listHeight = 0;
|
||||
if (stateChanged) {
|
||||
@@ -769,7 +828,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
break;
|
||||
case State.Loading:
|
||||
this.messageElement.textContent = SuggestWidget.LOADING_MESSAGE;
|
||||
hide(this.listElement, this.details.element);
|
||||
hide(this.listElement, this.details.element, this.statusBarElement);
|
||||
show(this.messageElement);
|
||||
removeClass(this.element, 'docs-side');
|
||||
this.show();
|
||||
@@ -777,7 +836,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
break;
|
||||
case State.Empty:
|
||||
this.messageElement.textContent = SuggestWidget.NO_SUGGESTIONS_MESSAGE;
|
||||
hide(this.listElement, this.details.element);
|
||||
hide(this.listElement, this.details.element, this.statusBarElement);
|
||||
show(this.messageElement);
|
||||
removeClass(this.element, 'docs-side');
|
||||
this.show();
|
||||
@@ -785,7 +844,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
break;
|
||||
case State.Open:
|
||||
hide(this.messageElement);
|
||||
show(this.listElement);
|
||||
show(this.listElement, this.statusBarElement);
|
||||
this.show();
|
||||
break;
|
||||
case State.Frozen:
|
||||
@@ -795,7 +854,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
break;
|
||||
case State.Details:
|
||||
hide(this.messageElement);
|
||||
show(this.details.element, this.listElement);
|
||||
show(this.details.element, this.listElement, this.statusBarElement);
|
||||
this.show();
|
||||
break;
|
||||
}
|
||||
@@ -836,7 +895,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
let visibleCount = this.completionModel.items.length;
|
||||
|
||||
const isEmpty = visibleCount === 0;
|
||||
this.suggestWidgetMultipleSuggestions.set(visibleCount > 1);
|
||||
this.ctxSuggestWidgetMultipleSuggestions.set(visibleCount > 1);
|
||||
|
||||
if (isEmpty) {
|
||||
if (isAuto) {
|
||||
@@ -1003,6 +1062,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
}
|
||||
|
||||
if (this.expandDocsSettingFromStorage()) {
|
||||
this.ctxSuggestWidgetDetailsVisible.set(false);
|
||||
this.updateExpandDocsSetting(false);
|
||||
hide(this.details.element);
|
||||
removeClass(this.element, 'docs-side');
|
||||
@@ -1014,6 +1074,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
return;
|
||||
}
|
||||
|
||||
this.ctxSuggestWidgetDetailsVisible.set(true);
|
||||
this.updateExpandDocsSetting(true);
|
||||
this.showDetails(false);
|
||||
this.telemetryService.publicLog2('suggestWidget:expandDetails');
|
||||
@@ -1021,7 +1082,10 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
}
|
||||
|
||||
showDetails(loading: boolean): void {
|
||||
this.expandSideOrBelow();
|
||||
if (!loading) {
|
||||
// When loading, don't re-layout docs, as item is not resolved yet #88731
|
||||
this.expandSideOrBelow();
|
||||
}
|
||||
|
||||
show(this.details.element);
|
||||
|
||||
@@ -1058,7 +1122,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.listHeight = newHeight;
|
||||
}
|
||||
|
||||
this.suggestWidgetVisible.set(true);
|
||||
this.ctxSuggestWidgetVisible.set(true);
|
||||
|
||||
this.showTimeout.cancelAndSet(() => {
|
||||
addClass(this.element, 'visible');
|
||||
@@ -1067,8 +1131,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
}
|
||||
|
||||
private hide(): void {
|
||||
this.suggestWidgetVisible.reset();
|
||||
this.suggestWidgetMultipleSuggestions.reset();
|
||||
this.ctxSuggestWidgetVisible.reset();
|
||||
this.ctxSuggestWidgetMultipleSuggestions.reset();
|
||||
removeClass(this.element, 'visible');
|
||||
}
|
||||
|
||||
@@ -1119,6 +1183,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
|
||||
this.element.style.lineHeight = `${this.unfocusedHeight}px`;
|
||||
this.listElement.style.height = `${height}px`;
|
||||
this.statusBarElement.style.top = `${height}px`;
|
||||
this.list.layout(height);
|
||||
return height;
|
||||
}
|
||||
@@ -1172,7 +1237,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the proper classes for positioning the docs to the side or below
|
||||
* Adds the proper classes for positioning the docs to the side or below depending on item
|
||||
*/
|
||||
private expandSideOrBelow() {
|
||||
if (!canExpandCompletionItem(this.focusedItem) && this.firstFocusInCurrentList) {
|
||||
|
||||
Reference in New Issue
Block a user