Drawing a line that’s always as wide as its parent BoxElement?

Tags: , , ,



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:

  1. How can that line adapt to its new width?
  2. (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                                     │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
│                                                          │
└──────────────────────────────────────────────────────────┘

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.



Source: stackoverflow