Terminal Kit
Terminal utilities for node.js, it supports 'xterm' compatible terminal and the Linux Console.
It does not depend on ncurses.
- License: MIT
- Current status: alpha/unstable
- Platform: linux, tested with gnome-terminal, Konsole, xterm and Linux Console so far
Features
- colors
- styles (bold, underline, italic, and many more)
- string formating
- style mixing
- cursor positionning
- keyboard input
- mouse support
- terminal window title
- event-driven
Quick example
var term = require( 'terminal-kit' ) ;
term( 'Hello world!\n' ) ;
term.red( 'red' ) ;
term.bold( 'bold' ) ;
term.bold.underline.red( 'mixed' ) ;
term.green( "My name is %s, I'm %d.\n" , 'Jack' , 32 ) ;
term( 'The terminal size is %dx%d' , term.width , term.height ) ;
term.moveTo( 1 , 1 ) ;
term.moveTo( 1 , 1 , 'Upper-left corner' ) ;
term.moveTo( 1 , 1 , "My name is %s, I'm %d.\n" , 'Jack' , 32 ) ;
term.moveTo.cyan( 1 , 1 , "My name is %s, I'm %d.\n" , 'Jack' , 32 ) ;
Install
Use Node Package Manager:
npm install terminal-kit
Standard methods description
Standard methods map low-level terminal capabilities.
For all the functions below, additionnal arguments can be provided.
If a boolean is provided, it will turn the feature on or off.
For example term.red( true )
turn all subsequent output in red, while term.red( false )
disable red and go back to default color.
Without arguments, it is always the same as true, e.g. term.red()
do the same thing than term.red()
.
Some function cannot be turned off, they just perform an action.
For example term.reset()
reset the terminal, usually to its default.
This is not reversible, thus term.reset( false )
does nothing.
If the additional argument is a string, then it will be sent to the output directly after turning on the feature... then the feature is turn off.
That's it:
term.red( 'Hello world!' )
... is the same as:
term.red( true ) ; term( 'Hello world!' ) ; term.red( false ) ;
.
Also those string support a printf()-like formating syntax.
So we can do term.red( "My name is %s, I'm %d." , 'Jack' , 32 )
to output "My name is Jack, I'm 32.".
All those functions are chainable, and their arguments can be combined.
We can do:
term.moveTo.red( 1 , 1 , "My name is %s, I'm %d.\n" , 'Jack' , 32 )
which will move the cursor to (1,1), then output "My name is Jack, I'm 32." in red.
Common/Misc
- .reset(): full reset the terminal.
- .error(): it just set error to true so it will write to STDERR instead of STDOUT
- .beep(): emit a beep
Foreground colors
- .defaultColor(): back to the default foreground color
- .black(): ...
- .red(): ...
- .green(): ...
- .yellow(): dark yellow, most of time brown or orange
- .blue(): ...
- .magenta(): ...
- .cyan(): ...
- .white(): ...
- .brightBlack(): ...
- .brightRed(): ...
- .brightGreen(): ...
- .brightYellow(): true yellow
- .brightBlue(): ...
- .brightMagenta(): ...
- .brightCyan(): ...
- .brightWhite(): ...
- .color(register): choose between 16 colors using an 0..15 integer
- .darkColor(register): choose between 8 regular (dark) colors using an 0..7 integer
- .brightColor(register): choose between 8 bright colors using an 0..7 integer
Background colors
- .bgDefaultColor(): back to the default background color
- .bgBlack(): ...
- .bgRed(): ...
- .bgGreen(): ...
- .bgYellow(): dark yellow, most of time brown or orange
- .bgBlue(): ...
- .bgMagenta(): ...
- .bgCyan(): ...
- .bgWhite(): ...
- .bgDarkColor(): ...
- .bgBrightBlack(): ...
- .bgBrightRed(): ...
- .bgBrightGreen(): ...
- .bgBrightYellow(): true yellow
- .bgBrightBlue(): ...
- .bgBrightMagenta(): ...
- .bgBrightCyan(): ...
- .bgColor(register): choose between 16 colors using an 0..15 integer
- .bgBrightWhite(): choose between 8 regular (dark) colors using an 0..7 integer
- .bgBrightColor(): choose between 8 bright colors using an 0..7 integer
Styles
- .styleReset(): reset all styles and go back to default colors without
- .bold(): bold text
- .dim(): faint color
- .italic(): italic
- .underline(): underline
- .blink(): blink text, not widely supported
- .inverse(): foreground and background color
- .hidden(): invisible, but can be copy/paste'd
- .strike(): strike through
Cursors
- .saveCursor(): save cursor position
- .restoreCursor(): restore a previously saved cursor position
- .up(n): move the cursor 'n' chars up
- .down(n): move the cursor 'n' chars down
- .right(n): move the cursor 'n' chars right
- .left(n): move the cursor 'n' chars left
- .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
- .scrollUp(n): scroll whole page up by 'n' lines, new lines are added at the bottom, the absolute cursor position do not change (Linux Console don't support it)
- .scrollDown(n): scroll whole page down by 'n' lines, new lines are added at the top, the absolute cursor position do not change (Linux Console don't support it)
- .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
- .hideCursor(): hide/show the cursor
Editing
- .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
- .alternateScreenBuffer(): this set/unset the alternate screen buffer, many terminal do not support it or inhibit it
Input/Output
- .requestCursorLocation(): request the cursor location, a 'terminal' event will be fired when available
- .requestScreenSize(): rarely useful request for screen size, a 'terminal' event will be fired when available
- .applicationKeypad(): should allow keypad to send different code than 0..9 keys, not widely supported
Internal input/output (do not use directly, use grabInput() instead)
- .mouseButton(): ask the terminal to send event when a mouse button is pressed, with the mouse cursor position
- .mouseDrag(): ask the terminal to send event when a mouse button is pressed and when draging, with the mouse cursor position
- .mouseMotion(): ask the terminal to send all mouse event, even mouse motion that occurs without buttons
- .mouseSGR(): another mouse protocol that extend coordinate mapping (without it, it supports only 223 rows and columns)
- .focusEvent(): ask the terminal to send event when it gains and loses focus, not widely supported
OS functions (not widely supported)
- .windowTitle(): set the title of an xterm-compatible window
Advanced methods description
Advanced methods are high-level librairie functions.
.getParentTerminalInfo( callback )
- callback
Function( error , codename , name , pid )
where:
- error: truthy if it has failed for some reason
- codename: the code name of the terminal, as used by terminfo
- name: the real binary name of the terminal
- pid: the PID of the terminal
This method detect on which terminal your application run.
It does *NOT* use the $TERM environment variable.
It iterates through parent process until a known terminal is found, or process of PID 1 is reached (the init process).
Obviously, it does not works over SSH.
.getDetectedTerminal( callback )
- callback
Function( error , codename , name , pid )
where:
- error: truthy if it has failed for some reason
- term: the terminal object created specifically for your terminal
This is a shortcut that call .getParentTerminalInfo()
then use .createTerminal()
with the correct arguments.
This will give you a terminal object with the best support that this lib is able to give to you.
It does not works over SSH.
Example *NOT* using .getDetectedTerminal()
:
var term = require( 'terminal-kit' ) ;
term.cyan( 'Hello world!' ) ;
This will give you a terminal object based on the $TERM environment variable, that works fine in most case.
But please consider that most of modern terminal report them as an xterm or an xterm-256color terminal.
They claim being xterm-compatible, but most of them support only 33% to 50% of xterm features,
and even major terminal like gnome-terminal or Konsole are terrible.
Example using .getDetectedTerminal()
:
require( 'terminal-kit' ).getDetectedTerminal( function( error , term ) {
term.cyan( 'Terminal name: %s\n' , term.appName ) ;
term.cyan( 'Terminal app: %s\n' , term.app ) ;
term.cyan( 'Terminal type: %s\n' , term.type ) ;
term.cyan( 'Config file: %s\n' , term.termconfigFile ) ;
} ) ;
This will give you the best compatibility possible, at the cost of a callback.
.fullscreen( options )
- options: true/false/object: if truthy it activate fullscreen mode, falsy return to normal mode,
if it is an object it supports those properties:
- noAlternate
boolean
true if the alternate screen buffer should not be used
Basically, this method try to achieve the same goal than the native terminal capability alternate screen buffer.
If alternate screen buffer is disabled on your terminal, it will provide a clean fallback, clearing the screen and positionning
the cursor at the upper-left corner.
.grabInput( options )
- options: false/true/Object, false disable input grabbing, true or an Object turn it on,
if it is an Object then those properties are supported:
- mouse: if defined, it activate mouse event, those values are supported for 'mouse':
- 'button': report only button-event
- 'drag': report button-event, report motion-event only when a button is pressed (i.e. it is a mouse drag)
- 'motion': report button-event & all motion-event, use it only when needed, many escape sequences are sent from the terminal
(for example, one may consider this for script running over SSH)
- focus: true/false: if defined and true, focus event will be reported (if your terminal support it - xterm does)
This function turns input grabbing on, keyboard entries will not be echoed, and every input will generate an event
on the term
object.
Quick example:
var term = require( 'terminal-kit' ) ;
function terminate()
{
term.grabInput( false ) ;
setTimeout( function() { process.exit() } , 100 ) ;
}
term.bold.cyan( 'Type anything on the keyboard...\n' ) ;
term.green( 'Hit CTRL-C to quit.\n\n' ) ;
term.grabInput( { mouse: 'button' } ) ;
term.on( 'key' , function( name , matches , data ) {
console.log( "'key' event:" , name ) ;
if ( matches.indexOf( 'CTRL_C' ) >= 0 ) { terminate() ; }
} ) ;
term.on( 'terminal' , function( name , data ) {
console.log( "'terminal' event:" , name , data ) ;
} ) ;
term.on( 'mouse' , function( name , data ) {
console.log( "'mouse' event:" , name , data ) ;
} ) ;
Events
Event are fired on your term
object.
'key' event ( name , matches )
- name: string, the key name
- matches: array of matched key name
The 'key' event is emited whenever the user type something on the keyboard.
If name
is a single char, this is a regular UTF8 character, entered by the user.
If the user type a word, each UTF8 character will produce its own 'key' event.
If name
is a multiple chars string, then it is a SPECIAL key.
List of SPECIAL keys:
ESCAPE ENTER BACKSPACE NUL TAB SHIFT_TAB
UP DOWN RIGHT LEFT
INSERT DELETE HOME END PAGE_UP PAGE_DOWN
KP_NUMLOCK KP_DIVIDE KP_MULTIPLY KP_MINUS KP_PLUS KP_DELETE KP_ENTER
KP_0 KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
SHIFT_UP SHIFT_DOWN SHIFT_RIGHT SHIFT_LEFT
ALT_UP ALT_DOWN ALT_RIGHT ALT_LEFT
CTRL_UP CTRL_DOWN CTRL_RIGHT CTRL_LEFT
And modifier on regular A-Z key:
CTRL_A ALT_A CTRL_ALT_A
CTRL_B ALT_B CTRL_ALT_B
CTRL_C ALT_C CTRL_ALT_C
...
Sometime, a key matches multiple combination. For example CTRL-M on linux boxes is always the same as ENTER.
So the event will provide as the 'name' argument the most useful/common, here ENTER.
However the 'matches' argument will contain [ ENTER , CTRL_M ]
.
Also notice that some terminal will support less keys. For example, the Linux Console does not support SHIFT/CTRL/ALT + Arrows keys,
it will produce a normal arrow key.
There is no workaround here, the underlying keyboard driver simply does not support this.
KP_* keys needs applicationKeypad()
, e.g. without it KP_1 will report '1' or END.
Some terminal does not support applicationKeypad()
very well, and it is nearly impossible to differenciate (for example) a KP_1 from
an END, or a KP_7 from a HOME, since most X terminal will be reported as xterm or xterm-256color happily, but still does not report key
the same way...
'terminal' event
- name: string, the name of the subtype of event
- data: Object, provide some data depending on the event
The 'terminal' event is emited for terminal generic information.
The argument 'name' can be:
-
CURSOR_LOCATION: it is emited in response of a requestCursorLocation(), data contains 'x' & 'y', the coordinate of the cursor.
-
SCREEN_RESIZE: it is emited when a terminal resizing is detected, most of time node.js will be notified of screen resizing, and so this event will be emited,
data contains 'width' & 'height', the size of the screen in characters
-
SCREEN_SIZE: rarely useful it is emited in response of a requestScreenSize(), data contains 'width' & 'height', the size of the screen in characters,
and 'resized' (true/false) if the size has changed without node.js being notified
-
FOCUS_IN: it is emited if the terminal gains focus (if supported by your terminal)
-
FOCUS_OUT: it is emited if the terminal loses focus (if supported by your terminal)
'mouse' event
- name: string, the name of the subtype of event
- data: Object, provide the mouse coordinate and keyboard modifier status, properties:
- x: integer, the row number where the mouse is
- y: integer, the column number where the mouse is
- ctrl: true/false, if the CTRL key is down or not
- alt: true/false, if the ALT key is down or not
- shift: true/false, if the SHIFT key is down or not
Activated when grabInput() is used with the 'mouse' options, e.g. { mouse: 'button' }
, { mouse: 'drag' }
or { mouse: 'motion' }
.
The argument 'name' can be:
- MOUSE_LEFT_BUTTON_PRESSED: well... it is emited when the left mouse button is pressed
- MOUSE_LEFT_BUTTON_RELEASED: when this button is released
- MOUSE_RIGHT_BUTTON_PRESSED, MOUSE_RIGHT_BUTTON_RELEASED, MOUSE_MIDDLE_BUTTON_PRESSED, MOUSE_MIDDEL_BUTTON_RELEASED: self explanatory
- MOUSE_WHEEL_UP, MOUSE_WHEEL_DOWN: self explanatory
- MOUSE_OTHER_BUTTON_PRESSED, MOUSE_OTHER_BUTTON_RELEASED: a fourth mouse button is sometime supported
- MOUSE_MOTION: if the options
{ mouse: 'motion' }
is given to grabInput(), every move of the mouse will fire this event,
if { mouse: 'drag' }
is given, it will be fired if the mouse move while a button is pressed