UNPKG

ascii-ui

Version:

Graphic terminal emulator for HTML canvas elements

137 lines 5.65 kB
import { Widget } from '../Widget'; import { clamp } from '../util/clamp'; import { coalesce } from '../util/coalesce'; import { deepAssign } from '../util/deepAssign'; import { noWrap, splitText, tokenizer } from '../util/tokenizer'; export class Text extends Widget { constructor(terminal, options, parent) { super(terminal, deepAssign({}, Text.defaultOptions, options), parent); this.startLine = 0; this.typewritterLine = 0; this.typewritterColumn = 0; this.render(); } render() { if (!this.splittedText || this.startLine === undefined) { return; } if (this.options.textStyle) { this.terminal.setTextStyle(this.options.textStyle); } clearTimeout(this.typewritterTimer); const typewritterEnabled = this.options.typewritterDelay > 0; const terminalColumn = this.options.col; let terminalLine = this.options.line; let lastLine = Math.min(this.startLine + this.options.height, this.splittedText.length); const completedLines = typewritterEnabled ? Math.min(this.typewritterLine, lastLine) : lastLine; let line = this.startLine; while (line < completedLines) { this.terminal.setText(this.splittedText[line], terminalColumn, terminalLine); line++; terminalLine++; } lastLine = this.options.line + this.options.height; if (terminalLine >= lastLine) { return; } if (this.typewritterColumn > 0) { const text = this.splittedText[line].substring(0, this.typewritterColumn) + ' '.repeat(this.options.width - this.typewritterColumn); this.terminal.setText(text, terminalColumn, terminalLine); terminalLine++; } const emptyLine = ' '.repeat(this.options.width); while (terminalLine < lastLine) { this.terminal.setText(emptyLine, terminalColumn, terminalLine); terminalLine++; } if (typewritterEnabled && this.typewritterLine - this.startLine < this.options.height) { this.typewritterTimer = setTimeout(this.renderInProgressText.bind(this), this.options.typewritterDelay, terminalColumn, this.options.line); } } getTextSize() { return { columns: this.options.tokenizer ? this.splittedText[0].length : this.options.text.length, rows: this.splittedText.length, }; } setScrollLine(line) { clearTimeout(this.typewritterTimer); const currentOffset = this.startLine; const maxLine = this.options.fitPageEnd ? this.splittedText.length - this.options.height : this.splittedText.length - 1; this.startLine = clamp(line, 0, maxLine); if (currentOffset !== this.startLine) { const oldTypewritterLine = this.typewritterLine; this.typewritterLine = clamp(this.typewritterLine, this.startLine, this.options.persistentTypewritter ? this.splittedText.length : maxLine); if (oldTypewritterLine !== this.typewritterLine) { this.typewritterColumn = 0; } } this.render(); return this.startLine < maxLine; } scrollLines(lines) { return this.setScrollLine(this.startLine + lines); } scrollPages(pages) { return this.setScrollLine(this.startLine + pages * this.options.height); } updateOptions(changes) { const dirtyText = coalesce(changes.tokenizer, changes.text, changes.width, changes.skip) !== undefined; const redraw = dirtyText || coalesce(changes.col, changes.line) !== undefined; if (changes.skip !== undefined) { this.options.skip = clamp(changes.skip, 0, this.options.text.length); } if (dirtyText) { this.splittedText = this.splitText(this.options.text); } if (redraw) { this.render(); } } renderInProgressText(textCol, textLine) { const line = this.splittedText[this.typewritterLine]; if (!line) { return; } const partialText = line[this.typewritterColumn]; const x = textCol + this.typewritterColumn; const y = textLine + this.typewritterLine - this.startLine; if (!this.isAt(x, y)) { return; } this.terminal.setText(partialText, x, y); this.typewritterColumn++; if (this.typewritterColumn >= this.splittedText[this.typewritterLine].trim().length) { this.typewritterColumn = 0; this.typewritterLine++; } if (this.typewritterLine - this.startLine < this.options.height && this.typewritterLine < this.splittedText.length) { this.typewritterTimer = setTimeout(this.renderInProgressText.bind(this), this.options.typewritterDelay, textCol, textLine); } } splitText(text) { if (!this.allocated) { return; } const txt = this.options.skip ? text.substr(this.options.skip) : text; if (!this.options.tokenizer) { const noWrappedText = noWrap(txt, this.options.width, this.options.ellipsis); return [noWrappedText + ' '.repeat(this.options.width - noWrappedText.length)]; } return splitText(txt, this.options.width, this.options.tokenizer); } } Text.defaultOptions = { tokenizer, text: '', ellipsis: '...', skip: 0, fitPageEnd: false, typewritterDelay: 0, persistentTypewritter: true, }; //# sourceMappingURL=Text.js.map