From 297de2a5710cba20db5666cf79cbf23d5b182ad6 Mon Sep 17 00:00:00 2001 From: Florrie Date: Tue, 4 Dec 2018 23:04:45 -0400 Subject: Broken optimization --- util/ansi.js | 161 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 82 insertions(+), 79 deletions(-) (limited to 'util/ansi.js') diff --git a/util/ansi.js b/util/ansi.js index 9645f0d..5902b70 100644 --- a/util/ansi.js +++ b/util/ansi.js @@ -118,9 +118,8 @@ const ansi = { ) }, - interpret(text, scrRows, scrCols, { - oldChars = null, oldLastChar = null, + oldChars = null, oldLastCharAttributes = null, oldCursorRow = 0, oldCursorCol = 0, oldShowCursor = true } = {}) { // Interprets the given ansi code, more or less. @@ -130,22 +129,26 @@ const ansi = { char: ' ' } - const chars = new Array(scrRows * scrCols).fill(blank) + const numChars = scrRows * scrCols + const chars = new Array(numChars * 2) + + const fillBlank = () => { + for (let i = 0; i < numChars; i++) { + chars[i * 2] = ' ' + chars[i * 2 + 1] = [] + } + } + + fillBlank() let showCursor = true let cursorRow = 1 let cursorCol = 1 const attributes = [] - const getCursorIndex = () => (cursorRow - 1) * scrCols + (cursorCol - 1) for (let charI = 0; charI < text.length; charI++) { + const cursorIndex = (cursorRow - 1) * scrCols + (cursorCol - 1) if (text[charI] === ESC) { - if (false) { - chars[getCursorIndex()] = {char: '%', attributes: []} - cursorCol++ - continue - } - charI++ if (text[charI] !== '[') { @@ -192,7 +195,7 @@ const ansi = { if (text[charI] === 'J') { // ESC[2J - erase whole display if (args[0] === '2') { - chars.fill(blank) + fillBlank() charI += 3 cursorCol = 1 cursorRow = 1 @@ -200,15 +203,17 @@ const ansi = { // ESC[1J - erase to beginning else if (args[0] === '1') { - for (let i = 0; i < getCursorIndex(); i++) { - chars[i] = blank + for (let i = 0; i < cursorIndex; i++) { + chars[i * 2] = ' ' + chars[i * 2 + 1] = [] } } // ESC[0J - erase to end else if (args.length === 0 || args[0] === '0') { - for (let i = getCursorIndex(); i < chars.length; i++) { - chars[i] = blank + for (let i = cursorIndex; i < numChars; i++) { + chars[i * 2] = ' ' + chars[i * 2 + 1] = [] } } } @@ -264,21 +269,8 @@ const ansi = { continue } - // debug - /* - if (text[charI] === '.') { - console.log( - `#1-char "${text[charI]}" at ` + - `(${cursorRow},${cursorCol}):${getCursorIndex()} ` + - ` attr:[${attributes.join(';')}]` - ) - } - */ - - chars[getCursorIndex()] = { - char: text[charI], - attributes: attributes.slice() - } + chars[cursorIndex * 2] = text[charI] + chars[cursorIndex * 2 + 1] = attributes.slice() cursorCol++ @@ -301,87 +293,98 @@ const ansi = { const differences = [] if (oldChars === null) { - differences.push({i: 0, chars: [...newChars]}) + differences.push(0) + differences.push(newChars.slice()) } else { - const charsEqual = (oldChar, newChar) => { - // TODO: Check attributes. + let curChars = null - if (oldChar.char !== newChar.char) { - return false - } + for (let i = 0; i < numChars; i++) { + const oldChar = oldChars[i * 2] + const newChar = newChars[i * 2] - let oldAttrs = oldChar.attributes.slice() - let newAttrs = newChar.attributes.slice() + let charsEqual = true - while (newAttrs.length) { - const attr = newAttrs.shift() - if (oldAttrs.includes(attr)) { - oldAttrs.splice(oldAttrs.indexOf(attr), 1) - } else { - return false - } - } + if (oldChars[i * 2] !== newChars[i * 2]) { + charsEqual = false + } else { + let oldAttrs = oldChars[i * 2 + 1].slice() + let newAttrs = newChars[i * 2 + 1].slice() - oldAttrs = oldChar.attributes.slice() - newAttrs = newChar.attributes.slice() + while (newAttrs.length) { + const attr = newAttrs.shift() + if (oldAttrs.includes(attr)) { + oldAttrs.splice(oldAttrs.indexOf(attr), 1) + } else { + charsEqual = false + break + } + } - while (oldAttrs.length) { - const attr = oldAttrs.shift() - if (newAttrs.includes(attr)) { - newAttrs.splice(newAttrs.indexOf(attr), 1) - } else { - return false + if (charsEqual) { + oldAttrs = oldChars[i * 2 + 1].slice() + newAttrs = newChars[i * 2 + 1].slice() + + while (oldAttrs.length) { + const attr = oldAttrs.shift() + if (newAttrs.includes(attr)) { + newAttrs.splice(newAttrs.indexOf(attr), 1) + } else { + charsEqual = false + break + } + } } } - return true - } - - let curDiff = null - - for (let i = 0; i < chars.length; i++) { - const oldChar = oldChars[i] - const newChar = newChars[i] - // TODO: Some sort of "distance" before we should clear curDiff? // It may take *less* characters if this diff and the next are merged // (entering a single character is smaller than the length of the code // used to move past that character). Probably not very significant of // an impact, though. - if (charsEqual(oldChar, newChar)) { - curDiff = null + if (charsEqual) { + curChars = null } else { - if (curDiff === null) { - curDiff = {i, chars: []} - differences.push(curDiff) + if (curChars === null) { + curChars = [] + differences.push(i, curChars) } - curDiff.chars.push(newChar) + const curAttrs = newChars[i * 2 + 1] + curChars.push(newChar, curAttrs) } } } // Character concatenation ----------- + /* let lastChar = oldLastChar || { char: '', attributes: [] } + */ + + let lastCharAttributes = [] const result = [] - for (const diff of differences) { - const col = diff.i % scrCols - const row = (diff.i - col) / scrCols + for (let parse = 0; parse < differences.length; parse += 2) { + const i = differences[parse] + const chars = differences[parse + 1] + + const col = i % scrCols + const row = (i - col) / scrCols result.push(ansi.moveCursor(row, col)) - for (const char of diff.chars) { + for (let charI = 0; charI < chars.length / 2; charI++) { + const charAttributes = chars[charI * 2 + 1] + const newAttributes = ( - char.attributes.filter(attr => !(lastChar.attributes.includes(attr))) + charAttributes.filter(attr => !(lastCharAttributes.includes(attr))) ) const removedAttributes = ( - lastChar.attributes.filter(attr => !(char.attributes.includes(attr))) + lastCharAttributes.filter(attr => !(charAttributes.includes(attr))) ) // The only way to practically remove any character attribute is to @@ -389,14 +392,14 @@ const ansi = { // If we do that, there's no need to add new attributes. if (removedAttributes.length) { result.push(ansi.resetAttributes()) - result.push(`${ESC}[${char.attributes.join(';')}m`) + result.push(`${ESC}[${charAttributes.join(';')}m`) } else if (newAttributes.length) { result.push(`${ESC}[${newAttributes.join(';')}m`) } - result.push(char.char) + result.push(chars[charI * 2]) - lastChar = char + lastCharAttributes = charAttributes } } @@ -419,7 +422,7 @@ const ansi = { oldCursorRow: cursorRow, oldCursorCol: cursorCol, oldShowCursor: showCursor, - oldLastChar: Object.assign({}, lastChar), + oldLastCharAttributes: lastCharAttributes.slice(), screen: result.join('') } } -- cgit 1.3.0-6-gf8a5