未验证 提交 cb63d2dd 编写于 作者: D Daniel Imms 提交者: GitHub

Merge pull request #97834 from microsoft/tyriar/97496

Move common parts of editor and terminal hover widget into base ui
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor-hover {
.monaco-hover {
cursor: default;
position: absolute;
overflow: hidden;
......@@ -16,34 +16,34 @@
line-height: 1.5em;
}
.monaco-editor-hover.hidden {
.monaco-hover.hidden {
display: none;
}
.monaco-editor-hover .hover-contents {
.monaco-hover .hover-contents {
padding: 4px 8px;
}
.monaco-editor-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
max-width: 500px;
word-wrap: break-word;
}
.monaco-editor-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
/* This is a strange rule but it avoids https://github.com/microsoft/vscode/issues/96795, just 100vw on its own caused the actual hover width to increase */
min-width: calc(100% + 100vw);
}
.monaco-editor-hover p,
.monaco-editor-hover ul {
.monaco-hover p,
.monaco-hover ul {
margin: 8px 0;
}
.monaco-editor-hover code {
.monaco-hover code {
font-family: var(--monaco-monospace-font);
}
.monaco-editor-hover hr {
.monaco-hover hr {
margin-top: 4px;
margin-bottom: -6px;
margin-left: -10px;
......@@ -51,78 +51,78 @@
height: 1px;
}
.monaco-editor-hover p:first-child,
.monaco-editor-hover ul:first-child {
.monaco-hover p:first-child,
.monaco-hover ul:first-child {
margin-top: 0;
}
.monaco-editor-hover p:last-child,
.monaco-editor-hover ul:last-child {
.monaco-hover p:last-child,
.monaco-hover ul:last-child {
margin-bottom: 0;
}
/* MarkupContent Layout */
.monaco-editor-hover ul {
.monaco-hover ul {
padding-left: 20px;
}
.monaco-editor-hover ol {
.monaco-hover ol {
padding-left: 20px;
}
.monaco-editor-hover li > p {
.monaco-hover li > p {
margin-bottom: 0;
}
.monaco-editor-hover li > ul {
.monaco-hover li > ul {
margin-top: 0;
}
.monaco-editor-hover code {
.monaco-hover code {
border-radius: 3px;
padding: 0 0.4em;
}
.monaco-editor-hover .monaco-tokenized-source {
.monaco-hover .monaco-tokenized-source {
white-space: pre-wrap;
word-break: break-all;
}
.monaco-editor-hover .hover-row.status-bar {
.monaco-hover .hover-row.status-bar {
font-size: 12px;
line-height: 22px;
}
.monaco-editor-hover .hover-row.status-bar .actions {
.monaco-hover .hover-row.status-bar .actions {
display: flex;
padding: 0px 8px;
}
.monaco-editor-hover .hover-row.status-bar .actions .action-container {
.monaco-hover .hover-row.status-bar .actions .action-container {
margin-right: 16px;
cursor: pointer;
}
.monaco-editor-hover .hover-row.status-bar .actions .action-container .action .icon {
.monaco-hover .hover-row.status-bar .actions .action-container .action .icon {
padding-right: 4px;
}
.monaco-editor-hover .markdown-hover .hover-contents .codicon {
.monaco-hover .markdown-hover .hover-contents .codicon {
color: inherit;
font-size: inherit;
vertical-align: middle;
}
.monaco-editor-hover .hover-contents a.code-link:before {
.monaco-hover .hover-contents a.code-link:before {
content: '(';
}
.monaco-editor-hover .hover-contents a.code-link:after {
.monaco-hover .hover-contents a.code-link:after {
content: ')';
}
.monaco-editor-hover .hover-contents a.code-link {
.monaco-hover .hover-contents a.code-link {
color: inherit;
}
.monaco-editor-hover .hover-contents a.code-link > span {
.monaco-hover .hover-contents a.code-link > span {
text-decoration: underline;
/** Hack to force underline to show **/
border-bottom: 1px solid transparent;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./hover';
import * as dom from 'vs/base/browser/dom';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
const $ = dom.$;
export class HoverWidget extends Disposable {
public readonly containerDomNode: HTMLElement;
public readonly contentsDomNode: HTMLElement;
private readonly _scrollbar: DomScrollableElement;
constructor() {
super();
this.containerDomNode = document.createElement('div');
this.containerDomNode.className = 'monaco-hover';
this.containerDomNode.tabIndex = 0;
this.containerDomNode.setAttribute('role', 'tooltip');
this.contentsDomNode = document.createElement('div');
this.contentsDomNode.className = 'monaco-hover-content';
this._scrollbar = this._register(new DomScrollableElement(this.contentsDomNode, {}));
this.containerDomNode.appendChild(this._scrollbar.getDomNode());
}
public onContentsChanged(): void {
this._scrollbar.scanDomNode();
}
}
export function renderHoverAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }, keybindingLabel: string | null): IDisposable {
const actionContainer = dom.append(parent, $('div.action-container'));
const action = dom.append(actionContainer, $('a.action'));
action.setAttribute('href', '#');
action.setAttribute('role', 'button');
if (actionOptions.iconClass) {
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
}
const label = dom.append(action, $('span'));
label.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
return dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
actionOptions.run(actionContainer);
});
}
......@@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./hover';
import * as nls from 'vs/nls';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
......@@ -205,7 +204,7 @@ export class ModesHoverController implements IEditorContribution {
}
private _createHoverWidgets() {
this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService);
this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._keybindingService, this._themeService, this._modeService, this._openerService);
this._glyphWidget.value = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService);
}
......@@ -312,29 +311,29 @@ registerThemingParticipant((theme, collector) => {
}
const hoverBackground = theme.getColor(editorHoverBackground);
if (hoverBackground) {
collector.addRule(`.monaco-editor .monaco-editor-hover { background-color: ${hoverBackground}; }`);
collector.addRule(`.monaco-editor .monaco-hover { background-color: ${hoverBackground}; }`);
}
const hoverBorder = theme.getColor(editorHoverBorder);
if (hoverBorder) {
collector.addRule(`.monaco-editor .monaco-editor-hover { border: 1px solid ${hoverBorder}; }`);
collector.addRule(`.monaco-editor .monaco-editor-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.monaco-editor .monaco-editor-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.monaco-editor .monaco-editor-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.monaco-editor .monaco-hover { border: 1px solid ${hoverBorder}; }`);
collector.addRule(`.monaco-editor .monaco-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.monaco-editor .monaco-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.monaco-editor .monaco-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(0.5)}; }`);
}
const link = theme.getColor(textLinkForeground);
if (link) {
collector.addRule(`.monaco-editor .monaco-editor-hover a { color: ${link}; }`);
collector.addRule(`.monaco-editor .monaco-hover a { color: ${link}; }`);
}
const hoverForeground = theme.getColor(editorHoverForeground);
if (hoverForeground) {
collector.addRule(`.monaco-editor .monaco-editor-hover { color: ${hoverForeground}; }`);
collector.addRule(`.monaco-editor .monaco-hover { color: ${hoverForeground}; }`);
}
const actionsBackground = theme.getColor(editorHoverStatusBarBackground);
if (actionsBackground) {
collector.addRule(`.monaco-editor .monaco-editor-hover .hover-row .actions { background-color: ${actionsBackground}; }`);
collector.addRule(`.monaco-editor .monaco-hover .hover-row .actions { background-color: ${actionsBackground}; }`);
}
const codeBackground = theme.getColor(textCodeBlockBackground);
if (codeBackground) {
collector.addRule(`.monaco-editor .monaco-editor-hover code { background-color: ${codeBackground}; }`);
collector.addRule(`.monaco-editor .monaco-hover code { background-color: ${codeBackground}; }`);
}
});
......@@ -3,27 +3,27 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { toggleClass } from 'vs/base/browser/dom';
import * as dom from 'vs/base/browser/dom';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { Widget } from 'vs/base/browser/ui/widget';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { renderHoverAction, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
export class ContentHoverWidget extends Widget implements IContentWidget {
protected readonly _hover: HoverWidget;
private readonly _id: string;
protected _editor: ICodeEditor;
private _isVisible: boolean;
private readonly _containerDomNode: HTMLElement;
protected readonly _domNode: HTMLElement;
protected _showAtPosition: Position | null;
protected _showAtRange: Range | null;
private _stoleFocus: boolean;
private readonly scrollbar: DomScrollableElement;
// Editor.IContentWidget.allowEditorOverflow
public allowEditorOverflow = true;
......@@ -34,29 +34,23 @@ export class ContentHoverWidget extends Widget implements IContentWidget {
protected set isVisible(value: boolean) {
this._isVisible = value;
toggleClass(this._containerDomNode, 'hidden', !this._isVisible);
dom.toggleClass(this._hover.containerDomNode, 'hidden', !this._isVisible);
}
constructor(id: string, editor: ICodeEditor) {
constructor(
id: string,
editor: ICodeEditor,
private readonly _keybindingService: IKeybindingService
) {
super();
this._hover = this._register(new HoverWidget());
this._id = id;
this._editor = editor;
this._isVisible = false;
this._stoleFocus = false;
this._containerDomNode = document.createElement('div');
this._containerDomNode.className = 'monaco-editor-hover hidden';
this._containerDomNode.tabIndex = 0;
this._containerDomNode.setAttribute('role', 'tooltip');
this._domNode = document.createElement('div');
this._domNode.className = 'monaco-editor-hover-content';
this.scrollbar = new DomScrollableElement(this._domNode, {});
this._register(this.scrollbar);
this._containerDomNode.appendChild(this.scrollbar.getDomNode());
this.onkeydown(this._containerDomNode, (e: IKeyboardEvent) => {
this.onkeydown(this._hover.containerDomNode, (e: IKeyboardEvent) => {
if (e.equals(KeyCode.Escape)) {
this.hide();
}
......@@ -82,7 +76,7 @@ export class ContentHoverWidget extends Widget implements IContentWidget {
}
public getDomNode(): HTMLElement {
return this._containerDomNode;
return this._hover.containerDomNode;
}
public showAt(position: Position, range: Range | null, focus: boolean): void {
......@@ -97,7 +91,7 @@ export class ContentHoverWidget extends Widget implements IContentWidget {
this._editor.render();
this._stoleFocus = focus;
if (focus) {
this._containerDomNode.focus();
this._hover.containerDomNode.focus();
}
}
......@@ -134,31 +128,33 @@ export class ContentHoverWidget extends Widget implements IContentWidget {
}
private updateFont(): void {
const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._domNode.getElementsByClassName('code'));
const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));
codeClasses.forEach(node => this._editor.applyFontInfo(node));
}
protected updateContents(node: Node): void {
this._domNode.textContent = '';
this._domNode.appendChild(node);
this._hover.contentsDomNode.textContent = '';
this._hover.contentsDomNode.appendChild(node);
this.updateFont();
this._editor.layoutContentWidget(this);
this.onContentsChange();
this._hover.onContentsChanged();
}
protected onContentsChange(): void {
this.scrollbar.scanDomNode();
protected _renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
return renderHoverAction(parent, actionOptions, keybindingLabel);
}
private layout(): void {
const height = Math.max(this._editor.getLayoutInfo().height / 4, 250);
const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo);
this._domNode.style.fontSize = `${fontSize}px`;
this._domNode.style.lineHeight = `${lineHeight}px`;
this._domNode.style.maxHeight = `${height}px`;
this._domNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;
this._hover.contentsDomNode.style.fontSize = `${fontSize}px`;
this._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`;
this._hover.contentsDomNode.style.maxHeight = `${height}px`;
this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;
}
}
......@@ -177,7 +173,7 @@ export class GlyphHoverWidget extends Widget implements IOverlayWidget {
this._isVisible = false;
this._domNode = document.createElement('div');
this._domNode.className = 'monaco-editor-hover hidden';
this._domNode.className = 'monaco-hover hidden';
this._domNode.setAttribute('aria-hidden', 'true');
this._domNode.setAttribute('role', 'tooltip');
......@@ -198,7 +194,7 @@ export class GlyphHoverWidget extends Widget implements IOverlayWidget {
protected set isVisible(value: boolean) {
this._isVisible = value;
toggleClass(this._domNode, 'hidden', !this._isVisible);
dom.toggleClass(this._domNode, 'hidden', !this._isVisible);
}
public getId(): string {
......
......@@ -213,12 +213,12 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
constructor(
editor: ICodeEditor,
markerDecorationsService: IMarkerDecorationsService,
keybindingService: IKeybindingService,
private readonly _themeService: IThemeService,
private readonly _keybindingService: IKeybindingService,
private readonly _modeService: IModeService,
private readonly _openerService: IOpenerService = NullOpenerService,
) {
super(ModesContentHoverWidget.ID, editor);
super(ModesContentHoverWidget.ID, editor, keybindingService);
this._messages = [];
this._lastRange = null;
......@@ -249,7 +249,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
}));
this._register(TokenizationRegistry.onDidChange((e) => {
if (this.isVisible && this._lastRange && this._messages.length > 0) {
this._domNode.textContent = '';
this._hover.contentsDomNode.textContent = '';
this._renderMessages(this._lastRange, this._messages);
}
}));
......@@ -461,7 +461,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
const renderer = markdownDisposeables.add(new MarkdownRenderer(this._editor, this._modeService, this._openerService));
markdownDisposeables.add(renderer.onDidRenderCodeBlock(() => {
hoverContentsElement.className = 'hover-contents code-hover-contents';
this.onContentsChange();
this._hover.onContentsChanged();
}));
const renderedContents = markdownDisposeables.add(renderer.render(contents));
hoverContentsElement.appendChild(renderedContents.element);
......@@ -562,7 +562,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
const disposables = new DisposableStore();
const actionsElement = dom.append(hoverElement, $('div.actions'));
if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
disposables.add(this.renderAction(actionsElement, {
disposables.add(this._renderAction(actionsElement, {
label: nls.localize('peek problem', "Peek Problem"),
commandId: NextMarkerAction.ID,
run: () => {
......@@ -600,7 +600,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
}
}));
disposables.add(this.renderAction(actionsElement, {
disposables.add(this._renderAction(actionsElement, {
label: nls.localize('quick fixes', "Quick Fix..."),
commandId: QuickFixAction.Id,
run: (target) => {
......@@ -633,25 +633,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
});
}
private renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
const actionContainer = dom.append(parent, $('div.action-container'));
const action = dom.append(actionContainer, $('a.action'));
action.setAttribute('href', '#');
action.setAttribute('role', 'button');
if (actionOptions.iconClass) {
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
}
const label = dom.append(action, $('span'));
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
label.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
return dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
actionOptions.run(actionContainer);
});
}
private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({
className: 'hoverHighlight'
});
......@@ -683,6 +664,6 @@ function hoverContentsEquals(first: HoverPart[], second: HoverPart[]): boolean {
registerThemingParticipant((theme, collector) => {
const linkFg = theme.getColor(textLinkForeground);
if (linkFg) {
collector.addRule(`.monaco-editor-hover .hover-contents a.code-link span:hover { color: ${linkFg}; }`);
collector.addRule(`.monaco-hover .hover-contents a.code-link span:hover { color: ${linkFg}; }`);
}
});
......@@ -18,7 +18,7 @@
stroke-width: 1.2px;
}
.monaco-editor-hover p {
.monaco-hover p {
margin: 0;
}
......
......@@ -3,10 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
import { Widget } from 'vs/base/browser/ui/widget';
import { Event, Emitter } from 'vs/base/common/event';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { editorHoverHighlight, editorHoverBackground, editorHoverBorder, textLinkForeground, editorHoverForeground, editorHoverStatusBarBackground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry';
......@@ -14,23 +13,23 @@ import * as dom from 'vs/base/browser/dom';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IHoverTarget, HorizontalAnchorSide, VerticalAnchorSide } from 'vs/workbench/contrib/terminal/browser/widgets/widgets';
import { KeyCode } from 'vs/base/common/keyCodes';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { HoverWidget as BaseHoverWidget, renderHoverAction } from 'vs/base/browser/ui/hover/hoverWidget';
import { Widget } from 'vs/base/browser/ui/widget';
const $ = dom.$;
export class HoverWidget extends Widget {
private readonly _containerDomNode: HTMLElement;
private readonly _domNode: HTMLElement;
private readonly _messageListeners = new DisposableStore();
private readonly _mouseTracker: CompositeMouseTracker;
private readonly _scrollbar: DomScrollableElement;
private readonly _hover: BaseHoverWidget;
private _isDisposed: boolean = false;
get isDisposed(): boolean { return this._isDisposed; }
get domNode(): HTMLElement { return this._containerDomNode; }
get domNode(): HTMLElement { return this._hover.containerDomNode; }
private readonly _onDispose = new Emitter<void>();
get onDispose(): Event<void> { return this._onDispose.event; }
......@@ -45,24 +44,16 @@ export class HoverWidget extends Widget {
@IConfigurationService private readonly _configurationService: IConfigurationService
) {
super();
this._containerDomNode = document.createElement('div');
this._containerDomNode.classList.add('terminal-hover-widget', 'fadeIn', 'monaco-editor-hover', 'xterm-hover');
this._containerDomNode.tabIndex = 0;
this._containerDomNode.setAttribute('role', 'tooltip');
this._domNode = document.createElement('div');
this._domNode.className = 'monaco-editor-hover-content';
this._scrollbar = new DomScrollableElement(this._domNode, {});
this._register(this._scrollbar);
this._containerDomNode.appendChild(this._scrollbar.getDomNode());
this._hover = this._register(new BaseHoverWidget());
this._hover.containerDomNode.classList.add('terminal-hover-widget', 'fadeIn', 'xterm-hover');
// Don't allow mousedown out of the widget, otherwise preventDefault will call and text will
// not be selected.
this.onmousedown(this._containerDomNode, e => e.stopPropagation());
this.onmousedown(this._hover.containerDomNode, e => e.stopPropagation());
// Hide hover on escape
this.onkeydown(this._containerDomNode, e => {
this.onkeydown(this._hover.containerDomNode, e => {
if (e.equals(KeyCode.Escape)) {
this.dispose();
}
......@@ -86,96 +77,85 @@ export class HoverWidget extends Widget {
});
contentsElement.appendChild(markdownElement);
rowElement.appendChild(contentsElement);
this._domNode.appendChild(rowElement);
this._hover.contentsDomNode.appendChild(rowElement);
if (this._actions && this._actions.length > 0) {
const statusBarElement = $('div.hover-row.status-bar');
const actionsElement = $('div.actions');
this._actions.forEach(action => this._renderAction(actionsElement, action));
this._actions.forEach(action => {
const keybinding = this._keybindingService.lookupKeybinding(action.commandId);
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
renderHoverAction(actionsElement, action, keybindingLabel);
});
statusBarElement.appendChild(actionsElement);
this._containerDomNode.appendChild(statusBarElement);
this._hover.containerDomNode.appendChild(statusBarElement);
}
this._mouseTracker = new CompositeMouseTracker([this._containerDomNode, ..._target.targetElements]);
this._mouseTracker = new CompositeMouseTracker([this._hover.containerDomNode, ..._target.targetElements]);
this._register(this._mouseTracker.onMouseOut(() => this.dispose()));
this._register(this._mouseTracker);
this._container.appendChild(this._containerDomNode);
this._container.appendChild(this._hover.containerDomNode);
this.layout();
}
private _renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
const actionContainer = dom.append(parent, $('div.action-container'));
const action = dom.append(actionContainer, $('a.action'));
action.setAttribute('href', '#');
action.setAttribute('role', 'button');
if (actionOptions.iconClass) {
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
}
const label = dom.append(action, $('span'));
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
label.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
return dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
actionOptions.run(actionContainer);
});
}
public layout(): void {
const anchor = this._target.anchor;
this._containerDomNode.classList.remove('right-aligned');
this._domNode.style.maxHeight = '';
this._hover.containerDomNode.classList.remove('right-aligned');
this._hover.contentsDomNode.style.maxHeight = '';
if (anchor.horizontalAnchorSide === HorizontalAnchorSide.Left) {
if (anchor.x + this._containerDomNode.clientWidth > document.documentElement.clientWidth) {
if (anchor.x + this._hover.containerDomNode.clientWidth > document.documentElement.clientWidth) {
// Shift the hover to the left when part of it would get cut off
const width = Math.round(this._containerDomNode.clientWidth);
this._containerDomNode.style.width = `${width - 1}px`;
this._containerDomNode.style.maxWidth = '';
const width = Math.round(this._hover.containerDomNode.clientWidth);
this._hover.containerDomNode.style.width = `${width - 1}px`;
this._hover.containerDomNode.style.maxWidth = '';
const left = document.documentElement.clientWidth - width - 1;
this._containerDomNode.style.left = `${left}px`;
this._hover.containerDomNode.style.left = `${left}px`;
// Right align if the right edge is closer to the anchor than the left edge
if (left + width / 2 < anchor.x) {
this._containerDomNode.classList.add('right-aligned');
this._hover.containerDomNode.classList.add('right-aligned');
}
} else {
this._containerDomNode.style.width = '';
this._containerDomNode.style.maxWidth = `${document.documentElement.clientWidth - anchor.x - 1}px`;
this._containerDomNode.style.left = `${anchor.x}px`;
this._hover.containerDomNode.style.width = '';
this._hover.containerDomNode.style.maxWidth = `${document.documentElement.clientWidth - anchor.x - 1}px`;
this._hover.containerDomNode.style.left = `${anchor.x}px`;
}
} else {
this._containerDomNode.style.right = `${anchor.x}px`;
this._hover.containerDomNode.style.right = `${anchor.x}px`;
}
// Use fallback y value if there is not enough vertical space
if (anchor.verticalAnchorSide === VerticalAnchorSide.Bottom) {
if (anchor.y + this._containerDomNode.clientHeight > document.documentElement.clientHeight) {
this._containerDomNode.style.top = `${anchor.fallbackY}px`;
this._domNode.style.maxHeight = `${document.documentElement.clientHeight - anchor.fallbackY}px`;
if (anchor.y + this._hover.containerDomNode.clientHeight > document.documentElement.clientHeight) {
this._hover.containerDomNode.style.top = `${anchor.fallbackY}px`;
this._hover.contentsDomNode.style.maxHeight = `${document.documentElement.clientHeight - anchor.fallbackY}px`;
} else {
this._containerDomNode.style.bottom = `${anchor.y}px`;
this._containerDomNode.style.maxHeight = '';
this._hover.containerDomNode.style.bottom = `${anchor.y}px`;
this._hover.containerDomNode.style.maxHeight = '';
}
} else {
if (anchor.y + this._containerDomNode.clientHeight > document.documentElement.clientHeight) {
this._containerDomNode.style.bottom = `${anchor.fallbackY}px`;
if (anchor.y + this._hover.containerDomNode.clientHeight > document.documentElement.clientHeight) {
this._hover.containerDomNode.style.bottom = `${anchor.fallbackY}px`;
} else {
this._containerDomNode.style.top = `${anchor.y}px`;
this._hover.containerDomNode.style.top = `${anchor.y}px`;
}
}
this._scrollbar.scanDomNode();
this._hover.onContentsChanged();
}
public focus() {
this._containerDomNode.focus();
this._hover.containerDomNode.focus();
}
public hide(): void {
this.dispose();
}
public dispose(): void {
if (!this._isDisposed) {
this._onDispose.fire();
this._containerDomNode.parentElement?.removeChild(this.domNode);
this._hover.containerDomNode.parentElement?.removeChild(this.domNode);
this._messageListeners.dispose();
this._target.dispose();
super.dispose();
......@@ -238,29 +218,29 @@ registerThemingParticipant((theme, collector) => {
}
const hoverBackground = theme.getColor(editorHoverBackground);
if (hoverBackground) {
collector.addRule(`.integrated-terminal .monaco-editor-hover { background-color: ${hoverBackground}; }`);
collector.addRule(`.integrated-terminal .monaco-hover { background-color: ${hoverBackground}; }`);
}
const hoverBorder = theme.getColor(editorHoverBorder);
if (hoverBorder) {
collector.addRule(`.integrated-terminal .monaco-editor-hover { border: 1px solid ${hoverBorder}; }`);
collector.addRule(`.integrated-terminal .monaco-editor-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.integrated-terminal .monaco-editor-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.integrated-terminal .monaco-editor-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.integrated-terminal .monaco-hover { border: 1px solid ${hoverBorder}; }`);
collector.addRule(`.integrated-terminal .monaco-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.integrated-terminal .monaco-hover hr { border-top: 1px solid ${hoverBorder.transparent(0.5)}; }`);
collector.addRule(`.integrated-terminal .monaco-hover hr { border-bottom: 0px solid ${hoverBorder.transparent(0.5)}; }`);
}
const link = theme.getColor(textLinkForeground);
if (link) {
collector.addRule(`.integrated-terminal .monaco-editor-hover a { color: ${link}; }`);
collector.addRule(`.integrated-terminal .monaco-hover a { color: ${link}; }`);
}
const hoverForeground = theme.getColor(editorHoverForeground);
if (hoverForeground) {
collector.addRule(`.integrated-terminal .monaco-editor-hover { color: ${hoverForeground}; }`);
collector.addRule(`.integrated-terminal .monaco-hover { color: ${hoverForeground}; }`);
}
const actionsBackground = theme.getColor(editorHoverStatusBarBackground);
if (actionsBackground) {
collector.addRule(`.integrated-terminal .monaco-editor-hover .hover-row .actions { background-color: ${actionsBackground}; }`);
collector.addRule(`.integrated-terminal .monaco-hover .hover-row .actions { background-color: ${actionsBackground}; }`);
}
const codeBackground = theme.getColor(textCodeBlockBackground);
if (codeBackground) {
collector.addRule(`.integrated-terminal .monaco-editor-hover code { background-color: ${codeBackground}; }`);
collector.addRule(`.integrated-terminal .monaco-hover code { background-color: ${codeBackground}; }`);
}
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册