I’m using a BoxElement
from blessed to display a chat history.
Sentences are added using pushLine
. For clarity, days are divided by lines (another string added using pushLine
). Each line is as wide as the parent BoxElement
.
If the TUI is resized however, the line no longer fits.
I have 2 questions:
- How can that line adapt to its new width?
- (bonus points) How can I center text in the middle of that line?
An example of the issue is shown below:
/** * Example.ts */ import * as blessed from 'blessed'; const screen = blessed.screen({ smartCSR: true, title: 'Chatr', dockBorders: true }); const chatBox = blessed.box({ parent: screen, title: 'Chatbox', top: 'top', left: 'center', height: '100%', width: '100%', border: { type: 'line' }, }); screen.append(chatBox); screen.render(); chatBox.pushLine("This is the first line"); // This is the separator - and will not resize with the terminal chatBox.pushLine("_".repeat(chatBox.width as number - 2)); chatBox.pushLine("This is a second line"); screen.render();
When the code is run ts-node ./Example.js
it renders this:
┌────────────────────────────────────────────────────────────────────────────────────────┐ │This is a line │ │________________________________________________________________________________________│ │This is a second line │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────────────────────────────────────────────────────────────────────────────────────────┘
Resizing the terminal gets this result:
┌──────────────────────────────────────────────────────────┐ │This is a line │ │__________________________________________________________│ │______________________________ │ │This is a second line │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────┘
Advertisement
Answer
It seems blessed
doesn’t implement something like a separator, but we can simply implement them by ourselves with a simple class which stores the line index of each separator and change them on resize
event. Something like:
import * as blessed from "blessed"; // The required Separators class class Separators { private box: any; private separators: number[] = []; public constructor(box: any) { this.box = box; box.on("resize", () => { const sep = this.sep(); this.separators.forEach(line => { box.deleteLine(line); box.insertLine(line, sep); }); }); } public add(): void { const { box, separators } = this; separators.push(box.getLines().length); box.pushLine(this.sep()); } private sep(): string { return "_".repeat((this.box.width as number) - 3); } } const screen = blessed.screen({ smartCSR: true, title: "Chatr", dockBorders: true }); const chatBox = blessed.box({ parent: screen, title: "Chatbox", top: "top", left: "center", height: "100%", width: "100%", border: { type: "line" } }); const sep = new Separators(chatBox); // <- the new Separator bound to the box screen.append(chatBox); screen.render(); chatBox.pushLine("This is the first line"); // This is the separator - and it resize with the terminal sep.add(); chatBox.pushLine("This is a second line"); chatBox.pushLine("While this is the third line"); // This is another separator - it resize with the terminal as well sep.add(); chatBox.pushLine("And last this is the last line"); screen.render();
About the bonus point, now it should be quite easy to achieve it; the hard part is to center a line longer than the box width: if we split it in more lines to center, all the line indexes (next to split centered line) will changes and could become harder to keep track of them.
A possible compromise could be to accept to center only lines shorter than box width, left padding them with the right amount of spaces.