├── scripts └── githooks │ ├── post-merge │ └── pre-commit ├── .travis.yml ├── screen-shot.png ├── tests ├── style.test.js ├── string.test.js ├── paint.test.js └── colors.test.js ├── .gitignore ├── .npmignore ├── nico.json ├── .jshintrc ├── package.json ├── Makefile ├── index.js ├── LICENSE ├── README.md └── lib └── ansi.js /scripts/githooks/post-merge: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | make 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.6 4 | - 0.8 5 | -------------------------------------------------------------------------------- /screen-shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lepture/colorful/HEAD/screen-shot.png -------------------------------------------------------------------------------- /tests/style.test.js: -------------------------------------------------------------------------------- 1 | var color = require('..'); 2 | 3 | var styles = [ 4 | 'bold', 'faint', 'italic', 'underline', 'blink', 'overline', 5 | 'inverse', 'conceal', 'strike' 6 | ]; 7 | 8 | styles.forEach(function(key) { 9 | console.log(color[key](key)); 10 | }); 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | .ipr 4 | .iws 5 | *~ 6 | ~* 7 | *.diff 8 | *.patch 9 | *.bak 10 | .DS_Store 11 | Thumbs.db 12 | .project 13 | .*proj 14 | .svn/ 15 | *.swp 16 | *.swo 17 | *.log 18 | node_modules/ 19 | .buildpath 20 | .settings 21 | .yml 22 | _docs 23 | _site 24 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | .ipr 4 | .iws 5 | *~ 6 | ~* 7 | *.diff 8 | *.patch 9 | *.bak 10 | .DS_Store 11 | Thumbs.db 12 | .project 13 | .*proj 14 | .svn/ 15 | *.swp 16 | *.swo 17 | *.log 18 | node_modules/ 19 | .buildpath 20 | .settings 21 | .yml 22 | _docs 23 | _site 24 | *.png 25 | tests/ 26 | scripts/ 27 | -------------------------------------------------------------------------------- /nico.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "_docs", 3 | "output": "_site", 4 | "permalink": "{{directory}}/{{filename}}", 5 | "sitename": "Colorful", 6 | "github": "https://github.com/lepture/colorful", 7 | "google": "UA-21475122-5", 8 | "writers": [ 9 | "nico.PageWriter", 10 | "nico.StaticWriter" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /tests/string.test.js: -------------------------------------------------------------------------------- 1 | require('..').colorful(); 2 | 3 | var styles = [ 4 | 'bold', 'faint', 'italic', 'underline', 'blink', 'overline', 5 | 'inverse', 'conceal', 'strike' 6 | ]; 7 | var colors = [ 8 | 'black', 'red', 'green', 'yellow', 'blue', 9 | 'magenta', 'cyan', 'white', 'grey', 'gray' 10 | ]; 11 | 12 | 13 | styles.forEach(function(key) { 14 | console.log(key.to[key].color); 15 | }); 16 | 17 | 18 | colors.forEach(function(key) { 19 | console.log(key.to[key].color); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/paint.test.js: -------------------------------------------------------------------------------- 1 | var paint = require('..').paint; 2 | 3 | var styles = [ 4 | 'bold', 'faint', 'italic', 'underline', 'blink', 'overline', 5 | 'inverse', 'conceal', 'strike' 6 | ]; 7 | var colors = [ 8 | 'black', 'red', 'green', 'yellow', 'blue', 9 | 'magenta', 'cyan', 'white', 'grey', 'gray' 10 | ]; 11 | 12 | 13 | styles.forEach(function(key) { 14 | console.log(paint(key)[key].color); 15 | }); 16 | 17 | colors.forEach(function(key) { 18 | console.log(paint(key)[key].color); 19 | }); 20 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "eqeqeq": true, 4 | "forin": false, 5 | "latedef": false, 6 | "newcap": true, 7 | "quotmark": false, 8 | "undef": false, 9 | "unused": false, 10 | "trailing": true, 11 | "boss": true, 12 | "expr": true, 13 | "strict": false, 14 | "es5": true, 15 | "funcscope": true, 16 | "loopfunc": true, 17 | "multistr": true, 18 | "proto": false, 19 | "smarttabs": true, 20 | "shadow": false, 21 | "sub": true, 22 | "passfail": false, 23 | "white": false 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "colorful", 3 | "version": "2.1.0", 4 | "description": "colorful if a terminal tool for colors", 5 | "keywords": [ 6 | "color", 7 | "ansi", 8 | "256color", 9 | "console", 10 | "terminal" 11 | ], 12 | "author": { 13 | "name": "Hsiaoming Yang", 14 | "email": "lepture@me.com" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/lepture/colorful.git" 19 | }, 20 | "devDependencies": { 21 | "jshint": "*" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @npm install -d 3 | @cp scripts/githooks/* .git/hooks/ 4 | @chmod -R +x .git/hooks/ 5 | 6 | colors: 7 | @node tests/colors.test.js 8 | 9 | 10 | files := $(shell find . -name '*.js' ! -path "*node_modules/*") 11 | lint: 12 | @node_modules/.bin/jshint ${files} 13 | 14 | theme = $(HOME)/.spm/themes/one 15 | documentation: 16 | @cp README.md _docs/index.md 17 | @nico build --theme=${theme} 18 | @cp screen-shot.png _site/ 19 | 20 | publish: clean documentation 21 | @ghp-import _site -p 22 | 23 | clean: 24 | @rm -fr _site 25 | 26 | server: 27 | @cp README.md _docs/index.md 28 | @nico server --theme=${theme} 29 | 30 | .PHONY: all build test lint coverage 31 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports = module.exports = require('./lib/ansi'); 2 | 3 | exports.paint = function(text) { 4 | return new exports.Color(text); 5 | }; 6 | 7 | exports.colorful = function() { 8 | // don't overwrite 9 | if (String.prototype.to) return; 10 | Object.defineProperty(String.prototype, 'to', { 11 | get: function() { 12 | return new exports.Color(this.valueOf()); 13 | } 14 | }); 15 | }; 16 | 17 | exports.toxic = function() { 18 | // poison the String prototype 19 | var colors = exports.color; 20 | Object.keys(colors).forEach(function(key) { 21 | var fn = colors[key]; 22 | Object.defineProperty(String.prototype, key, { 23 | get: function() { 24 | return fn(this.valueOf()); 25 | } 26 | }); 27 | }); 28 | }; 29 | 30 | Object.defineProperty(exports, 'isSupported', { 31 | get: exports.isColorSupported 32 | }); 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hsiaoming Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/colors.test.js: -------------------------------------------------------------------------------- 1 | 2 | var Color = require('..').Color; 3 | 4 | console.log(); 5 | console.log('System colors'); 6 | for (var i = 0; i < 16; i++) { 7 | var c = new Color(' '); 8 | c.bgcolor = i; 9 | if (i === 8) { 10 | console.log(); 11 | } 12 | process.stdout.write(c.valueOf()); 13 | } 14 | console.log(); 15 | console.log(); 16 | console.log('Background') 17 | for (var green = 0; green < 6; green++) { 18 | for (var red = 0; red < 6; red++) { 19 | for (var blue = 0; blue < 6; blue++) { 20 | var c = new Color(' '); 21 | c.bgcolor = 16 + red * 36 + green * 6 + blue; 22 | process.stdout.write(c.valueOf()); 23 | } 24 | } 25 | console.log(); 26 | } 27 | console.log(); 28 | console.log('Grayscale'); 29 | for (var i = 232; i < 256; i++) { 30 | var c = new Color(' '); 31 | c.bgcolor = i; 32 | process.stdout.write(c.valueOf()); 33 | } 34 | console.log(); 35 | console.log(); 36 | console.log('Colors'); 37 | for (var i = 0; i < 256; i++) { 38 | if (i !== 0 && i % 16 === 0) { 39 | console.log(); 40 | } 41 | var c = new Color(wordwrap(i)); 42 | c.fgcolor = i; 43 | process.stdout.write(c.valueOf()); 44 | } 45 | console.log(); 46 | 47 | function wordwrap(i) { 48 | i = String(i) 49 | return i + new Array(5 - i.length).join(' '); 50 | } 51 | -------------------------------------------------------------------------------- /scripts/githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function failCommit() { 4 | tput setaf 1 5 | echo "----------------------------------------" 6 | echo "FATAL ERROR: $1" 7 | echo "----------------------------------------" 8 | tput sgr0 9 | exit 1 10 | } 11 | 12 | function testFail() { 13 | tput setaf 3 14 | echo "----------------------------------------" 15 | echo "$1" 16 | echo "----------------------------------------" 17 | tput sgr0 18 | } 19 | 20 | if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then 21 | against=HEAD 22 | else 23 | # Initial commit: diff against an empty tree object 24 | against=af6266a03b218876a11655e4f653dd05d0424641 25 | fi 26 | 27 | # Remove all of the trailing whitespace in this commit 28 | for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -E 's/:[0-9]+:.*//' | uniq` ; do 29 | sed -i '' -E 's/[[:space:]]*$//' "$FILE" 30 | git add $FILE 31 | done 32 | 33 | echo 'Running Jshint...' 34 | result=$(make lint) 35 | if grep "error" <<< $result; then 36 | num=$(grep "[0-9]+ error" <<< "$result") 37 | testFail "Jshint: $num" 38 | echo "$result" 39 | echo '' 40 | echo 'Jslint fail' 41 | lintFailed=1 42 | fi 43 | 44 | if [[ $lint_errors -gt 0 ]]; then 45 | failCommit "Lint Errors" 46 | fi 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Colorful 2 | 3 | It's not just color, it's everything colorful in terminal. 4 | 5 | --------------------- 6 | 7 | # Color 8 | 9 | Color in terminal and only terminal. 10 | 11 | ![screen shot](./screen-shot.png) 12 | 13 | ## Programmer 14 | 15 | As a programmer, you think they are functions: 16 | 17 | ```javascript 18 | var color = require('colorful') 19 | color.red('hello') 20 | color.underline('hello') 21 | color.red(color.underline('hello')) 22 | ``` 23 | 24 | ## Human 25 | 26 | As a human, you think you are a painter: 27 | 28 | ```javascript 29 | var paint = require('colorful').paint 30 | paint('hello').red.color 31 | paint('hello').bold.underline.red.color 32 | ``` 33 | 34 | **WTF**, is bold, underline a color? If you don't like the idea, try: 35 | 36 | ```javascript 37 | paint('hello').bold.underline.red.style 38 | ``` 39 | 40 | ## Alien 41 | 42 | As an alien, you are from outer space, you think it should be: 43 | 44 | ```javascript 45 | require('colorful').colorful() 46 | 'hello'.to.red.color 47 | 'hello'.to.underline.bold.red.color 48 | 'hello'.to.underline.bold.red.style 49 | ``` 50 | 51 | 52 | ## Artist 53 | 54 | As an artist, you need more colors. 55 | 56 | ```javascript 57 | var Color = require('colorful').Color; 58 | 59 | var s = new Color('colorful'); 60 | s.fgcolor = 13; 61 | s.bgcolor = 61; 62 | ``` 63 | 64 | Support ANSI 256 colors. [0 - 255] 65 | 66 | 67 | ## Toxic 68 | 69 | Let's posion the string object, just like colors does. 70 | 71 | ```javascript 72 | require('colorful').toxic() 73 | 'hello'.bold 74 | 'hello'.red 75 | ``` 76 | 77 | 78 | ## Detective 79 | 80 | As a detective, you think we should detect if color is supported: 81 | 82 | ```javascript 83 | require('colorful').isSupported 84 | 85 | // we can disable color 86 | require('colorful').disabled = true 87 | require('colorful').isSupported 88 | // => false 89 | ``` 90 | 91 | # Colors 92 | 93 | - bold 94 | - faint 95 | - italic 96 | - underline 97 | - blink 98 | - overline 99 | - inverse 100 | - conceal 101 | - strike 102 | - black 103 | - black_bg 104 | - red 105 | - red_bg 106 | - green 107 | - green_bg 108 | - yellow 109 | - yellow_bg 110 | - blue 111 | - blue_bg 112 | - magenta 113 | - magenta_bg 114 | - cyan 115 | - cyan_bg 116 | - white 117 | - white_bg 118 | - grey 119 | - gray 120 | 121 | # Changelog 122 | 123 | **2013-05-22** `2.1.0` 124 | 125 | Add toxic API. 126 | 127 | **2013-03-22** `2.0.2` 128 | 129 | Merge terminal into ansi. 130 | 131 | **2013-03-18** `2.0.1` 132 | 133 | Add gray color. 134 | 135 | **2013-03-18** `2.0.0` 136 | 137 | Redesign. Support for ANSI 256 colors. 138 | -------------------------------------------------------------------------------- /lib/ansi.js: -------------------------------------------------------------------------------- 1 | 2 | /* ANSI color support in terminal 3 | * @author: Hsiaoming Yang 4 | * 5 | * http://en.wikipedia.org/wiki/ANSI_escape_code 6 | */ 7 | 8 | 9 | var util = require('util'); 10 | var tty = require('tty'); 11 | 12 | exports.disabled = false; 13 | exports.isatty = false; 14 | 15 | function isColorSupported() { 16 | if (exports.disabled) return false; 17 | 18 | // you can force to tty 19 | if (!exports.isatty && !tty.isatty()) return false; 20 | 21 | if ('COLORTERM' in process.env) return true; 22 | // windows will support color 23 | if (process.platform === 'win32') return true; 24 | 25 | var term = process.env.TERM; 26 | if (!term) return false; 27 | 28 | term = term.toLowerCase(); 29 | if (term.indexOf('color') !== -1) return true; 30 | return term === 'xterm' || term === 'linux'; 31 | } 32 | 33 | 34 | function is256ColorSupported() { 35 | if (!isColorSupported()) return false; 36 | 37 | var term = process.env.TERM; 38 | if (!term) return false; 39 | 40 | term = term.toLowerCase(); 41 | return term.indexOf('256') !== -1; 42 | } 43 | exports.isColorSupported = isColorSupported; 44 | exports.is256ColorSupported = is256ColorSupported; 45 | 46 | var colors = [ 47 | 'black', 'red', 'green', 'yellow', 'blue', 48 | 'magenta', 'cyan', 'white' 49 | ]; 50 | 51 | var styles = [ 52 | 'bold', 'faint', 'italic', 'underline', 'blink', 'overline', 53 | 'inverse', 'conceal', 'strike' 54 | ]; 55 | 56 | exports.color = {}; 57 | 58 | function Color(obj) { 59 | this.string = obj; 60 | 61 | this.styles = []; 62 | this.fgcolor = null; 63 | this.bgcolor = null; 64 | } 65 | util.inherits(Color, String); 66 | 67 | for (var i = 0; i < colors.length; i++) { 68 | (function(i) { 69 | var name = colors[i]; 70 | Object.defineProperty(Color.prototype, name, { 71 | get: function() { 72 | this.fgcolor = i; 73 | return this; 74 | } 75 | }); 76 | Object.defineProperty(Color.prototype, name + '_bg', { 77 | get: function() { 78 | this.bgcolor = i; 79 | return this; 80 | } 81 | }); 82 | exports.color[name] = exports[name] = function(text) { 83 | if (!isColorSupported()) return text; 84 | return '\x1b[' + (30 + i) + 'm' + text + '\x1b[0m'; 85 | }; 86 | exports.color[name + '_bg'] = exports[name + '_bg'] = function(text) { 87 | if (!isColorSupported()) return text; 88 | return '\x1b[' + (40 + i) + 'm' + text + '\x1b[0m'; 89 | }; 90 | })(i); 91 | } 92 | for (var i = 0; i < styles.length; i++) { 93 | (function(i) { 94 | var name = styles[i]; 95 | Object.defineProperty(Color.prototype, name, { 96 | get: function() { 97 | if (this.styles.indexOf(i) === -1) { 98 | this.styles = this.styles.concat(i + 1); 99 | } 100 | return this; 101 | } 102 | }); 103 | exports.color[name] = exports[name] = function(text) { 104 | if (!isColorSupported()) return text; 105 | return '\x1b[' + (i + 1) + 'm' + text + '\x1b[0m'; 106 | }; 107 | })(i); 108 | } 109 | 110 | exports.color.grey = exports.color.gray = exports.grey = exports.gray = function(text) { 111 | if (!isColorSupported()) return text; 112 | if (is256ColorSupported()) { 113 | return '\x1b[38;5;8m' + text + '\x1b[0m'; 114 | } 115 | return '\x1b[30;1m' + text + '\x1b[0m'; 116 | }; 117 | Object.defineProperty(Color.prototype, 'gray', { 118 | get: function() { 119 | if (isColorSupported) { 120 | this.fgcolor = 8; 121 | } else { 122 | this.styles = this.styles.concat(1); 123 | this.fgcolor = 0; 124 | } 125 | return this; 126 | } 127 | }); 128 | Object.defineProperty(Color.prototype, 'grey', { 129 | get: function() { 130 | if (isColorSupported) { 131 | this.fgcolor = 8; 132 | } else { 133 | this.styles = this.styles.concat(1); 134 | this.fgcolor = 0; 135 | } 136 | return this; 137 | } 138 | }); 139 | 140 | 141 | Color.prototype.valueOf = function() { 142 | if (!isColorSupported()) return this.string; 143 | var is256 = is256ColorSupported(); 144 | 145 | var text = this.string; 146 | var reset = '\x1b[0m'; 147 | 148 | if (is256) { 149 | if (this.fgcolor !== null) { 150 | text = '\x1b[38;5;' + this.fgcolor + 'm' + text + reset; 151 | } 152 | if (this.bgcolor !== null) { 153 | text = '\x1b[48;5;' + this.bgcolor + 'm' + text + reset; 154 | } 155 | } else { 156 | if (this.fgcolor !== null && this.fgcolor < 8) { 157 | text = '\x1b[' + (30 + this.fgcolor) + 'm' + text + reset; 158 | } 159 | if (this.bgcolor !== null && this.bgcolor < 8) { 160 | text = '\x1b[' + (40 + this.bgcolor) + 'm' + text + reset; 161 | } 162 | } 163 | if (this.styles.length) { 164 | text = '\x1b[' + this.styles.join(';') + 'm' + text + reset; 165 | } 166 | return text; 167 | }; 168 | Color.prototype.toString = function() { 169 | return this.valueOf(); 170 | }; 171 | Object.defineProperty(Color.prototype, 'color', { 172 | get: function() { 173 | return this.valueOf(); 174 | } 175 | }); 176 | Object.defineProperty(Color.prototype, 'style', { 177 | get: function() { 178 | return this.valueOf(); 179 | } 180 | }); 181 | Object.defineProperty(Color.prototype, 'length', { 182 | get: function() { 183 | return this.string.length; 184 | } 185 | }); 186 | 187 | exports.Color = Color; 188 | --------------------------------------------------------------------------------