Curses!

This tutorial will focus exclusively on the terminal-kit lib for Node.js. Make sure to npm install terminal-kit before trying the given examples.

For those who have already done some C/C++ coding with Ncurses, you may know that there is a saying:

More than often, a programmer dealing with Ncurses will curse.

The goal of terminal-kit is to provide a simple and modern way to interact with the terminal. The design should be simple and intuitive, and yet give maximum power in the hand of the user. Hopefully, you will say goodbye to the good ol' Ncurses' days!

Moving the cursor

That cannot be easier! 

To move the cursor relative to its position:

  • .up( n ): move the cursor up by n cells
  • .down( n ): move it down by n cells…
  • .left( n ): …
  • .right( n ): …
  • .nextLine(n): move the cursor to beginning of the line, n lines down
  • .previousLine(n): move the cursor to beginning of the line, n lines up
  • .column(x): move the cursor to column x

Example:

var term = require( 'terminal-kit' ).terminal ;
term( "Hello" ) ;
term.down( 1 ) ;
term.left( 1 ) ;
term( "^-- world!\n" ) ;
/* It writes:
Hello
    ^-- world!
*/

Also, you can one-line that, this way:

term( "Hello" ).down.left( 1 , 1 , "^-- world!\n" ) ;

Also you can use move() and moveTo() to achieve relative and absolute positioning:

  • .moveTo(x,y): move the cursor to the (x,y) coordinate (1,1 is the upper-left corner)
  • .move(x,y): relative move of the cursor

With those methods, you can move it move it anywhere. Creating an app with a nice layout is almost at our finger...

One last couple of function that can be useful:

  • .saveCursor(): save cursor position
  • .restoreCursor(): restore a previously saved cursor position

This is extremely useful in many case, for example i you want to update status bar:

var term = require( 'terminal-kit' ).terminal ;

term( "Mike says: " ) ;

term.saveCursor() ;
term.moveTo.bgWhite.black( 1 , 1 ).eraseLine() ;
term( "This is a status bar update!" ) ;
term.white.bgBlack() ;
term.restoreCursor() ;

term( '"Hey hey hey!"\n' ) ;
// Cursor is back to its previous position
// Thus producing: Mike says: "Hey hey hey!"

This creates a status bar with a white background and black text color, on the top of the screen. The update code saves the cursor's position and restores it, so it doesn't disturb the main text flow, that's why it still writes Mike says: "Hey hey hey!" as if no cursor movement happened.

Triforce?!

Editing the screen

Now that we've learn how to move the cursor, let's see how to edit what is already displayed.

Let's see what we can do:

  • .clear(): clear the screen and move the cursor to the upper-left corner
  • .eraseDisplayBelow(): erase everything below the cursor
  • .eraseDisplayAbove(): erase everything above the cursor
  • .eraseDisplay(): erase everything
  • .eraseLineAfter(): erase current line after the cursor
  • .eraseLineBefore(): erase current line before the cursor
  • .eraseLine(): erase current line
  • .insertLine(n): insert n lines
  • .deleteLine(n): delete n lines
  • .insert(n): insert n char after (works like INSERT on the keyboard)
  • .delete(n): delete n char after (works like DELETE on the keyboard)
  • .backDelete(): delete one char backward (works like BACKSPACE on the keyboard), shorthand composed by a .left(1) followed by a .delete(1)

E.g., move the cursor and then erase anything below it to clean the area:

term.moveTo( 1 , 5 ) ;
term.eraseDisplayBelow() ;

For all erase-like methods, note that the screen is erased using the current background color! Hence, if we wanted to erase the screen, and paint anything below the cursor with a red background, we can modify the above code this way:

term.moveTo( 1 , 5 ) ;
term.bgRed() ;
term.eraseDisplayBelow() ;

This apply to .clear() as well, so term.bgBlue.clear() will erase the whole screen, paint it blue, and move the cursor to the top-left corner.

Colorful background

Also there is the advanced method .fullscreen( true ) (not chainable) that clears the screen, moves the cursor to the top-left corner, and if the terminal supports it, it turns the alternate screen buffer on.

If alternate screen buffer is available, when you invoke .fullscreen( false ), the screen will be restored into the state it was before calling .fullscreen( true ).

This is really a key feature for writing cool terminal application! Now you can code something that behaves like the htop linux command, using the whole terminal display area, and when users quit your app, the command history of their shell will be restored. Neat!

If alternate screen buffer is not supported by your terminal, it will fail gracefully.

Last words

Now the cool factor: you can change your terminal window's title with the method .windowTitle():

term.windowTitle( "My wonderful app" )` ;    // set the title of the window to "My wonderful app"

Hehe ;)

Next time we will focus on input: keyboard and mouse!

I hope you have found this tutorial useful, and will be happy if you drop me a line or two!

Have a nice day!