Getting the Terminal Size in Node

For a terminal-UI that I am working on - written in Node - I needed to get the size of the terminal so that I can appropriately make calculations for drawing the UI. This is easy using the ncurses-library, but I am using Charm instead(I have good reasons...I think).

Attempt 1: $COLUMNS and $LINES

The first possible solution is using the shell variables $COLS and $LINES.

$ echo $COLUMNS
88
$ echo $LINES
22

The problem with this is it doesn't work inside a node process, because apparently, shell variables are only accessible to the shell.

Attempt 2: TPUT

The next thing I tried is using the tput command:

$ tput cols
88
$ tput lines
22

Okay, I'll just child_process.spawn to shell out to the command and get the results back.

var spawn = require('child_process').spawn
function getTermSize(cb){
    var cols, lines
    spawn('tput', ['cols']).stdout.on('data', function(data){
        cols = Number(data)
        if (cols && lines && cb)
            cb(cols, lines)
    })
    spawn('tput', ['lines']).stdout.on('data', function(data){
        lines = Number(data)
        if (cols && lines && cb)
            cb(cols, lines)
    })
}

At first glance, this seemed to work. Except that it always returned 80, 24 when run from a node process. I have no idea why, since it works inside a ruby process. If someone knows, please tell me.

Attempt 3: RESIZE

Researching further still, I found a command called resize. resize apparently sets the $COLUMN and $LINES shell variables, so that they become available. But in the process, it also prints the dimensions to the screen.

$ resize
COLUMNS=82;
LINES=10;
export COLUMNS LINES;

So, again, I'll shell out and parse the output. Parsing this output is a little more involved, but no worries, I am no stranger to regex.

var spawn = require('child_process').spawn
function getTermSize(cb){
    spawn('resize').stdout.on('data', function(data){
        data = String(data)
        var lines = data.split('\n'),
            cols = Number(lines[0].match(/^COLUMNS=([0-9]+);$/)[1]),
            lines = Number(lines[1].match(/^LINES=([0-9]+);$/)[1])
        if (cb)
            cb(cols, lines)
    })
}

And voila! This method seems to work for my purposes. Usage of this function - in case you haven't figured it out

getTermSize(function(cols, lines){
    // You have the terminal size!
})

Notes

I've only tested this on my Macbook Air. I am pretty sure resize runs on Linux, possible pre-installed. But I would guess no luck on Windows. If there's a better way to do this, please let me know.

blog comments powered by Disqus