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 ) ;
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.
.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