From 478d824fa788773679c58309b1a900da580c5d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agusti=CC=81n=20Rodri=CC=81guez?= Date: Thu, 20 Sep 2018 01:52:37 -0300 Subject: [PATCH 1/4] fix underline don't appearing when using the fallback DOM renderer --- src/renderer/dom/DomRenderer.ts | 51 ++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 9a2ef46983..399ac40682 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -4,12 +4,13 @@ */ import { IRenderer, IRenderDimensions, IColorSet } from '../Types'; -import { ITerminal, CharacterJoinerHandler } from '../../Types'; +import { ILinkHoverEvent, ITerminal, CharacterJoinerHandler, LinkHoverEventTypes } from '../../Types'; import { ITheme } from 'xterm'; import { EventEmitter } from '../../common/EventEmitter'; import { ColorManager } from '../ColorManager'; import { RenderDebouncer } from '../../ui/RenderDebouncer'; import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory'; +import { INVERTED_DEFAULT_COLOR } from '../atlas/Types'; const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; const ROW_CONTAINER_CLASS = 'xterm-rows'; @@ -79,6 +80,9 @@ export class DomRenderer extends EventEmitter implements IRenderer { this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); this._terminal.screenElement.appendChild(this._rowContainer); this._terminal.screenElement.appendChild(this._selectionContainer); + + this._terminal.linkifier.on(LinkHoverEventTypes.HOVER, (e: ILinkHoverEvent) => this._onLinkHover(e)); + this._terminal.linkifier.on(LinkHoverEventTypes.LEAVE, (e: ILinkHoverEvent) => this._onLinkLeave(e)); } public dispose(): void { @@ -116,6 +120,7 @@ export class DomRenderer extends EventEmitter implements IRenderer { const styles = `${this._terminalSelector} .${ROW_CONTAINER_CLASS} span {` + + ` box-sizing: border-box;` + ` display: inline-block;` + ` height: 100%;` + ` vertical-align: top;` + @@ -338,4 +343,48 @@ export class DomRenderer extends EventEmitter implements IRenderer { public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return -1; } public deregisterCharacterJoiner(joinerId: number): boolean { return false; } + + private _onLinkHover(e: ILinkHoverEvent): void { + let color = this.colorManager.colors.foreground.css; + + if (e.fg === INVERTED_DEFAULT_COLOR) { + color = this.colorManager.colors.background.css; + } else if (e.fg < 256) { + // 256 color support + color = this.colorManager.colors.ansi[e.fg].css; + } + + this._setBorderBottomAtCells(e.x1, e.x2, e.y1, e.y2, e.cols, `1px solid ${color}`); + } + + private _onLinkLeave(e: ILinkHoverEvent): void { + this._setBorderBottomAtCells(e.x1, e.x2, e.y1, e.y2, e.cols, null); + } + + private _setBorderBottomAtCells(x1: number, x2: number, y1: number, y2: number, cols: number, value?: string) { + if (y1 === y2) { + // Single line link + for (let x = x1; x < x2; x++) { + let span = (this._rowElements[y1].children[x]); + span.style.borderBottom = value; + } + } else { + // Multi-line link + for (let x = x1; x < cols - x1; x++) { + let span = (this._rowElements[y1].children[x]); + span.style.borderBottom = value; + } + for (let y = y1 + 1; y < y2 - 1; y++) { + for (let x = 0; x < cols; x++) { + let span = (this._rowElements[y].children[x]); + span.style.borderBottom = value; + } + } + for (let x = 0; x < x2; x++) { + let span = (this._rowElements[y2].children[x]); + span.style.borderBottom = value; + } + } + } + } From d1991396e758f5d36ecce8403bf56f046b65d42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agusti=CC=81n=20Rodri=CC=81guez?= Date: Fri, 21 Sep 2018 01:09:20 -0300 Subject: [PATCH 2/4] generalized loops to handle both single and multi line links --- src/renderer/dom/DomRenderer.ts | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 399ac40682..9933276cdd 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -361,29 +361,10 @@ export class DomRenderer extends EventEmitter implements IRenderer { this._setBorderBottomAtCells(e.x1, e.x2, e.y1, e.y2, e.cols, null); } - private _setBorderBottomAtCells(x1: number, x2: number, y1: number, y2: number, cols: number, value?: string) { - if (y1 === y2) { - // Single line link - for (let x = x1; x < x2; x++) { - let span = (this._rowElements[y1].children[x]); - span.style.borderBottom = value; - } - } else { - // Multi-line link - for (let x = x1; x < cols - x1; x++) { - let span = (this._rowElements[y1].children[x]); - span.style.borderBottom = value; - } - for (let y = y1 + 1; y < y2 - 1; y++) { - for (let x = 0; x < cols; x++) { - let span = (this._rowElements[y].children[x]); - span.style.borderBottom = value; - } - } - for (let x = 0; x < x2; x++) { - let span = (this._rowElements[y2].children[x]); - span.style.borderBottom = value; - } + private _setBorderBottomAtCells(x: number, x2: number, y: number, y2: number, cols: number, value?: string) { + for (; x != x2 || y != y2; x = ++x % cols, y += +(x === 0)) { + let span = (this._rowElements[y].children[x]); + span.style.borderBottom = value; } } From 1f2d223e649e0ecf63839806252737d254a8aac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agusti=CC=81n=20Rodri=CC=81guez?= Date: Fri, 21 Sep 2018 01:42:20 -0300 Subject: [PATCH 3/4] remove line in xterm.d.ts that says link underlines are not supported --- typings/xterm.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index cc1ebcd9e3..49f3810f5f 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -148,7 +148,6 @@ declare module 'xterm' { * when canvas is too slow for the environment. The following features do * not work when the DOM renderer is used: * - * - Link underlines * - Line height * - Letter spacing * - Cursor blink From 4941d5a19e5f81b40982d95259c00b74a0a7e552 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 21 Sep 2018 07:08:17 -0700 Subject: [PATCH 4/4] Simplify loop, pass lint --- src/renderer/dom/DomRenderer.ts | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 9933276cdd..8f51c4ef3e 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -10,7 +10,6 @@ import { EventEmitter } from '../../common/EventEmitter'; import { ColorManager } from '../ColorManager'; import { RenderDebouncer } from '../../ui/RenderDebouncer'; import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory'; -import { INVERTED_DEFAULT_COLOR } from '../atlas/Types'; const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; const ROW_CONTAINER_CLASS = 'xterm-rows'; @@ -120,7 +119,6 @@ export class DomRenderer extends EventEmitter implements IRenderer { const styles = `${this._terminalSelector} .${ROW_CONTAINER_CLASS} span {` + - ` box-sizing: border-box;` + ` display: inline-block;` + ` height: 100%;` + ` vertical-align: top;` + @@ -345,27 +343,21 @@ export class DomRenderer extends EventEmitter implements IRenderer { public deregisterCharacterJoiner(joinerId: number): boolean { return false; } private _onLinkHover(e: ILinkHoverEvent): void { - let color = this.colorManager.colors.foreground.css; - - if (e.fg === INVERTED_DEFAULT_COLOR) { - color = this.colorManager.colors.background.css; - } else if (e.fg < 256) { - // 256 color support - color = this.colorManager.colors.ansi[e.fg].css; - } - - this._setBorderBottomAtCells(e.x1, e.x2, e.y1, e.y2, e.cols, `1px solid ${color}`); + this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, true); } private _onLinkLeave(e: ILinkHoverEvent): void { - this._setBorderBottomAtCells(e.x1, e.x2, e.y1, e.y2, e.cols, null); + this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, false); } - private _setBorderBottomAtCells(x: number, x2: number, y: number, y2: number, cols: number, value?: string) { - for (; x != x2 || y != y2; x = ++x % cols, y += +(x === 0)) { - let span = (this._rowElements[y].children[x]); - span.style.borderBottom = value; + private _setCellUnderline(x: number, x2: number, y: number, y2: number, cols: number, enabled: boolean): void { + while (x !== x2 || y !== y2) { + const span = this._rowElements[y].children[x]; + span.style.textDecoration = enabled ? 'underline' : 'none'; + x = (x + 1) % cols; + if (x === 0) { + y++; + } } } - }