├── README.md ├── example.js ├── index.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # clivas 2 | 3 | Turn your terminal into a canvas. 4 | 5 | It is available through npm: 6 | 7 | npm install clivas 8 | 9 | ## Usage 10 | 11 | It is easy to use 12 | 13 | ``` js 14 | var clivas = require('clivas'); 15 | 16 | var frame = 0; 17 | 18 | setInterval(function() { 19 | clivas.clear(); // clears the canvas 20 | clivas.line('hello world (#frame '+frame+')'); 21 | clivas.line('{red:also} {green:colors}!'); 22 | frame++; 23 | }, 200); 24 | ``` 25 | 26 | When you draw something with clivas you can use the format patten to help you 27 | 28 | ``` js 29 | clivas.line('{red:i am red} and {blue: i am blue}'); 30 | ``` 31 | 32 | If you wanted to inverse a color you would provide the inverse tag 33 | 34 | ``` js 35 | clivas.line('{red+inverse:i am inversed}'); 36 | ``` 37 | 38 | The format pattern can also help you add whitespace 39 | 40 | ``` js 41 | clivas.line('[{10:===>}]'); // prints [===> ] 42 | ``` 43 | 44 | ## API 45 | 46 | * `clivas.clear()` - Clears the screen. If you called `clivas.pin()` it would only clear up until the pin. 47 | 48 | * `clivas.flush()` - Clears everything below the cursor. 49 | 50 | * `clivas.pin([lineNumber])` - Only clear to here when `clivas.clear()` is called 51 | 52 | * `clivas.line(str)` - Write a line (accepts a format string as described above) 53 | 54 | * `clivas.write(str)` - Same as `clivas.line(str)` except it does not add a newline 55 | 56 | * `clivas.cursor(enable)` - Enable or disable the terminal cursor 57 | 58 | * `clivas.alias(name, value)` - Add an alias to the format pattern i.e. `clivas.alias('link', 'red+underline')` enables you to use `{link:http://google.com}` 59 | 60 | ## License 61 | 62 | MIT -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var clivas = require('clivas'); 2 | 3 | var width = 0; 4 | var draw = function() { 5 | clivas.clear(); 6 | 7 | width++; 8 | if (width > 20) return clivas.line('({red:boom!})'); 9 | clivas.line('[{20+green:'+Array(width).join('=')+'>}]'); 10 | }; 11 | 12 | setInterval(draw, 200); 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | var ANSI = {}; 4 | 5 | ANSI.bold = ['\x1B[1m', '\x1B[22m']; 6 | ANSI.italic = ['\x1B[3m', '\x1B[23m']; 7 | ANSI.underline = ['\x1B[4m', '\x1B[24m'], 8 | ANSI.inverse = ['\x1B[7m', '\x1B[27m'], 9 | ANSI.blink = ['\x1B[5m', '\x1B[25m'], 10 | ANSI.white = ['\x1B[37m', '\x1B[39m'], 11 | ANSI.grey = ['\x1B[90m', '\x1B[39m'], 12 | ANSI.black = ['\x1B[30m', '\x1B[39m'], 13 | ANSI.blue = ['\x1B[34m', '\x1B[39m'], 14 | ANSI.cyan = ['\x1B[36m', '\x1B[39m'], 15 | ANSI.green = ['\x1B[32m', '\x1B[39m'], 16 | ANSI.magenta = ['\x1B[35m', '\x1B[39m'], 17 | ANSI.red = ['\x1B[31m', '\x1B[39m'], 18 | ANSI.yellow = ['\x1B[33m', '\x1B[39m'] 19 | 20 | var WHITESPACE = Array(1000).join(' '); 21 | 22 | var SYNTAX = /\{([^:\}]+)(?::([^\{\}]*))?\}/g; 23 | var SYNTAX_REPLACE = function(value, head) { 24 | if (alias[head]) { 25 | return alias[head].reduce(SYNTAX_REPLACE, value); 26 | } 27 | var num = parseInt(head,10); 28 | if (num) return value+WHITESPACE.slice(0, Math.max(num-value.length,0)); 29 | if (!ANSI[head]) return value; 30 | return ANSI[head][0]+value+ANSI[head][1]; 31 | }; 32 | var SYNTAX_REPLACE_ALL = function(_, heads, value) { 33 | return heads.split('+').reduce(SYNTAX_REPLACE, value || ''); 34 | }; 35 | 36 | var offset = 0; 37 | var offsetPin = 0; 38 | var lastClear = 0; 39 | var shouldFlush = true; 40 | var shouldResetCursor = false; 41 | var canvasStream; 42 | 43 | var linesCache = []; 44 | var alias = {}; 45 | 46 | exports.__defineGetter__('width', function() { 47 | return canvasStream.columns; 48 | }); 49 | exports.__defineGetter__('height', function() { 50 | return canvasStream.rows; 51 | }); 52 | exports.alias = function(name, value) { 53 | linesCache = []; 54 | if (typeof name === 'object') { 55 | Object.keys(name).forEach(function(key) { 56 | exports.alias(key, name[key]); 57 | }); 58 | return; 59 | } 60 | alias[name] = typeof value === 'string' ? value.split('+') : [value]; 61 | }; 62 | exports.use = function(stream) { 63 | return canvasStream = stream; 64 | }; 65 | exports.flush = function(bool) { 66 | shouldFlush = bool; 67 | if (shouldFlush !== false && canvasStream.clearScreenDown) { 68 | canvasStream.clearScreenDown(); 69 | } 70 | }; 71 | exports.cursor = function(bool) { 72 | if (bool === false) { 73 | shouldResetCursor = true; 74 | canvasStream.write('\x1B[?25l'); 75 | } else { 76 | canvasStream.write('\x1B[?25h'); 77 | } 78 | }; 79 | exports.clear = function(wait) { 80 | if (Date.now() - lastClear < wait) { 81 | return false; 82 | } 83 | lastClear = Date.now(); 84 | if (canvasStream.moveCursor) { 85 | canvasStream.moveCursor(0, -offset); 86 | } 87 | if (shouldFlush && canvasStream.clearScreenDown) { 88 | canvasStream.clearScreenDown(); 89 | } 90 | offset = offsetPin; 91 | return true; 92 | }; 93 | exports.write = function(line) { 94 | if (!Buffer.isBuffer(line)) { 95 | line = util.format.apply(util, arguments); 96 | line = line.replace(SYNTAX, SYNTAX_REPLACE_ALL).replace(SYNTAX, SYNTAX_REPLACE_ALL); 97 | } 98 | canvasStream.write(line); 99 | return line; 100 | }; 101 | exports.line = function(line) { 102 | offset++; 103 | line += '\n'; 104 | 105 | if (arguments.length === 1 && linesCache[offset] && linesCache[offset][0] === line) { 106 | canvasStream.write(linesCache[offset][1]); 107 | return linesCache[offset][1]; 108 | } 109 | if (arguments.length === 1) { 110 | linesCache[offset] = [line, exports.write(line)]; 111 | return linesCache[offset][1]; 112 | } 113 | 114 | return exports.write.apply(exports, arguments); 115 | }; 116 | exports.pin = function(pos) { 117 | if (pos === true || pos === undefined) return exports.pin(offset); 118 | if (pos === false) return exports.pin(0); 119 | offsetPin = pos; 120 | }; 121 | exports.times = function(str, num) { 122 | if (typeof num === 'string') { 123 | var tmp = num; 124 | num = str; 125 | str = tmp; 126 | } 127 | return Array(num+1).join(str); 128 | } 129 | exports.use(process.stdout); 130 | 131 | process.on('exit', function() { 132 | if (!shouldResetCursor) return; 133 | exports.cursor(true); 134 | }); 135 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clivas", 3 | "version": "0.2.0", 4 | "repository": "git://github.com/mafintosh/clivas", 5 | "description": "use your terminal as a canvas. features easy redrawing, colors and more", 6 | "keywords": [ 7 | "canvas", 8 | "cli", 9 | "console", 10 | "terminal" 11 | ], 12 | "author": "Mathias Buus Madsen " 13 | } 14 | --------------------------------------------------------------------------------