From edd866780110b759b947a9317f33bca1376e0861 Mon Sep 17 00:00:00 2001 From: Guillermo Rauch Date: Fri, 19 May 2017 16:52:36 -0700 Subject: [PATCH] Revert "Fix unicode display: CJK, powerline, tmux (#1536)" (#1847) This reverts commit 687df4ed06531f8bda284a1c3e0b2cea41d17bfa. --- lib/hterm.js | 206 ++++++++++++--------------------------------------- 1 file changed, 49 insertions(+), 157 deletions(-) diff --git a/lib/hterm.js b/lib/hterm.js index b718c92a..6282e77e 100644 --- a/lib/hterm.js +++ b/lib/hterm.js @@ -86,17 +86,21 @@ lib.wc.substr = function (str, start, optWidth) { const chars = runes(str); let startIndex; let endIndex; - let width; + let width = 0; - for (startIndex = 0, width = 0; startIndex < chars.length; startIndex++) { - width += lib.wc.charWidth(chars[startIndex].codePointAt(0)); - if (width > start) { + for (let i = 0; i < chars.length; i++) { + const codePoint = chars[i].codePointAt(0); + const charWidth = lib.wc.charWidth(codePoint); + if ((width + charWidth) > start) { + startIndex = i; break; } + width += charWidth; } if (optWidth) { - for (endIndex = startIndex, width = 0; endIndex < chars.length && width < optWidth; endIndex++) { + width = 0; + for (endIndex = startIndex; endIndex < chars.length && width < optWidth; endIndex++) { width += lib.wc.charWidth(chars[endIndex].charCodeAt(0)); } @@ -116,6 +120,28 @@ hterm.Keyboard.prototype.onTextInput_ = function (e) { runes(e.data).forEach(this.terminal.onVTKeystroke.bind(this.terminal)); }; +hterm.Terminal.IO.prototype.writeUTF8 = function (string) { + if (this.terminal_.io !== this) { + throw new Error('Attempt to print from inactive IO object.'); + } + + if (!containsNonLatinCodepoints(string)) { + this.terminal_.interpret(string); + return; + } + + runes(string).forEach(rune => { + this.terminal_.getTextAttributes().unicodeNode = containsNonLatinCodepoints(rune); + this.terminal_.interpret(rune); + this.terminal_.getTextAttributes().unicodeNode = false; + }); +}; + +const oldIsDefault = hterm.TextAttributes.prototype.isDefault; +hterm.TextAttributes.prototype.isDefault = function () { + return !this.unicodeNode && oldIsDefault.call(this); +}; + const oldSetFontSize = hterm.Terminal.prototype.setFontSize; hterm.Terminal.prototype.setFontSize = function (px) { oldSetFontSize.call(this, px); @@ -127,7 +153,7 @@ hterm.Terminal.prototype.setFontSize = function (px) { doc.head.appendChild(unicodeNodeStyle); } unicodeNodeStyle.innerHTML = ` - .unicode-node:not(.wc-node) { + .unicode-node { display: inline-block; vertical-align: top; width: ${this.scrollPort_.characterSize.width}px; @@ -135,6 +161,23 @@ hterm.Terminal.prototype.setFontSize = function (px) { `; }; +const oldCreateContainer = hterm.TextAttributes.prototype.createContainer; +hterm.TextAttributes.prototype.createContainer = function (text) { + const container = oldCreateContainer.call(this, text); + if (container.style && runes(text).length === 1 && containsNonLatinCodepoints(text)) { + container.className += ' unicode-node'; + } + return container; +}; + +// Do not match containers when one of them has unicode text (unicode chars need to be alone in their containers) +const oldMatchesContainer = hterm.TextAttributes.prototype.matchesContainer; +hterm.TextAttributes.prototype.matchesContainer = function (obj) { + return oldMatchesContainer.call(this, obj) && + !this.unicodeNode && + !containsNonLatinCodepoints(obj.textContent); +}; + // there's no option to turn off the size overlay hterm.Terminal.prototype.overlaySize = function () {}; @@ -345,157 +388,6 @@ hterm.Terminal.prototype.focusHyperCaret = function () { this.hyperCaret.focus(); }; -// patch for unicode encapsulation -// see comments in original code -hterm.Screen.prototype.insertString = function (str) { - let cursorNode = this.cursorNode_; - let cursorNodeText = cursorNode.textContent; - this.cursorRowNode_.removeAttribute('line-overflow'); - const strWidth = lib.wc.strWidth(str); - this.cursorPosition.column += strWidth; - let offset = this.cursorOffset_; - let reverseOffset = hterm.TextAttributes.nodeWidth(cursorNode) - offset; - if (reverseOffset < 0) { - const ws = lib.f.getWhitespace(-reverseOffset); - if (!(this.textAttributes.underline || - this.textAttributes.strikethrough || - this.textAttributes.background || - this.textAttributes.wcNode || - this.textAttributes.tileData !== null)) { - str = ws + str; - } else if (cursorNode.nodeType === 3 || - !(cursorNode.wcNode || - cursorNode.tileNode || - cursorNode.style.textDecoration || - cursorNode.style.backgroundColor)) { - cursorNode.textContent = (cursorNodeText += ws); - } else { - const wsNode = cursorNode.ownerDocument.createTextNode(ws); - this.cursorRowNode_.insertBefore(wsNode, cursorNode.nextSibling); - this.cursorNode_ = cursorNode = wsNode; - this.cursorOffset_ = offset = -reverseOffset; - cursorNodeText = ws; - } - reverseOffset = 0; - } - this.wrapUnicode(cursorNode); - if (this.textAttributes.matchesContainer(cursorNode)) { - if (reverseOffset === 0) { - cursorNode.textContent = cursorNodeText + str; - } else if (offset === 0) { - cursorNode.textContent = str + cursorNodeText; - } else { - cursorNode.textContent = - hterm.TextAttributes.nodeSubstr(cursorNode, 0, offset) + - str + hterm.TextAttributes.nodeSubstr(cursorNode, offset); - } - this.cursorOffset_ += strWidth; - this.wrapUnicode(cursorNode); - return; - } - if (offset === 0) { - const previousSibling = cursorNode.previousSibling; - if (previousSibling && - this.textAttributes.matchesContainer(previousSibling)) { - previousSibling.textContent += str; - this.cursorNode_ = previousSibling; - this.cursorOffset_ = lib.wc.strWidth(previousSibling.textContent); - this.wrapUnicode(previousSibling); - return; - } - const newNode = this.textAttributes.createContainer(str); - this.cursorRowNode_.insertBefore(newNode, cursorNode); - this.cursorNode_ = newNode; - this.cursorOffset_ = strWidth; - this.wrapUnicode(newNode); - return; - } - if (reverseOffset === 0) { - const nextSibling = cursorNode.nextSibling; - if (nextSibling && - this.textAttributes.matchesContainer(nextSibling)) { - nextSibling.textContent = str + nextSibling.textContent; - this.cursorNode_ = nextSibling; - this.cursorOffset_ = lib.wc.strWidth(str); - this.wrapUnicode(nextSibling); - return; - } - const newNode = this.textAttributes.createContainer(str); - this.cursorRowNode_.insertBefore(newNode, nextSibling); - this.cursorNode_ = newNode; - this.cursorOffset_ = hterm.TextAttributes.nodeWidth(newNode); - this.wrapUnicode(newNode); - return; - } - this.splitNode_(cursorNode, offset); - const newNode = this.textAttributes.createContainer(str); - this.cursorRowNode_.insertBefore(newNode, cursorNode.nextSibling); - this.cursorNode_ = newNode; - this.cursorOffset_ = strWidth; - this.wrapUnicode(newNode); -}; - -// patch for unicode encapsulation -hterm.Screen.prototype.splitNode_ = function (node, offset) { - const afterNode = node.cloneNode(false); - const textContent = node.textContent; - node.textContent = hterm.TextAttributes.nodeSubstr(node, 0, offset); - afterNode.textContent = lib.wc.substr(textContent, offset); - this.wrapUnicode(node); - this.wrapUnicode(afterNode); - if (afterNode.textContent) { - node.parentNode.insertBefore(afterNode, node.nextSibling); - } - if (!node.textContent) { - node.parentNode.removeChild(node); - } -}; - -// encapsulate unicode chars in individual spans -// keep them in the parent node with the rest of the content -// maintains styling and overflow display in divs with a background color -hterm.Screen.prototype.wrapUnicode = function (node) { - const nodeContent = node.textContent; - if (containsNonLatinCodepoints(nodeContent) && !node.className.includes('wc-node')) { - const doc = this.terminal.document_; - if (!node.className.includes('unicode-parent-node')) { - node.className += ' unicode-parent-node'; - } - node.textContent = null; - let strBuffer = ''; - runes(nodeContent).forEach(rune => { - if (containsNonLatinCodepoints(rune)) { - if (strBuffer !== '') { - const stringNode = doc.createTextNode(strBuffer); - node.appendChild(stringNode); - strBuffer = ''; - } - const unicodeNode = doc.createElement('span'); - unicodeNode.className = 'unicode-node'; - unicodeNode.textContent = rune; - node.appendChild(unicodeNode); - } else { - strBuffer += rune; - } - }); - if (strBuffer !== '') { - const stringNode = doc.createTextNode(strBuffer); - node.appendChild(stringNode); - } - } -}; - -// ensure no text node contains unicode -const oldCreateContainer = hterm.TextAttributes.prototype.createContainer; -hterm.TextAttributes.prototype.createContainer = function (text) { - if (this.isDefault() && text && containsNonLatinCodepoints(text)) { - const span = this.document_.createElement('span'); - span.textContent = text; - return span; - } - return oldCreateContainer.call(this, text); -}; - hterm.Screen.prototype.syncSelectionCaret = function () { const p = this.terminal.hyperCaret; const doc = this.terminal.document_;