From e01e9c9584fb9d1fb4eedb6c282439edfad38893 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 9 Aug 2021 14:23:09 -0700 Subject: [PATCH 01/37] start on #130406 --- src/browser/renderer/BaseRenderLayer.ts | 109 +++++++++++- src/browser/renderer/BoxCharacters.ts | 213 ++++++++++++++++++++++++ 2 files changed, 313 insertions(+), 9 deletions(-) create mode 100644 src/browser/renderer/BoxCharacters.ts diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 7986e510..ce2d8058 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,6 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; +import { boxDrawingBoxes, boxDrawingLineSegments } from 'browser/renderer/BoxCharacters'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -259,10 +260,13 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._ctx.font = this._getFont(false, false); this._ctx.textBaseline = 'ideographic'; this._clipRow(y); - this._ctx.fillText( - cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); + // TODO: fix + if (!this._drawBoxChar(cell, x, y)) { + this._ctx.fillText( + cell.getChars(), + x * this._scaledCellWidth + this._scaledCharLeft, + y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); + } } /** @@ -373,14 +377,101 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (cell.isDim()) { this._ctx.globalAlpha = DIM_OPACITY; } - // Draw the character - this._ctx.fillText( - cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); + if (!this._drawBoxChar(cell, x, y)) { + // Draw the character + this._ctx.fillText( + cell.getChars(), + x * this._scaledCellWidth + this._scaledCharLeft, + y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); + } this._ctx.restore(); } + private _drawBoxChar(cell: ICellData, x: number, y: number): boolean { + const char = cell.getChars(); + + const boxes = boxDrawingBoxes[char]; + if (boxes) { + this._ctx.strokeStyle = this._ctx.fillStyle; + const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; + const yOffset = y * this._scaledCellHeight + this._scaledCharTop; + const xEighth = this._scaledCellWidth / 8; + const yEighth = this._scaledCellHeight / 8; + + for (let i = 0; i < boxes.length; i++) { + const box = boxes[i]; + this._ctx.fillRect( + xOffset + (box.x * xEighth), + yOffset + (box.y * yEighth), + (box.w * xEighth), + (box.h * yEighth)); + } + + return true; + } + + const ops = boxDrawingLineSegments[char]; + if (!ops) { + return false; + } + + // TODO: Clean below + const scale = window.devicePixelRatio; + this._ctx.strokeStyle = this._ctx.fillStyle; + this._ctx.lineWidth = scale; + + const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; + const yOffset = y * this._scaledCellHeight + this._scaledCharTop; + const horizontalCenter = this._scaledCellWidth / 2; + const verticalCenter = this._scaledCellHeight / 2; + const xPoints = [ + xOffset, + xOffset + horizontalCenter - scale, + xOffset + horizontalCenter - scale / 2, + xOffset + horizontalCenter, + xOffset + horizontalCenter + scale / 2, + xOffset + horizontalCenter + scale, + xOffset + this._scaledCellWidth + ]; + const yPoints = [ + yOffset, + yOffset + verticalCenter - scale, + yOffset + verticalCenter - scale / 2, + yOffset + verticalCenter, + yOffset + verticalCenter + scale / 2, + yOffset + verticalCenter + scale, + yOffset + this._scaledCellHeight + ]; + + for (let i = 0; i < ops.length; i++) { + const op = ops[i]; + + if (i === 0 || (op.x1 !== ops[i - 1].x2 || op.y1 !== ops[i - 1].y2)) { + this._ctx.beginPath(); + this._ctx.moveTo(xPoints[op.x1], yPoints[op.y1]); + } + + if (typeof op.cx1 !== 'undefined') { + // Draw curve + this._ctx.bezierCurveTo( + xPoints[op.cx1], + yPoints[op.cy1], + xPoints[op.cx2], + yPoints[op.cy2], + xPoints[op.x2], + yPoints[op.y2]); + } else { + // Draw line + this._ctx.lineTo(xPoints[op.x2], yPoints[op.y2]); + } + + this._ctx.stroke(); + } + + return true; + } + + /** * Clips a row to ensure no pixels will be drawn outside the cells in the row. * @param y The row to clip. diff --git a/src/browser/renderer/BoxCharacters.ts b/src/browser/renderer/BoxCharacters.ts new file mode 100644 index 00000000..221a0e4f --- /dev/null +++ b/src/browser/renderer/BoxCharacters.ts @@ -0,0 +1,213 @@ +export const boxDrawingLineSegments: { [index: string]: any } = { + '─': [{ x1: 0, y1: 3, x2: 6, y2: 3 }], + '━': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }], + '│': [{ x1: 3, y1: 0, x2: 3, y2: 6 }], + '┃': [{ x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], + '┌': [{ x1: 6, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┍': [{ x1: 6, y1: 2, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 3, y2: 6 }, { x1: 6, y1: 4, x2: 3, y2: 4 }], + '┎': [{ x1: 6, y1: 3, x2: 2, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '┏': [{ x1: 6, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 6 }, { x1: 6, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 6 }], + '┐': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┑': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 3, y2: 6 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], + '┒': [{ x1: 0, y1: 3, x2: 4, y2: 3 }, { x1: 4, y1: 3, x2: 4, y2: 6 }, { x1: 2, y1: 3, x2: 2, y2: 6 }], + '┓': [{ x1: 0, y1: 2, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 4, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }], + '└': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '┕': [{ x1: 3, y1: 0, x2: 3, y2: 4 }, { x1: 3, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 2, x2: 6, y2: 2 }], + '┖': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 2, y1: 3, x2: 6, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], + '┗': [{ x1: 2, y1: 0, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 6, y2: 4 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }], + '┘': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 0 }], + '┙': [{ x1: 0, y1: 4, x2: 3, y2: 4 }, { x1: 3, y1: 4, x2: 3, y2: 0 }, { x1: 0, y1: 2, x2: 3, y2: 2 }], + '┚': [{ x1: 0, y1: 3, x2: 4, y2: 3 }, { x1: 4, y1: 3, x2: 4, y2: 0 }, { x1: 2, y1: 3, x2: 2, y2: 0 }], + '┛': [{ x1: 0, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 0 }, { x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }], + '├': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '┝': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], + '┞': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }, { x1: 4, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┟': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '┠': [{ x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }, { x1: 4, y1: 3, x2: 6, y2: 3 }], + '┡': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 2, y1: 3, x2: 6, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┢': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 2, y1: 6, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '┣': [{ x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 6, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 6 }], + '┤': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 3, x2: 3, y2: 3 }], + '┥': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], + '┦': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }, { x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┧': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 0, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '┨': [{ x1: 0, y1: 3, x2: 2, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], + '┩': [{ x1: 2, y1: 0, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 0, y2: 2 }, { x1: 4, y1: 0, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 0, y2: 4 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┪': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 3, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 3, y1: 0, x2: 3, y2: 3 }], + '┫': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], + '┬': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '┭': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }, { x1: 3, y1: 6, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '┮': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], + '┯': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 4, x2: 3, y2: 6 }], + '┰': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '┱': [{ x1: 0, y1: 2, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 4, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '┲': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 2, y1: 6, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '┳': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '┴': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 0, x2: 3, y2: 3 }], + '┵': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], + '┶': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 0 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], + '┷': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 0, x2: 3, y2: 3 }], + '┸': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], + '┹': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 0 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '┺': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 0, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 6, y2: 2 }], + '┻': [{ x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }], + '┼': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 0, x2: 3, y2: 6 }], + '┽': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], + '┾': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], + '┿': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }], + '╀': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }, { x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], + '╁': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '╂': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], + '╃': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 0 }, { x1: 3, y1: 6, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '╄': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }, { x1: 2, y1: 0, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 6, y2: 4 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }], + '╅': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 0, y1: 2, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 4, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }], + '╆': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 0 }, { x1: 2, y1: 6, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '╇': [{ x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], + '╈': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '╉': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '╊': [{ x1: 0, y1: 3, x2: 2, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '╋': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], + '╌': [{ x1: 0, y1: 3, x2: 2, y2: 3 }, { x1: 4, y1: 3, x2: 6, y2: 3 }], + '╍': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], + '╎': [{ x1: 3, y1: 0, x2: 3, y2: 2 }, { x1: 3, y1: 4, x2: 3, y2: 6 }], + '╏': [{ x1: 2, y1: 0, x2: 2, y2: 2 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '═': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }], + '║': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }], + '╒': [{ x1: 6, y1: 1, x2: 3, y2: 1 }, { x1: 3, y1: 1, x2: 3, y2: 6 }, { x1: 6, y1: 5, x2: 3, y2: 5 }], + '╓': [{ x1: 6, y1: 3, x2: 1, y2: 3 }, { x1: 1, y1: 3, x2: 1, y2: 6 }, { x1: 5, y1: 3, x2: 5, y2: 6 }], + '╔': [{ x1: 6, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 6 }, { x1: 6, y1: 5, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 5, y2: 6 }], + '╕': [{ x1: 0, y1: 1, x2: 3, y2: 1 }, { x1: 3, y1: 1, x2: 3, y2: 6 }, { x1: 0, y1: 5, x2: 3, y2: 5 }], + '╖': [{ x1: 0, y1: 3, x2: 5, y2: 3 }, { x1: 5, y1: 3, x2: 5, y2: 6 }, { x1: 1, y1: 3, x2: 1, y2: 6 }], + '╗': [{ x1: 0, y1: 1, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 5, y2: 6 }, { x1: 0, y1: 5, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 1, y2: 6 }], + '╘': [{ x1: 3, y1: 0, x2: 3, y2: 5 }, { x1: 3, y1: 5, x2: 6, y2: 5 }, { x1: 3, y1: 1, x2: 6, y2: 1 }], + '╙': [{ x1: 1, y1: 0, x2: 1, y2: 3 }, { x1: 1, y1: 3, x2: 6, y2: 3 }, { x1: 5, y1: 0, x2: 5, y2: 3 }], + '╚': [{ x1: 1, y1: 0, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 6, y2: 5 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }], + '╛': [{ x1: 0, y1: 1, x2: 3, y2: 1 }, { x1: 0, y1: 5, x2: 3, y2: 5 }, { x1: 3, y1: 5, x2: 3, y2: 0 }], + '╜': [{ x1: 0, y1: 3, x2: 5, y2: 3 }, { x1: 5, y1: 3, x2: 5, y2: 0 }, { x1: 1, y1: 3, x2: 1, y2: 0 }], + '╝': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 0, y1: 5, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 5, y2: 0 }], + '╞': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 1, x2: 6, y2: 1 }, { x1: 3, y1: 5, x2: 6, y2: 5 }], + '╟': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }, { x1: 5, y1: 3, x2: 6, y2: 3 }], + '╠': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }, { x1: 5, y1: 6, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 6, y2: 5 }], + '╡': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 1, x2: 3, y2: 1 }, { x1: 0, y1: 5, x2: 3, y2: 5 }], + '╢': [{ x1: 0, y1: 3, x2: 1, y2: 3 }, { x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }], + '╣': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 0, y1: 5, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }], + '╤': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }, { x1: 3, y1: 5, x2: 3, y2: 6 }], + '╥': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 1, y1: 3, x2: 1, y2: 6 }, { x1: 5, y1: 3, x2: 5, y2: 6 }], + '╦': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 1, y2: 6 }, { x1: 5, y1: 6, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 6, y2: 5 }], + '╧': [{ x1: 0, y1: 5, x2: 6, y2: 5 }, { x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 3, y1: 0, x2: 3, y2: 1 }], + '╨': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 1, y1: 0, x2: 1, y2: 3 }, { x1: 5, y1: 0, x2: 5, y2: 3 }], + '╩': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }], + '╪': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }, { x1: 3, y1: 0, x2: 3, y2: 6 }], + '╫': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }, { x1: 0, y1: 3, x2: 6, y2: 3 }], + '╬': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }, { x1: 6, y1: 5, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 5, y2: 6 }, { x1: 1, y1: 6, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 0, y2: 5 }], + '╭': [{ x1: 6, y1: 3, x2: 3, y2: 6, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], + '╮': [{ x1: 0, y1: 3, x2: 3, y2: 6, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], + '╯': [{ x1: 0, y1: 3, x2: 3, y2: 0, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], + '╰': [{ x1: 3, y1: 0, x2: 6, y2: 3, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], + '╱': [{ x1: 0, y1: 6, x2: 6, y2: 0 }], + '╲': [{ x1: 0, y1: 0, x2: 6, y2: 6 }], + '╳': [{ x1: 0, y1: 6, x2: 6, y2: 0 }, { x1: 0, y1: 0, x2: 6, y2: 6 }], + '╴': [{ x1: 0, y1: 3, x2: 3, y2: 3 }], + '╵': [{ x1: 3, y1: 0, x2: 3, y2: 3 }], + '╶': [{ x1: 3, y1: 3, x2: 6, y2: 3 }], + '╷': [{ x1: 3, y1: 3, x2: 3, y2: 6 }], + '╸': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], + '╹': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], + '╺': [{ x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], + '╻': [{ x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '╼': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], + '╽': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], + '╾': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], + '╿': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }] +}; + +export const boxDrawingBoxes: { [index: string]: any } = { + '▀': [{ x: 0, y: 0, w: 8, h: 4 }], + '█': [{ x: 0, y: 0, w: 8, h: 8 }], + '▇': [{ x: 0, y: 1, w: 8, h: 7 }], + '▆': [{ x: 0, y: 2, w: 8, h: 6 }], + '▅': [{ x: 0, y: 3, w: 8, h: 5 }], + '▄': [{ x: 0, y: 4, w: 8, h: 4 }], + '▃': [{ x: 0, y: 5, w: 8, h: 3 }], + '▂': [{ x: 0, y: 6, w: 8, h: 2 }], + '▁': [{ x: 0, y: 7, w: 8, h: 1 }], + '▉': [{ x: 0, y: 0, w: 7, h: 8 }], + '▊': [{ x: 0, y: 0, w: 6, h: 8 }], + '▋': [{ x: 0, y: 0, w: 5, h: 8 }], + '▌': [{ x: 0, y: 0, w: 4, h: 8 }], + '▍': [{ x: 0, y: 0, w: 3, h: 8 }], + '▎': [{ x: 0, y: 0, w: 2, h: 8 }], + '▏': [{ x: 0, y: 0, w: 1, h: 8 }], + + // VERTICAL ONE EIGHTH BLOCK-2 through VERTICAL ONE EIGHTH BLOCK-7 + '\u{1FB70}': [{ x: 1, y: 0, w: 1, h: 8 }], + '\u{1FB71}': [{ x: 2, y: 0, w: 1, h: 8 }], + '\u{1FB72}': [{ x: 3, y: 0, w: 1, h: 8 }], + '\u{1FB73}': [{ x: 4, y: 0, w: 1, h: 8 }], + '\u{1FB74}': [{ x: 5, y: 0, w: 1, h: 8 }], + '\u{1FB75}': [{ x: 6, y: 0, w: 1, h: 8 }], + // RIGHT ONE EIGHTH BLOCK + '▕': [{ x: 7, y: 0, w: 1, h: 8 }], + + // UPPER ONE EIGHTH BLOCK + '▔': [{ x: 0, y: 0, w: 8, h: 1 }], + // HORIZONTAL ONE EIGHTH BLOCK-2 through HORIZONTAL ONE EIGHTH BLOCK-7 + '\u{1FB76}': [{ x: 0, y: 1, w: 8, h: 1 }], + '\u{1FB77}': [{ x: 0, y: 2, w: 8, h: 1 }], + '\u{1FB78}': [{ x: 0, y: 3, w: 8, h: 1 }], + '\u{1FB79}': [{ x: 0, y: 4, w: 8, h: 1 }], + '\u{1FB7A}': [{ x: 0, y: 5, w: 8, h: 1 }], + '\u{1FB7B}': [{ x: 0, y: 6, w: 8, h: 1 }], + + // LEFT AND LOWER ONE EIGHTH BLOCK + '\u{1FB7C}': [{ x: 0, y: 0, w: 1, h: 8 }, { x: 0, y: 7, w: 8, h: 1 }], + // LEFT AND UPPER ONE EIGHTH BLOCK + '\u{1FB7D}': [{ x: 0, y: 0, w: 1, h: 8 }, { x: 0, y: 0, w: 8, h: 1 }], + // RIGHT AND UPPER ONE EIGHTH BLOCK + '\u{1FB7E}': [{ x: 7, y: 0, w: 1, h: 8 }, { x: 0, y: 0, w: 8, h: 1 }], + // RIGHT AND LOWER ONE EIGHTH BLOCK + '\u{1FB7F}': [{ x: 7, y: 0, w: 1, h: 8 }, { x: 0, y: 7, w: 8, h: 1 }], + // UPPER AND LOWER ONE EIGHTH BLOCK + '\u{1FB80}': [{ x: 0, y: 0, w: 8, h: 1 }, { x: 0, y: 7, w: 8, h: 1 }], + // HORIZONTAL ONE EIGHTH BLOCK-1358 + '\u{1FB81}': [{ x: 0, y: 0, w: 8, h: 1 }, { x: 0, y: 2, w: 8, h: 1 }, { x: 0, y: 4, w: 8, h: 1 }, { x: 0, y: 7, w: 8, h: 1 }], + + // UPPER ONE QUARTER BLOCK + '\u{1FB82}': [{ x: 0, y: 0, w: 8, h: 2 }], + // UPPER THREE EIGHTHS BLOCK + '\u{1FB83}': [{ x: 0, y: 0, w: 8, h: 3 }], + // UPPER FIVE EIGHTHS BLOCK + '\u{1FB84}': [{ x: 0, y: 0, w: 8, h: 5 }], + // UPPER THREE QUARTERS BLOCK + '\u{1FB85}': [{ x: 0, y: 0, w: 8, h: 6 }], + // UPPER SEVEN EIGHTHS BLOCK + '\u{1FB86}': [{ x: 0, y: 0, w: 8, h: 7 }], + + // RIGHT ONE QUARTER BLOCK + '\u{1FB87}': [{ x: 6, y: 0, w: 2, h: 8 }], + // RIGHT THREE EIGHTHS B0OCK + '\u{1FB88}': [{ x: 5, y: 0, w: 3, h: 8 }], + // RIGHT FIVE EIGHTHS BL0CK + '\u{1FB89}': [{ x: 3, y: 0, w: 5, h: 8 }], + // RIGHT THREE QUARTERS 0LOCK + '\u{1FB8A}': [{ x: 2, y: 0, w: 6, h: 8 }], + // RIGHT SEVEN EIGHTHS B0OCK + '\u{1FB8B}': [{ x: 1, y: 0, w: 7, h: 8 }], + + // CHECKER BOARD FILL + '\u{1FB95}': [ + { x: 0, y: 0, w: 2, h: 2 }, { x: 4, y: 0, w: 2, h: 2 }, + { x: 2, y: 2, w: 2, h: 2 }, { x: 6, y: 2, w: 2, h: 2 }, + { x: 0, y: 4, w: 2, h: 2 }, { x: 4, y: 4, w: 2, h: 2 }, + { x: 2, y: 6, w: 2, h: 2 }, { x: 6, y: 6, w: 2, h: 2 } + ], + // INVERSE CHECKER BOARD FILL + '\u{1FB96}': [ + { x: 2, y: 0, w: 2, h: 2 }, { x: 6, y: 0, w: 2, h: 2 }, + { x: 0, y: 2, w: 2, h: 2 }, { x: 4, y: 2, w: 2, h: 2 }, + { x: 2, y: 4, w: 2, h: 2 }, { x: 6, y: 4, w: 2, h: 2 }, + { x: 0, y: 6, w: 2, h: 2 }, { x: 4, y: 6, w: 2, h: 2 } + ], + // HEAVY HORIZONTAL FILL (upper middle and lower one quarter block) + '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] +}; From 3b3ef09d87ca6df46bfddb2d44c7d37def094a38 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 9 Aug 2021 14:52:47 -0700 Subject: [PATCH 02/37] keep working --- src/browser/renderer/BaseRenderLayer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index ce2d8058..188816ec 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -401,8 +401,8 @@ export abstract class BaseRenderLayer implements IRenderLayer { for (let i = 0; i < boxes.length; i++) { const box = boxes[i]; this._ctx.fillRect( - xOffset + (box.x * xEighth), - yOffset + (box.y * yEighth), + xOffset + (box.x*xEighth), + yOffset + (box.y*yEighth), (box.w * xEighth), (box.h * yEighth)); } From 3b8218e36e5da16c9724c7b812672879a3779b3e Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 10 Aug 2021 10:03:38 -0700 Subject: [PATCH 03/37] work with Daniel --- src/browser/renderer/BaseRenderLayer.ts | 45 +++++++++++-------- ...Characters.ts => BoxAndBlockCharacters.ts} | 0 src/common/CoreTerminal.ts | 11 +++++ 3 files changed, 38 insertions(+), 18 deletions(-) rename src/browser/renderer/{BoxCharacters.ts => BoxAndBlockCharacters.ts} (100%) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 188816ec..e6ad0af0 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,7 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; -import { boxDrawingBoxes, boxDrawingLineSegments } from 'browser/renderer/BoxCharacters'; +import { boxDrawingBoxes, boxDrawingLineSegments } from 'browser/renderer/BoxAndBlockCharacters'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -395,18 +395,16 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._ctx.strokeStyle = this._ctx.fillStyle; const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; const yOffset = y * this._scaledCellHeight + this._scaledCharTop; - const xEighth = this._scaledCellWidth / 8; - const yEighth = this._scaledCellHeight / 8; - for (let i = 0; i < boxes.length; i++) { const box = boxes[i]; + const xEighth = this._scaledCellWidth / 8; + const yEighth = this._scaledCellHeight / 8; this._ctx.fillRect( - xOffset + (box.x*xEighth), - yOffset + (box.y*yEighth), - (box.w * xEighth), - (box.h * yEighth)); + xOffset, + yOffset, + box.w * xEighth, + box.h * yEighth); } - return true; } @@ -418,28 +416,30 @@ export abstract class BaseRenderLayer implements IRenderLayer { // TODO: Clean below const scale = window.devicePixelRatio; this._ctx.strokeStyle = this._ctx.fillStyle; - this._ctx.lineWidth = scale; + + // increase # of pixels when font size incremented by 10 + this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; const yOffset = y * this._scaledCellHeight + this._scaledCharTop; - const horizontalCenter = this._scaledCellWidth / 2; - const verticalCenter = this._scaledCellHeight / 2; + const horizontalCenter = Math.round(this._scaledCellWidth / 2); + const verticalCenter = Math.round(this._scaledCellHeight / 2); const xPoints = [ xOffset, + xOffset + horizontalCenter - scale * 2, xOffset + horizontalCenter - scale, - xOffset + horizontalCenter - scale / 2, xOffset + horizontalCenter, - xOffset + horizontalCenter + scale / 2, xOffset + horizontalCenter + scale, + xOffset + horizontalCenter + scale * 2, xOffset + this._scaledCellWidth ]; const yPoints = [ yOffset, + yOffset + verticalCenter - scale * 2, yOffset + verticalCenter - scale, - yOffset + verticalCenter - scale / 2, yOffset + verticalCenter, - yOffset + verticalCenter + scale / 2, yOffset + verticalCenter + scale, + yOffset + verticalCenter + scale * 2, yOffset + this._scaledCellHeight ]; @@ -448,7 +448,12 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (i === 0 || (op.x1 !== ops[i - 1].x2 || op.y1 !== ops[i - 1].y2)) { this._ctx.beginPath(); - this._ctx.moveTo(xPoints[op.x1], yPoints[op.y1]); + if (this._ctx.lineWidth % 2 === 1) { + + this._ctx.moveTo(op.x1 === 0 ? xPoints[op.x1] : xPoints[op.x1] + .5, yPoints[op.y1] + .5); + } else { + this._ctx.moveTo(xPoints[op.x1], yPoints[op.y1]); + } } if (typeof op.cx1 !== 'undefined') { @@ -462,7 +467,11 @@ export abstract class BaseRenderLayer implements IRenderLayer { yPoints[op.y2]); } else { // Draw line - this._ctx.lineTo(xPoints[op.x2], yPoints[op.y2]); + if (this._ctx.lineWidth % 2 === 1) { + this._ctx.lineTo(op.x2 === 0 ? xPoints[op.x2] : xPoints[op.x2] + .5, yPoints[op.y2] + .5); + } else { + this._ctx.lineTo(xPoints[op.x2], yPoints[op.y2]); + } } this._ctx.stroke(); diff --git a/src/browser/renderer/BoxCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts similarity index 100% rename from src/browser/renderer/BoxCharacters.ts rename to src/browser/renderer/BoxAndBlockCharacters.ts diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index e61a8e16..14b08abd 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -132,6 +132,17 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { // Setup WriteBuffer this._writeBuffer = new WriteBuffer((data, promiseResult) => this._inputHandler.parse(data, promiseResult)); + setTimeout(() => { + this.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\r\n'); + this.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\r\n'); + this.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\r\n'); + this.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\r\n'); + this.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\r\n'); + this.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\r\n'); + this.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\r\n'); + this.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); + this.write('└─┐╘═╕╚═╕╗'); + }, 1500); } public dispose(): void { From ee759e245dee465b4bad879ae65fe7d99bd8fd40 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 10 Aug 2021 13:41:03 -0700 Subject: [PATCH 04/37] line up vertically --- src/browser/renderer/BaseRenderLayer.ts | 35 ++++++++++++------------- src/common/CoreTerminal.ts | 7 ++++- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index e6ad0af0..aefc0369 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -408,8 +408,8 @@ export abstract class BaseRenderLayer implements IRenderLayer { return true; } - const ops = boxDrawingLineSegments[char]; - if (!ops) { + const lineSegments = boxDrawingLineSegments[char]; + if (!lineSegments) { return false; } @@ -434,7 +434,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { xOffset + this._scaledCellWidth ]; const yPoints = [ - yOffset, + yOffset - 1, yOffset + verticalCenter - scale * 2, yOffset + verticalCenter - scale, yOffset + verticalCenter, @@ -443,34 +443,33 @@ export abstract class BaseRenderLayer implements IRenderLayer { yOffset + this._scaledCellHeight ]; - for (let i = 0; i < ops.length; i++) { - const op = ops[i]; + for (let i = 0; i < lineSegments.length; i++) { + const line = lineSegments[i]; - if (i === 0 || (op.x1 !== ops[i - 1].x2 || op.y1 !== ops[i - 1].y2)) { + if (i === 0 || (line.x1 !== lineSegments[i - 1].x2 || line.y1 !== lineSegments[i - 1].y2)) { this._ctx.beginPath(); if (this._ctx.lineWidth % 2 === 1) { - - this._ctx.moveTo(op.x1 === 0 ? xPoints[op.x1] : xPoints[op.x1] + .5, yPoints[op.y1] + .5); + this._ctx.moveTo(line.x1 === 0 ? xPoints[line.x1] : xPoints[line.x1] + .5, yPoints[line.y1] + .5); } else { - this._ctx.moveTo(xPoints[op.x1], yPoints[op.y1]); + this._ctx.moveTo(xPoints[line.x1], yPoints[line.y1]); } } - if (typeof op.cx1 !== 'undefined') { + if (typeof line.cx1 !== 'undefined') { // Draw curve this._ctx.bezierCurveTo( - xPoints[op.cx1], - yPoints[op.cy1], - xPoints[op.cx2], - yPoints[op.cy2], - xPoints[op.x2], - yPoints[op.y2]); + xPoints[line.cx1], + yPoints[line.cy1], + xPoints[line.cx2], + yPoints[line.cy2], + xPoints[line.x2], + yPoints[line.y2]); } else { // Draw line if (this._ctx.lineWidth % 2 === 1) { - this._ctx.lineTo(op.x2 === 0 ? xPoints[op.x2] : xPoints[op.x2] + .5, yPoints[op.y2] + .5); + this._ctx.lineTo(line.x2 === 0 ? xPoints[line.x2] : xPoints[line.x2] + .5, yPoints[line.y2] + .5); } else { - this._ctx.lineTo(xPoints[op.x2], yPoints[op.y2]); + this._ctx.lineTo(xPoints[line.x2], yPoints[line.y2]); } } diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 14b08abd..5758957e 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -141,7 +141,12 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { this.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\r\n'); this.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\r\n'); this.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); - this.write('└─┐╘═╕╚═╕╗'); + this.write('▇▇▇▇▇▇▇▇▇'); + this.write(' ╔═════════════════════════════════════════════════════════╕\r\n'); + this.write(' ║ │\r\n'); + this.write(' ║ ╔═══════════════╦════════╤════════╗ │\r\n'); + this.write(' ║ ║ ║ │ ║ │\r\n'); + this.write(' ║ ║ ║ │ ║ │\r\n'); }, 1500); } From 12980fbe0c020f4087320e69c85b01b7ede919b4 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Aug 2021 11:18:47 -0700 Subject: [PATCH 05/37] start from scratch, some progress --- src/browser/renderer/BaseRenderLayer.ts | 131 +++++++------- src/browser/renderer/BoxAndBlockCharacters.ts | 162 ++++++++++++++++++ src/common/CoreTerminal.ts | 31 ++-- 3 files changed, 250 insertions(+), 74 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index aefc0369..0fbd9455 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,7 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; -import { boxDrawingBoxes, boxDrawingLineSegments } from 'browser/renderer/BoxAndBlockCharacters'; +import { boxDrawingBoxes, boxDrawingLineSegments, draw } from 'browser/renderer/BoxAndBlockCharacters'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -412,71 +412,84 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (!lineSegments) { return false; } + const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; + const verticalCenter = Math.round(this._scaledCellHeight / 2); - // TODO: Clean below - const scale = window.devicePixelRatio; + const yOffset = y * this._scaledCellHeight + this._scaledCharTop + verticalCenter; + // const scale = window.devicePixelRatio; this._ctx.strokeStyle = this._ctx.fillStyle; // increase # of pixels when font size incremented by 10 this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); - - const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; - const yOffset = y * this._scaledCellHeight + this._scaledCharTop; const horizontalCenter = Math.round(this._scaledCellWidth / 2); - const verticalCenter = Math.round(this._scaledCellHeight / 2); - const xPoints = [ - xOffset, - xOffset + horizontalCenter - scale * 2, - xOffset + horizontalCenter - scale, - xOffset + horizontalCenter, - xOffset + horizontalCenter + scale, - xOffset + horizontalCenter + scale * 2, - xOffset + this._scaledCellWidth - ]; - const yPoints = [ - yOffset - 1, - yOffset + verticalCenter - scale * 2, - yOffset + verticalCenter - scale, - yOffset + verticalCenter, - yOffset + verticalCenter + scale, - yOffset + verticalCenter + scale * 2, - yOffset + this._scaledCellHeight - ]; - - for (let i = 0; i < lineSegments.length; i++) { - const line = lineSegments[i]; - - if (i === 0 || (line.x1 !== lineSegments[i - 1].x2 || line.y1 !== lineSegments[i - 1].y2)) { - this._ctx.beginPath(); - if (this._ctx.lineWidth % 2 === 1) { - this._ctx.moveTo(line.x1 === 0 ? xPoints[line.x1] : xPoints[line.x1] + .5, yPoints[line.y1] + .5); - } else { - this._ctx.moveTo(xPoints[line.x1], yPoints[line.y1]); - } - } - - if (typeof line.cx1 !== 'undefined') { - // Draw curve - this._ctx.bezierCurveTo( - xPoints[line.cx1], - yPoints[line.cy1], - xPoints[line.cx2], - yPoints[line.cy2], - xPoints[line.x2], - yPoints[line.y2]); - } else { - // Draw line - if (this._ctx.lineWidth % 2 === 1) { - this._ctx.lineTo(line.x2 === 0 ? xPoints[line.x2] : xPoints[line.x2] + .5, yPoints[line.y2] + .5); - } else { - this._ctx.lineTo(xPoints[line.x2], yPoints[line.y2]); - } - } - - this._ctx.stroke(); - } - + draw(this._ctx, char, xOffset, yOffset - verticalCenter, this._scaledCellWidth, this._scaledCellHeight); return true; + + + // // TODO: Clean below + // const scale = window.devicePixelRatio; + // this._ctx.strokeStyle = this._ctx.fillStyle; + + // // increase # of pixels when font size incremented by 10 + // this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); + + // const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; + // const yOffset = y * this._scaledCellHeight + this._scaledCharTop; + // const horizontalCenter = Math.round(this._scaledCellWidth / 2); + // const verticalCenter = Math.round(this._scaledCellHeight / 2); + // const xPoints = [ + // xOffset, + // xOffset + horizontalCenter - scale * 2, + // xOffset + horizontalCenter - scale, + // xOffset + horizontalCenter, + // xOffset + horizontalCenter + scale, + // xOffset + horizontalCenter + scale * 2, + // xOffset + this._scaledCellWidth + // ]; + // const yPoints = [ + // yOffset - 1, + // yOffset + verticalCenter - scale * 2, + // yOffset + verticalCenter - scale, + // yOffset + verticalCenter, + // yOffset + verticalCenter + scale, + // yOffset + verticalCenter + scale * 2, + // yOffset + this._scaledCellHeight + // ]; + + // for (let i = 0; i < lineSegments.length; i++) { + // const line = lineSegments[i]; + + // if (i === 0 || (line.x1 !== lineSegments[i - 1].x2 || line.y1 !== lineSegments[i - 1].y2)) { + // this._ctx.beginPath(); + // if (this._ctx.lineWidth % 2 === 1) { + // this._ctx.moveTo(line.x1 === 0 ? xPoints[line.x1] : xPoints[line.x1] + .5, yPoints[line.y1] + .5); + // } else { + // this._ctx.moveTo(xPoints[line.x1], yPoints[line.y1]); + // } + // } + + // if (typeof line.cx1 !== 'undefined') { + // // Draw curve + // this._ctx.bezierCurveTo( + // xPoints[line.cx1], + // yPoints[line.cy1], + // xPoints[line.cx2], + // yPoints[line.cy2], + // xPoints[line.x2], + // yPoints[line.y2]); + // } else { + // // Draw line + // if (this._ctx.lineWidth % 2 === 1) { + // this._ctx.lineTo(line.x2 === 0 ? xPoints[line.x2] : xPoints[line.x2] + .5, yPoints[line.y2] + .5); + // } else { + // this._ctx.lineTo(xPoints[line.x2], yPoints[line.y2]); + // } + // } + + // this._ctx.stroke(); + // } + + // return true; } diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 221a0e4f..eda53725 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -211,3 +211,165 @@ export const boxDrawingBoxes: { [index: string]: any } = { // HEAVY HORIZONTAL FILL (upper middle and lower one quarter block) '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] }; + +export const chars: { [index: string]: string } = { + '━': 'M0,.5, L1,.5 z', + '│': 'M0,0, L0,2 z', + '┃': 'M0,0, L0,2 z!', + '┌': 'M , L , z', + '┍': 'M , L , z', + '┎': 'M , L , z', + '┏': 'M , L , z', + '┐': 'M , L , z', + '┑': 'M , L , z', + '┒': 'M , L , z', + '┓': 'M , L , z', + '└': 'M , L , z', + '┕': 'M , L , z', + '┖': 'M , L , z', + '┗': 'M , L , z', + '┘': 'M , L , z', + '┙': 'M , L , z', + '┚': 'M , L , z', + '┛': 'M , L , z', + '├': 'M , L , z', + '┝': 'M , L , z', + '┞': 'M , L , z', + '┟': 'M , L , z', + '┠': 'M , L , z', + '┡': 'M , L , z', + '┢': 'M , L , z', + '┣': 'M , L , z', + '┤': 'M , L , z', + '┥': 'M , L , z', + '┦': 'M , L , z', + '┧': 'M , L , z', + '┨': 'M , L , z', + '┩': 'M , L , z', + '┪': 'M , L , z', + '┫': 'M , L , z', + '┬': 'M , L , z', + '┭': 'M , L , z', + '┮': 'M , L , z', + '┯': 'M , L , z', + '┰': 'M , L , z', + '┱': 'M , L , z', + '┲': 'M , L , z', + '┳': 'M , L , z', + '┴': 'M , L , z', + '┵': 'M , L , z', + '┶': 'M , L , z', + '┷': 'M , L , z', + '┸': 'M , L , z', + '┹': 'M , L , z', + '┺': 'M , L , z', + '┻': 'M , L , z', + '┼': 'M , L , z', + '┽': 'M , L , z', + '┾': 'M , L , z', + '┿': 'M , L , z', + '╀': 'M , L , z', + '╁': 'M , L , z', + '╂': 'M , L , z', + '╃': 'M , L , z', + '╄': 'M , L , z', + '╅': 'M , L , z', + '╆': 'M , L , z', + '╇': 'M , L , z', + '╈': 'M , L , z', + '╉': 'M , L , z', + '╊': 'M , L , z', + '╋': 'M , L , z', + '╌': 'M , L , z', + '╍': 'M , L , z', + '╎': 'M , L , z', + '╏': 'M , L , z', + '═': 'M , L , z', + '║': 'M , L , z', + '╒': 'M , L , z', + '╓': 'M , L , z', + '╔': 'M , L , z', + '╕': 'M , L , z', + '╖': 'M , L , z', + '╗': 'M , L , z', + '╘': 'M , L , z', + '╙': 'M , L , z', + '╚': 'M , L , z', + '╛': 'M , L , z', + '╜': 'M , L , z', + '╝': 'M , L , z', + '╞': 'M , L , z', + '╟': 'M , L , z', + '╠': 'M , L , z', + '╡': 'M , L , z', + '╢': 'M , L , z', + '╣': 'M , L , z', + '╤': 'M , L , z', + '╥': 'M , L , z', + '╦': 'M , L , z', + '╧': 'M , L , z', + '╨': 'M , L , z', + '╩': 'M , L , z', + '╪': 'M , L , z', + '╫': 'M , L , z', + '╬': 'M , L , z', + '╭': 'M , L , z', + '╮': 'M , L , z', + '╯': 'M , L , z', + '╰': 'M , L , z', + '╱': 'M , L , z', + '╲': 'M , L , z', + '╳': 'M , L , z', + '╴': 'M , L , z', + '╵': 'M , L , z', + '╶': 'M , L , z', + '╷': 'M , L , z', + '╸': 'M , L , z', + '╹': 'M , L , z', + '╺': 'M , L , z', + '╻': 'M , L , z', + '╼': 'M , L , z', + '╽': 'M , L , z', + '╾': 'M , L , z', + '╿': 'M0,0, L0,10 z' +}; + +export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { + const entry = chars[c]; + console.log(c); + if (!entry) { + return; + } + const instructions = entry.split(' '); + for (const instruction of instructions) { + if (instruction.endsWith('!')) { + ctx.lineWidth = ctx.lineWidth * 2; + } + const type = instruction[0]; + const spec = instructionMap[type]; + const coords: string[] = instruction.substring(1).split(','); + if (!coords[0] || !coords[1]) { + continue; + } + + + const numX = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); + const numY = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); + spec(ctx, xOffset + Math.round((numX)*cellWidth), yOffset + ((numY))*cellHeight); + } + ctx.stroke(); +} + +const instructionMap: { [index: string]: any } = { + 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => { + ctx.beginPath(); + ctx.moveTo(x, y); + }, + 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => { + ctx.lineTo(x, y); + }, + 'z': (ctx: CanvasRenderingContext2D) => { + ctx.closePath(); + console.log('closing path'); + } +}; diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 5758957e..710f6164 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -133,21 +133,22 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { // Setup WriteBuffer this._writeBuffer = new WriteBuffer((data, promiseResult) => this._inputHandler.parse(data, promiseResult)); setTimeout(() => { - this.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\r\n'); - this.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\r\n'); - this.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\r\n'); - this.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\r\n'); - this.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\r\n'); - this.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\r\n'); - this.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\r\n'); - this.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); - this.write('▇▇▇▇▇▇▇▇▇'); - this.write(' ╔═════════════════════════════════════════════════════════╕\r\n'); - this.write(' ║ │\r\n'); - this.write(' ║ ╔═══════════════╦════════╤════════╗ │\r\n'); - this.write(' ║ ║ ║ │ ║ │\r\n'); - this.write(' ║ ║ ║ │ ║ │\r\n'); - }, 1500); + // this.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\r\n'); + // this.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\r\n'); + // this.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\r\n'); + // this.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\r\n'); + // this.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\r\n'); + // this.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\r\n'); + // this.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\r\n'); + // this.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); + // this.write(' ╔═════════════════════════════════════════════════════════╕\r\n'); + // this.write(' ║ │\r\n'); + // this.write(' ║ ╔═══════════════╦════════╤════════╗ │\r\n'); + // this.write(' ║ ║ ║ │ ║ │\r\n'); + // this.write(' ║ ║ ║ │ ║ │\r\n'); + // this.write('▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇'); + this.write('━│┃'); + }, 1000); } public dispose(): void { From db845a6f24c9492199081eb0f569acc0871e4de7 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Aug 2021 14:14:17 -0700 Subject: [PATCH 06/37] make a bunch of progress --- src/browser/renderer/BaseRenderLayer.ts | 3 +- src/browser/renderer/BoxAndBlockCharacters.ts | 282 ++++++++++-------- src/common/CoreTerminal.ts | 4 +- 3 files changed, 156 insertions(+), 133 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 0fbd9455..39819353 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -422,7 +422,8 @@ export abstract class BaseRenderLayer implements IRenderLayer { // increase # of pixels when font size incremented by 10 this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); const horizontalCenter = Math.round(this._scaledCellWidth / 2); - draw(this._ctx, char, xOffset, yOffset - verticalCenter, this._scaledCellWidth, this._scaledCellHeight); + // yOffset - verticalCenter + draw(this._ctx, char, xOffset, y * this._scaledCellHeight + this._scaledCharTop, this._scaledCellWidth, this._scaledCellHeight); return true; diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index eda53725..de8a349c 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -212,152 +212,173 @@ export const boxDrawingBoxes: { [index: string]: any } = { '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] }; +export const enum CENTER { + BOTTOM ='.5,1', + TOP = '.5,0', + MIDDLE = '.5,.5' +} + +export const enum LEFT { + BOTTOM = '0,1', + TOP = '0,0', + MIDDLE = '0,.5' +} + +export const enum RIGHT { + BOTTOM = '1,1', + TOP = '1,0', + MIDDLE = '1,.5' +} + +const MOVE = 'M'; +const TO = 'L'; +const BOLD = '!'; + export const chars: { [index: string]: string } = { - '━': 'M0,.5, L1,.5 z', - '│': 'M0,0, L0,2 z', - '┃': 'M0,0, L0,2 z!', - '┌': 'M , L , z', - '┍': 'M , L , z', - '┎': 'M , L , z', - '┏': 'M , L , z', - '┐': 'M , L , z', - '┑': 'M , L , z', - '┒': 'M , L , z', - '┓': 'M , L , z', - '└': 'M , L , z', - '┕': 'M , L , z', - '┖': 'M , L , z', - '┗': 'M , L , z', - '┘': 'M , L , z', - '┙': 'M , L , z', - '┚': 'M , L , z', - '┛': 'M , L , z', - '├': 'M , L , z', - '┝': 'M , L , z', - '┞': 'M , L , z', - '┟': 'M , L , z', - '┠': 'M , L , z', - '┡': 'M , L , z', - '┢': 'M , L , z', - '┣': 'M , L , z', - '┤': 'M , L , z', - '┥': 'M , L , z', - '┦': 'M , L , z', - '┧': 'M , L , z', - '┨': 'M , L , z', - '┩': 'M , L , z', - '┪': 'M , L , z', - '┫': 'M , L , z', - '┬': 'M , L , z', - '┭': 'M , L , z', - '┮': 'M , L , z', - '┯': 'M , L , z', - '┰': 'M , L , z', - '┱': 'M , L , z', - '┲': 'M , L , z', - '┳': 'M , L , z', - '┴': 'M , L , z', - '┵': 'M , L , z', - '┶': 'M , L , z', - '┷': 'M , L , z', - '┸': 'M , L , z', - '┹': 'M , L , z', - '┺': 'M , L , z', - '┻': 'M , L , z', - '┼': 'M , L , z', - '┽': 'M , L , z', - '┾': 'M , L , z', - '┿': 'M , L , z', - '╀': 'M , L , z', - '╁': 'M , L , z', - '╂': 'M , L , z', - '╃': 'M , L , z', - '╄': 'M , L , z', - '╅': 'M , L , z', - '╆': 'M , L , z', - '╇': 'M , L , z', - '╈': 'M , L , z', - '╉': 'M , L , z', - '╊': 'M , L , z', - '╋': 'M , L , z', - '╌': 'M , L , z', - '╍': 'M , L , z', - '╎': 'M , L , z', - '╏': 'M , L , z', - '═': 'M , L , z', - '║': 'M , L , z', - '╒': 'M , L , z', - '╓': 'M , L , z', - '╔': 'M , L , z', - '╕': 'M , L , z', - '╖': 'M , L , z', - '╗': 'M , L , z', - '╘': 'M , L , z', - '╙': 'M , L , z', - '╚': 'M , L , z', - '╛': 'M , L , z', - '╜': 'M , L , z', - '╝': 'M , L , z', - '╞': 'M , L , z', - '╟': 'M , L , z', - '╠': 'M , L , z', - '╡': 'M , L , z', - '╢': 'M , L , z', - '╣': 'M , L , z', - '╤': 'M , L , z', - '╥': 'M , L , z', - '╦': 'M , L , z', - '╧': 'M , L , z', - '╨': 'M , L , z', - '╩': 'M , L , z', - '╪': 'M , L , z', - '╫': 'M , L , z', - '╬': 'M , L , z', - '╭': 'M , L , z', - '╮': 'M , L , z', - '╯': 'M , L , z', - '╰': 'M , L , z', - '╱': 'M , L , z', - '╲': 'M , L , z', - '╳': 'M , L , z', - '╴': 'M , L , z', - '╵': 'M , L , z', - '╶': 'M , L , z', - '╷': 'M , L , z', - '╸': 'M , L , z', - '╹': 'M , L , z', - '╺': 'M , L , z', - '╻': 'M , L , z', - '╼': 'M , L , z', - '╽': 'M , L , z', - '╾': 'M , L , z', - '╿': 'M0,0, L0,10 z' + '━': `${MOVE}${LEFT.MIDDLE} ${TO}${RIGHT.MIDDLE}`, + '│': `${MOVE}${CENTER.TOP} ${TO}${CENTER.BOTTOM}`, + '┃': `${MOVE}${CENTER.TOP} ${TO}${CENTER.BOTTOM}${BOLD}`, + '┌': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`, + '┍': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}${BOLD}`, + '┎': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${RIGHT.MIDDLE}`, + '┏': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${RIGHT.MIDDLE}${BOLD}`, + '┐': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`, + '┑': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}${BOLD}`, + '┒': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${LEFT.MIDDLE}`, + '┓': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${LEFT.MIDDLE}${BOLD}` + // '└': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┕': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┖': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┗': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┘': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┙': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┚': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┛': `${MOVE}${} ${TO}${} ${TO}${}`, + // '├': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┝': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┞': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┟': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┠': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┡': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┢': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┣': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┤': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┥': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┦': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┧': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┨': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┩': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┪': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┫': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┬': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┭': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┮': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┯': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┰': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┱': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┲': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┳': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┴': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┵': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┶': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┷': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┸': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┹': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┺': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┻': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┼': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┽': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┾': `${MOVE}${} ${TO}${} ${TO}${}`, + // '┿': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╀': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╁': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╂': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╃': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╄': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╅': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╆': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╇': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╈': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╉': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╊': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╋': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╌': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╍': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╎': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╏': `${MOVE}${} ${TO}${} ${TO}${}`, + // '═': `${MOVE}${} ${TO}${} ${TO}${}`, + // '║': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╒': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╓': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╔': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╕': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╖': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╗': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╘': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╙': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╚': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╛': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╜': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╝': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╞': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╟': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╠': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╡': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╢': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╣': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╤': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╥': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╦': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╧': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╨': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╩': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╪': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╫': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╬': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╭': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╮': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╯': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╰': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╱': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╲': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╴': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╵': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╶': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╷': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╸': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╹': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╺': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╻': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╼': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╽': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╾': `${MOVE}${} ${TO}${} ${TO}${}`, + // '╿': `${MOVE}${} ${TO}${} ${TO}${}` }; export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { const entry = chars[c]; - console.log(c); if (!entry) { return; } + const lineWidth = ctx.lineWidth; const instructions = entry.split(' '); for (const instruction of instructions) { - if (instruction.endsWith('!')) { - ctx.lineWidth = ctx.lineWidth * 2; - } const type = instruction[0]; const spec = instructionMap[type]; const coords: string[] = instruction.substring(1).split(','); if (!coords[0] || !coords[1]) { continue; } - - const numX = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); const numY = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); - spec(ctx, xOffset + Math.round((numX)*cellWidth), yOffset + ((numY))*cellHeight); + if (instruction.endsWith(BOLD)) { + ctx.lineWidth = lineWidth * 2; + } else { + ctx.lineWidth = lineWidth; + } + spec(ctx, xOffset + Math.round((numX) * cellWidth), yOffset + ((numY)) * cellHeight); } - ctx.stroke(); } const instructionMap: { [index: string]: any } = { @@ -367,9 +388,8 @@ const instructionMap: { [index: string]: any } = { }, 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => { ctx.lineTo(x, y); - }, - 'z': (ctx: CanvasRenderingContext2D) => { - ctx.closePath(); - console.log('closing path'); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(x, y); } }; diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 710f6164..32341d8d 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -147,7 +147,9 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { // this.write(' ║ ║ ║ │ ║ │\r\n'); // this.write(' ║ ║ ║ │ ║ │\r\n'); // this.write('▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇'); - this.write('━│┃'); + this.write('━━│┃\r\n'); + this.write(' ━━│┃┌┍┎┏\r\n'); + this.write(' ━━│┃┌┐┍┑┎┒┏┓'); }, 1000); } From 57c7e6af4703cd4040da36baa36bd3f47a166e14 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Aug 2021 15:19:12 -0700 Subject: [PATCH 07/37] add more characters --- src/browser/renderer/BoxAndBlockCharacters.ts | 147 ++++++++++-------- src/common/CoreTerminal.ts | 7 +- 2 files changed, 84 insertions(+), 70 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index de8a349c..b57a9c56 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -232,76 +232,85 @@ export const enum RIGHT { const MOVE = 'M'; const TO = 'L'; -const BOLD = '!'; +const THICK = '!'; + +const yAxis = `${MOVE}${CENTER.TOP} ${TO}${CENTER.BOTTOM}`; +const xAxis = `${MOVE}${LEFT.MIDDLE} ${TO}${RIGHT.MIDDLE}`; +const bottomYAxisFromBottom = `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}`; +const bottomYAxisFromMiddle = `${MOVE}${CENTER.MIDDLE} ${TO}${CENTER.BOTTOM}`; +const topYAxisFromTop = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; +const topYAxisFromMiddle = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; +const rightMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`; +const leftMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`; export const chars: { [index: string]: string } = { - '━': `${MOVE}${LEFT.MIDDLE} ${TO}${RIGHT.MIDDLE}`, - '│': `${MOVE}${CENTER.TOP} ${TO}${CENTER.BOTTOM}`, - '┃': `${MOVE}${CENTER.TOP} ${TO}${CENTER.BOTTOM}${BOLD}`, - '┌': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`, - '┍': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}${BOLD}`, - '┎': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${RIGHT.MIDDLE}`, - '┏': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${RIGHT.MIDDLE}${BOLD}`, - '┐': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`, - '┑': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}${BOLD}`, - '┒': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${LEFT.MIDDLE}`, - '┓': `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}${BOLD} ${TO}${LEFT.MIDDLE}${BOLD}` - // '└': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┕': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┖': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┗': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┘': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┙': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┚': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┛': `${MOVE}${} ${TO}${} ${TO}${}`, - // '├': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┝': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┞': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┟': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┠': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┡': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┢': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┣': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┤': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┥': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┦': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┧': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┨': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┩': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┪': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┫': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┬': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┭': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┮': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┯': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┰': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┱': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┲': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┳': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┴': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┵': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┶': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┷': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┸': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┹': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┺': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┻': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┼': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┽': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┾': `${MOVE}${} ${TO}${} ${TO}${}`, - // '┿': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╀': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╁': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╂': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╃': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╄': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╅': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╆': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╇': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╈': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╉': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╊': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╋': `${MOVE}${} ${TO}${} ${TO}${}`, + '━': `${xAxis}`, + '│': `${yAxis}`, + '┃': `${yAxis}${THICK}`, + '┌': `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}`, + '┍': `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}${THICK}`, + '┎': `${bottomYAxisFromBottom}${THICK} ${TO}${RIGHT.MIDDLE}`, + '┏': `${bottomYAxisFromBottom}${THICK} ${TO}${RIGHT.MIDDLE}${THICK}`, + '┐': `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}`, + '┑': `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}${THICK}`, + '┒': `${bottomYAxisFromBottom}${THICK} ${TO}${LEFT.MIDDLE}`, + '┓': `${bottomYAxisFromBottom}${THICK} ${TO}${LEFT.MIDDLE}${THICK}`, + '└': `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}`, + '┕': `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}${THICK}`, + '┖': `${topYAxisFromTop}${THICK} ${TO}${RIGHT.MIDDLE}`, + '┗': `${topYAxisFromTop}${THICK} ${TO}${RIGHT.MIDDLE}${THICK}`, + '┘': `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}`, + '┙': `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}${THICK}`, + '┚': `${topYAxisFromTop}${THICK} ${TO}${LEFT.MIDDLE}`, + '┛': `${topYAxisFromTop}${THICK} ${TO}${LEFT.MIDDLE}${THICK}`, + '├': `${yAxis} ${rightMiddleXAxis}`, + '┝': `${yAxis} ${rightMiddleXAxis}${THICK}`, + '┞': `${topYAxisFromTop}${THICK} ${bottomYAxisFromMiddle} ${rightMiddleXAxis}`, + '┟': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${rightMiddleXAxis}${THICK}`, + '┠': `${yAxis}${THICK} ${rightMiddleXAxis}`, + '┡': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK} ${rightMiddleXAxis}${THICK}`, + '┢': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${rightMiddleXAxis}${THICK}`, + '┣': `${yAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + '┤': `${yAxis} ${leftMiddleXAxis}`, + '┥': `${yAxis} ${leftMiddleXAxis}${THICK}`, + '┦': `${topYAxisFromTop}${THICK} ${bottomYAxisFromMiddle} ${leftMiddleXAxis}`, + '┧': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, + '┨': `${yAxis}${THICK} ${leftMiddleXAxis}`, + '┩': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK} ${leftMiddleXAxis}${THICK}`, + '┪': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, + '┫': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK}`, + '┬': `${bottomYAxisFromBottom} ${xAxis}`, + '┭': `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '┮': `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '┯': `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + '┰': `${bottomYAxisFromBottom}${THICK} ${xAxis}`, + '┱': `${bottomYAxisFromBottom}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '┲': `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '┳': `${bottomYAxisFromBottom}${THICK} ${xAxis}${THICK}`, + '┴': `${topYAxisFromTop} ${xAxis}`, + '┵': `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '┶': `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '┷': `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + '┸': `${topYAxisFromTop}${THICK} ${xAxis}`, + '┹': `${topYAxisFromTop}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '┺': `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '┻': `${topYAxisFromTop}${THICK} ${xAxis}${THICK}`, + '┼': `${yAxis} ${xAxis}`, + '┽': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '┾': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '┿': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + '╀': `${yAxis}${THICK} ${xAxis}`, + '╁': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '╂': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '╃': `${yAxis}${THICK} ${xAxis}${THICK}`, + '╄': `${yAxis} ${xAxis}`, + '╅': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '╆': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '╇': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + '╈': `${yAxis}${THICK} ${xAxis}`, + '╉': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '╊': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '╋': `${yAxis}${THICK} ${xAxis}${THICK}` // '╌': `${MOVE}${} ${TO}${} ${TO}${}`, // '╍': `${MOVE}${} ${TO}${} ${TO}${}`, // '╎': `${MOVE}${} ${TO}${} ${TO}${}`, @@ -372,7 +381,7 @@ export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, } const numX = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); const numY = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); - if (instruction.endsWith(BOLD)) { + if (instruction.endsWith(THICK)) { ctx.lineWidth = lineWidth * 2; } else { ctx.lineWidth = lineWidth; diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 32341d8d..7c3f0e03 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -149,7 +149,12 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { // this.write('▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇'); this.write('━━│┃\r\n'); this.write(' ━━│┃┌┍┎┏\r\n'); - this.write(' ━━│┃┌┐┍┑┎┒┏┓'); + this.write(' ━━│┃┌┐┍┑┎┒┏┓\r\n'); + this.write(' └┘┕┙┖┚┗┛\r\n'); + this.write('├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿\r\n'); + this.write('├ ┝ ┞ ┟ ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻\r\n'); + this.write('┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋\r\n'); + this.write('╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); }, 1000); } From 927a1424809d2cbbb4888923cbcf0fd9b32eca5a Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Aug 2021 15:36:29 -0700 Subject: [PATCH 08/37] add more --- src/browser/renderer/BoxAndBlockCharacters.ts | 34 +++++++++---------- src/common/CoreTerminal.ts | 6 ++-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index b57a9c56..bbba5090 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -310,11 +310,11 @@ export const chars: { [index: string]: string } = { '╈': `${yAxis}${THICK} ${xAxis}`, '╉': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, '╊': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '╋': `${yAxis}${THICK} ${xAxis}${THICK}` - // '╌': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╍': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╎': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╏': `${MOVE}${} ${TO}${} ${TO}${}`, + '╋': `${yAxis}${THICK} ${xAxis}${THICK}`, + '╌': `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}`, + '╍': `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'}${THICK} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, + '╎':`${MOVE}${CENTER.BOTTOM} ${TO}${'.5,.3'} ${MOVE}${'.5,.7'} ${TO}${CENTER.TOP}`, + '╏':`${MOVE}${CENTER.BOTTOM} ${TO}${'.5,.3'}${THICK} ${MOVE}${'.5,.7'} ${TO}${CENTER.TOP}${THICK}`, // '═': `${MOVE}${} ${TO}${} ${TO}${}`, // '║': `${MOVE}${} ${TO}${} ${TO}${}`, // '╒': `${MOVE}${} ${TO}${} ${TO}${}`, @@ -351,18 +351,18 @@ export const chars: { [index: string]: string } = { // '╱': `${MOVE}${} ${TO}${} ${TO}${}`, // '╲': `${MOVE}${} ${TO}${} ${TO}${}`, // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╴': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╵': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╶': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╷': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╸': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╹': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╺': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╻': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╼': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╽': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╾': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╿': `${MOVE}${} ${TO}${} ${TO}${}` + '╴': `${leftMiddleXAxis}`, + '╵': `${topYAxisFromMiddle}`, + '╶': `${rightMiddleXAxis}`, + '╷': `${bottomYAxisFromMiddle}`, + '╸': `${leftMiddleXAxis}${THICK}`, + '╹': `${topYAxisFromMiddle}${THICK}`, + '╺': `${rightMiddleXAxis}${THICK}`, + '╻': `${bottomYAxisFromMiddle}${THICK}`, + '╼': `${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + '╽': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle}`, + '╾': `${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + '╿': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK}` }; export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 7c3f0e03..a3026016 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -151,10 +151,12 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { this.write(' ━━│┃┌┍┎┏\r\n'); this.write(' ━━│┃┌┐┍┑┎┒┏┓\r\n'); this.write(' └┘┕┙┖┚┗┛\r\n'); - this.write('├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿\r\n'); + this.write('├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋ ╌ ╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬\r\n'); + this.write('╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿\r\n'); this.write('├ ┝ ┞ ┟ ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻\r\n'); this.write('┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋\r\n'); - this.write('╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); + this.write(' ╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬\r\n'); + this.write('╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); }, 1000); } From 46cb37876deea04f11401aad6a365f06a3a0b555 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 11 Aug 2021 15:46:50 -0700 Subject: [PATCH 09/37] more working --- src/browser/renderer/BoxAndBlockCharacters.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index bbba5090..379bc2d7 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -311,10 +311,10 @@ export const chars: { [index: string]: string } = { '╉': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, '╊': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, '╋': `${yAxis}${THICK} ${xAxis}${THICK}`, - '╌': `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}`, - '╍': `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'}${THICK} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, - '╎':`${MOVE}${CENTER.BOTTOM} ${TO}${'.5,.3'} ${MOVE}${'.5,.7'} ${TO}${CENTER.TOP}`, - '╏':`${MOVE}${CENTER.BOTTOM} ${TO}${'.5,.3'}${THICK} ${MOVE}${'.5,.7'} ${TO}${CENTER.TOP}${THICK}`, + '╌': `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}`, + '╍': `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'}${THICK} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, + '╎':`${MOVE}${CENTER.TOP} ${TO}${'.5,.47'} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}`, + '╏':`${MOVE}${CENTER.TOP} ${TO}${'.5,.47'}${THICK} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}${THICK}`, // '═': `${MOVE}${} ${TO}${} ${TO}${}`, // '║': `${MOVE}${} ${TO}${} ${TO}${}`, // '╒': `${MOVE}${} ${TO}${} ${TO}${}`, From d13afa1b37afc43f505ed573db576a469c75e2cf Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Aug 2021 10:12:43 -0700 Subject: [PATCH 10/37] get things to work Co-authored-by: Daniel Imms --- src/browser/renderer/BaseRenderLayer.ts | 6 ++--- src/browser/renderer/BoxAndBlockCharacters.ts | 25 +++++++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 39819353..3d0128fe 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -412,7 +412,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (!lineSegments) { return false; } - const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; + const xOffset = x * this._scaledCellWidth; const verticalCenter = Math.round(this._scaledCellHeight / 2); const yOffset = y * this._scaledCellHeight + this._scaledCharTop + verticalCenter; @@ -420,10 +420,10 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._ctx.strokeStyle = this._ctx.fillStyle; // increase # of pixels when font size incremented by 10 - this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); + // this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); const horizontalCenter = Math.round(this._scaledCellWidth / 2); // yOffset - verticalCenter - draw(this._ctx, char, xOffset, y * this._scaledCellHeight + this._scaledCharTop, this._scaledCellWidth, this._scaledCellHeight); + draw(this._ctx, char, xOffset, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); return true; diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 379bc2d7..0bbc487f 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -372,6 +372,7 @@ export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, } const lineWidth = ctx.lineWidth; const instructions = entry.split(' '); + for (const instruction of instructions) { const type = instruction[0]; const spec = instructionMap[type]; @@ -379,17 +380,31 @@ export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, if (!coords[0] || !coords[1]) { continue; } - const numX = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); - const numY = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); + let numX = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); + let numY = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); if (instruction.endsWith(THICK)) { - ctx.lineWidth = lineWidth * 2; + ctx.lineWidth = window.devicePixelRatio * 2; } else { - ctx.lineWidth = lineWidth; + ctx.lineWidth = window.devicePixelRatio; } - spec(ctx, xOffset + Math.round((numX) * cellWidth), yOffset + ((numY)) * cellHeight); + + numX *= cellWidth; + numY *= cellHeight; + + if (numY !== 0) { + numY = clamp(Math.round(numY + .5) - .5, cellHeight, 0); + } + if (numX !== 0) { + numX = clamp(Math.round(numX + .5) - .5, cellWidth, 0); + } + spec(ctx, xOffset + numX, yOffset + numY); } } +function clamp(value: number, max: number, min: number = 0): number { + return Math.max(Math.min(value, max), min); +} + const instructionMap: { [index: string]: any } = { 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => { ctx.beginPath(); From 91043858837b64d3c402d14d95d7686c9069baf0 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Aug 2021 11:38:45 -0700 Subject: [PATCH 11/37] convert a bunch of them --- src/browser/renderer/BaseRenderLayer.ts | 67 --- src/browser/renderer/BoxAndBlockCharacters.ts | 515 +++++++++++++----- 2 files changed, 364 insertions(+), 218 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 3d0128fe..31773f64 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -421,76 +421,9 @@ export abstract class BaseRenderLayer implements IRenderLayer { // increase # of pixels when font size incremented by 10 // this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); - const horizontalCenter = Math.round(this._scaledCellWidth / 2); // yOffset - verticalCenter draw(this._ctx, char, xOffset, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); return true; - - - // // TODO: Clean below - // const scale = window.devicePixelRatio; - // this._ctx.strokeStyle = this._ctx.fillStyle; - - // // increase # of pixels when font size incremented by 10 - // this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); - - // const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; - // const yOffset = y * this._scaledCellHeight + this._scaledCharTop; - // const horizontalCenter = Math.round(this._scaledCellWidth / 2); - // const verticalCenter = Math.round(this._scaledCellHeight / 2); - // const xPoints = [ - // xOffset, - // xOffset + horizontalCenter - scale * 2, - // xOffset + horizontalCenter - scale, - // xOffset + horizontalCenter, - // xOffset + horizontalCenter + scale, - // xOffset + horizontalCenter + scale * 2, - // xOffset + this._scaledCellWidth - // ]; - // const yPoints = [ - // yOffset - 1, - // yOffset + verticalCenter - scale * 2, - // yOffset + verticalCenter - scale, - // yOffset + verticalCenter, - // yOffset + verticalCenter + scale, - // yOffset + verticalCenter + scale * 2, - // yOffset + this._scaledCellHeight - // ]; - - // for (let i = 0; i < lineSegments.length; i++) { - // const line = lineSegments[i]; - - // if (i === 0 || (line.x1 !== lineSegments[i - 1].x2 || line.y1 !== lineSegments[i - 1].y2)) { - // this._ctx.beginPath(); - // if (this._ctx.lineWidth % 2 === 1) { - // this._ctx.moveTo(line.x1 === 0 ? xPoints[line.x1] : xPoints[line.x1] + .5, yPoints[line.y1] + .5); - // } else { - // this._ctx.moveTo(xPoints[line.x1], yPoints[line.y1]); - // } - // } - - // if (typeof line.cx1 !== 'undefined') { - // // Draw curve - // this._ctx.bezierCurveTo( - // xPoints[line.cx1], - // yPoints[line.cy1], - // xPoints[line.cx2], - // yPoints[line.cy2], - // xPoints[line.x2], - // yPoints[line.y2]); - // } else { - // // Draw line - // if (this._ctx.lineWidth % 2 === 1) { - // this._ctx.lineTo(line.x2 === 0 ? xPoints[line.x2] : xPoints[line.x2] + .5, yPoints[line.y2] + .5); - // } else { - // this._ctx.lineTo(xPoints[line.x2], yPoints[line.y2]); - // } - // } - - // this._ctx.stroke(); - // } - - // return true; } diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 0bbc487f..1b6fef41 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -243,161 +243,378 @@ const topYAxisFromMiddle = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; const rightMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`; const leftMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`; -export const chars: { [index: string]: string } = { - '━': `${xAxis}`, - '│': `${yAxis}`, - '┃': `${yAxis}${THICK}`, - '┌': `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}`, - '┍': `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}${THICK}`, - '┎': `${bottomYAxisFromBottom}${THICK} ${TO}${RIGHT.MIDDLE}`, - '┏': `${bottomYAxisFromBottom}${THICK} ${TO}${RIGHT.MIDDLE}${THICK}`, - '┐': `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}`, - '┑': `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}${THICK}`, - '┒': `${bottomYAxisFromBottom}${THICK} ${TO}${LEFT.MIDDLE}`, - '┓': `${bottomYAxisFromBottom}${THICK} ${TO}${LEFT.MIDDLE}${THICK}`, - '└': `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}`, - '┕': `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}${THICK}`, - '┖': `${topYAxisFromTop}${THICK} ${TO}${RIGHT.MIDDLE}`, - '┗': `${topYAxisFromTop}${THICK} ${TO}${RIGHT.MIDDLE}${THICK}`, - '┘': `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}`, - '┙': `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}${THICK}`, - '┚': `${topYAxisFromTop}${THICK} ${TO}${LEFT.MIDDLE}`, - '┛': `${topYAxisFromTop}${THICK} ${TO}${LEFT.MIDDLE}${THICK}`, - '├': `${yAxis} ${rightMiddleXAxis}`, - '┝': `${yAxis} ${rightMiddleXAxis}${THICK}`, - '┞': `${topYAxisFromTop}${THICK} ${bottomYAxisFromMiddle} ${rightMiddleXAxis}`, - '┟': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${rightMiddleXAxis}${THICK}`, - '┠': `${yAxis}${THICK} ${rightMiddleXAxis}`, - '┡': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK} ${rightMiddleXAxis}${THICK}`, - '┢': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${rightMiddleXAxis}${THICK}`, - '┣': `${yAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - '┤': `${yAxis} ${leftMiddleXAxis}`, - '┥': `${yAxis} ${leftMiddleXAxis}${THICK}`, - '┦': `${topYAxisFromTop}${THICK} ${bottomYAxisFromMiddle} ${leftMiddleXAxis}`, - '┧': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, - '┨': `${yAxis}${THICK} ${leftMiddleXAxis}`, - '┩': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK} ${leftMiddleXAxis}${THICK}`, - '┪': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, - '┫': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK}`, - '┬': `${bottomYAxisFromBottom} ${xAxis}`, - '┭': `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '┮': `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '┯': `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - '┰': `${bottomYAxisFromBottom}${THICK} ${xAxis}`, - '┱': `${bottomYAxisFromBottom}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '┲': `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '┳': `${bottomYAxisFromBottom}${THICK} ${xAxis}${THICK}`, - '┴': `${topYAxisFromTop} ${xAxis}`, - '┵': `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '┶': `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '┷': `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - '┸': `${topYAxisFromTop}${THICK} ${xAxis}`, - '┹': `${topYAxisFromTop}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '┺': `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '┻': `${topYAxisFromTop}${THICK} ${xAxis}${THICK}`, - '┼': `${yAxis} ${xAxis}`, - '┽': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '┾': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '┿': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - '╀': `${yAxis}${THICK} ${xAxis}`, - '╁': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '╂': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '╃': `${yAxis}${THICK} ${xAxis}${THICK}`, - '╄': `${yAxis} ${xAxis}`, - '╅': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '╆': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '╇': `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - '╈': `${yAxis}${THICK} ${xAxis}`, - '╉': `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '╊': `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '╋': `${yAxis}${THICK} ${xAxis}${THICK}`, - '╌': `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}`, - '╍': `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'}${THICK} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, - '╎':`${MOVE}${CENTER.TOP} ${TO}${'.5,.47'} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}`, - '╏':`${MOVE}${CENTER.TOP} ${TO}${'.5,.47'}${THICK} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}${THICK}`, - // '═': `${MOVE}${} ${TO}${} ${TO}${}`, - // '║': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╒': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╓': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╔': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╕': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╖': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╗': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╘': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╙': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╚': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╛': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╜': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╝': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╞': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╟': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╠': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╡': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╢': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╣': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╤': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╥': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╦': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╧': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╨': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╩': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╪': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╫': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╬': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╭': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╮': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╯': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╰': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╱': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╲': `${MOVE}${} ${TO}${} ${TO}${}`, - // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, - '╴': `${leftMiddleXAxis}`, - '╵': `${topYAxisFromMiddle}`, - '╶': `${rightMiddleXAxis}`, - '╷': `${bottomYAxisFromMiddle}`, - '╸': `${leftMiddleXAxis}${THICK}`, - '╹': `${topYAxisFromMiddle}${THICK}`, - '╺': `${rightMiddleXAxis}${THICK}`, - '╻': `${bottomYAxisFromMiddle}${THICK}`, - '╼': `${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - '╽': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle}`, - '╾': `${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - '╿': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK}` +const map: { [character: string]: { [fontWeight: number]: string } } = { + '━': { + 1: `${xAxis}` + }, + '│': { + 1: `${yAxis}` + }, + '┃': { + 2: `${yAxis}` + }, + '┌': { + 1: `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}` + }, + '┍': { + 1: `${bottomYAxisFromBottom}`, + 2: `${rightMiddleXAxis}` + }, + '┎': { + 1: `${rightMiddleXAxis}`, + 2: `${bottomYAxisFromBottom}` + }, + '┏': { + 2: `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}` + }, + '┐': { + 1: `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}` + }, + '┑': { + 1: `${bottomYAxisFromBottom}`, + 2: `${leftMiddleXAxis}` + }, + '┒': { + 1: `${leftMiddleXAxis}`, + 2: `${bottomYAxisFromBottom}` + }, + '┓': { + 2: `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}` + }, + '└': { + 1: `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}` + }, + '┕': { + 1: `${topYAxisFromTop}`, + 2: `${rightMiddleXAxis}` + }, + '┖': { + 1: `${rightMiddleXAxis}`, + 2: `${topYAxisFromTop}` + }, + '┗': { + 2: `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}` + }, + '┘': { + 1: `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}` + }, + '┙': { + 1: `${topYAxisFromTop}`, + 2: `${leftMiddleXAxis}` + }, + '┚': { + 1: `${leftMiddleXAxis}`, + 2: `${topYAxisFromTop}` + }, + '┛': { + 2: `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}` + }, + '├': { + 1: `${yAxis} ${rightMiddleXAxis}` + }, + '┝': { + 1: `${yAxis}`, + 2: `${rightMiddleXAxis}` + }, + '┞': { + 1: `${bottomYAxisFromMiddle} ${rightMiddleXAxis}`, + 2: `${topYAxisFromTop}` + }, + '┟': { + 1: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, + 2: `${bottomYAxisFromBottom}` + }, + '┠': { + 1: `${rightMiddleXAxis}`, + 2: `${yAxis}` + }, + '┡': { + 1: `${bottomYAxisFromBottom}`, + 2: `${topYAxisFromMiddle} ${rightMiddleXAxis}` + }, + '┢': { + 1: `${topYAxisFromMiddle}`, + 2: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` + }, + '┣': { + 2: `${yAxis} ${rightMiddleXAxis}` + }, + '┤': { + 1: `${yAxis} ${leftMiddleXAxis}` + }, + '┥': { + 1: `${yAxis}`, + 2: `${leftMiddleXAxis}` + }, + '┦': { + 1: `${bottomYAxisFromMiddle} ${leftMiddleXAxis}`, + 2: `${topYAxisFromTop}` + }, + '┧': { + 1: `${topYAxisFromMiddle}`, + 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` + }, + '┨': { + 1: `${leftMiddleXAxis}`, + 2: `${yAxis}` + }, + '┩': { + 2: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, + 1: `${bottomYAxisFromMiddle}` + } +}; + +const chars: { [index: string]: string } = { + + + // } // '┩{ + // 1: ': `${leftMiddleXAxis}${THICK} ${topYAxisFromMiddle}${THICK} ${MOVE}${CENTER.MIDDLE} ${bottomYAxisFromMiddle + // 1: ': `${leftMiddleXAxis}${THICK} ${topYAxisFromMiddle}${THICK} ${MOVE}${CENTER.MIDDLE} ${bottomYAxisFromMiddle + // }`, + + // } '┪': { + // 1: `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, + // 1: `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, + // } + // '┫': { + // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK}`, + // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK}`, + // } + // '┬': { + // 1: `${bottomYAxisFromBottom} ${xAxis}`, + // 1: `${bottomYAxisFromBottom} ${xAxis}`, + // } + // '┭': { + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '┮': { + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '┯': { + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // } + // '┰': { + // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}`, + // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}`, + // } + // '┱': { + // 1: `${bottomYAxisFromBottom}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${bottomYAxisFromBottom}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '┲': { + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '┳': { + // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}${THICK}`, + // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}${THICK}`, + // } + // '┴': { + // 1: `${topYAxisFromTop} ${xAxis}`, + // 1: `${topYAxisFromTop} ${xAxis}`, + // } + // '┵': { + // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '┶': { + // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '┷': { + // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // } + // '┸': { + // 1: `${topYAxisFromTop}${THICK} ${xAxis}`, + // 1: `${topYAxisFromTop}${THICK} ${xAxis}`, + // } + // '┹': { + // 1: `${topYAxisFromTop}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${topYAxisFromTop}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '┺': { + // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '┻': { + // 1: `${topYAxisFromTop}${THICK} ${xAxis}${THICK}`, + // 1: `${topYAxisFromTop}${THICK} ${xAxis}${THICK}`, + // } + // '┼': { + // 1: `${yAxis} ${xAxis}`, + // 1: `${yAxis} ${xAxis}`, + // } + // '┽': { + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '┾': { + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '┿': { + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // } + // '╀': { + // 1: `${yAxis}${THICK} ${xAxis}`, + // 1: `${yAxis}${THICK} ${xAxis}`, + // } + // '╁': { + // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '╂': { + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '╃': { + // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, + // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, + // } + // '╄': { + // 1: `${yAxis} ${xAxis}`, + // 1: `${yAxis} ${xAxis}`, + // } + // '╅': { + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '╆': { + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '╇': { + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, + // } + // '╈': { + // 1: `${yAxis}${THICK} ${xAxis}`, + // 1: `${yAxis}${THICK} ${xAxis}`, + // } + // '╉': { + // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, + // } + // '╊': { + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, + // } + // '╋': { + // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, + // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, + // } + // '╌': { + // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}`, + // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}`, + // } + // '╍': { + // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'}${THICK} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, + // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'}${THICK} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, + // } + // '╎':`{ + // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}` + // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}` + // }, + // '╏':`{ + // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'}${THICK} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}${THICK}` + // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'}${THICK} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}${THICK}` + // }, + // // '═{ + // 1: ': `${MOVE}${} ${TO}${} ${TO}${ + // 1: ': `${MOVE}${} ${TO}${} ${TO}${ + + // }`, + + // } // '║{ + // 1: ': `${MOVE}${} ${TO}${} ${TO}${ + // 1: ': `${MOVE}${} ${TO}${} ${TO}${ + + // }`, + +// } // '╒': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╓': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╔': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╕': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╖': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╗': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╘': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╙': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╚': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╛': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╜': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╝': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╞': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╟': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╠': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╡': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╢': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╣': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╤': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╥': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╦': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╧': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╨': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╩': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╪': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╫': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╬': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╭': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╮': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╯': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╰': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╱': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╲': `${MOVE}${} ${TO}${} ${TO}${}`, +// // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, +// '╴': `${leftMiddleXAxis}`, +// '╵': `${topYAxisFromMiddle}`, +// '╶': `${rightMiddleXAxis}`, +// '╷': `${bottomYAxisFromMiddle}`, +// '╸': `${leftMiddleXAxis}${THICK}`, +// '╹': `${topYAxisFromMiddle}${THICK}`, +// '╺': `${rightMiddleXAxis}${THICK}`, +// '╻': `${bottomYAxisFromMiddle}${THICK}`, +// '╼': `${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, +// '╽': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle}`, +// '╾': `${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, +// '╿': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK}` }; export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { - const entry = chars[c]; - if (!entry) { + const match: { [fontWeight: number]: string } = map[c]; + if (!match) { return; } - const lineWidth = ctx.lineWidth; - const instructions = entry.split(' '); + for (const [fontWeight, instructions] of Object.entries(match)) { + ctx.beginPath(); + ctx.lineWidth = window.devicePixelRatio * Number.parseInt(fontWeight); + for (const instruction of instructions.split(' ')) { + const type = instruction[0]; + const f = instructionMap[type]; + const coords: string[] = instruction.substring(1).split(','); + if (!coords[0] || !coords[1]) { + continue; + } + let x = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); + let y = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); - for (const instruction of instructions) { - const type = instruction[0]; - const spec = instructionMap[type]; - const coords: string[] = instruction.substring(1).split(','); - if (!coords[0] || !coords[1]) { - continue; - } - let numX = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); - let numY = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); - if (instruction.endsWith(THICK)) { - ctx.lineWidth = window.devicePixelRatio * 2; - } else { - ctx.lineWidth = window.devicePixelRatio; - } + x *= cellWidth; + y *= cellHeight; - numX *= cellWidth; - numY *= cellHeight; - - if (numY !== 0) { - numY = clamp(Math.round(numY + .5) - .5, cellHeight, 0); + if (y !== 0) { + y = clamp(Math.round(y + .5) - .5, cellHeight, 0); + } + if (x !== 0) { + x = clamp(Math.round(x + .5) - .5, cellWidth, 0); + } + f(ctx, xOffset + x, yOffset + y); } - if (numX !== 0) { - numX = clamp(Math.round(numX + .5) - .5, cellWidth, 0); - } - spec(ctx, xOffset + numX, yOffset + numY); + ctx.stroke(); + ctx.closePath(); } } @@ -407,13 +624,9 @@ function clamp(value: number, max: number, min: number = 0): number { const instructionMap: { [index: string]: any } = { 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => { - ctx.beginPath(); ctx.moveTo(x, y); }, 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => { ctx.lineTo(x, y); - ctx.stroke(); - ctx.beginPath(); - ctx.moveTo(x, y); } }; From 07513c927f851f47fd76ca8adf7cf9a8c2cdd4f8 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 12 Aug 2021 11:46:52 -0700 Subject: [PATCH 12/37] more --- src/browser/renderer/BoxAndBlockCharacters.ts | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 1b6fef41..b6ac8dc9 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -361,25 +361,17 @@ const map: { [character: string]: { [fontWeight: number]: string } } = { '┩': { 2: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, 1: `${bottomYAxisFromMiddle}` + }, + '┪': { + 1: `${topYAxisFromMiddle}`, + 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` + }, + '┫': { + 2: `${yAxis} ${leftMiddleXAxis}` } }; const chars: { [index: string]: string } = { - - - // } // '┩{ - // 1: ': `${leftMiddleXAxis}${THICK} ${topYAxisFromMiddle}${THICK} ${MOVE}${CENTER.MIDDLE} ${bottomYAxisFromMiddle - // 1: ': `${leftMiddleXAxis}${THICK} ${topYAxisFromMiddle}${THICK} ${MOVE}${CENTER.MIDDLE} ${bottomYAxisFromMiddle - // }`, - - // } '┪': { - // 1: `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, - // 1: `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle} ${leftMiddleXAxis}${THICK}`, - // } - // '┫': { - // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK}`, - // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK}`, - // } // '┬': { // 1: `${bottomYAxisFromBottom} ${xAxis}`, // 1: `${bottomYAxisFromBottom} ${xAxis}`, From 6b7b279742fdd57d0d627c5038a3c2b2a5f006f0 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 13 Aug 2021 10:47:30 -0700 Subject: [PATCH 13/37] refactor --- src/browser/renderer/BoxAndBlockCharacters.ts | 414 ++++++++++-------- 1 file changed, 234 insertions(+), 180 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index b6ac8dc9..a3d88351 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -243,6 +243,24 @@ const topYAxisFromMiddle = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; const rightMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`; const leftMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`; +const topXLine = `${MOVE}${'0,.45'} ${TO}${'1,.45'}`; +const bottomXLine = `${MOVE}${'0,.55'} ${TO}${'1,.55'}`; +const leftYLine = `${MOVE}${'.35,0'} ${TO}${'.35,1'}`; +const rightYLine = `${MOVE}${'.65,0'} ${TO}${'.65,1'}`; + +const leftTopXLine = `${MOVE}${'0,.45'} ${TO}${'.5,.45'}`; +const rightTopXLine = `${MOVE}${'.5,.45'} ${TO}${'1,.45'}`; + +const leftBottomXLine = `${MOVE}${'0,.55'} ${TO}${'.5,.55'}`; +const rightBottomXLine = `${MOVE}${'.5,.55'} ${TO}${'1,.55'}`; + +const bottomLeftYLine = `${MOVE}${'.35,.5'} ${TO}${'.35,1'}`; +const topLeftYLine = `${MOVE}${'.35,0'} ${TO}${'.35,.5'}`; + +const bottomRightYLine = `${MOVE}${'.65,.5'} ${TO}${'.65,1'}`; +const topRightYLine = `${MOVE}${'.65,0'} ${TO}${'.65,.5'}`; + + const map: { [character: string]: { [fontWeight: number]: string } } = { '━': { 1: `${xAxis}` @@ -368,178 +386,226 @@ const map: { [character: string]: { [fontWeight: number]: string } } = { }, '┫': { 2: `${yAxis} ${leftMiddleXAxis}` + }, + '┬': { + 1: `${bottomYAxisFromBottom} ${xAxis}` + }, + '┭': { + 1: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, + 2: `${leftMiddleXAxis}` + }, + '┮': { + 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '┯': { + 1: `${bottomYAxisFromBottom}`, + 2: `${leftMiddleXAxis} ${rightMiddleXAxis}` + }, + '┰': { + 1: `${xAxis}`, + 2: `${bottomYAxisFromBottom}` + }, + '┱': { + 1: `${rightMiddleXAxis}`, + 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` + }, + '┲': { + 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '┳': { + 2: `${bottomYAxisFromBottom} ${xAxis}` + }, + '┴': { + 1: `${topYAxisFromMiddle} ${xAxis}` + }, + '┵': { + 1: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, + 2: `${leftMiddleXAxis}` + }, + '┶': { + 1: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '┷': { + 1: `${topYAxisFromMiddle}`, + 2: `${leftMiddleXAxis} ${rightMiddleXAxis}` + }, + '┸': { + 1: `${xAxis}`, + 2: `${topYAxisFromMiddle}` + }, + '┹': { + 1: `${rightMiddleXAxis}`, + 2: `${topYAxisFromMiddle} ${leftMiddleXAxis}` + }, + '┺': { + 1: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '┻': { + 2: `${topYAxisFromMiddle} ${xAxis}` + }, + '┼': { + 1: `${yAxis} ${xAxis}` + }, + '┽': { + 1: `${yAxis} ${rightMiddleXAxis}`, + 2: `${leftMiddleXAxis}` + }, + '┾': { + 1: `${yAxis} ${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '┿': { + 1: `${yAxis}`, + 2: `${leftMiddleXAxis} ${rightMiddleXAxis}` + }, + '╀': { + 1: `${xAxis}`, + 2: `${yAxis}` + }, + '╁': { + 1: `${rightMiddleXAxis}`, + 2: `${yAxis} ${leftMiddleXAxis}` + }, + '╂': { + 1: `${yAxis} ${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '╃': { + 1: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, + 2: `${topYAxisFromTop} ${leftMiddleXAxis}` + }, + '╄': { + 1: `${topYAxisFromTop} ${leftMiddleXAxis}`, + 2: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` + }, + '╅': { + 1: `${topYAxisFromTop} ${rightMiddleXAxis}`, + 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` + }, + '╆': { + 1: `${topYAxisFromTop} ${leftMiddleXAxis}`, + 2: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` + }, + '╇': { + 1: `${bottomYAxisFromBottom}`, + 2: `${leftMiddleXAxis} ${topYAxisFromTop} ${rightMiddleXAxis}` + }, + '╈': { + 1: `${topYAxisFromTop}`, + 2: `${leftMiddleXAxis} ${bottomYAxisFromBottom} ${rightMiddleXAxis}` + }, + '╉': { + 1: `${rightMiddleXAxis}`, + 2: `${leftMiddleXAxis} ${yAxis}` + }, + '╊': { + 1: `${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis} ${yAxis}` + }, + '╋': { + 2: `${yAxis} ${xAxis}` + }, + '╌': { + 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` + }, + '╍': { + 2: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` + }, + '╎': { + 1: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` + }, + '╏': { + 2: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` + }, + '═': { + 1: `${MOVE}${'0,.45'} ${TO}${'1,.45'} ${MOVE}${'0,.55'} ${TO}${'1,.55'}` + }, + '║': { + 1: `${MOVE}${'.35,0'} ${TO}${'.35,1'} ${MOVE}${'.65,0'} ${TO}${'.65,1'}` + }, + '╒': { + 1: `${rightTopXLine} ${rightBottomXLine} ${MOVE}${'.55,1'} ${TO}${'.55,.45'}` + }, + '╓': { + 1: `${bottomLeftYLine} ${bottomRightYLine} ${MOVE}${'.3,.5'} ${TO}${'1,.5'}` + }, + '╔': { + 1: `${MOVE}${'.35,.45'} ${TO}${'1,.45'} ${MOVE}${'.35,.45'} ${TO}${'.35,1'} ${MOVE}${'.65,.65'} ${TO}${'1,.65'} ${MOVE}${'.65,.625'} ${TO}${'.65,1'}` + }, + '╕': { + 1: `${leftTopXLine} ${leftBottomXLine} ${MOVE}${'.55,1'} ${TO}${'.55,.45'}` + }, + '╖': { + 1: `${bottomLeftYLine} ${bottomRightYLine} ${MOVE}${'0,.5'} ${TO}${'.7,.5'}` + }, + '╗': { + 1: `${MOVE}${'.35,.45'} ${TO}${'1,.45'} ${MOVE}${'1,.45'} ${TO}${'1,1'} ${MOVE}${'.35,.65'} ${TO}${'.7,.65'} ${MOVE}${'.7,.65'} ${TO}${'.7,1'}` + }, + '╘': { + 1: `${MOVE}${'0,.85'} ${TO}${'.5,.85'} ${MOVE}${'0,1'} ${TO}${'.5,1'} ${MOVE}${'0,.5'} ${TO}${'0,1'}` + }, + '╙': { + 1: `${MOVE}${'0,.5'} ${TO}${'0,1'} ${MOVE}${'.35,.5'} ${TO}${'.35,1'} ${MOVE}${'0,1'} ${TO}${'.7,1'}` + }, + '╚': { + 1: `${MOVE}${'0,.5'} ${TO}${'0,1'} ${MOVE}${'.35,.5'} ${TO}${'.35,.85'} ${MOVE}${'0,1'} ${TO}${'.7,1'} ${MOVE}${'.5,.85'} ${TO}${'1,.85'}` + }, + '╛': { + 1: `${MOVE}${'0,.85'} ${TO}${'.5,.85'} ${MOVE}${'0,1'} ${TO}${'.5,1'} ${MOVE}${'.55,1'} ${TO}${'.55,.45'}` + }, + '╜': { + 1: `${bottomLeftYLine} ${bottomRightYLine} ${MOVE}${'0,1'} ${TO}${'.7,1'}` + }, + '╝': { + 1: `${MOVE}${'.35,.45'} ${TO}${'.35,.85'} ${MOVE}${'.65,.45'} ${TO} ${'.65,1'} ${MOVE}${'0,.85'} ${TO}${'.45,.85'} ${MOVE}${'0,1'} ${TO}${'.65,1'}` + }, + '╴': { + 1: `${leftMiddleXAxis}` + }, + '╵': { + 1: `${topYAxisFromMiddle}` + }, + '╶': { + 1: `${rightMiddleXAxis}` + }, + '╷': { + 1: `${bottomYAxisFromMiddle}` + }, + '╸': { + 2: `${leftMiddleXAxis}` + }, + '╹': { + 2: `${topYAxisFromMiddle}` + }, + '╺': { + 2: `${rightMiddleXAxis}` + }, + '╻': { + 2: `${bottomYAxisFromMiddle}` + }, + '╼': { + 1: `${leftMiddleXAxis}`, + 2: `${rightMiddleXAxis}` + }, + '╽': { + 1: `${topYAxisFromMiddle}`, + 2: `${bottomYAxisFromBottom}` + }, + '╾': { + 1: `${rightMiddleXAxis}`, + 2: `${leftMiddleXAxis}` + }, + '╿': { + 1: `${bottomYAxisFromBottom}`, + 2: `${topYAxisFromMiddle}` } }; const chars: { [index: string]: string } = { - // '┬': { - // 1: `${bottomYAxisFromBottom} ${xAxis}`, - // 1: `${bottomYAxisFromBottom} ${xAxis}`, - // } - // '┭': { - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '┮': { - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '┯': { - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // } - // '┰': { - // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}`, - // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}`, - // } - // '┱': { - // 1: `${bottomYAxisFromBottom}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${bottomYAxisFromBottom}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '┲': { - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '┳': { - // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}${THICK}`, - // 1: `${bottomYAxisFromBottom}${THICK} ${xAxis}${THICK}`, - // } - // '┴': { - // 1: `${topYAxisFromTop} ${xAxis}`, - // 1: `${topYAxisFromTop} ${xAxis}`, - // } - // '┵': { - // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '┶': { - // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '┷': { - // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // 1: `${topYAxisFromTop} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // } - // '┸': { - // 1: `${topYAxisFromTop}${THICK} ${xAxis}`, - // 1: `${topYAxisFromTop}${THICK} ${xAxis}`, - // } - // '┹': { - // 1: `${topYAxisFromTop}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${topYAxisFromTop}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '┺': { - // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${topYAxisFromTop} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '┻': { - // 1: `${topYAxisFromTop}${THICK} ${xAxis}${THICK}`, - // 1: `${topYAxisFromTop}${THICK} ${xAxis}${THICK}`, - // } - // '┼': { - // 1: `${yAxis} ${xAxis}`, - // 1: `${yAxis} ${xAxis}`, - // } - // '┽': { - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '┾': { - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '┿': { - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // } - // '╀': { - // 1: `${yAxis}${THICK} ${xAxis}`, - // 1: `${yAxis}${THICK} ${xAxis}`, - // } - // '╁': { - // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '╂': { - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '╃': { - // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, - // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, - // } - // '╄': { - // 1: `${yAxis} ${xAxis}`, - // 1: `${yAxis} ${xAxis}`, - // } - // '╅': { - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '╆': { - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '╇': { - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // 1: `${yAxis} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}${THICK}`, - // } - // '╈': { - // 1: `${yAxis}${THICK} ${xAxis}`, - // 1: `${yAxis}${THICK} ${xAxis}`, - // } - // '╉': { - // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // 1: `${yAxis}${THICK} ${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, - // } - // '╊': { - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // 1: `${yAxis} ${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, - // } - // '╋': { - // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, - // 1: `${yAxis}${THICK} ${xAxis}${THICK}`, - // } - // '╌': { - // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}`, - // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}`, - // } - // '╍': { - // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'}${THICK} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, - // 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.47,.5'}${THICK} ${MOVE}${'.53,.5'} ${TO}${RIGHT.MIDDLE}${THICK}`, - // } - // '╎':`{ - // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}` - // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}` - // }, - // '╏':`{ - // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'}${THICK} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}${THICK}` - // 1: ${MOVE}${CENTER.TOP} ${TO}${'.5,.47'}${THICK} ${MOVE}${'.5,.53'} ${TO}${CENTER.BOTTOM}${THICK}` - // }, - // // '═{ - // 1: ': `${MOVE}${} ${TO}${} ${TO}${ - // 1: ': `${MOVE}${} ${TO}${} ${TO}${ - - // }`, - - // } // '║{ - // 1: ': `${MOVE}${} ${TO}${} ${TO}${ - // 1: ': `${MOVE}${} ${TO}${} ${TO}${ - - // }`, - -// } // '╒': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╓': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╔': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╕': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╖': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╗': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╘': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╙': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╚': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╛': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╜': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╝': `${MOVE}${} ${TO}${} ${TO}${}`, // // '╞': `${MOVE}${} ${TO}${} ${TO}${}`, // // '╟': `${MOVE}${} ${TO}${} ${TO}${}`, // // '╠': `${MOVE}${} ${TO}${} ${TO}${}`, @@ -562,18 +628,6 @@ const chars: { [index: string]: string } = { // // '╱': `${MOVE}${} ${TO}${} ${TO}${}`, // // '╲': `${MOVE}${} ${TO}${} ${TO}${}`, // // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, -// '╴': `${leftMiddleXAxis}`, -// '╵': `${topYAxisFromMiddle}`, -// '╶': `${rightMiddleXAxis}`, -// '╷': `${bottomYAxisFromMiddle}`, -// '╸': `${leftMiddleXAxis}${THICK}`, -// '╹': `${topYAxisFromMiddle}${THICK}`, -// '╺': `${rightMiddleXAxis}${THICK}`, -// '╻': `${bottomYAxisFromMiddle}${THICK}`, -// '╼': `${leftMiddleXAxis} ${rightMiddleXAxis}${THICK}`, -// '╽': `${bottomYAxisFromBottom}${THICK} ${topYAxisFromMiddle}`, -// '╾': `${leftMiddleXAxis}${THICK} ${rightMiddleXAxis}`, -// '╿': `${bottomYAxisFromBottom} ${topYAxisFromMiddle}${THICK}` }; export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { From 263e5b95cf177c78acc09fa4fbe449102b2e806a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Aug 2021 12:52:50 -0700 Subject: [PATCH 14/37] Improve testing characters and use fake terminal for demo --- demo/client.ts | 53 +++++++++++++++++++++++++++----------- src/common/CoreTerminal.ts | 26 ------------------- 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index 0bb124cd..d7c0f840 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -214,16 +214,17 @@ function createTerminal(): void { // Set terminal size again to set the specific dimensions on the demo updateTerminalSize(); - fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then((res) => { - res.text().then((processId) => { - pid = processId; - socketURL += processId; - socket = new WebSocket(socketURL); - socket.onopen = runRealTerminal; - socket.onclose = runFakeTerminal; - socket.onerror = runFakeTerminal; - }); - }); + // fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then((res) => { + // res.text().then((processId) => { + // pid = processId; + // socketURL += processId; + // socket = new WebSocket(socketURL); + // socket.onopen = runRealTerminal; + // socket.onclose = runFakeTerminal; + // socket.onerror = runFakeTerminal; + // }); + // }); + runFakeTerminal(); }, 0); } @@ -246,11 +247,33 @@ function runFakeTerminal(): void { term.write('\r\n$ '); }; - term.writeln('Welcome to xterm.js'); - term.writeln('This is a local terminal emulation, without a real terminal in the back-end.'); - term.writeln('Type some keys and commands to play around.'); - term.writeln(''); - term.prompt(); + // term.writeln('Welcome to xterm.js'); + // term.writeln('This is a local terminal emulation, without a real terminal in the back-end.'); + // term.writeln('Type some keys and commands to play around.'); + // term.writeln(''); + // term.prompt(); + + term.write('Box styles: ┎┰┒┍┯┑╓╥╖╒╤╕ ┏┳┓┌┲┓┌┬┐┏┱┐\n\r'); + term.write('┌─┬─┐ ┏━┳━┓ ╔═╦═╗ ┠╂┨┝┿┥╟╫╢╞╪╡ ┡╇┩├╊┫┢╈┪┣╉┤\n\r'); + term.write('│ │ │ ┃ ┃ ┃ ║ ║ ║ ┖┸┚┕┷┙╙╨╜╘╧╛ └┴┘└┺┛┗┻┛┗┹┘\n\r'); + term.write('├─┼─┤ ┣━╋━┫ ╠═╬═╣ ┏┱┐┌┲┓┌┬┐┌┬┐ ┏┳┓┌┮┓┌┬┐┏┭┐\n\r'); + term.write('│ │ │ ┃ ┃ ┃ ║ ║ ║ ┡╃┤├╄┩├╆┪┢╅┤ ┞╀┦├┾┫┟╁┧┣┽┤\n\r'); + term.write('└─┴─┘ ┗━┻━┛ ╚═╩═╝ └┴┘└┴┘└┺┛┗┹┘ └┴┘└┶┛┗┻┛┗┵┘\n\r'); + term.write('\n\r'); + term.write('Other:\n\r'); + term.write('╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌ ┄┄ ┈┈\n\r'); + term.write('│ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍ ┅┅ ┉┉\n\r'); + term.write('╰─╯ ╱ ╲ ╹╵╎╏┆┇┊┋\n\r'); + term.write('\n\r'); + term.write('All box drawing characters:\n\r'); + term.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\n\r'); + term.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\n\r'); + term.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\n\r'); + term.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\n\r'); + term.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\n\r'); + term.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\n\r'); + term.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\n\r'); + term.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\n\r'); term.onKey((e: { key: string, domEvent: KeyboardEvent }) => { const ev = e.domEvent; diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index a3026016..e61a8e16 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -132,32 +132,6 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { // Setup WriteBuffer this._writeBuffer = new WriteBuffer((data, promiseResult) => this._inputHandler.parse(data, promiseResult)); - setTimeout(() => { - // this.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\r\n'); - // this.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\r\n'); - // this.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\r\n'); - // this.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\r\n'); - // this.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\r\n'); - // this.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\r\n'); - // this.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\r\n'); - // this.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); - // this.write(' ╔═════════════════════════════════════════════════════════╕\r\n'); - // this.write(' ║ │\r\n'); - // this.write(' ║ ╔═══════════════╦════════╤════════╗ │\r\n'); - // this.write(' ║ ║ ║ │ ║ │\r\n'); - // this.write(' ║ ║ ║ │ ║ │\r\n'); - // this.write('▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇'); - this.write('━━│┃\r\n'); - this.write(' ━━│┃┌┍┎┏\r\n'); - this.write(' ━━│┃┌┐┍┑┎┒┏┓\r\n'); - this.write(' └┘┕┙┖┚┗┛\r\n'); - this.write('├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋ ╌ ╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬\r\n'); - this.write('╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿\r\n'); - this.write('├ ┝ ┞ ┟ ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻\r\n'); - this.write('┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋\r\n'); - this.write(' ╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬\r\n'); - this.write('╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\r\n'); - }, 1000); } public dispose(): void { From f83ebdbe67fcdf6631322485a57d9c689dadb146 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Aug 2021 14:53:45 -0700 Subject: [PATCH 15/37] Refactors and implementing new shapes Co-authored-by: Megan Rogge --- src/browser/renderer/BoxAndBlockCharacters.ts | 525 ++++++------------ 1 file changed, 179 insertions(+), 346 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index a3d88351..c220c9aa 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -260,349 +260,170 @@ const topLeftYLine = `${MOVE}${'.35,0'} ${TO}${'.35,.5'}`; const bottomRightYLine = `${MOVE}${'.65,.5'} ${TO}${'.65,1'}`; const topRightYLine = `${MOVE}${'.65,0'} ${TO}${'.65,.5'}`; +const enum Shapes { + /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', + /** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5', -const map: { [character: string]: { [fontWeight: number]: string } } = { - '━': { - 1: `${xAxis}` - }, - '│': { - 1: `${yAxis}` - }, - '┃': { - 2: `${yAxis}` - }, - '┌': { - 1: `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}` - }, - '┍': { - 1: `${bottomYAxisFromBottom}`, - 2: `${rightMiddleXAxis}` - }, - '┎': { - 1: `${rightMiddleXAxis}`, - 2: `${bottomYAxisFromBottom}` - }, - '┏': { - 2: `${bottomYAxisFromBottom} ${TO}${RIGHT.MIDDLE}` - }, - '┐': { - 1: `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}` - }, - '┑': { - 1: `${bottomYAxisFromBottom}`, - 2: `${leftMiddleXAxis}` - }, - '┒': { - 1: `${leftMiddleXAxis}`, - 2: `${bottomYAxisFromBottom}` - }, - '┓': { - 2: `${bottomYAxisFromBottom} ${TO}${LEFT.MIDDLE}` - }, - '└': { - 1: `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}` - }, - '┕': { - 1: `${topYAxisFromTop}`, - 2: `${rightMiddleXAxis}` - }, - '┖': { - 1: `${rightMiddleXAxis}`, - 2: `${topYAxisFromTop}` - }, - '┗': { - 2: `${topYAxisFromTop} ${TO}${RIGHT.MIDDLE}` - }, - '┘': { - 1: `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}` - }, - '┙': { - 1: `${topYAxisFromTop}`, - 2: `${leftMiddleXAxis}` - }, - '┚': { - 1: `${leftMiddleXAxis}`, - 2: `${topYAxisFromTop}` - }, - '┛': { - 2: `${topYAxisFromTop} ${TO}${LEFT.MIDDLE}` - }, - '├': { - 1: `${yAxis} ${rightMiddleXAxis}` - }, - '┝': { - 1: `${yAxis}`, - 2: `${rightMiddleXAxis}` - }, - '┞': { - 1: `${bottomYAxisFromMiddle} ${rightMiddleXAxis}`, - 2: `${topYAxisFromTop}` - }, - '┟': { - 1: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, - 2: `${bottomYAxisFromBottom}` - }, - '┠': { - 1: `${rightMiddleXAxis}`, - 2: `${yAxis}` - }, - '┡': { - 1: `${bottomYAxisFromBottom}`, - 2: `${topYAxisFromMiddle} ${rightMiddleXAxis}` - }, - '┢': { - 1: `${topYAxisFromMiddle}`, - 2: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` - }, - '┣': { - 2: `${yAxis} ${rightMiddleXAxis}` - }, - '┤': { - 1: `${yAxis} ${leftMiddleXAxis}` - }, - '┥': { - 1: `${yAxis}`, - 2: `${leftMiddleXAxis}` - }, - '┦': { - 1: `${bottomYAxisFromMiddle} ${leftMiddleXAxis}`, - 2: `${topYAxisFromTop}` - }, - '┧': { - 1: `${topYAxisFromMiddle}`, - 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` - }, - '┨': { - 1: `${leftMiddleXAxis}`, - 2: `${yAxis}` - }, - '┩': { - 2: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, - 1: `${bottomYAxisFromMiddle}` - }, - '┪': { - 1: `${topYAxisFromMiddle}`, - 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` - }, - '┫': { - 2: `${yAxis} ${leftMiddleXAxis}` - }, - '┬': { - 1: `${bottomYAxisFromBottom} ${xAxis}` - }, - '┭': { - 1: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, - 2: `${leftMiddleXAxis}` - }, - '┮': { - 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '┯': { - 1: `${bottomYAxisFromBottom}`, - 2: `${leftMiddleXAxis} ${rightMiddleXAxis}` - }, - '┰': { - 1: `${xAxis}`, - 2: `${bottomYAxisFromBottom}` - }, - '┱': { - 1: `${rightMiddleXAxis}`, - 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` - }, - '┲': { - 1: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '┳': { - 2: `${bottomYAxisFromBottom} ${xAxis}` - }, - '┴': { - 1: `${topYAxisFromMiddle} ${xAxis}` - }, - '┵': { - 1: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, - 2: `${leftMiddleXAxis}` - }, - '┶': { - 1: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '┷': { - 1: `${topYAxisFromMiddle}`, - 2: `${leftMiddleXAxis} ${rightMiddleXAxis}` - }, - '┸': { - 1: `${xAxis}`, - 2: `${topYAxisFromMiddle}` - }, - '┹': { - 1: `${rightMiddleXAxis}`, - 2: `${topYAxisFromMiddle} ${leftMiddleXAxis}` - }, - '┺': { - 1: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '┻': { - 2: `${topYAxisFromMiddle} ${xAxis}` - }, - '┼': { - 1: `${yAxis} ${xAxis}` - }, - '┽': { - 1: `${yAxis} ${rightMiddleXAxis}`, - 2: `${leftMiddleXAxis}` - }, - '┾': { - 1: `${yAxis} ${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '┿': { - 1: `${yAxis}`, - 2: `${leftMiddleXAxis} ${rightMiddleXAxis}` - }, - '╀': { - 1: `${xAxis}`, - 2: `${yAxis}` - }, - '╁': { - 1: `${rightMiddleXAxis}`, - 2: `${yAxis} ${leftMiddleXAxis}` - }, - '╂': { - 1: `${yAxis} ${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '╃': { - 1: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, - 2: `${topYAxisFromTop} ${leftMiddleXAxis}` - }, - '╄': { - 1: `${topYAxisFromTop} ${leftMiddleXAxis}`, - 2: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` - }, - '╅': { - 1: `${topYAxisFromTop} ${rightMiddleXAxis}`, - 2: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` - }, - '╆': { - 1: `${topYAxisFromTop} ${leftMiddleXAxis}`, - 2: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` - }, - '╇': { - 1: `${bottomYAxisFromBottom}`, - 2: `${leftMiddleXAxis} ${topYAxisFromTop} ${rightMiddleXAxis}` - }, - '╈': { - 1: `${topYAxisFromTop}`, - 2: `${leftMiddleXAxis} ${bottomYAxisFromBottom} ${rightMiddleXAxis}` - }, - '╉': { - 1: `${rightMiddleXAxis}`, - 2: `${leftMiddleXAxis} ${yAxis}` - }, - '╊': { - 1: `${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis} ${yAxis}` - }, - '╋': { - 2: `${yAxis} ${xAxis}` - }, - '╌': { - 1: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` - }, - '╍': { - 2: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` - }, - '╎': { - 1: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` - }, - '╏': { - 2: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` - }, - '═': { - 1: `${MOVE}${'0,.45'} ${TO}${'1,.45'} ${MOVE}${'0,.55'} ${TO}${'1,.55'}` - }, - '║': { - 1: `${MOVE}${'.35,0'} ${TO}${'.35,1'} ${MOVE}${'.65,0'} ${TO}${'.65,1'}` - }, - '╒': { - 1: `${rightTopXLine} ${rightBottomXLine} ${MOVE}${'.55,1'} ${TO}${'.55,.45'}` - }, - '╓': { - 1: `${bottomLeftYLine} ${bottomRightYLine} ${MOVE}${'.3,.5'} ${TO}${'1,.5'}` - }, - '╔': { - 1: `${MOVE}${'.35,.45'} ${TO}${'1,.45'} ${MOVE}${'.35,.45'} ${TO}${'.35,1'} ${MOVE}${'.65,.65'} ${TO}${'1,.65'} ${MOVE}${'.65,.625'} ${TO}${'.65,1'}` - }, - '╕': { - 1: `${leftTopXLine} ${leftBottomXLine} ${MOVE}${'.55,1'} ${TO}${'.55,.45'}` - }, - '╖': { - 1: `${bottomLeftYLine} ${bottomRightYLine} ${MOVE}${'0,.5'} ${TO}${'.7,.5'}` - }, - '╗': { - 1: `${MOVE}${'.35,.45'} ${TO}${'1,.45'} ${MOVE}${'1,.45'} ${TO}${'1,1'} ${MOVE}${'.35,.65'} ${TO}${'.7,.65'} ${MOVE}${'.7,.65'} ${TO}${'.7,1'}` - }, - '╘': { - 1: `${MOVE}${'0,.85'} ${TO}${'.5,.85'} ${MOVE}${'0,1'} ${TO}${'.5,1'} ${MOVE}${'0,.5'} ${TO}${'0,1'}` - }, - '╙': { - 1: `${MOVE}${'0,.5'} ${TO}${'0,1'} ${MOVE}${'.35,.5'} ${TO}${'.35,1'} ${MOVE}${'0,1'} ${TO}${'.7,1'}` - }, - '╚': { - 1: `${MOVE}${'0,.5'} ${TO}${'0,1'} ${MOVE}${'.35,.5'} ${TO}${'.35,.85'} ${MOVE}${'0,1'} ${TO}${'.7,1'} ${MOVE}${'.5,.85'} ${TO}${'1,.85'}` - }, - '╛': { - 1: `${MOVE}${'0,.85'} ${TO}${'.5,.85'} ${MOVE}${'0,1'} ${TO}${'.5,1'} ${MOVE}${'.55,1'} ${TO}${'.55,.45'}` - }, - '╜': { - 1: `${bottomLeftYLine} ${bottomRightYLine} ${MOVE}${'0,1'} ${TO}${'.7,1'}` - }, - '╝': { - 1: `${MOVE}${'.35,.45'} ${TO}${'.35,.85'} ${MOVE}${'.65,.45'} ${TO} ${'.65,1'} ${MOVE}${'0,.85'} ${TO}${'.45,.85'} ${MOVE}${'0,1'} ${TO}${'.65,1'}` - }, - '╴': { - 1: `${leftMiddleXAxis}` - }, - '╵': { - 1: `${topYAxisFromMiddle}` - }, - '╶': { - 1: `${rightMiddleXAxis}` - }, - '╷': { - 1: `${bottomYAxisFromMiddle}` - }, - '╸': { - 2: `${leftMiddleXAxis}` - }, - '╹': { - 2: `${topYAxisFromMiddle}` - }, - '╺': { - 2: `${rightMiddleXAxis}` - }, - '╻': { - 2: `${bottomYAxisFromMiddle}` - }, - '╼': { - 1: `${leftMiddleXAxis}`, - 2: `${rightMiddleXAxis}` - }, - '╽': { - 1: `${topYAxisFromMiddle}`, - 2: `${bottomYAxisFromBottom}` - }, - '╾': { - 1: `${rightMiddleXAxis}`, - 2: `${leftMiddleXAxis}` - }, - '╿': { - 1: `${bottomYAxisFromBottom}`, - 2: `${topYAxisFromMiddle}` - } + /** └ */ TOP_TO_RIGHT = 'M.5,0 L.5,.5 L1,.5', + /** ┘ */ TOP_TO_LEFT = 'M.5,0 L.5,.5 L0,.5', + /** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1', + /** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5', + + /** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L0,.5', + /** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L.5,0', + /** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5', + /** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1', + + /** ┴ */ T_TOP = 'M0,.5 L1,.5 M.5,.5 L.5,0', + /** ┤ */ T_LEFT = 'M.5,0 L.5,1 M.5,.5 L0,.5', + /** ├ */ T_RIGHT = 'M.5,0 L.5,1 M.5,.5 L1,.5', + /** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1', + + /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', +} + +const enum Style { + NORMAL = 1, + BOLD = 2 +} + +// TODO: Tweak normal and bold weights +const map: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } } = { + // Uniform normal and bold + '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, + '━': { [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, + '│': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM }, + '┃': { [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, + '┌': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM }, + '┏': { [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, + '┐': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM }, + '┓': { [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, + '└': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT }, + '┗': { [Style.BOLD]: Shapes.TOP_TO_RIGHT }, + '┘': { [Style.NORMAL]: Shapes.TOP_TO_LEFT }, + '┛': { [Style.BOLD]: Shapes.TOP_TO_LEFT }, + '├': { [Style.NORMAL]: Shapes.T_RIGHT }, + '┣': { [Style.BOLD]: Shapes.T_RIGHT }, + '┤': { [Style.NORMAL]: Shapes.T_LEFT }, + '┫': { [Style.BOLD]: Shapes.T_LEFT }, + '┬': { [Style.NORMAL]: Shapes.T_BOTTOM }, + '┳': { [Style.BOLD]: Shapes.T_BOTTOM }, + '┴': { [Style.NORMAL]: Shapes.T_TOP }, + '┻': { [Style.BOLD]: Shapes.T_TOP }, + '┼': { [Style.NORMAL]: Shapes.CROSS }, + '╋': { [Style.BOLD]: Shapes.CROSS }, + '╴': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT }, + '╸': { [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '╵': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP }, + '╹': { [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '╶': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT }, + '╺': { [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '╷': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM }, + '╻': { [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + + // Mixed normal/bold + '┍': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┎': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + + // Double border + '═': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, + '║': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, + '╒': { [Style.NORMAL]: (xp, yp) => `M.5,1 L.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` }, + '╓': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},1 L${.5 - xp},.5 L1,.5 M${.5 + xp},.5 L${.5 + xp},1` }, + '╔': { [Style.NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1` }, + '╕': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L.5,${.5 - yp} L.5,1 M0,${.5 + yp} L.5,${.5 + yp}` }, + '╖': { [Style.NORMAL]: (xp, yp) => `M${.5 + xp},1 L${.5 + xp},.5 L0,.5 M${.5 - xp},.5 L${.5 - xp},1` }, + '╗': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M0,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},1` }, + '╘': { [Style.NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 + yp} L1,${.5 + yp} M.5,${.5 - yp} L1,${.5 - yp}` }, + '╙': { [Style.NORMAL]: (xp, yp) => `M1,.5 L${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` }, + '╚': { [Style.NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0 M1,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},0` }, + '╛': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L.5,${.5 + yp} L.5,0 M0,${.5 - yp} L.5,${.5 - yp}` }, + '╜': { [Style.NORMAL]: (xp, yp) => `M0,.5 L${.5 + xp},.5 L${.5 + xp},0 M${.5 - xp},.5 L${.5 - xp},0 ` }, + '╝': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M0,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},0` }, + '╞': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` }, + '╟': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1 M${.5 + xp},.5 L1,.5` }, + '╠': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` }, + '╡': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M0,${.5 - yp} L.5,${.5 - yp} M0,${.5 + yp} L.5,${.5 + yp}` }, + '╢': { [Style.NORMAL]: (xp, yp) => `M0,.5 L${.5 - xp},.5 M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, + '╣': { [Style.NORMAL]: (xp, yp) => `M${.5 + xp},0 L${.5 + xp},1 M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0` }, + '╤': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp} M.5,${.5 + yp} L.5,1` }, + '╥': { [Style.NORMAL]: (xp, yp) => `${Shapes.LEFT_TO_RIGHT} M${.5 - xp},.5 L${.5 - xp},1 M${.5 + xp},.5 L${.5 + xp},1` }, + '╦': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1` }, + '╧': { [Style.NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 - yp} M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, + '╨': { [Style.NORMAL]: (xp, yp) => `${Shapes.LEFT_TO_RIGHT} M${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` }, + '╩': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L1,${.5 + yp} M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` }, + '╪': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, + '╫': { [Style.NORMAL]: (xp, yp) => `${Shapes.LEFT_TO_RIGHT} M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, + '╬': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1 M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` }, + + // Diagonal + '╱': { [Style.NORMAL]: 'M1,0 L0,1' }, + '╲': { [Style.NORMAL]: 'M0,0 L1,1' }, + '╳': { [Style.NORMAL]: 'M1,0 L0,1 M0,0 L1,1' }, + + // Mixed weight + '┑': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '┒': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, + '┕': { [Style.NORMAL]: `${topYAxisFromTop}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┖': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, + '┙': { [Style.NORMAL]: `${topYAxisFromTop}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '┚': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, + '┝': { [Style.NORMAL]: `${yAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┞': { [Style.NORMAL]: `${bottomYAxisFromMiddle} ${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, + '┟': { [Style.NORMAL]: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, + '┠': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${yAxis}` }, + '┡': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${topYAxisFromMiddle} ${rightMiddleXAxis}` }, + '┢': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, + '┥': { [Style.NORMAL]: `${yAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '┦': { [Style.NORMAL]: `${bottomYAxisFromMiddle} ${leftMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, + '┧': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, + '┨': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${yAxis}` }, + '┩': { [Style.NORMAL]: `${bottomYAxisFromMiddle}`, [Style.BOLD]: `${topYAxisFromMiddle} ${leftMiddleXAxis}` }, + '┪': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, + '┭': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '┮': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┯': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${leftMiddleXAxis} ${rightMiddleXAxis}` }, + '┰': { [Style.NORMAL]: `${xAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, + '┱': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, + '┲': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┵': { [Style.NORMAL]: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '┶': { [Style.NORMAL]: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┷': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${leftMiddleXAxis} ${rightMiddleXAxis}` }, + '┸': { [Style.NORMAL]: `${xAxis}`, [Style.BOLD]: `${topYAxisFromMiddle}` }, + '┹': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromMiddle} ${leftMiddleXAxis}` }, + '┺': { [Style.NORMAL]: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┽': { [Style.NORMAL]: `${yAxis} ${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '┾': { [Style.NORMAL]: `${yAxis} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '┿': { [Style.NORMAL]: `${yAxis}`, [Style.BOLD]: `${leftMiddleXAxis} ${rightMiddleXAxis}` }, + '╀': { [Style.NORMAL]: `${xAxis}`, [Style.BOLD]: `${yAxis}` }, + '╁': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${yAxis} ${leftMiddleXAxis}` }, + '╂': { [Style.NORMAL]: `${yAxis} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '╃': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop} ${leftMiddleXAxis}` }, + '╄': { [Style.NORMAL]: `${topYAxisFromTop} ${leftMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, + '╅': { [Style.NORMAL]: `${topYAxisFromTop} ${rightMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, + '╆': { [Style.NORMAL]: `${topYAxisFromTop} ${leftMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, + '╇': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${leftMiddleXAxis} ${topYAxisFromTop} ${rightMiddleXAxis}` }, + '╈': { [Style.NORMAL]: `${topYAxisFromTop}`, [Style.BOLD]: `${leftMiddleXAxis} ${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, + '╉': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis} ${yAxis}` }, + '╊': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis} ${yAxis}` }, + '╼': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, + '╽': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, + '╾': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, + '╿': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${topYAxisFromMiddle}` }, + + // Dashed + '╌': { [Style.NORMAL]: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, + '╍': { [Style.BOLD]: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, + '┄': { [Style.NORMAL]: `` }, + '┅': { [Style.BOLD]: `` }, + '┈': { [Style.NORMAL]: `` }, + '┉': { [Style.BOLD]: `` }, + '╎': { [Style.NORMAL]: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` }, + '╏': { [Style.BOLD]: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` }, + '┆': { [Style.NORMAL]: `` }, + '┇': { [Style.BOLD]: `` }, + '┊': { [Style.NORMAL]: `` }, + '┋': { [Style.BOLD]: `` } }; const chars: { [index: string]: string } = { @@ -630,17 +451,30 @@ const chars: { [index: string]: string } = { // // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, }; +// Give more specific name export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { - const match: { [fontWeight: number]: string } = map[c]; + const match: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } = map[c]; if (!match) { return; } for (const [fontWeight, instructions] of Object.entries(match)) { ctx.beginPath(); ctx.lineWidth = window.devicePixelRatio * Number.parseInt(fontWeight); - for (const instruction of instructions.split(' ')) { + let actualInstructions: string; + if (typeof instructions === 'function') { + const xp = .15; + const yp = .15 / cellHeight * cellWidth; + actualInstructions = instructions(xp, yp); + } else { + actualInstructions = instructions; + } + for (const instruction of actualInstructions.split(' ')) { const type = instruction[0]; const f = instructionMap[type]; + if (!f) { + console.error(`Could not find drawing instructions for "${type}"`); + continue; + } const coords: string[] = instruction.substring(1).split(','); if (!coords[0] || !coords[1]) { continue; @@ -670,8 +504,7 @@ function clamp(value: number, max: number, min: number = 0): number { const instructionMap: { [index: string]: any } = { 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => { - ctx.moveTo(x, y); - }, + ctx.moveTo(x, y); }, 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => { ctx.lineTo(x, y); } From 7549f0e92410f78007cdf29cd73c504eaec29c47 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Aug 2021 15:09:04 -0700 Subject: [PATCH 16/37] Clean up --- demo/client.ts | 4 ++-- src/browser/renderer/BoxAndBlockCharacters.ts | 21 +++---------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index d7c0f840..cc467908 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -261,8 +261,8 @@ function runFakeTerminal(): void { term.write('└─┴─┘ ┗━┻━┛ ╚═╩═╝ └┴┘└┴┘└┺┛┗┹┘ └┴┘└┶┛┗┻┛┗┵┘\n\r'); term.write('\n\r'); term.write('Other:\n\r'); - term.write('╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌ ┄┄ ┈┈\n\r'); - term.write('│ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍ ┅┅ ┉┉\n\r'); + term.write('╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌╌ ┄┄┄ ┈┈┈\n\r'); + term.write('│ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍╍ ┅┅┅ ┉┉┉\n\r'); term.write('╰─╯ ╱ ╲ ╹╵╎╏┆┇┊┋\n\r'); term.write('\n\r'); term.write('All box drawing characters:\n\r'); diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index c220c9aa..9d99c285 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -243,22 +243,6 @@ const topYAxisFromMiddle = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; const rightMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`; const leftMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`; -const topXLine = `${MOVE}${'0,.45'} ${TO}${'1,.45'}`; -const bottomXLine = `${MOVE}${'0,.55'} ${TO}${'1,.55'}`; -const leftYLine = `${MOVE}${'.35,0'} ${TO}${'.35,1'}`; -const rightYLine = `${MOVE}${'.65,0'} ${TO}${'.65,1'}`; - -const leftTopXLine = `${MOVE}${'0,.45'} ${TO}${'.5,.45'}`; -const rightTopXLine = `${MOVE}${'.5,.45'} ${TO}${'1,.45'}`; - -const leftBottomXLine = `${MOVE}${'0,.55'} ${TO}${'.5,.55'}`; -const rightBottomXLine = `${MOVE}${'.5,.55'} ${TO}${'1,.55'}`; - -const bottomLeftYLine = `${MOVE}${'.35,.5'} ${TO}${'.35,1'}`; -const topLeftYLine = `${MOVE}${'.35,0'} ${TO}${'.35,.5'}`; - -const bottomRightYLine = `${MOVE}${'.65,.5'} ${TO}${'.65,1'}`; -const topRightYLine = `${MOVE}${'.65,0'} ${TO}${'.65,.5'}`; const enum Shapes { /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', @@ -412,9 +396,10 @@ const map: { [character: string]: { [fontWeight: number]: string | ((xp: number, '╿': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${topYAxisFromMiddle}` }, // Dashed - '╌': { [Style.NORMAL]: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, + // TODO: Spacing dashes evenly, use 1/2 padding on each edge so the line is continuous + '╌': { [Style.NORMAL]: `` }, // `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, '╍': { [Style.BOLD]: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, - '┄': { [Style.NORMAL]: `` }, + '┄': { [Style.NORMAL]: `M.04,.5 L.96,.5` }, '┅': { [Style.BOLD]: `` }, '┈': { [Style.NORMAL]: `` }, '┉': { [Style.BOLD]: `` }, From 7344d62e81d3b4afaa628fc1cdd1cfbf01cc9f42 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Aug 2021 09:39:44 -0700 Subject: [PATCH 17/37] clean up --- src/browser/renderer/BaseRenderLayer.ts | 4 +- src/browser/renderer/BoxAndBlockCharacters.ts | 59 +++++++------------ 2 files changed, 22 insertions(+), 41 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 31773f64..7b85d75e 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,7 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; -import { boxDrawingBoxes, boxDrawingLineSegments, draw } from 'browser/renderer/BoxAndBlockCharacters'; +import { boxDrawingBoxes, boxDrawingLineSegments, drawBoxChar } from 'browser/renderer/BoxAndBlockCharacters'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -422,7 +422,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // increase # of pixels when font size incremented by 10 // this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); // yOffset - verticalCenter - draw(this._ctx, char, xOffset, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); + drawBoxChar(this._ctx, char, xOffset, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); return true; } diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 9d99c285..cdb8f259 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -264,6 +264,13 @@ const enum Shapes { /** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1', /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', + + /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.45,.5 M.55,.5 L.9,.5', + /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.052,.5 L.316,.5 M.0.421,.5 L.6315,.5 M.684,.5 L.947,.5', + /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.0588,.5 L.235,.5 M.294,.5 L.4705,.5 M.529,.5 L.7058,.5 M.765,.5 L.947,.5', + /** ╌ */ TWO_DASHES_VERTICAL = 'M.5,0 T.5,.45 M.5,.55 T.5,1', + /** ┄ */ THREE_DASHES_VERTICAL = 'M.5,.052 L.5,.316 M.5,.0.368 L.5.632 M.5,.684 L.5,.947', + /** ┉ */ FOUR_DASHES_VERTICAL = 'M.5,.0588 L.5,.235 M.5,.294 L.5,.4705 29 L.5,.7058 M.5,.765 L.5,.947', } const enum Style { @@ -397,47 +404,21 @@ const map: { [character: string]: { [fontWeight: number]: string | ((xp: number, // Dashed // TODO: Spacing dashes evenly, use 1/2 padding on each edge so the line is continuous - '╌': { [Style.NORMAL]: `` }, // `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, - '╍': { [Style.BOLD]: `${MOVE}${LEFT.MIDDLE} ${TO}${'.4,.5'} ${MOVE}${'.6,.5'} ${TO}${RIGHT.MIDDLE}` }, - '┄': { [Style.NORMAL]: `M.04,.5 L.96,.5` }, - '┅': { [Style.BOLD]: `` }, - '┈': { [Style.NORMAL]: `` }, - '┉': { [Style.BOLD]: `` }, - '╎': { [Style.NORMAL]: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` }, - '╏': { [Style.BOLD]: `${MOVE}${CENTER.TOP} ${TO}${'.5,.45'} ${MOVE}${'.5,.55'} ${TO}${CENTER.BOTTOM}` }, - '┆': { [Style.NORMAL]: `` }, - '┇': { [Style.BOLD]: `` }, - '┊': { [Style.NORMAL]: `` }, - '┋': { [Style.BOLD]: `` } + '╌': { [Style.NORMAL]: Shapes.TWO_DASHES_HORIZONTAL }, + '╍': { [Style.BOLD]: Shapes.TWO_DASHES_HORIZONTAL }, + '┄': { [Style.NORMAL]: Shapes.THREE_DASHES_HORIZONTAL }, + '┅': { [Style.BOLD]: Shapes.THREE_DASHES_HORIZONTAL }, + '┈': { [Style.NORMAL]: Shapes.FOUR_DASHES_HORIZONTAL }, + '┉': { [Style.BOLD]: Shapes.FOUR_DASHES_HORIZONTAL }, + '╎': { [Style.NORMAL]: Shapes.TWO_DASHES_VERTICAL }, + '╏': { [Style.BOLD]: Shapes.TWO_DASHES_VERTICAL }, + '┆': { [Style.NORMAL]: Shapes.THREE_DASHES_VERTICAL }, + '┇': { [Style.BOLD]: Shapes.THREE_DASHES_VERTICAL }, + '┊': { [Style.NORMAL]: Shapes.FOUR_DASHES_VERTICAL }, + '┋': { [Style.BOLD]: Shapes.FOUR_DASHES_VERTICAL } }; -const chars: { [index: string]: string } = { -// // '╞': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╟': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╠': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╡': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╢': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╣': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╤': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╥': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╦': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╧': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╨': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╩': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╪': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╫': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╬': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╭': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╮': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╯': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╰': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╱': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╲': `${MOVE}${} ${TO}${} ${TO}${}`, -// // '╳': `${MOVE}${} ${TO}${} ${TO}${}`, -}; - -// Give more specific name -export function draw(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { +export function drawBoxChar(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { const match: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } = map[c]; if (!match) { return; From 62aa91a34dbfb8363fe4415b8658e58523e960e1 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Mon, 16 Aug 2021 09:51:20 -0700 Subject: [PATCH 18/37] clean up --- src/browser/renderer/BaseRenderLayer.ts | 15 +- src/browser/renderer/BoxAndBlockCharacters.ts | 165 ++---------------- 2 files changed, 13 insertions(+), 167 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 7b85d75e..44b23840 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,7 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; -import { boxDrawingBoxes, boxDrawingLineSegments, drawBoxChar } from 'browser/renderer/BoxAndBlockCharacters'; +import { boxCharacters, boxDrawingBoxes, drawBoxChar } from 'browser/renderer/BoxAndBlockCharacters'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -408,21 +408,12 @@ export abstract class BaseRenderLayer implements IRenderLayer { return true; } - const lineSegments = boxDrawingLineSegments[char]; + const lineSegments = boxCharacters[char]; if (!lineSegments) { return false; } - const xOffset = x * this._scaledCellWidth; - const verticalCenter = Math.round(this._scaledCellHeight / 2); - - const yOffset = y * this._scaledCellHeight + this._scaledCharTop + verticalCenter; - // const scale = window.devicePixelRatio; this._ctx.strokeStyle = this._ctx.fillStyle; - - // increase # of pixels when font size incremented by 10 - // this._ctx.lineWidth = Math.max(Math.floor(this._optionsService.options.fontSize / 10), 1); - // yOffset - verticalCenter - drawBoxChar(this._ctx, char, xOffset, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); + drawBoxChar(this._ctx, char, x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); return true; } diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index cdb8f259..23e76963 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -1,125 +1,3 @@ -export const boxDrawingLineSegments: { [index: string]: any } = { - '─': [{ x1: 0, y1: 3, x2: 6, y2: 3 }], - '━': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }], - '│': [{ x1: 3, y1: 0, x2: 3, y2: 6 }], - '┃': [{ x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], - '┌': [{ x1: 6, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┍': [{ x1: 6, y1: 2, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 3, y2: 6 }, { x1: 6, y1: 4, x2: 3, y2: 4 }], - '┎': [{ x1: 6, y1: 3, x2: 2, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '┏': [{ x1: 6, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 6 }, { x1: 6, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 6 }], - '┐': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┑': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 3, y2: 6 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], - '┒': [{ x1: 0, y1: 3, x2: 4, y2: 3 }, { x1: 4, y1: 3, x2: 4, y2: 6 }, { x1: 2, y1: 3, x2: 2, y2: 6 }], - '┓': [{ x1: 0, y1: 2, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 4, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }], - '└': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '┕': [{ x1: 3, y1: 0, x2: 3, y2: 4 }, { x1: 3, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 2, x2: 6, y2: 2 }], - '┖': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 2, y1: 3, x2: 6, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], - '┗': [{ x1: 2, y1: 0, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 6, y2: 4 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }], - '┘': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 0 }], - '┙': [{ x1: 0, y1: 4, x2: 3, y2: 4 }, { x1: 3, y1: 4, x2: 3, y2: 0 }, { x1: 0, y1: 2, x2: 3, y2: 2 }], - '┚': [{ x1: 0, y1: 3, x2: 4, y2: 3 }, { x1: 4, y1: 3, x2: 4, y2: 0 }, { x1: 2, y1: 3, x2: 2, y2: 0 }], - '┛': [{ x1: 0, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 0 }, { x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }], - '├': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '┝': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], - '┞': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }, { x1: 4, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┟': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '┠': [{ x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }, { x1: 4, y1: 3, x2: 6, y2: 3 }], - '┡': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 2, y1: 3, x2: 6, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┢': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 2, y1: 6, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '┣': [{ x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 6, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 6 }], - '┤': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 3, x2: 3, y2: 3 }], - '┥': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], - '┦': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }, { x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┧': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 0, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '┨': [{ x1: 0, y1: 3, x2: 2, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], - '┩': [{ x1: 2, y1: 0, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 0, y2: 2 }, { x1: 4, y1: 0, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 0, y2: 4 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┪': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 3, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 3, y1: 0, x2: 3, y2: 3 }], - '┫': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], - '┬': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '┭': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }, { x1: 3, y1: 6, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '┮': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], - '┯': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 4, x2: 3, y2: 6 }], - '┰': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '┱': [{ x1: 0, y1: 2, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 4, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '┲': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 2, y1: 6, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '┳': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '┴': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 0, x2: 3, y2: 3 }], - '┵': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], - '┶': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 0 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], - '┷': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 0, x2: 3, y2: 3 }], - '┸': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], - '┹': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 0 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '┺': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 6, y2: 4 }, { x1: 3, y1: 0, x2: 3, y2: 2 }, { x1: 3, y1: 2, x2: 6, y2: 2 }], - '┻': [{ x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }], - '┼': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 0, x2: 3, y2: 6 }], - '┽': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], - '┾': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], - '┿': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }], - '╀': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }, { x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], - '╁': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '╂': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], - '╃': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 4, y2: 0 }, { x1: 3, y1: 6, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '╄': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }, { x1: 2, y1: 0, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 6, y2: 4 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }], - '╅': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 6, y2: 3 }, { x1: 0, y1: 2, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 4, y2: 6 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }], - '╆': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 0 }, { x1: 2, y1: 6, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '╇': [{ x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 3, x2: 3, y2: 6 }], - '╈': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '╉': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 2, y1: 2, x2: 2, y2: 0 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 2, y1: 4, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '╊': [{ x1: 0, y1: 3, x2: 2, y2: 3 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 6, x2: 4, y2: 4 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '╋': [{ x1: 0, y1: 2, x2: 6, y2: 2 }, { x1: 0, y1: 4, x2: 6, y2: 4 }, { x1: 2, y1: 0, x2: 2, y2: 6 }, { x1: 4, y1: 0, x2: 4, y2: 6 }], - '╌': [{ x1: 0, y1: 3, x2: 2, y2: 3 }, { x1: 4, y1: 3, x2: 6, y2: 3 }], - '╍': [{ x1: 0, y1: 2, x2: 2, y2: 2 }, { x1: 0, y1: 4, x2: 2, y2: 4 }, { x1: 4, y1: 2, x2: 6, y2: 2 }, { x1: 4, y1: 4, x2: 6, y2: 4 }], - '╎': [{ x1: 3, y1: 0, x2: 3, y2: 2 }, { x1: 3, y1: 4, x2: 3, y2: 6 }], - '╏': [{ x1: 2, y1: 0, x2: 2, y2: 2 }, { x1: 4, y1: 0, x2: 4, y2: 2 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '═': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }], - '║': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }], - '╒': [{ x1: 6, y1: 1, x2: 3, y2: 1 }, { x1: 3, y1: 1, x2: 3, y2: 6 }, { x1: 6, y1: 5, x2: 3, y2: 5 }], - '╓': [{ x1: 6, y1: 3, x2: 1, y2: 3 }, { x1: 1, y1: 3, x2: 1, y2: 6 }, { x1: 5, y1: 3, x2: 5, y2: 6 }], - '╔': [{ x1: 6, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 6 }, { x1: 6, y1: 5, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 5, y2: 6 }], - '╕': [{ x1: 0, y1: 1, x2: 3, y2: 1 }, { x1: 3, y1: 1, x2: 3, y2: 6 }, { x1: 0, y1: 5, x2: 3, y2: 5 }], - '╖': [{ x1: 0, y1: 3, x2: 5, y2: 3 }, { x1: 5, y1: 3, x2: 5, y2: 6 }, { x1: 1, y1: 3, x2: 1, y2: 6 }], - '╗': [{ x1: 0, y1: 1, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 5, y2: 6 }, { x1: 0, y1: 5, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 1, y2: 6 }], - '╘': [{ x1: 3, y1: 0, x2: 3, y2: 5 }, { x1: 3, y1: 5, x2: 6, y2: 5 }, { x1: 3, y1: 1, x2: 6, y2: 1 }], - '╙': [{ x1: 1, y1: 0, x2: 1, y2: 3 }, { x1: 1, y1: 3, x2: 6, y2: 3 }, { x1: 5, y1: 0, x2: 5, y2: 3 }], - '╚': [{ x1: 1, y1: 0, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 6, y2: 5 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }], - '╛': [{ x1: 0, y1: 1, x2: 3, y2: 1 }, { x1: 0, y1: 5, x2: 3, y2: 5 }, { x1: 3, y1: 5, x2: 3, y2: 0 }], - '╜': [{ x1: 0, y1: 3, x2: 5, y2: 3 }, { x1: 5, y1: 3, x2: 5, y2: 0 }, { x1: 1, y1: 3, x2: 1, y2: 0 }], - '╝': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 0, y1: 5, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 5, y2: 0 }], - '╞': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 3, y1: 1, x2: 6, y2: 1 }, { x1: 3, y1: 5, x2: 6, y2: 5 }], - '╟': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }, { x1: 5, y1: 3, x2: 6, y2: 3 }], - '╠': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }, { x1: 5, y1: 6, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 6, y2: 5 }], - '╡': [{ x1: 3, y1: 0, x2: 3, y2: 6 }, { x1: 0, y1: 1, x2: 3, y2: 1 }, { x1: 0, y1: 5, x2: 3, y2: 5 }], - '╢': [{ x1: 0, y1: 3, x2: 1, y2: 3 }, { x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }], - '╣': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 0, y1: 5, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }], - '╤': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }, { x1: 3, y1: 5, x2: 3, y2: 6 }], - '╥': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 1, y1: 3, x2: 1, y2: 6 }, { x1: 5, y1: 3, x2: 5, y2: 6 }], - '╦': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 1, y2: 6 }, { x1: 5, y1: 6, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 6, y2: 5 }], - '╧': [{ x1: 0, y1: 5, x2: 6, y2: 5 }, { x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 3, y1: 0, x2: 3, y2: 1 }], - '╨': [{ x1: 0, y1: 3, x2: 6, y2: 3 }, { x1: 1, y1: 0, x2: 1, y2: 3 }, { x1: 5, y1: 0, x2: 5, y2: 3 }], - '╩': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }], - '╪': [{ x1: 0, y1: 1, x2: 6, y2: 1 }, { x1: 0, y1: 5, x2: 6, y2: 5 }, { x1: 3, y1: 0, x2: 3, y2: 6 }], - '╫': [{ x1: 1, y1: 0, x2: 1, y2: 6 }, { x1: 5, y1: 0, x2: 5, y2: 6 }, { x1: 0, y1: 3, x2: 6, y2: 3 }], - '╬': [{ x1: 0, y1: 1, x2: 1, y2: 1 }, { x1: 1, y1: 1, x2: 1, y2: 0 }, { x1: 5, y1: 0, x2: 5, y2: 1 }, { x1: 5, y1: 1, x2: 6, y2: 1 }, { x1: 6, y1: 5, x2: 5, y2: 5 }, { x1: 5, y1: 5, x2: 5, y2: 6 }, { x1: 1, y1: 6, x2: 1, y2: 5 }, { x1: 1, y1: 5, x2: 0, y2: 5 }], - '╭': [{ x1: 6, y1: 3, x2: 3, y2: 6, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], - '╮': [{ x1: 0, y1: 3, x2: 3, y2: 6, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], - '╯': [{ x1: 0, y1: 3, x2: 3, y2: 0, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], - '╰': [{ x1: 3, y1: 0, x2: 6, y2: 3, cx1: 3, cy1: 3, cx2: 3, cy2: 3 }], - '╱': [{ x1: 0, y1: 6, x2: 6, y2: 0 }], - '╲': [{ x1: 0, y1: 0, x2: 6, y2: 6 }], - '╳': [{ x1: 0, y1: 6, x2: 6, y2: 0 }, { x1: 0, y1: 0, x2: 6, y2: 6 }], - '╴': [{ x1: 0, y1: 3, x2: 3, y2: 3 }], - '╵': [{ x1: 3, y1: 0, x2: 3, y2: 3 }], - '╶': [{ x1: 3, y1: 3, x2: 6, y2: 3 }], - '╷': [{ x1: 3, y1: 3, x2: 3, y2: 6 }], - '╸': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }], - '╹': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }], - '╺': [{ x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], - '╻': [{ x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '╼': [{ x1: 0, y1: 3, x2: 3, y2: 3 }, { x1: 3, y1: 2, x2: 6, y2: 2 }, { x1: 3, y1: 4, x2: 6, y2: 4 }], - '╽': [{ x1: 3, y1: 0, x2: 3, y2: 3 }, { x1: 2, y1: 3, x2: 2, y2: 6 }, { x1: 4, y1: 3, x2: 4, y2: 6 }], - '╾': [{ x1: 0, y1: 2, x2: 3, y2: 2 }, { x1: 0, y1: 4, x2: 3, y2: 4 }, { x1: 3, y1: 3, x2: 6, y2: 3 }], - '╿': [{ x1: 2, y1: 0, x2: 2, y2: 3 }, { x1: 4, y1: 0, x2: 4, y2: 3 }, { x1: 3, y1: 3, x2: 3, y2: 6 }] -}; export const boxDrawingBoxes: { [index: string]: any } = { '▀': [{ x: 0, y: 0, w: 8, h: 4 }], @@ -212,37 +90,14 @@ export const boxDrawingBoxes: { [index: string]: any } = { '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] }; -export const enum CENTER { - BOTTOM ='.5,1', - TOP = '.5,0', - MIDDLE = '.5,.5' -} - -export const enum LEFT { - BOTTOM = '0,1', - TOP = '0,0', - MIDDLE = '0,.5' -} - -export const enum RIGHT { - BOTTOM = '1,1', - TOP = '1,0', - MIDDLE = '1,.5' -} - -const MOVE = 'M'; -const TO = 'L'; -const THICK = '!'; - -const yAxis = `${MOVE}${CENTER.TOP} ${TO}${CENTER.BOTTOM}`; -const xAxis = `${MOVE}${LEFT.MIDDLE} ${TO}${RIGHT.MIDDLE}`; -const bottomYAxisFromBottom = `${MOVE}${CENTER.BOTTOM} ${TO}${CENTER.MIDDLE}`; -const bottomYAxisFromMiddle = `${MOVE}${CENTER.MIDDLE} ${TO}${CENTER.BOTTOM}`; -const topYAxisFromTop = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; -const topYAxisFromMiddle = `${MOVE}${CENTER.TOP} ${TO}${CENTER.MIDDLE}`; -const rightMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${RIGHT.MIDDLE}`; -const leftMiddleXAxis = `${MOVE}${CENTER.MIDDLE} ${TO}${LEFT.MIDDLE}`; - +const yAxis = `M.5,0 L.5,1`; +const xAxis = `M0,.5 L1,.5`; +const bottomYAxisFromBottom = `M.5,1 L.5,.5`; +const bottomYAxisFromMiddle = `M.5,.5 L.5,1`; +const topYAxisFromTop = `M.5,0 L.5,.5`; +const topYAxisFromMiddle = `M.5,0 L.5,.5`; +const rightMiddleXAxis = `M.5,.5 L1,.5`; +const leftMiddleXAxis = `M.5,.5 L0,.5`; const enum Shapes { /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', @@ -279,7 +134,7 @@ const enum Style { } // TODO: Tweak normal and bold weights -const map: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } } = { +export const boxCharacters: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } } = { // Uniform normal and bold '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, '━': { [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, @@ -419,7 +274,7 @@ const map: { [character: string]: { [fontWeight: number]: string | ((xp: number, }; export function drawBoxChar(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { - const match: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } = map[c]; + const match: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } = boxCharacters[c]; if (!match) { return; } From 2b3c7639824468067f05009f60a091b5f047b4f6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Aug 2021 07:42:47 -0700 Subject: [PATCH 19/37] Clean up mixed weight characters --- src/browser/renderer/BoxAndBlockCharacters.ts | 122 ++++++++---------- 1 file changed, 54 insertions(+), 68 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 23e76963..7882d03e 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -90,15 +90,6 @@ export const boxDrawingBoxes: { [index: string]: any } = { '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] }; -const yAxis = `M.5,0 L.5,1`; -const xAxis = `M0,.5 L1,.5`; -const bottomYAxisFromBottom = `M.5,1 L.5,.5`; -const bottomYAxisFromMiddle = `M.5,.5 L.5,1`; -const topYAxisFromTop = `M.5,0 L.5,.5`; -const topYAxisFromMiddle = `M.5,0 L.5,.5`; -const rightMiddleXAxis = `M.5,.5 L1,.5`; -const leftMiddleXAxis = `M.5,.5 L0,.5`; - const enum Shapes { /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', /** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5', @@ -108,8 +99,8 @@ const enum Shapes { /** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1', /** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5', - /** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L0,.5', - /** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L.5,0', + /** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L.5,0', + /** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L0,.5', /** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5', /** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1', @@ -167,10 +158,6 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin '╷': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM }, '╻': { [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - // Mixed normal/bold - '┍': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┎': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - // Double border '═': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, '║': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, @@ -208,54 +195,56 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin '╳': { [Style.NORMAL]: 'M1,0 L0,1 M0,0 L1,1' }, // Mixed weight - '┑': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '┒': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, - '┕': { [Style.NORMAL]: `${topYAxisFromTop}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┖': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, - '┙': { [Style.NORMAL]: `${topYAxisFromTop}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '┚': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, - '┝': { [Style.NORMAL]: `${yAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┞': { [Style.NORMAL]: `${bottomYAxisFromMiddle} ${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, - '┟': { [Style.NORMAL]: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, - '┠': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${yAxis}` }, - '┡': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${topYAxisFromMiddle} ${rightMiddleXAxis}` }, - '┢': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, - '┥': { [Style.NORMAL]: `${yAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '┦': { [Style.NORMAL]: `${bottomYAxisFromMiddle} ${leftMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop}` }, - '┧': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, - '┨': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${yAxis}` }, - '┩': { [Style.NORMAL]: `${bottomYAxisFromMiddle}`, [Style.BOLD]: `${topYAxisFromMiddle} ${leftMiddleXAxis}` }, - '┪': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, - '┭': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '┮': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┯': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${leftMiddleXAxis} ${rightMiddleXAxis}` }, - '┰': { [Style.NORMAL]: `${xAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, - '┱': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, - '┲': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┵': { [Style.NORMAL]: `${topYAxisFromMiddle} ${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '┶': { [Style.NORMAL]: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┷': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${leftMiddleXAxis} ${rightMiddleXAxis}` }, - '┸': { [Style.NORMAL]: `${xAxis}`, [Style.BOLD]: `${topYAxisFromMiddle}` }, - '┹': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromMiddle} ${leftMiddleXAxis}` }, - '┺': { [Style.NORMAL]: `${topYAxisFromMiddle} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┽': { [Style.NORMAL]: `${yAxis} ${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '┾': { [Style.NORMAL]: `${yAxis} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '┿': { [Style.NORMAL]: `${yAxis}`, [Style.BOLD]: `${leftMiddleXAxis} ${rightMiddleXAxis}` }, - '╀': { [Style.NORMAL]: `${xAxis}`, [Style.BOLD]: `${yAxis}` }, - '╁': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${yAxis} ${leftMiddleXAxis}` }, - '╂': { [Style.NORMAL]: `${yAxis} ${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '╃': { [Style.NORMAL]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}`, [Style.BOLD]: `${topYAxisFromTop} ${leftMiddleXAxis}` }, - '╄': { [Style.NORMAL]: `${topYAxisFromTop} ${leftMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, - '╅': { [Style.NORMAL]: `${topYAxisFromTop} ${rightMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${leftMiddleXAxis}` }, - '╆': { [Style.NORMAL]: `${topYAxisFromTop} ${leftMiddleXAxis}`, [Style.BOLD]: `${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, - '╇': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${leftMiddleXAxis} ${topYAxisFromTop} ${rightMiddleXAxis}` }, - '╈': { [Style.NORMAL]: `${topYAxisFromTop}`, [Style.BOLD]: `${leftMiddleXAxis} ${bottomYAxisFromBottom} ${rightMiddleXAxis}` }, - '╉': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis} ${yAxis}` }, - '╊': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis} ${yAxis}` }, - '╼': { [Style.NORMAL]: `${leftMiddleXAxis}`, [Style.BOLD]: `${rightMiddleXAxis}` }, - '╽': { [Style.NORMAL]: `${topYAxisFromMiddle}`, [Style.BOLD]: `${bottomYAxisFromBottom}` }, - '╾': { [Style.NORMAL]: `${rightMiddleXAxis}`, [Style.BOLD]: `${leftMiddleXAxis}` }, - '╿': { [Style.NORMAL]: `${bottomYAxisFromBottom}`, [Style.BOLD]: `${topYAxisFromMiddle}` }, + '╼': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '╽': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '╾': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '╿': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '┍': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┎': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '┑': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '┒': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '┕': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┖': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '┙': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '┚': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '┝': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┞': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '┟': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '┠': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, + '┡': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_RIGHT }, + '┢': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, + '┥': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '┦': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '┧': { [Style.NORMAL]: Shapes.TOP_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '┨': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, + '┩': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_LEFT }, + '┪': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, + '┭': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '┮': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┯': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, + '┰': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '┱': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, + '┲': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, + '┵': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '┶': { [Style.NORMAL]: Shapes.TOP_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┷': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, + '┸': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, + '┹': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_LEFT }, + '┺': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.TOP_TO_RIGHT }, + '┽': { [Style.NORMAL]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_RIGHT}`, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, + '┾': { [Style.NORMAL]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_LEFT}`, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, + '┿': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, + '╀': { [Style.NORMAL]: `${Shapes.LEFT_TO_RIGHT} ${Shapes.MIDDLE_TO_BOTTOM}`, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, + '╁': { [Style.NORMAL]: `${Shapes.MIDDLE_TO_TOP} ${Shapes.LEFT_TO_RIGHT}`, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, + '╂': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, + '╃': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_LEFT }, + '╄': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_RIGHT }, + '╅': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT, [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, + '╆': { [Style.NORMAL]: Shapes.TOP_TO_LEFT, [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, + '╇': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: `${Shapes.MIDDLE_TO_TOP} ${Shapes.LEFT_TO_RIGHT}` }, + '╈': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: `${Shapes.LEFT_TO_RIGHT} ${Shapes.MIDDLE_TO_BOTTOM}` }, + '╉': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_LEFT}` }, + '╊': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_RIGHT}` }, // Dashed // TODO: Spacing dashes evenly, use 1/2 padding on each edge so the line is continuous @@ -324,9 +313,6 @@ function clamp(value: number, max: number, min: number = 0): number { } const instructionMap: { [index: string]: any } = { - 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => { - ctx.moveTo(x, y); }, - 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => { - ctx.lineTo(x, y); - } + 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => ctx.moveTo(x, y), + 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => ctx.lineTo(x, y) }; From f43ae16a47d6062face1de48504d08f061a40797 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Aug 2021 07:57:32 -0700 Subject: [PATCH 20/37] Implement curved lines --- src/browser/renderer/BoxAndBlockCharacters.ts | 71 ++++++++++++------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 7882d03e..42608295 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -248,18 +248,24 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin // Dashed // TODO: Spacing dashes evenly, use 1/2 padding on each edge so the line is continuous - '╌': { [Style.NORMAL]: Shapes.TWO_DASHES_HORIZONTAL }, - '╍': { [Style.BOLD]: Shapes.TWO_DASHES_HORIZONTAL }, - '┄': { [Style.NORMAL]: Shapes.THREE_DASHES_HORIZONTAL }, - '┅': { [Style.BOLD]: Shapes.THREE_DASHES_HORIZONTAL }, - '┈': { [Style.NORMAL]: Shapes.FOUR_DASHES_HORIZONTAL }, - '┉': { [Style.BOLD]: Shapes.FOUR_DASHES_HORIZONTAL }, + '╌': { [Style.NORMAL]: Shapes.TWO_DASHES_HORIZONTAL }, + '╍': { [Style.BOLD]: Shapes.TWO_DASHES_HORIZONTAL }, + '┄': { [Style.NORMAL]: Shapes.THREE_DASHES_HORIZONTAL }, + '┅': { [Style.BOLD]: Shapes.THREE_DASHES_HORIZONTAL }, + '┈': { [Style.NORMAL]: Shapes.FOUR_DASHES_HORIZONTAL }, + '┉': { [Style.BOLD]: Shapes.FOUR_DASHES_HORIZONTAL }, '╎': { [Style.NORMAL]: Shapes.TWO_DASHES_VERTICAL }, '╏': { [Style.BOLD]: Shapes.TWO_DASHES_VERTICAL }, '┆': { [Style.NORMAL]: Shapes.THREE_DASHES_VERTICAL }, - '┇': { [Style.BOLD]: Shapes.THREE_DASHES_VERTICAL }, + '┇': { [Style.BOLD]: Shapes.THREE_DASHES_VERTICAL }, '┊': { [Style.NORMAL]: Shapes.FOUR_DASHES_VERTICAL }, - '┋': { [Style.BOLD]: Shapes.FOUR_DASHES_VERTICAL } + '┋': { [Style.BOLD]: Shapes.FOUR_DASHES_VERTICAL }, + + // Curved + '╭': { [Style.NORMAL]: 'C.5,1,.5,.5,1,.5' }, + '╮': { [Style.NORMAL]: 'C.5,1,.5,.5,0,.5' }, + '╯': { [Style.NORMAL]: 'C.5,0,.5,.5,0,.5' }, + '╰': { [Style.NORMAL]: 'C.5,0,.5,.5,1,.5' } }; export function drawBoxChar(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { @@ -285,23 +291,11 @@ export function drawBoxChar(ctx: CanvasRenderingContext2D, c: string, xOffset: n console.error(`Could not find drawing instructions for "${type}"`); continue; } - const coords: string[] = instruction.substring(1).split(','); - if (!coords[0] || !coords[1]) { + const args: string[] = instruction.substring(1).split(','); + if (!args[0] || !args[1]) { continue; } - let x = Number.parseFloat(coords[0].toString()) || Number.parseInt(coords[0].toString()); - let y = Number.parseFloat(coords[1].toString()) || Number.parseInt(coords[1].toString()); - - x *= cellWidth; - y *= cellHeight; - - if (y !== 0) { - y = clamp(Math.round(y + .5) - .5, cellHeight, 0); - } - if (x !== 0) { - x = clamp(Math.round(x + .5) - .5, cellWidth, 0); - } - f(ctx, xOffset + x, yOffset + y); + f(ctx, translateArgs(args, cellWidth, cellHeight, xOffset, yOffset)); } ctx.stroke(); ctx.closePath(); @@ -313,6 +307,33 @@ function clamp(value: number, max: number, min: number = 0): number { } const instructionMap: { [index: string]: any } = { - 'M': (ctx: CanvasRenderingContext2D, x: number, y: number) => ctx.moveTo(x, y), - 'L': (ctx: CanvasRenderingContext2D, x: number, y: number) => ctx.lineTo(x, y) + 'C': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.bezierCurveTo(args[0], args[1], args[2], args[3], args[4], args[5]), + 'L': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.lineTo(args[0], args[1]), + 'M': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.moveTo(args[0], args[1]) }; + +function translateArgs(args: string[], cellWidth: number, cellHeight: number, xOffset: number, yOffset: number): number[] { + const result = args.map(e => parseFloat(e) || parseInt(e)); + + if (result.length < 2) { + throw new Error('Too few arguments for instruction'); + } + + for (let x = 0; x < result.length; x += 2) { + result[x] *= cellWidth; + if (result[x] !== 0) { + result[x] = clamp(Math.round(result[x] + 0.5) - 0.5, cellWidth, 0); + } + result[x] += xOffset; + } + + for (let y = 1; y < result.length; y += 2) { + result[y] *= cellHeight; + if (result[y] !== 0) { + result[y] = clamp(Math.round(result[y] + 0.5) - 0.5, cellHeight, 0); + } + result[y] += yOffset; + } + + return result; +} From fd25ee0127c4b88421723ab212af0313c20fef4b Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Aug 2021 08:02:19 -0700 Subject: [PATCH 21/37] Add some doc comments --- src/browser/renderer/BoxAndBlockCharacters.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 42608295..48645d03 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -125,6 +125,7 @@ const enum Style { } // TODO: Tweak normal and bold weights +// This contains the definitions of all box drawing characters as SVG paths (ie. the svg d attribute) export const boxCharacters: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } } = { // Uniform normal and bold '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, @@ -320,18 +321,26 @@ function translateArgs(args: string[], cellWidth: number, cellHeight: number, xO } for (let x = 0; x < result.length; x += 2) { + // Translate from 0-1 to 0-cellWidth result[x] *= cellWidth; + // Ensure coordinate doesn't escape cell bounds and round to the nearest 0.5 to ensure a crisp + // line at 100% devicePixelRatio if (result[x] !== 0) { result[x] = clamp(Math.round(result[x] + 0.5) - 0.5, cellWidth, 0); } + // Apply the cell's offset (ie. x*cellWidth) result[x] += xOffset; } for (let y = 1; y < result.length; y += 2) { + // Translate from 0-1 to 0-cellHeight result[y] *= cellHeight; + // Ensure coordinate doesn't escape cell bounds and round to the nearest 0.5 to ensure a crisp + // line at 100% devicePixelRatio if (result[y] !== 0) { result[y] = clamp(Math.round(result[y] + 0.5) - 0.5, cellHeight, 0); } + // Apply the cell's offset (ie. x*cellHeight) result[y] += yOffset; } From 9269e91c49de1c70b4fcb46d915fab862782d49e Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Aug 2021 08:04:17 -0700 Subject: [PATCH 22/37] Make bold triple normal weight so 1 dpr = 3px bold --- src/browser/renderer/BoxAndBlockCharacters.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 48645d03..af239191 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -121,10 +121,9 @@ const enum Shapes { const enum Style { NORMAL = 1, - BOLD = 2 + BOLD = 3 } -// TODO: Tweak normal and bold weights // This contains the definitions of all box drawing characters as SVG paths (ie. the svg d attribute) export const boxCharacters: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } } = { // Uniform normal and bold From bcfbbb481c5608aabd1079957e56f27b9b73b89c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Aug 2021 08:14:46 -0700 Subject: [PATCH 23/37] Correct horizontal dash and a mixed weight char --- src/browser/renderer/BoxAndBlockCharacters.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index af239191..030c06e8 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -111,12 +111,12 @@ const enum Shapes { /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', - /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.45,.5 M.55,.5 L.9,.5', + /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.052,.5 L.316,.5 M.0.421,.5 L.6315,.5 M.684,.5 L.947,.5', /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.0588,.5 L.235,.5 M.294,.5 L.4705,.5 M.529,.5 L.7058,.5 M.765,.5 L.947,.5', - /** ╌ */ TWO_DASHES_VERTICAL = 'M.5,0 T.5,.45 M.5,.55 T.5,1', - /** ┄ */ THREE_DASHES_VERTICAL = 'M.5,.052 L.5,.316 M.5,.0.368 L.5.632 M.5,.684 L.5,.947', - /** ┉ */ FOUR_DASHES_VERTICAL = 'M.5,.0588 L.5,.235 M.5,.294 L.5,.4705 29 L.5,.7058 M.5,.765 L.5,.947', + /** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 T.5,.4 M.5,.6 T.5,.9', + /** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.052 L.5,.316 M.5,.0.368 L.5.632 M.5,.684 L.5,.947', + /** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.0588 L.5,.235 M.5,.294 L.5,.4705 29 L.5,.7058 M.5,.765 L.5,.947', } const enum Style { @@ -234,7 +234,7 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin '┽': { [Style.NORMAL]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_RIGHT}`, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, '┾': { [Style.NORMAL]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_LEFT}`, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, '┿': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, - '╀': { [Style.NORMAL]: `${Shapes.LEFT_TO_RIGHT} ${Shapes.MIDDLE_TO_BOTTOM}`, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, + '╀': { [Style.NORMAL]: `${Shapes.LEFT_TO_RIGHT} ${Shapes.MIDDLE_TO_BOTTOM}`, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, '╁': { [Style.NORMAL]: `${Shapes.MIDDLE_TO_TOP} ${Shapes.LEFT_TO_RIGHT}`, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, '╂': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, '╃': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_LEFT }, From ca88476934de016346e2bc57336d7e512631b81a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 17 Aug 2021 08:48:23 -0700 Subject: [PATCH 24/37] Improve spacing of dash characters --- src/browser/renderer/BoxAndBlockCharacters.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 030c06e8..ac37c761 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -111,12 +111,12 @@ const enum Shapes { /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', - /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', - /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.052,.5 L.316,.5 M.0.421,.5 L.6315,.5 M.684,.5 L.947,.5', - /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.0588,.5 L.235,.5 M.294,.5 L.4705,.5 M.529,.5 L.7058,.5 M.765,.5 L.947,.5', - /** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 T.5,.4 M.5,.6 T.5,.9', - /** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.052 L.5,.316 M.5,.0.368 L.5.632 M.5,.684 L.5,.947', - /** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.0588 L.5,.235 M.5,.294 L.5,.4705 29 L.5,.7058 M.5,.765 L.5,.947', + /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', // .2 empty, .3 filled + /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5', // .1333 empty, .2 filled + /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5', // .1 empty, .15 filled + /** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 L.5,.4 M.5,.6 L.5,.9', + /** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333', + /** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95', } const enum Style { @@ -171,7 +171,7 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin '╙': { [Style.NORMAL]: (xp, yp) => `M1,.5 L${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` }, '╚': { [Style.NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0 M1,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},0` }, '╛': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L.5,${.5 + yp} L.5,0 M0,${.5 - yp} L.5,${.5 - yp}` }, - '╜': { [Style.NORMAL]: (xp, yp) => `M0,.5 L${.5 + xp},.5 L${.5 + xp},0 M${.5 - xp},.5 L${.5 - xp},0 ` }, + '╜': { [Style.NORMAL]: (xp, yp) => `M0,.5 L${.5 + xp},.5 L${.5 + xp},0 M${.5 - xp},.5 L${.5 - xp},0` }, '╝': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M0,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},0` }, '╞': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` }, '╟': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1 M${.5 + xp},.5 L1,.5` }, From 9fb1ce11fb2708b89ea32c4940cb953fd15e9fc8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 06:44:13 -0700 Subject: [PATCH 25/37] Add setting, clean up drawing, fix true color --- src/browser/renderer/BaseRenderLayer.ts | 55 +++++------- src/browser/renderer/BoxAndBlockCharacters.ts | 90 ++++++++++++++++--- src/common/services/OptionsService.ts | 1 + src/common/services/Services.ts | 1 + typings/xterm-headless.d.ts | 8 ++ typings/xterm.d.ts | 8 ++ 6 files changed, 118 insertions(+), 45 deletions(-) diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 44b23840..e7116ed6 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,7 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; -import { boxCharacters, boxDrawingBoxes, drawBoxChar } from 'browser/renderer/BoxAndBlockCharacters'; +import { tryDrawCustomChar } from 'browser/renderer/BoxAndBlockCharacters'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; @@ -260,8 +260,15 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._ctx.font = this._getFont(false, false); this._ctx.textBaseline = 'ideographic'; this._clipRow(y); - // TODO: fix - if (!this._drawBoxChar(cell, x, y)) { + + // Draw custom characters if applicable + let drawSuccess = false; + if (this._optionsService.options.customBlockAndBoxCharacters !== false) { + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x, y, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + } + + // Draw the character + if (!drawSuccess) { this._ctx.fillText( cell.getChars(), x * this._scaledCellWidth + this._scaledCharLeft, @@ -377,46 +384,24 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (cell.isDim()) { this._ctx.globalAlpha = DIM_OPACITY; } - if (!this._drawBoxChar(cell, x, y)) { - // Draw the character + + // Draw custom characters if applicable + let drawSuccess = false; + if (this._optionsService.options.customBlockAndBoxCharacters !== false) { + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x, y, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + } + + // Draw the character + if (!drawSuccess) { this._ctx.fillText( cell.getChars(), x * this._scaledCellWidth + this._scaledCharLeft, y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); } + this._ctx.restore(); } - private _drawBoxChar(cell: ICellData, x: number, y: number): boolean { - const char = cell.getChars(); - - const boxes = boxDrawingBoxes[char]; - if (boxes) { - this._ctx.strokeStyle = this._ctx.fillStyle; - const xOffset = x * this._scaledCellWidth + this._scaledCharLeft; - const yOffset = y * this._scaledCellHeight + this._scaledCharTop; - for (let i = 0; i < boxes.length; i++) { - const box = boxes[i]; - const xEighth = this._scaledCellWidth / 8; - const yEighth = this._scaledCellHeight / 8; - this._ctx.fillRect( - xOffset, - yOffset, - box.w * xEighth, - box.h * yEighth); - } - return true; - } - - const lineSegments = boxCharacters[char]; - if (!lineSegments) { - return false; - } - this._ctx.strokeStyle = this._ctx.fillStyle; - drawBoxChar(this._ctx, char, x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); - return true; - } - /** * Clips a row to ensure no pixels will be drawn outside the cells in the row. diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index ac37c761..81cfaba8 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -1,5 +1,16 @@ +/** + * Copyright (c) 2021 The xterm.js authors. All rights reserved. + * @license MIT + */ -export const boxDrawingBoxes: { [index: string]: any } = { +interface IBlockVector { + x: number; + y: number; + w: number; + h: number; +} + +export const blockElementChars: { [index: string]: IBlockVector[] | undefined } = { '▀': [{ x: 0, y: 0, w: 8, h: 4 }], '█': [{ x: 0, y: 0, w: 8, h: 8 }], '▇': [{ x: 0, y: 1, w: 8, h: 7 }], @@ -125,7 +136,7 @@ const enum Style { } // This contains the definitions of all box drawing characters as SVG paths (ie. the svg d attribute) -export const boxCharacters: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } } = { +export const boxDrawingChars: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } | undefined } = { // Uniform normal and bold '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, '━': { [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, @@ -247,7 +258,6 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin '╊': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_RIGHT}` }, // Dashed - // TODO: Spacing dashes evenly, use 1/2 padding on each edge so the line is continuous '╌': { [Style.NORMAL]: Shapes.TWO_DASHES_HORIZONTAL }, '╍': { [Style.BOLD]: Shapes.TWO_DASHES_HORIZONTAL }, '┄': { [Style.NORMAL]: Shapes.THREE_DASHES_HORIZONTAL }, @@ -268,18 +278,78 @@ export const boxCharacters: { [character: string]: { [fontWeight: number]: strin '╰': { [Style.NORMAL]: 'C.5,0,.5,.5,1,.5' } }; -export function drawBoxChar(ctx: CanvasRenderingContext2D, c: string, xOffset: number, yOffset: number, cellWidth: number, cellHeight: number): void { - const match: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } = boxCharacters[c]; - if (!match) { - return; +/** + * Try drawing a custom block element or box drawing character, returning whether it was + * successfully drawn. + */ +export function tryDrawCustomChar( + ctx: CanvasRenderingContext2D, + c: string, + x: number, + y: number, + scaledCellWidth: number, + scaledCellHeight: number, + scaledCharLeft: number, + scaledCharTop: number +): boolean { + const blockElementInstruction = blockElementChars[c]; + if (blockElementInstruction) { + drawBlockElementChar(ctx, blockElementInstruction, x, y, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); + return true; } - for (const [fontWeight, instructions] of Object.entries(match)) { + + const boxDrawingInstruction = boxDrawingChars[c]; + if (boxDrawingInstruction) { + drawBoxDrawingChar(ctx, boxDrawingInstruction, x, y, scaledCellWidth, scaledCellHeight); + return true; + } + + return false; +} + +function drawBlockElementChar( + ctx: CanvasRenderingContext2D, + instruction: IBlockVector[], + x: number, + y: number, + scaledCellWidth: number, + scaledCellHeight: number, + scaledCharLeft: number, + scaledCharTop: number +): void { + const xOffset = x * scaledCellWidth + scaledCharLeft; + const yOffset = y * scaledCellHeight + scaledCharTop; + for (let i = 0; i < instruction.length; i++) { + const box = instruction[i]; + const xEighth = scaledCellWidth / 8; + const yEighth = scaledCellHeight / 8; + ctx.fillRect( + xOffset, + yOffset, + box.w * xEighth, + box.h * yEighth + ); + } +} + +function drawBoxDrawingChar( + ctx: CanvasRenderingContext2D, + charDefinition: { [fontWeight: number]: string | ((xp: number, yp: number) => string) }, + x: number, + y: number, + scaledCellWidth: number, + scaledCellHeight: number +): void { + const xOffset = x * scaledCellWidth; + const yOffset = y * scaledCellHeight; + ctx.strokeStyle = ctx.fillStyle; + for (const [fontWeight, instructions] of Object.entries(charDefinition)) { ctx.beginPath(); ctx.lineWidth = window.devicePixelRatio * Number.parseInt(fontWeight); let actualInstructions: string; if (typeof instructions === 'function') { const xp = .15; - const yp = .15 / cellHeight * cellWidth; + const yp = .15 / scaledCellHeight * scaledCellWidth; actualInstructions = instructions(xp, yp); } else { actualInstructions = instructions; @@ -295,7 +365,7 @@ export function drawBoxChar(ctx: CanvasRenderingContext2D, c: string, xOffset: n if (!args[0] || !args[1]) { continue; } - f(ctx, translateArgs(args, cellWidth, cellHeight, xOffset, yOffset)); + f(ctx, translateArgs(args, scaledCellWidth, scaledCellHeight, xOffset, yOffset)); } ctx.stroke(); ctx.closePath(); diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index b7a1c58e..062166bc 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -21,6 +21,7 @@ export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({ cursorBlink: false, cursorStyle: 'block', cursorWidth: 1, + customBlockAndBoxCharacters: true, bellSound: DEFAULT_BELL_SOUND, bellStyle: 'none', drawBoldTextInBrightColors: true, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index ce297322..07615a41 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -244,6 +244,7 @@ export interface ITerminalOptions { cursorBlink: boolean; cursorStyle: 'block' | 'underline' | 'bar'; cursorWidth: number; + customBlockAndBoxCharacters: boolean; disableStdin: boolean; drawBoldTextInBrightColors: boolean; fastScrollModifier: 'alt' | 'ctrl' | 'shift' | undefined; diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index b6e1505b..dc886aa1 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -78,6 +78,14 @@ declare module 'xterm-headless' { */ cursorWidth?: number; + /** + * Whether to draw custom block element and box drawing characters instead of using the font. + * This should typically result in better rendering with continuous lines. Note that this + * doesn't work with the DOM renderer which renders all characters using the font. The default + * is true. + */ + customBlockAndBoxCharacters?: boolean; + /** * Whether input should be disabled. */ diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 3828b415..f6fbe709 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -90,6 +90,14 @@ declare module 'xterm' { */ cursorWidth?: number; + /** + * Whether to draw custom block element and box drawing characters instead of using the font. + * This should typically result in better rendering with continuous lines. Note that this + * doesn't work with the DOM renderer which renders all characters using the font. The default + * is true. + */ + customBlockAndBoxCharacters?: boolean; + /** * Whether input should be disabled. */ From 86a30dc689d20a776688404fdc88f3dc10145bdb Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 06:45:40 -0700 Subject: [PATCH 26/37] Clean up usage of instruction/definition --- src/browser/renderer/BoxAndBlockCharacters.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index 81cfaba8..e4d549fb 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -10,7 +10,7 @@ interface IBlockVector { h: number; } -export const blockElementChars: { [index: string]: IBlockVector[] | undefined } = { +export const blockElementDefinitions: { [index: string]: IBlockVector[] | undefined } = { '▀': [{ x: 0, y: 0, w: 8, h: 4 }], '█': [{ x: 0, y: 0, w: 8, h: 8 }], '▇': [{ x: 0, y: 1, w: 8, h: 7 }], @@ -136,7 +136,7 @@ const enum Style { } // This contains the definitions of all box drawing characters as SVG paths (ie. the svg d attribute) -export const boxDrawingChars: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } | undefined } = { +export const boxDrawingDefinitions: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } | undefined } = { // Uniform normal and bold '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, '━': { [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, @@ -292,15 +292,15 @@ export function tryDrawCustomChar( scaledCharLeft: number, scaledCharTop: number ): boolean { - const blockElementInstruction = blockElementChars[c]; - if (blockElementInstruction) { - drawBlockElementChar(ctx, blockElementInstruction, x, y, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); + const blockElementDefinition = blockElementDefinitions[c]; + if (blockElementDefinition) { + drawBlockElementChar(ctx, blockElementDefinition, x, y, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); return true; } - const boxDrawingInstruction = boxDrawingChars[c]; - if (boxDrawingInstruction) { - drawBoxDrawingChar(ctx, boxDrawingInstruction, x, y, scaledCellWidth, scaledCellHeight); + const boxDrawingDefinition = boxDrawingDefinitions[c]; + if (boxDrawingDefinition) { + drawBoxDrawingChar(ctx, boxDrawingDefinition, x, y, scaledCellWidth, scaledCellHeight); return true; } @@ -309,7 +309,7 @@ export function tryDrawCustomChar( function drawBlockElementChar( ctx: CanvasRenderingContext2D, - instruction: IBlockVector[], + charDefinition: IBlockVector[], x: number, y: number, scaledCellWidth: number, @@ -319,8 +319,8 @@ function drawBlockElementChar( ): void { const xOffset = x * scaledCellWidth + scaledCharLeft; const yOffset = y * scaledCellHeight + scaledCharTop; - for (let i = 0; i < instruction.length; i++) { - const box = instruction[i]; + for (let i = 0; i < charDefinition.length; i++) { + const box = charDefinition[i]; const xEighth = scaledCellWidth / 8; const yEighth = scaledCellHeight / 8; ctx.fillRect( From e5d66d63f5efedaedd152af9c6cd2fe1a7f8e1ae Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 07:00:10 -0700 Subject: [PATCH 27/37] Fix offset of block elements --- src/browser/renderer/BoxAndBlockCharacters.ts | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index e4d549fb..fd897675 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -135,7 +135,10 @@ const enum Style { BOLD = 3 } -// This contains the definitions of all box drawing characters as SVG paths (ie. the svg d attribute) +/** + * This contains the definitions of all box drawing characters in the format of SVG paths (ie. the + * svg d attribute). + */ export const boxDrawingDefinitions: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } | undefined } = { // Uniform normal and bold '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, @@ -324,14 +327,54 @@ function drawBlockElementChar( const xEighth = scaledCellWidth / 8; const yEighth = scaledCellHeight / 8; ctx.fillRect( - xOffset, - yOffset, + xOffset + box.x * xEighth, + yOffset + box.y * yEighth, box.w * xEighth, box.h * yEighth ); } } +/** + * Draws the following box drawing characters by mapping a subset of SVG d attribute instructions to + * canvas draw calls. + * + * Box styles: ┎┰┒┍┯┑╓╥╖╒╤╕ ┏┳┓┌┲┓┌┬┐┏┱┐ + * ┌─┬─┐ ┏━┳━┓ ╔═╦═╗ ┠╂┨┝┿┥╟╫╢╞╪╡ ┡╇┩├╊┫┢╈┪┣╉┤ + * │ │ │ ┃ ┃ ┃ ║ ║ ║ ┖┸┚┕┷┙╙╨╜╘╧╛ └┴┘└┺┛┗┻┛┗┹┘ + * ├─┼─┤ ┣━╋━┫ ╠═╬═╣ ┏┱┐┌┲┓┌┬┐┌┬┐ ┏┳┓┌┮┓┌┬┐┏┭┐ + * │ │ │ ┃ ┃ ┃ ║ ║ ║ ┡╃┤├╄┩├╆┪┢╅┤ ┞╀┦├┾┫┟╁┧┣┽┤ + * └─┴─┘ ┗━┻━┛ ╚═╩═╝ └┴┘└┴┘└┺┛┗┹┘ └┴┘└┶┛┗┻┛┗┵┘ + * + * Other: + * ╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌╌ ┄┄┄ ┈┈┈ + * │ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍╍ ┅┅┅ ┉┉┉ + * ╰─╯ ╱ ╲ ╹╵╎╏┆┇┊┋ + * + * All box drawing characters: + * ─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏ + * ┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟ + * ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ + * ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿ + * ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏ + * ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ + * ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ + * ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿ + * + * --- + * + * Box drawing alignment tests: █ + * ▉ + * ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ + * ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ + * ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ + * ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ + * ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ + * ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ + * ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ + * + * Source: https://www.w3.org/2001/06/utf-8-test/UTF-8-demo.html + */ function drawBoxDrawingChar( ctx: CanvasRenderingContext2D, charDefinition: { [fontWeight: number]: string | ((xp: number, yp: number) => string) }, @@ -356,7 +399,7 @@ function drawBoxDrawingChar( } for (const instruction of actualInstructions.split(' ')) { const type = instruction[0]; - const f = instructionMap[type]; + const f = svgToCanvasInstructionMap[type]; if (!f) { console.error(`Could not find drawing instructions for "${type}"`); continue; @@ -376,7 +419,7 @@ function clamp(value: number, max: number, min: number = 0): number { return Math.max(Math.min(value, max), min); } -const instructionMap: { [index: string]: any } = { +const svgToCanvasInstructionMap: { [index: string]: any } = { 'C': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.bezierCurveTo(args[0], args[1], args[2], args[3], args[4], args[5]), 'L': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.lineTo(args[0], args[1]), 'M': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.moveTo(args[0], args[1]) From 0aaa20f87338442036cb80d3a127362d37a00684 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 07:31:35 -0700 Subject: [PATCH 28/37] Start of webgl integration --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 2 +- .../src/atlas/CharAtlasCache.ts | 4 +++- .../src/atlas/CharAtlasUtils.ts | 5 +++- addons/xterm-addon-webgl/src/atlas/Types.d.ts | 3 +++ .../src/atlas/WebglCharAtlas.ts | 11 ++++++++- .../src/renderLayer/BaseRenderLayer.ts | 2 +- src/browser/Terminal.ts | 1 + src/browser/renderer/BaseRenderLayer.ts | 4 ++-- src/browser/renderer/BoxAndBlockCharacters.ts | 23 +++++++++---------- 9 files changed, 36 insertions(+), 19 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 29e97d6d..75b6230c 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -230,7 +230,7 @@ export class WebglRenderer extends Disposable implements IRenderer { return; } - const atlas = acquireCharAtlas(this._terminal, this._colors, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight); + const atlas = acquireCharAtlas(this._terminal, this._colors, this.dimensions.scaledCellWidth, this.dimensions.scaledCellHeight, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight); if (!('getRasterizedGlyph' in atlas)) { throw new Error('The webgl renderer only works with the webgl char atlas'); } diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts index 5046006f..41114de0 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts @@ -28,10 +28,12 @@ const charAtlasCache: ICharAtlasCacheEntry[] = []; export function acquireCharAtlas( terminal: Terminal, colors: IColorSet, + scaledCellWidth: number, + scaledCellHeight: number, scaledCharWidth: number, scaledCharHeight: number ): WebglCharAtlas { - const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors); + const newConfig = generateConfig(scaledCellWidth, scaledCellHeight, scaledCharWidth, scaledCharHeight, terminal, colors); // Check to see if the terminal already owns this config for (let i = 0; i < charAtlasCache.length; i++) { diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 5496a500..e91c5fd1 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -13,7 +13,7 @@ const NULL_COLOR: IColor = { rgba: 0 }; -export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig { +export function generateConfig(scaledCellWidth: number, scaledCellHeight: number, scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig { // null out some fields that don't matter const clonedColors: IColorSet = { foreground: colors.foreground, @@ -28,7 +28,10 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number contrastCache: colors.contrastCache }; return { + customBlockAndBoxCharacters: terminal.getOption('customBlockAndBoxCharacters'), devicePixelRatio: window.devicePixelRatio, + scaledCellWidth, + scaledCellHeight, scaledCharWidth, scaledCharHeight, fontFamily: terminal.getOption('fontFamily'), diff --git a/addons/xterm-addon-webgl/src/atlas/Types.d.ts b/addons/xterm-addon-webgl/src/atlas/Types.d.ts index cd73393c..37384306 100644 --- a/addons/xterm-addon-webgl/src/atlas/Types.d.ts +++ b/addons/xterm-addon-webgl/src/atlas/Types.d.ts @@ -17,11 +17,14 @@ export interface IGlyphIdentifier { } export interface ICharAtlasConfig { + customBlockAndBoxCharacters: boolean; devicePixelRatio: number; fontSize: number; fontFamily: string; fontWeight: FontWeight; fontWeightBold: FontWeight; + scaledCellWidth: number; + scaledCellHeight: number; scaledCharWidth: number; scaledCharHeight: number; allowTransparency: boolean; diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 5f729e28..8fd43e1e 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -12,6 +12,7 @@ import { IColor } from 'browser/Types'; import { IDisposable } from 'xterm'; import { AttributeData } from 'common/buffer/AttributeData'; import { channels, rgba } from 'browser/Color'; +import { tryDrawCustomChar } from 'browser/renderer/BoxAndBlockCharacters'; // In practice we're probably never going to exhaust a texture this large. For debugging purposes, // however, it can be useful to set this to a really tiny value, to verify that LRU eviction works. @@ -390,8 +391,16 @@ export class WebglCharAtlas implements IDisposable { // For powerline glyphs left/top padding is excluded (https://github.com/microsoft/vscode/issues/120129) const padding = isPowerlineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING; + // Draw custom characters if applicable + let drawSuccess = false; + if (this._config.customBlockAndBoxCharacters !== false) { + drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING, this._config.scaledCellWidth, this._config.scaledCellHeight, this._config.scaledCharWidth, this._config.scaledCharHeight); + } + // Draw the character - this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight); + if (!drawSuccess) { + this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight); + } // Draw underline and strikethrough if (underline || strikethrough) { diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index cc210fd3..532836ee 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -92,7 +92,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) { return; } - this._charAtlas = acquireCharAtlas(terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight); + this._charAtlas = acquireCharAtlas(terminal, colorSet, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharWidth, this._scaledCharHeight); this._charAtlas.warmUp(); } diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index e702e61e..3ab343da 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -224,6 +224,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // The DOM renderer needs a row refresh to update the cursor styles this.refresh(this.buffer.y, this.buffer.y); break; + case 'customBlockAndBoxCharacters': case 'drawBoldTextInBrightColors': case 'letterSpacing': case 'lineHeight': diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index e7116ed6..afa12bb2 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -264,7 +264,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.options.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x, y, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); } // Draw the character @@ -388,7 +388,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.options.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x, y, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); } // Draw the character diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index fd897675..b38199ad 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -288,8 +288,8 @@ export const boxDrawingDefinitions: { [character: string]: { [fontWeight: number export function tryDrawCustomChar( ctx: CanvasRenderingContext2D, c: string, - x: number, - y: number, + xOffset: number, + yOffset: number, scaledCellWidth: number, scaledCellHeight: number, scaledCharLeft: number, @@ -297,13 +297,13 @@ export function tryDrawCustomChar( ): boolean { const blockElementDefinition = blockElementDefinitions[c]; if (blockElementDefinition) { - drawBlockElementChar(ctx, blockElementDefinition, x, y, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); + drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); return true; } const boxDrawingDefinition = boxDrawingDefinitions[c]; if (boxDrawingDefinition) { - drawBoxDrawingChar(ctx, boxDrawingDefinition, x, y, scaledCellWidth, scaledCellHeight); + drawBoxDrawingChar(ctx, boxDrawingDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); return true; } @@ -313,15 +313,16 @@ export function tryDrawCustomChar( function drawBlockElementChar( ctx: CanvasRenderingContext2D, charDefinition: IBlockVector[], - x: number, - y: number, + xOffset: number, + yOffset: number, scaledCellWidth: number, scaledCellHeight: number, scaledCharLeft: number, scaledCharTop: number ): void { - const xOffset = x * scaledCellWidth + scaledCharLeft; - const yOffset = y * scaledCellHeight + scaledCharTop; + // TODO: Scale to cell not char? + xOffset += scaledCharLeft; + yOffset += scaledCharTop; for (let i = 0; i < charDefinition.length; i++) { const box = charDefinition[i]; const xEighth = scaledCellWidth / 8; @@ -378,13 +379,11 @@ function drawBlockElementChar( function drawBoxDrawingChar( ctx: CanvasRenderingContext2D, charDefinition: { [fontWeight: number]: string | ((xp: number, yp: number) => string) }, - x: number, - y: number, + xOffset: number, + yOffset: number, scaledCellWidth: number, scaledCellHeight: number ): void { - const xOffset = x * scaledCellWidth; - const yOffset = y * scaledCellHeight; ctx.strokeStyle = ctx.fillStyle; for (const [fontWeight, instructions] of Object.entries(charDefinition)) { ctx.beginPath(); From fe7f28a7a0685f9ba83b5fe856bc241cb6207d32 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 07:38:02 -0700 Subject: [PATCH 29/37] Fix block elements on webgl, scale block elements to cell --- .../xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 2 +- src/browser/renderer/BaseRenderLayer.ts | 4 ++-- src/browser/renderer/BoxAndBlockCharacters.ts | 13 +++---------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 8fd43e1e..3b40659e 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -394,7 +394,7 @@ export class WebglCharAtlas implements IDisposable { // Draw custom characters if applicable let drawSuccess = false; if (this._config.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING, this._config.scaledCellWidth, this._config.scaledCellHeight, this._config.scaledCharWidth, this._config.scaledCharHeight); + drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING, this._config.scaledCellWidth, this._config.scaledCellHeight); } // Draw the character diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index afa12bb2..b994a8df 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -264,7 +264,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.options.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); } // Draw the character @@ -388,7 +388,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.options.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); } // Draw the character diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index b38199ad..7d9a32bf 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -291,13 +291,11 @@ export function tryDrawCustomChar( xOffset: number, yOffset: number, scaledCellWidth: number, - scaledCellHeight: number, - scaledCharLeft: number, - scaledCharTop: number + scaledCellHeight: number ): boolean { const blockElementDefinition = blockElementDefinitions[c]; if (blockElementDefinition) { - drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); + drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); return true; } @@ -316,13 +314,8 @@ function drawBlockElementChar( xOffset: number, yOffset: number, scaledCellWidth: number, - scaledCellHeight: number, - scaledCharLeft: number, - scaledCharTop: number + scaledCellHeight: number ): void { - // TODO: Scale to cell not char? - xOffset += scaledCharLeft; - yOffset += scaledCharTop; for (let i = 0; i < charDefinition.length; i++) { const box = charDefinition[i]; const xEighth = scaledCellWidth / 8; From da0928102b72e7c28d3513033b08524b76b48bb8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 08:19:23 -0700 Subject: [PATCH 30/37] Support shade char with patterns --- .../src/atlas/WebglCharAtlas.ts | 2 +- src/browser/renderer/BaseRenderLayer.ts | 2 +- ...xAndBlockCharacters.ts => CustomGlyphs.ts} | 88 +++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) rename src/browser/renderer/{BoxAndBlockCharacters.ts => CustomGlyphs.ts} (90%) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 3b40659e..e1f69555 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -12,7 +12,7 @@ import { IColor } from 'browser/Types'; import { IDisposable } from 'xterm'; import { AttributeData } from 'common/buffer/AttributeData'; import { channels, rgba } from 'browser/Color'; -import { tryDrawCustomChar } from 'browser/renderer/BoxAndBlockCharacters'; +import { tryDrawCustomChar } from 'browser/renderer/CustomGlyphs'; // In practice we're probably never going to exhaust a texture this large. For debugging purposes, // however, it can be useful to set this to a really tiny value, to verify that LRU eviction works. diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index b994a8df..117213eb 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -17,7 +17,7 @@ import { IBufferService, IOptionsService } from 'common/services/Services'; import { throwIfFalsy } from 'browser/renderer/RendererUtils'; import { channels, color, rgba } from 'browser/Color'; import { removeElementFromParent } from 'browser/Dom'; -import { tryDrawCustomChar } from 'browser/renderer/BoxAndBlockCharacters'; +import { tryDrawCustomChar } from 'browser/renderer/CustomGlyphs'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/CustomGlyphs.ts similarity index 90% rename from src/browser/renderer/BoxAndBlockCharacters.ts rename to src/browser/renderer/CustomGlyphs.ts index 7d9a32bf..55dafc6b 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/CustomGlyphs.ts @@ -3,6 +3,8 @@ * @license MIT */ +import { throwIfFalsy } from 'browser/renderer/RendererUtils'; + interface IBlockVector { x: number; y: number; @@ -101,6 +103,33 @@ export const blockElementDefinitions: { [index: string]: IBlockVector[] | undefi '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] }; +type PatternDefinition = number[][]; + +/** + * Defines the repeating pattern used by special characters, the pattern is made up of a 2d array of + * pixel values to be filled (1) or not filled (0). + */ +const patternCharacterDefinitions: { [key: string]: PatternDefinition | undefined } = { + '░': [ + [1, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 0] + ], + '▒': [ + [1, 0], + [0, 0], + [0, 1], + [0, 0] + ], + '▓': [ + [0, 1], + [1, 1], + [1, 0], + [1, 1] + ] +}; + const enum Shapes { /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', /** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5', @@ -299,6 +328,13 @@ export function tryDrawCustomChar( return true; } + const patternDefinition = patternCharacterDefinitions[c]; + if (patternDefinition) { + console.log('draw pattern', c); + drawPatternChar(ctx, patternDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); + return true; + } + const boxDrawingDefinition = boxDrawingDefinitions[c]; if (boxDrawingDefinition) { drawBoxDrawingChar(ctx, boxDrawingDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); @@ -329,6 +365,58 @@ function drawBlockElementChar( } } +const cachedPatterns: Map> = new Map(); + +function drawPatternChar( + ctx: CanvasRenderingContext2D, + charDefinition: number[][], + xOffset: number, + yOffset: number, + scaledCellWidth: number, + scaledCellHeight: number +): void { + let patternSet = cachedPatterns.get(charDefinition); + if (!patternSet) { + patternSet = new Map(); + cachedPatterns.set(charDefinition, patternSet); + } + // TODO: Unsafe? + const fillStyle = ctx.fillStyle as string; + let pattern = patternSet.get(fillStyle); + if (!pattern) { + const width = charDefinition[0].length; + const height = charDefinition.length; + const tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = width; + tmpCanvas.height = height; + const tmpCtx = throwIfFalsy(tmpCanvas.getContext('2d')); + const imageData = new ImageData(width, height); + // TODO: This is a little unsafe, fillStyle could be rgb/rgba format + const r = parseInt(fillStyle.substr(1, 2), 16); + const g = parseInt(fillStyle.substr(3, 2), 16); + const b = parseInt(fillStyle.substr(5, 2), 16); + const a = fillStyle.length > 7 && parseInt(fillStyle.substr(7, 2), 16) || undefined; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + imageData.data[(y * width + x) * 4 ] = r; + imageData.data[(y * width + x) * 4 + 1] = g; + imageData.data[(y * width + x) * 4 + 2] = b; + imageData.data[(y * width + x) * 4 + 3] = charDefinition[y][x] * (a ?? 255); + } + } + console.log('put', imageData); + tmpCtx.putImageData(imageData, 0, 0); + // TODO: This will break for different colored patterns + // TODO: This could happen multiple times + pattern = throwIfFalsy(ctx.createPattern(tmpCanvas, null)); + patternSet.set(fillStyle, pattern); + } + + console.log('fill style', pattern); + ctx.fillStyle = pattern; + ctx.fillRect(xOffset, yOffset, scaledCellWidth, scaledCellHeight); +} + /** * Draws the following box drawing characters by mapping a subset of SVG d attribute instructions to * canvas draw calls. From 011026a8d15fac5546d10c2fbe033516b7a09492 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 08:29:07 -0700 Subject: [PATCH 31/37] Get webgl glyphs scaling to cell size, invalidate on option change --- addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts | 5 +++++ addons/xterm-addon-webgl/src/atlas/Types.d.ts | 2 ++ addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 6 +++--- src/browser/renderer/CustomGlyphs.ts | 5 ----- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index e91c5fd1..6a478338 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -30,6 +30,8 @@ export function generateConfig(scaledCellWidth: number, scaledCellHeight: number return { customBlockAndBoxCharacters: terminal.getOption('customBlockAndBoxCharacters'), devicePixelRatio: window.devicePixelRatio, + letterSpacing: terminal.getOption('letterSpacing'), + lineHeight: terminal.getOption('lineHeight'), scaledCellWidth, scaledCellHeight, scaledCharWidth, @@ -52,6 +54,9 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean } } return a.devicePixelRatio === b.devicePixelRatio && + a.customBlockAndBoxCharacters === b.customBlockAndBoxCharacters && + a.lineHeight === b.lineHeight && + a.letterSpacing === b.letterSpacing && a.fontFamily === b.fontFamily && a.fontSize === b.fontSize && a.fontWeight === b.fontWeight && diff --git a/addons/xterm-addon-webgl/src/atlas/Types.d.ts b/addons/xterm-addon-webgl/src/atlas/Types.d.ts index 37384306..acbe3c71 100644 --- a/addons/xterm-addon-webgl/src/atlas/Types.d.ts +++ b/addons/xterm-addon-webgl/src/atlas/Types.d.ts @@ -19,6 +19,8 @@ export interface IGlyphIdentifier { export interface ICharAtlasConfig { customBlockAndBoxCharacters: boolean; devicePixelRatio: number; + letterSpacing: number; + lineHeight: number; fontSize: number; fontFamily: string; fontWeight: FontWeight; diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index e1f69555..6da70522 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -84,8 +84,8 @@ export class WebglCharAtlas implements IDisposable { this._cacheCtx = throwIfFalsy(this.cacheCanvas.getContext('2d', { alpha: true })); this._tmpCanvas = document.createElement('canvas'); - this._tmpCanvas.width = this._config.scaledCharWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2; - this._tmpCanvas.height = this._config.scaledCharHeight + TMP_CANVAS_GLYPH_PADDING * 2; + this._tmpCanvas.width = this._config.scaledCellWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2; + this._tmpCanvas.height = this._config.scaledCellHeight + TMP_CANVAS_GLYPH_PADDING * 2; this._tmpCtx = throwIfFalsy(this._tmpCanvas.getContext('2d', { alpha: this._config.allowTransparency })); } @@ -321,7 +321,7 @@ export class WebglCharAtlas implements IDisposable { // Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used // to draw the glyph to the canvas as well as to restrict the bounding box search to ensure // giant ligatures (eg. =====>) don't impact overall performance. - const allowedWidth = this._config.scaledCharWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; + let allowedWidth = this._config.scaledCharWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; if (this._tmpCanvas.width < allowedWidth) { this._tmpCanvas.width = allowedWidth; } diff --git a/src/browser/renderer/CustomGlyphs.ts b/src/browser/renderer/CustomGlyphs.ts index 55dafc6b..7457441b 100644 --- a/src/browser/renderer/CustomGlyphs.ts +++ b/src/browser/renderer/CustomGlyphs.ts @@ -404,15 +404,10 @@ function drawPatternChar( imageData.data[(y * width + x) * 4 + 3] = charDefinition[y][x] * (a ?? 255); } } - console.log('put', imageData); tmpCtx.putImageData(imageData, 0, 0); - // TODO: This will break for different colored patterns - // TODO: This could happen multiple times pattern = throwIfFalsy(ctx.createPattern(tmpCanvas, null)); patternSet.set(fillStyle, pattern); } - - console.log('fill style', pattern); ctx.fillStyle = pattern; ctx.fillRect(xOffset, yOffset, scaledCellWidth, scaledCellHeight); } From 54ce0172b416d8bfe53a8fc8e55fddd487488d51 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 18 Aug 2021 09:48:27 -0700 Subject: [PATCH 32/37] Add test custom glyph button to demo --- .../src/atlas/WebglCharAtlas.ts | 2 +- .../test/WebglRenderer.api.ts | 55 +++++++++- demo/client.ts | 100 +++++++++++------- demo/index.html | 1 + src/browser/renderer/CustomGlyphs.ts | 1 - 5 files changed, 118 insertions(+), 41 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 6da70522..557e23ef 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -321,7 +321,7 @@ export class WebglCharAtlas implements IDisposable { // Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used // to draw the glyph to the canvas as well as to restrict the bounding box search to ensure // giant ligatures (eg. =====>) don't impact overall performance. - let allowedWidth = this._config.scaledCharWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; + const allowedWidth = this._config.scaledCharWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; if (this._tmpCanvas.width < allowedWidth) { this._tmpCanvas.width = allowedWidth; } diff --git a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts index 1722e570..b666ceb4 100644 --- a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts @@ -6,7 +6,7 @@ import { ITerminalOptions } from '../../../src/common/Types'; import { ITheme } from 'xterm'; import { assert } from 'chai'; -import { openTerminal, pollFor, writeSync, getBrowserType } from '../../../out-test/api/TestUtils'; +import { openTerminal, pollFor, writeSync, getBrowserType, timeout } from '../../../out-test/api/TestUtils'; import { Browser, Page } from 'playwright'; const APP = 'http://127.0.0.1:3001/test'; @@ -830,6 +830,45 @@ describe('WebGL Renderer Integration Tests', async () => { }); }); + describe.only('custom glyphs', () => { + if (areTestsEnabled) { + before(async () => setupBrowser()); + after(async () => browser.close()); + beforeEach(async () => page.evaluate(`window.term.reset()`)); + } + + itWebgl('should draw normal weight characters pixel perfect', async () => { + const theme: ITheme = { + background: '#000000', + foreground: '#ffffff' + }; + await page.evaluate(` + window.term.setOption('theme', ${JSON.stringify(theme)}); + window.term.setOption('fontSize', 12); + window.term.setOption('minimumContrastRatio', 1); + `); + await writeSync(page, + 'Box drawing alignment tests: █\\n\\r' + + ' ▉\\n\\r' + + ' ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳\\n\\r' + + ' ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳\\n\\r' + + ' ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳\\n\\r' + + ' ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳\\n\\r' + + ' ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎\\n\\r' + + ' ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏\\n\\r' + + ' ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█' + ); + // Validate before minimumContrastRatio is applied + await pollFor(page, () => getCellColor(1, 1), [0x2e, 0x34, 0x36, 255]); + const pixels = await getCellPixels(1, 1); + for (let y = 0; y < pixels.length / 20; y++) { + console.log(`pixels ${y}: ` + pixels.slice(y * 20, y * 20 + 20).join(', ')); + } + console.log('cellPixels', pixels.length); + await timeout(2000); + }); + }); + describe('selection', async () => { if (areTestsEnabled) { before(async () => setupBrowser()); @@ -890,6 +929,20 @@ async function getCellColor(col: number, row: number): Promise { return await page.evaluate(`Array.from(window.result)`); } +async function getCellPixels(col: number, row: number): Promise { + await page.evaluate(` + window.gl = window.term._core._renderService._renderer._gl; + window.result = new Uint8Array(window.d.scaledCellWidth * window.d.scaledCellHeight * 4); + window.d = window.term._core._renderService.dimensions; + window.gl.readPixels( + Math.floor(${col - 1} * window.d.scaledCellWidth), + Math.floor(window.gl.drawingBufferHeight - ${row} * window.d.scaledCellHeight), + window.d.scaledCellWidth, window.d.scaledCellHeight, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result + ); + `); + return await page.evaluate(`Array.from(window.result)`); +} + async function setupBrowser(options: ITerminalOptions = { rendererType: 'dom' }): Promise { const browserType = getBrowserType(); browser = await browserType.launch({ diff --git a/demo/client.ts b/demo/client.ts index cc467908..de1faa37 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -147,6 +147,7 @@ if (document.location.pathname === '/test') { createTerminal(); document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler); document.getElementById('serialize').addEventListener('click', serializeButtonHandler); + document.getElementById('custom-glyph').addEventListener('click', writeCustomGlyphHandler); } function createTerminal(): void { @@ -214,17 +215,16 @@ function createTerminal(): void { // Set terminal size again to set the specific dimensions on the demo updateTerminalSize(); - // fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then((res) => { - // res.text().then((processId) => { - // pid = processId; - // socketURL += processId; - // socket = new WebSocket(socketURL); - // socket.onopen = runRealTerminal; - // socket.onclose = runFakeTerminal; - // socket.onerror = runFakeTerminal; - // }); - // }); - runFakeTerminal(); + fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then((res) => { + res.text().then((processId) => { + pid = processId; + socketURL += processId; + socket = new WebSocket(socketURL); + socket.onopen = runRealTerminal; + socket.onclose = runFakeTerminal; + socket.onerror = runFakeTerminal; + }); + }); }, 0); } @@ -247,33 +247,11 @@ function runFakeTerminal(): void { term.write('\r\n$ '); }; - // term.writeln('Welcome to xterm.js'); - // term.writeln('This is a local terminal emulation, without a real terminal in the back-end.'); - // term.writeln('Type some keys and commands to play around.'); - // term.writeln(''); - // term.prompt(); - - term.write('Box styles: ┎┰┒┍┯┑╓╥╖╒╤╕ ┏┳┓┌┲┓┌┬┐┏┱┐\n\r'); - term.write('┌─┬─┐ ┏━┳━┓ ╔═╦═╗ ┠╂┨┝┿┥╟╫╢╞╪╡ ┡╇┩├╊┫┢╈┪┣╉┤\n\r'); - term.write('│ │ │ ┃ ┃ ┃ ║ ║ ║ ┖┸┚┕┷┙╙╨╜╘╧╛ └┴┘└┺┛┗┻┛┗┹┘\n\r'); - term.write('├─┼─┤ ┣━╋━┫ ╠═╬═╣ ┏┱┐┌┲┓┌┬┐┌┬┐ ┏┳┓┌┮┓┌┬┐┏┭┐\n\r'); - term.write('│ │ │ ┃ ┃ ┃ ║ ║ ║ ┡╃┤├╄┩├╆┪┢╅┤ ┞╀┦├┾┫┟╁┧┣┽┤\n\r'); - term.write('└─┴─┘ ┗━┻━┛ ╚═╩═╝ └┴┘└┴┘└┺┛┗┹┘ └┴┘└┶┛┗┻┛┗┵┘\n\r'); - term.write('\n\r'); - term.write('Other:\n\r'); - term.write('╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌╌ ┄┄┄ ┈┈┈\n\r'); - term.write('│ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍╍ ┅┅┅ ┉┉┉\n\r'); - term.write('╰─╯ ╱ ╲ ╹╵╎╏┆┇┊┋\n\r'); - term.write('\n\r'); - term.write('All box drawing characters:\n\r'); - term.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\n\r'); - term.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\n\r'); - term.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\n\r'); - term.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\n\r'); - term.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\n\r'); - term.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\n\r'); - term.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\n\r'); - term.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\n\r'); + term.writeln('Welcome to xterm.js'); + term.writeln('This is a local terminal emulation, without a real terminal in the back-end.'); + term.writeln('Type some keys and commands to play around.'); + term.writeln(''); + term.prompt(); term.onKey((e: { key: string, domEvent: KeyboardEvent }) => { const ev = e.domEvent; @@ -454,3 +432,49 @@ function serializeButtonHandler(): void { term.write(output); } } + + +function writeCustomGlyphHandler() { + term.write('\n\r'); + term.write('\n\r'); + term.write('Box styles: ┎┰┒┍┯┑╓╥╖╒╤╕ ┏┳┓┌┲┓┌┬┐┏┱┐\n\r'); + term.write('┌─┬─┐ ┏━┳━┓ ╔═╦═╗ ┠╂┨┝┿┥╟╫╢╞╪╡ ┡╇┩├╊┫┢╈┪┣╉┤\n\r'); + term.write('│ │ │ ┃ ┃ ┃ ║ ║ ║ ┖┸┚┕┷┙╙╨╜╘╧╛ └┴┘└┺┛┗┻┛┗┹┘\n\r'); + term.write('├─┼─┤ ┣━╋━┫ ╠═╬═╣ ┏┱┐┌┲┓┌┬┐┌┬┐ ┏┳┓┌┮┓┌┬┐┏┭┐\n\r'); + term.write('│ │ │ ┃ ┃ ┃ ║ ║ ║ ┡╃┤├╄┩├╆┪┢╅┤ ┞╀┦├┾┫┟╁┧┣┽┤\n\r'); + term.write('└─┴─┘ ┗━┻━┛ ╚═╩═╝ └┴┘└┴┘└┺┛┗┹┘ └┴┘└┶┛┗┻┛┗┵┘\n\r'); + term.write('\n\r'); + term.write('Other:\n\r'); + term.write('╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌╌ ┄┄┄ ┈┈┈\n\r'); + term.write('│ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍╍ ┅┅┅ ┉┉┉\n\r'); + term.write('╰─╯ ╱ ╲ ╹╵╎╏┆┇┊┋\n\r'); + term.write('\n\r'); + term.write('All box drawing characters:\n\r'); + term.write('─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏\n\r'); + term.write('┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟\n\r'); + term.write('┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯\n\r'); + term.write('┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿\n\r'); + term.write('╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏\n\r'); + term.write('═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟\n\r'); + term.write('╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯\n\r'); + term.write('╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿\n\r'); + term.write('Box drawing alignment tests:\x1b[31m █\n\r'); + term.write(' ▉\n\r'); + term.write(' ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳\n\r'); + term.write(' ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳\n\r'); + term.write(' ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳\n\r'); + term.write(' ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳\n\r'); + term.write(' ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎\n\r'); + term.write(' ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏\n\r'); + term.write(' ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█\n\r'); + term.write('Box drawing alignment tests:\x1b[32m █\n\r'); + term.write(' ▉\n\r'); + term.write(' ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳\n\r'); + term.write(' ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳\n\r'); + term.write(' ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳\n\r'); + term.write(' ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳\n\r'); + term.write(' ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎\n\r'); + term.write(' ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏\n\r'); + term.write(' ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█\n\r'); + window.scrollTo(0, 0); +} diff --git a/demo/index.html b/demo/index.html index ab5b2040..910397c3 100644 --- a/demo/index.html +++ b/demo/index.html @@ -50,6 +50,7 @@
+ diff --git a/src/browser/renderer/CustomGlyphs.ts b/src/browser/renderer/CustomGlyphs.ts index 7457441b..82e086c4 100644 --- a/src/browser/renderer/CustomGlyphs.ts +++ b/src/browser/renderer/CustomGlyphs.ts @@ -330,7 +330,6 @@ export function tryDrawCustomChar( const patternDefinition = patternCharacterDefinitions[c]; if (patternDefinition) { - console.log('draw pattern', c); drawPatternChar(ctx, patternDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); return true; } From 158dcb06bdcf68bcfafcec872861f1773fa8f848 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 19 Aug 2021 05:16:01 -0700 Subject: [PATCH 33/37] Remove custom glyph tests --- .../test/WebglRenderer.api.ts | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts index b666ceb4..48f9c3d0 100644 --- a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts @@ -830,45 +830,6 @@ describe('WebGL Renderer Integration Tests', async () => { }); }); - describe.only('custom glyphs', () => { - if (areTestsEnabled) { - before(async () => setupBrowser()); - after(async () => browser.close()); - beforeEach(async () => page.evaluate(`window.term.reset()`)); - } - - itWebgl('should draw normal weight characters pixel perfect', async () => { - const theme: ITheme = { - background: '#000000', - foreground: '#ffffff' - }; - await page.evaluate(` - window.term.setOption('theme', ${JSON.stringify(theme)}); - window.term.setOption('fontSize', 12); - window.term.setOption('minimumContrastRatio', 1); - `); - await writeSync(page, - 'Box drawing alignment tests: █\\n\\r' + - ' ▉\\n\\r' + - ' ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳\\n\\r' + - ' ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳\\n\\r' + - ' ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳\\n\\r' + - ' ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳\\n\\r' + - ' ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎\\n\\r' + - ' ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏\\n\\r' + - ' ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█' - ); - // Validate before minimumContrastRatio is applied - await pollFor(page, () => getCellColor(1, 1), [0x2e, 0x34, 0x36, 255]); - const pixels = await getCellPixels(1, 1); - for (let y = 0; y < pixels.length / 20; y++) { - console.log(`pixels ${y}: ` + pixels.slice(y * 20, y * 20 + 20).join(', ')); - } - console.log('cellPixels', pixels.length); - await timeout(2000); - }); - }); - describe('selection', async () => { if (areTestsEnabled) { before(async () => setupBrowser()); From 3be97841a3c91178b7a3e88425a0c32498150b41 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 19 Aug 2021 05:19:28 -0700 Subject: [PATCH 34/37] Rename setting customGlyphs --- addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts | 4 ++-- addons/xterm-addon-webgl/src/atlas/Types.d.ts | 2 +- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 2 +- src/browser/Terminal.ts | 2 +- src/browser/renderer/BaseRenderLayer.ts | 4 ++-- src/common/services/OptionsService.ts | 2 +- src/common/services/Services.ts | 2 +- typings/xterm-headless.d.ts | 10 +++++----- typings/xterm.d.ts | 10 +++++----- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 6a478338..962eb7b3 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -28,7 +28,7 @@ export function generateConfig(scaledCellWidth: number, scaledCellHeight: number contrastCache: colors.contrastCache }; return { - customBlockAndBoxCharacters: terminal.getOption('customBlockAndBoxCharacters'), + customGlyphs: terminal.getOption('customGlyphs'), devicePixelRatio: window.devicePixelRatio, letterSpacing: terminal.getOption('letterSpacing'), lineHeight: terminal.getOption('lineHeight'), @@ -54,7 +54,7 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean } } return a.devicePixelRatio === b.devicePixelRatio && - a.customBlockAndBoxCharacters === b.customBlockAndBoxCharacters && + a.customGlyphs === b.customGlyphs && a.lineHeight === b.lineHeight && a.letterSpacing === b.letterSpacing && a.fontFamily === b.fontFamily && diff --git a/addons/xterm-addon-webgl/src/atlas/Types.d.ts b/addons/xterm-addon-webgl/src/atlas/Types.d.ts index acbe3c71..8d2870cd 100644 --- a/addons/xterm-addon-webgl/src/atlas/Types.d.ts +++ b/addons/xterm-addon-webgl/src/atlas/Types.d.ts @@ -17,7 +17,7 @@ export interface IGlyphIdentifier { } export interface ICharAtlasConfig { - customBlockAndBoxCharacters: boolean; + customGlyphs: boolean; devicePixelRatio: number; letterSpacing: number; lineHeight: number; diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 557e23ef..4c45fce1 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -393,7 +393,7 @@ export class WebglCharAtlas implements IDisposable { // Draw custom characters if applicable let drawSuccess = false; - if (this._config.customBlockAndBoxCharacters !== false) { + if (this._config.customGlyphs !== false) { drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING, this._config.scaledCellWidth, this._config.scaledCellHeight); } diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 3ab343da..dde4a1b6 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -224,7 +224,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // The DOM renderer needs a row refresh to update the cursor styles this.refresh(this.buffer.y, this.buffer.y); break; - case 'customBlockAndBoxCharacters': + case 'customGlyphs': case 'drawBoldTextInBrightColors': case 'letterSpacing': case 'lineHeight': diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 117213eb..448451d0 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -263,7 +263,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; - if (this._optionsService.options.customBlockAndBoxCharacters !== false) { + if (this._optionsService.options.customGlyphs !== false) { drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); } @@ -387,7 +387,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; - if (this._optionsService.options.customBlockAndBoxCharacters !== false) { + if (this._optionsService.options.customGlyphs !== false) { drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); } diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 062166bc..5add8283 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -21,7 +21,7 @@ export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({ cursorBlink: false, cursorStyle: 'block', cursorWidth: 1, - customBlockAndBoxCharacters: true, + customGlyphs: true, bellSound: DEFAULT_BELL_SOUND, bellStyle: 'none', drawBoldTextInBrightColors: true, diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 07615a41..2190a0f8 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -244,7 +244,7 @@ export interface ITerminalOptions { cursorBlink: boolean; cursorStyle: 'block' | 'underline' | 'bar'; cursorWidth: number; - customBlockAndBoxCharacters: boolean; + customGlyphs: boolean; disableStdin: boolean; drawBoldTextInBrightColors: boolean; fastScrollModifier: 'alt' | 'ctrl' | 'shift' | undefined; diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index dc886aa1..13a32126 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -79,12 +79,12 @@ declare module 'xterm-headless' { cursorWidth?: number; /** - * Whether to draw custom block element and box drawing characters instead of using the font. - * This should typically result in better rendering with continuous lines. Note that this - * doesn't work with the DOM renderer which renders all characters using the font. The default - * is true. + * Whether to draw custom glyphs for block element and box drawing characters instead of using + * the font. This should typically result in better rendering with continuous lines, even when + * line height and letter spacing is used. Note that this doesn't work with the DOM renderer + * which renders all characters using the font. The default is true. */ - customBlockAndBoxCharacters?: boolean; + customGlyphs?: boolean; /** * Whether input should be disabled. diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index f6fbe709..ba2be988 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -91,12 +91,12 @@ declare module 'xterm' { cursorWidth?: number; /** - * Whether to draw custom block element and box drawing characters instead of using the font. - * This should typically result in better rendering with continuous lines. Note that this - * doesn't work with the DOM renderer which renders all characters using the font. The default - * is true. + * Whether to draw custom glyphs for block element and box drawing characters instead of using + * the font. This should typically result in better rendering with continuous lines, even when + * line height and letter spacing is used. Note that this doesn't work with the DOM renderer + * which renders all characters using the font. The default is true. */ - customBlockAndBoxCharacters?: boolean; + customGlyphs?: boolean; /** * Whether input should be disabled. From 24cbedb71528bc2d65b7c200af7ae1eac1fe85ab Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 19 Aug 2021 05:32:46 -0700 Subject: [PATCH 35/37] Fix custom glyphs when using transparency --- .../test/WebglRenderer.api.ts | 6 ++-- src/browser/renderer/CustomGlyphs.ts | 30 ++++++++++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts index 48f9c3d0..793929e9 100644 --- a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts @@ -3,11 +3,11 @@ * @license MIT */ -import { ITerminalOptions } from '../../../src/common/Types'; -import { ITheme } from 'xterm'; import { assert } from 'chai'; -import { openTerminal, pollFor, writeSync, getBrowserType, timeout } from '../../../out-test/api/TestUtils'; import { Browser, Page } from 'playwright'; +import { ITheme } from 'xterm'; +import { getBrowserType, openTerminal, pollFor, writeSync } from '../../../out-test/api/TestUtils'; +import { ITerminalOptions } from '../../../src/common/Types'; const APP = 'http://127.0.0.1:3001/test'; diff --git a/src/browser/renderer/CustomGlyphs.ts b/src/browser/renderer/CustomGlyphs.ts index 82e086c4..a132877a 100644 --- a/src/browser/renderer/CustomGlyphs.ts +++ b/src/browser/renderer/CustomGlyphs.ts @@ -379,8 +379,10 @@ function drawPatternChar( patternSet = new Map(); cachedPatterns.set(charDefinition, patternSet); } - // TODO: Unsafe? - const fillStyle = ctx.fillStyle as string; + const fillStyle = ctx.fillStyle; + if (typeof fillStyle !== 'string') { + throw new Error(`Unexpected fillStyle type "${fillStyle}"`); + } let pattern = patternSet.get(fillStyle); if (!pattern) { const width = charDefinition[0].length; @@ -390,17 +392,29 @@ function drawPatternChar( tmpCanvas.height = height; const tmpCtx = throwIfFalsy(tmpCanvas.getContext('2d')); const imageData = new ImageData(width, height); - // TODO: This is a little unsafe, fillStyle could be rgb/rgba format - const r = parseInt(fillStyle.substr(1, 2), 16); - const g = parseInt(fillStyle.substr(3, 2), 16); - const b = parseInt(fillStyle.substr(5, 2), 16); - const a = fillStyle.length > 7 && parseInt(fillStyle.substr(7, 2), 16) || undefined; + + // Extract rgba from fillStyle + let r: number; + let g: number; + let b: number; + let a: number; + if (fillStyle.startsWith('#')) { + r = parseInt(fillStyle.substr(1, 2), 16); + g = parseInt(fillStyle.substr(3, 2), 16); + b = parseInt(fillStyle.substr(5, 2), 16); + a = fillStyle.length > 7 && parseInt(fillStyle.substr(7, 2), 16) || 1; + } else if (fillStyle.startsWith('rgba')) { + ([r, g, b, a] = fillStyle.substring(5, fillStyle.length - 1).split(',').map(e => parseFloat(e))); + } else { + throw new Error(`Unexpected fillStyle color format "${fillStyle}" when drawing pattern glyph`); + } + for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { imageData.data[(y * width + x) * 4 ] = r; imageData.data[(y * width + x) * 4 + 1] = g; imageData.data[(y * width + x) * 4 + 2] = b; - imageData.data[(y * width + x) * 4 + 3] = charDefinition[y][x] * (a ?? 255); + imageData.data[(y * width + x) * 4 + 3] = charDefinition[y][x] * (a * 255); } } tmpCtx.putImageData(imageData, 0, 0); From 338d94daf9be0aed05e1d15b4d47dd6f6b090e43 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 19 Aug 2021 05:41:49 -0700 Subject: [PATCH 36/37] Fix webgl alignment issues No idea why this worked but it did --- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 4c45fce1..340e83c9 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -394,7 +394,7 @@ export class WebglCharAtlas implements IDisposable { // Draw custom characters if applicable let drawSuccess = false; if (this._config.customGlyphs !== false) { - drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING, this._config.scaledCellWidth, this._config.scaledCellHeight); + drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, padding, padding, this._config.scaledCellWidth, this._config.scaledCellHeight); } // Draw the character From 1a75416dbfe762f32aeeb2ee5faccafe80583841 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 19 Aug 2021 06:00:27 -0700 Subject: [PATCH 37/37] Add missing block elements (include all 0x2580-0x259F) --- src/browser/renderer/CustomGlyphs.ts | 61 +++++++++++++++++----------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/browser/renderer/CustomGlyphs.ts b/src/browser/renderer/CustomGlyphs.ts index a132877a..77562790 100644 --- a/src/browser/renderer/CustomGlyphs.ts +++ b/src/browser/renderer/CustomGlyphs.ts @@ -13,22 +13,40 @@ interface IBlockVector { } export const blockElementDefinitions: { [index: string]: IBlockVector[] | undefined } = { - '▀': [{ x: 0, y: 0, w: 8, h: 4 }], - '█': [{ x: 0, y: 0, w: 8, h: 8 }], - '▇': [{ x: 0, y: 1, w: 8, h: 7 }], - '▆': [{ x: 0, y: 2, w: 8, h: 6 }], - '▅': [{ x: 0, y: 3, w: 8, h: 5 }], - '▄': [{ x: 0, y: 4, w: 8, h: 4 }], - '▃': [{ x: 0, y: 5, w: 8, h: 3 }], - '▂': [{ x: 0, y: 6, w: 8, h: 2 }], - '▁': [{ x: 0, y: 7, w: 8, h: 1 }], - '▉': [{ x: 0, y: 0, w: 7, h: 8 }], - '▊': [{ x: 0, y: 0, w: 6, h: 8 }], - '▋': [{ x: 0, y: 0, w: 5, h: 8 }], - '▌': [{ x: 0, y: 0, w: 4, h: 8 }], - '▍': [{ x: 0, y: 0, w: 3, h: 8 }], - '▎': [{ x: 0, y: 0, w: 2, h: 8 }], - '▏': [{ x: 0, y: 0, w: 1, h: 8 }], + // Block elements (0x2580-0x2590) + '▀': [{ x: 0, y: 0, w: 8, h: 4 }], // UPPER HALF BLOCK + '▁': [{ x: 0, y: 7, w: 8, h: 1 }], // LOWER ONE EIGHTH BLOCK + '▂': [{ x: 0, y: 6, w: 8, h: 2 }], // LOWER ONE QUARTER BLOCK + '▃': [{ x: 0, y: 5, w: 8, h: 3 }], // LOWER THREE EIGHTHS BLOCK + '▄': [{ x: 0, y: 4, w: 8, h: 4 }], // LOWER HALF BLOCK + '▅': [{ x: 0, y: 3, w: 8, h: 5 }], // LOWER FIVE EIGHTHS BLOCK + '▆': [{ x: 0, y: 2, w: 8, h: 6 }], // LOWER THREE QUARTERS BLOCK + '▇': [{ x: 0, y: 1, w: 8, h: 7 }], // LOWER SEVEN EIGHTHS BLOCK + '█': [{ x: 0, y: 0, w: 8, h: 8 }], // FULL BLOCK + '▉': [{ x: 0, y: 0, w: 7, h: 8 }], // LEFT SEVEN EIGHTHS BLOCK + '▊': [{ x: 0, y: 0, w: 6, h: 8 }], // LEFT THREE QUARTERS BLOCK + '▋': [{ x: 0, y: 0, w: 5, h: 8 }], // LEFT FIVE EIGHTHS BLOCK + '▌': [{ x: 0, y: 0, w: 4, h: 8 }], // LEFT HALF BLOCK + '▍': [{ x: 0, y: 0, w: 3, h: 8 }], // LEFT THREE EIGHTHS BLOCK + '▎': [{ x: 0, y: 0, w: 2, h: 8 }], // LEFT ONE QUARTER BLOCK + '▏': [{ x: 0, y: 0, w: 1, h: 8 }], // LEFT ONE EIGHTH BLOCK + '▐': [{ x: 4, y: 0, w: 4, h: 8 }], // RIGHT HALF BLOCK + + // Block elements (0x2594-0x2595) + '▔': [{ x: 0, y: 0, w: 9, h: 1 }], // UPPER ONE EIGHTH BLOCK + '▕': [{ x: 7, y: 0, w: 1, h: 8 }], // RIGHT ONE EIGHTH BLOCK + + // Terminal graphic characters (0x2596-0x259F) + '▖': [{ x: 0, y: 4, w: 4, h: 4 }], // QUADRANT LOWER LEFT + '▗': [{ x: 4, y: 4, w: 4, h: 4 }], // QUADRANT LOWER RIGHT + '▘': [{ x: 0, y: 0, w: 4, h: 4 }], // QUADRANT UPPER LEFT + '▙': [{ x: 0, y: 0, w: 4, h: 8 }, { x: 0, y: 4, w: 8, h: 4 }], // QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT + '▚': [{ x: 0, y: 0, w: 4, h: 4 }, { x: 4, y: 4, w: 4, h: 4 }], // QUADRANT UPPER LEFT AND LOWER RIGHT + '▛': [{ x: 0, y: 0, w: 4, h: 8 }, { x: 0, y: 0, w: 4, h: 8 }], // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT + '▜': [{ x: 0, y: 0, w: 8, h: 4 }, { x: 4, y: 0, w: 4, h: 8 }], // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT + '▝': [{ x: 4, y: 0, w: 4, h: 4 }], // QUADRANT UPPER RIGHT + '▞': [{ x: 4, y: 0, w: 4, h: 4 }, { x: 0, y: 4, w: 4, h: 4 }], // QUADRANT UPPER RIGHT AND LOWER LEFT + '▟': [{ x: 4, y: 0, w: 4, h: 8 }, { x: 0, y: 4, w: 8, h: 4 }], // QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT // VERTICAL ONE EIGHTH BLOCK-2 through VERTICAL ONE EIGHTH BLOCK-7 '\u{1FB70}': [{ x: 1, y: 0, w: 1, h: 8 }], @@ -37,11 +55,7 @@ export const blockElementDefinitions: { [index: string]: IBlockVector[] | undefi '\u{1FB73}': [{ x: 4, y: 0, w: 1, h: 8 }], '\u{1FB74}': [{ x: 5, y: 0, w: 1, h: 8 }], '\u{1FB75}': [{ x: 6, y: 0, w: 1, h: 8 }], - // RIGHT ONE EIGHTH BLOCK - '▕': [{ x: 7, y: 0, w: 1, h: 8 }], - // UPPER ONE EIGHTH BLOCK - '▔': [{ x: 0, y: 0, w: 8, h: 1 }], // HORIZONTAL ONE EIGHTH BLOCK-2 through HORIZONTAL ONE EIGHTH BLOCK-7 '\u{1FB76}': [{ x: 0, y: 1, w: 8, h: 1 }], '\u{1FB77}': [{ x: 0, y: 2, w: 8, h: 1 }], @@ -110,19 +124,20 @@ type PatternDefinition = number[][]; * pixel values to be filled (1) or not filled (0). */ const patternCharacterDefinitions: { [key: string]: PatternDefinition | undefined } = { - '░': [ + // Shade characters (0x2591-0x2593) + '░': [ // LIGHT SHADE (25%) [1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0] ], - '▒': [ + '▒': [ // MEDIUM SHADE (50%) [1, 0], [0, 0], [0, 1], [0, 0] ], - '▓': [ + '▓': [ // DARK SHADE (75%) [0, 1], [1, 1], [1, 0],