1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | "use strict" ;
|
28 |
|
29 |
|
30 |
|
31 | const termkit = require( './termkit.js' ) ;
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | const defaultAdaptivePaletteDef = [
|
55 | { names: [ 'red' ] , code: '#e32322' } ,
|
56 | { names: [ 'orange' ] , code: '#f18e1c' } ,
|
57 | { names: [ 'gold' , 'yellow-orange' , 'amber' ] , code: '#fdc60b' } ,
|
58 | { names: [ 'yellow' ] , code: '#f4e500' } ,
|
59 | { names: [ 'chartreuse' , 'yellow-green' ] , code: '#8cbb26' } ,
|
60 | { names: [ 'green' ] , code: '#25ad28' } ,
|
61 | { names: [ 'turquoise' , 'turquoise-green' ] , code: '#1bc17d' } ,
|
62 | { names: [ 'cyan' , 'turquoise-blue' ] , code: '#0dc0cd' } ,
|
63 | { names: [ 'blue' ] , code: '#2a60b0' } ,
|
64 | { names: [ 'indigo' ] , code: '#3b3ba2' } ,
|
65 | { names: [ 'violet' , 'purple' ] , code: '#713795' } ,
|
66 | { names: [ 'magenta' ] , code: '#bd0a7d' }
|
67 | ] ;
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | const defaultExtraPaletteDef = [
|
73 | { names: [ 'crimson' ] , code: '#dc143c' } ,
|
74 | { names: [ 'vermilion' , 'cinnabar' ] , code: '#e34234' } ,
|
75 | { names: [ 'brown' ] , code: '#a52a2a' } ,
|
76 | { names: [ 'bronze' ] , code: '#cd7f32' } ,
|
77 | { names: [ 'coquelicot' ] , code: '#ff3800' } ,
|
78 |
|
79 |
|
80 | { names: [ 'coral-pink' ] , code: '#f88379' } ,
|
81 | { names: [ 'see-green' ] , code: '#2e8b57' } ,
|
82 | { names: [ 'medium-spring-green' ] , code: '#00fa9a' } ,
|
83 | { names: [ 'olivine' ] , code: '#9ab973' } ,
|
84 | { names: [ 'royal-blue' ] , code: '#4169e1' } ,
|
85 | { names: [ 'purple' ] , code: '#800080' } ,
|
86 |
|
87 |
|
88 | { names: [ 'lavender-purple' ] , code: '#967bb6' } ,
|
89 |
|
90 | { names: [ 'pink' ] , code: '#ffc0cb' }
|
91 |
|
92 | ] ;
|
93 |
|
94 |
|
95 |
|
96 | const ansiColorIndex = {
|
97 | black: 0 ,
|
98 | red: 1 ,
|
99 | green: 2 ,
|
100 | yellow: 3 ,
|
101 | blue: 4 ,
|
102 | magenta: 5 ,
|
103 | violet: 5 ,
|
104 | cyan: 6 ,
|
105 | white: 7 ,
|
106 | grey: 8 ,
|
107 | gray: 8 ,
|
108 | 'bright-black': 8 ,
|
109 | 'bright-red': 9 ,
|
110 | 'bright-green': 10 ,
|
111 | 'bright-yellow': 11 ,
|
112 | 'bright-blue': 12 ,
|
113 | 'bright-magenta': 13 ,
|
114 | 'bright-violet': 13 ,
|
115 | 'bright-cyan': 14 ,
|
116 | 'bright-white': 15
|
117 | } ;
|
118 |
|
119 |
|
120 | function Palette( options = {} ) {
|
121 | this.term = options.term || termkit.terminal ;
|
122 | this.system = !! options.system ;
|
123 | this.adaptivePaletteDef = this.system ? null : options.adaptivePaletteDef || defaultAdaptivePaletteDef ;
|
124 | this.extraPaletteDef = this.system ? null : options.extraPaletteDef || defaultExtraPaletteDef ;
|
125 | this.escape = [] ;
|
126 | this.bgEscape = [] ;
|
127 | this.chromaColors = [] ;
|
128 | this.colorIndex = {} ;
|
129 |
|
130 |
|
131 | this.colorNameToIndex = this.colorNameToIndex.bind( this ) ;
|
132 |
|
133 | this.generate() ;
|
134 | }
|
135 |
|
136 | module.exports = Palette ;
|
137 |
|
138 |
|
139 |
|
140 | Palette.prototype.colorNameToIndex = function( name ) {
|
141 | name = name.toLowerCase() ;
|
142 | return this.colorIndex[ name ] || termkit.colorNameToIndex( name ) ;
|
143 | } ;
|
144 |
|
145 |
|
146 |
|
147 | Palette.prototype.generate = function() {
|
148 | this.generateDefaultMapping() ;
|
149 | this.generateAnsiColorNames() ;
|
150 | this.generateAdaptive() ;
|
151 | this.generateExtra() ;
|
152 | this.generateGrayscale() ;
|
153 | } ;
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | Palette.prototype.generateDefaultMapping = function() {
|
159 | var register ;
|
160 |
|
161 | for ( register = 0 ; register < 256 ; register ++ ) {
|
162 | this.escape[ register ] = this.term.str.color256( register ) ;
|
163 | this.bgEscape[ register ] = this.term.str.bgColor256( register ) ;
|
164 | }
|
165 | } ;
|
166 |
|
167 |
|
168 |
|
169 |
|
170 | Palette.prototype.generateAnsiColorNames = function() {
|
171 | var name , strippedName ;
|
172 |
|
173 | for ( name in ansiColorIndex ) {
|
174 | strippedName = name.replace( /-/g , '' ) ;
|
175 | this.colorIndex[ name ] = ansiColorIndex[ name ] ;
|
176 |
|
177 | if ( strippedName !== name ) {
|
178 | this.colorIndex[ strippedName ] = ansiColorIndex[ name ] ;
|
179 | }
|
180 | }
|
181 | } ;
|
182 |
|
183 |
|
184 |
|
185 | Palette.prototype.generateAdaptive = function() {
|
186 | if ( this.system ) { return ; }
|
187 |
|
188 | var i , j , z , register ,
|
189 | baseChromaColors , chromaColor ,
|
190 | saturationMark , lightnessMark , suffix ;
|
191 |
|
192 | baseChromaColors = this.adaptivePaletteDef.map( color => termkit.chroma( color.code ) ) ;
|
193 |
|
194 | register = 16 ;
|
195 |
|
196 | for ( z = 0 ; z >= -2 ; z -- ) {
|
197 | if ( z > 0 ) {
|
198 | saturationMark = '!'.repeat( z ) ;
|
199 | }
|
200 | else if ( z < 0 ) {
|
201 | saturationMark = '~'.repeat( -z ) ;
|
202 | }
|
203 | else {
|
204 | saturationMark = '' ;
|
205 | }
|
206 |
|
207 | for ( j = 2 ; j >= -3 ; j -- ) {
|
208 |
|
209 | if ( j > 0 ) {
|
210 | lightnessMark = '+'.repeat( j ) ;
|
211 | }
|
212 | else if ( j < 0 ) {
|
213 | lightnessMark = '-'.repeat( -j ) ;
|
214 | }
|
215 | else {
|
216 | lightnessMark = '' ;
|
217 | }
|
218 |
|
219 | suffix = saturationMark + lightnessMark ;
|
220 |
|
221 | for ( i = 0 ; i < 12 ; i ++ ) {
|
222 | chromaColor = this.clStep( baseChromaColors[ i ] , z , j ) ;
|
223 | this.addColor( register , chromaColor , this.adaptivePaletteDef[ i ].names , '@' , suffix ) ;
|
224 | register ++ ;
|
225 | }
|
226 | }
|
227 |
|
228 | }
|
229 | } ;
|
230 |
|
231 |
|
232 |
|
233 | Palette.prototype.generateExtra = function() {
|
234 | if ( this.system ) { return ; }
|
235 |
|
236 | var i , register ;
|
237 |
|
238 | register = 232 ;
|
239 |
|
240 | for ( i = 0 ; i < 13 && i < this.extraPaletteDef.length ; i ++ ) {
|
241 | this.addColor( register , termkit.chroma( this.extraPaletteDef[ i ].code ) , this.extraPaletteDef[ i ].names , '*' ) ;
|
242 | register ++ ;
|
243 | }
|
244 | } ;
|
245 |
|
246 |
|
247 |
|
248 | const grayscaleNames = [
|
249 | [ 'black' ] ,
|
250 | [ 'darkest-gray' ] ,
|
251 | [ 'darker-gray' ] ,
|
252 | [ 'dark-gray' ] ,
|
253 | [ 'dark-medium-gray' ] ,
|
254 | [ 'medium-gray' , 'gray' ] ,
|
255 | [ 'light-medium-gray' ] ,
|
256 | [ 'light-gray' ] ,
|
257 | [ 'lighter-gray' ] ,
|
258 | [ 'lightest-gray' ] ,
|
259 | [ 'white' ]
|
260 | ] ;
|
261 |
|
262 | Palette.prototype.generateGrayscale = function() {
|
263 | if ( this.system ) { return ; }
|
264 |
|
265 | var i , register , chromaColor ;
|
266 |
|
267 | register = 245 ;
|
268 |
|
269 | for ( i = 0 ; i <= 10 ; i ++ ) {
|
270 | chromaColor = termkit.chroma( 0 , 0 , 10 * i , 'hcl' ) ;
|
271 | this.addColor( register , chromaColor , grayscaleNames[ i ] , '@' ) ;
|
272 | register ++ ;
|
273 | }
|
274 | } ;
|
275 |
|
276 |
|
277 |
|
278 | Palette.prototype.getRgb = function( register ) {
|
279 | var chromaColor = this.chromaColors[ register ] ;
|
280 | if ( ! chromaColor ) { return null ; }
|
281 | var [ r , g , b ] = chromaColor.rgb() ;
|
282 | return { r , g , b } ;
|
283 | } ;
|
284 |
|
285 |
|
286 |
|
287 | Palette.prototype.addColor = function( register , chromaColor , names , prefix = '' , suffix = '' ) {
|
288 | var targetRegister ,
|
289 | [ r , g , b ] = chromaColor.rgb() ;
|
290 |
|
291 | this.chromaColors[ register ] = chromaColor ;
|
292 |
|
293 | if ( this.term.support.trueColor ) {
|
294 | this.escape[ register ] = this.term.str.colorRgb( r , g , b ) ;
|
295 | this.bgEscape[ register ] = this.term.str.bgColorRgb( r , g , b ) ;
|
296 | }
|
297 | else if ( this.term.support['256colors'] ) {
|
298 | targetRegister = this.term.registerForRgb(
|
299 | { r , g , b } ,
|
300 | r === g && g === b ? 232 : 0 ,
|
301 | 255
|
302 | ) ;
|
303 |
|
304 | this.escape[ register ] = this.term.str.color256( targetRegister ) ;
|
305 | this.bgEscape[ register ] = this.term.str.bgColor256( targetRegister ) ;
|
306 | }
|
307 | else {
|
308 | targetRegister = this.term.registerForRgb( { r , g , b } , 0 , 15 ) ;
|
309 | this.escape[ register ] = this.term.str.color256( targetRegister ) ;
|
310 | this.bgEscape[ register ] = this.term.str.bgColor256( targetRegister ) ;
|
311 | }
|
312 |
|
313 | names.forEach( name => {
|
314 | var strippedName = prefix + name.replace( /-/g , '' ) + suffix ;
|
315 | name = prefix + name + suffix ;
|
316 | this.colorIndex[ name ] = register ;
|
317 |
|
318 | if ( strippedName !== name ) {
|
319 | this.colorIndex[ strippedName ] = register ;
|
320 | }
|
321 | } ) ;
|
322 | } ;
|
323 |
|
324 |
|
325 |
|
326 | const FIX_STEP = 1.1 ;
|
327 |
|
328 | Palette.prototype.clStep = function( chromaColor , cAdjust , lAdjust , fixRgb = true ) {
|
329 | var c , l , rgb , avg , sortedChannels , preserveLOverC ;
|
330 |
|
331 | if ( ! cAdjust && ! lAdjust ) { return chromaColor ; }
|
332 |
|
333 | c = chromaColor.get( 'hcl.c' ) ;
|
334 | l = chromaColor.get( 'hcl.l' ) ;
|
335 |
|
336 | |
337 |
|
338 |
|
339 |
|
340 |
|
341 | c *= ( cAdjust > 0 ? 1.6 : 1.7 ) ** cAdjust ;
|
342 | l *= ( lAdjust > 0 ? 1.2 : 1.35 ) ** lAdjust ;
|
343 |
|
344 | chromaColor = chromaColor.set( 'hcl.c' , c ).set( 'hcl.l' , l ) ;
|
345 |
|
346 | if ( ! fixRgb || ! chromaColor.clipped ) { return chromaColor ; }
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 | preserveLOverC = Math.abs( lAdjust ) >= cAdjust ;
|
355 |
|
356 | for ( ;; ) {
|
357 |
|
358 | rgb = chromaColor._rgb._unclipped ;
|
359 | rgb.length = 3 ;
|
360 |
|
361 | if ( rgb.every( channel => channel > -5 && channel < 260 ) ) { return chromaColor ; }
|
362 |
|
363 | sortedChannels = [ ... rgb ].sort() ;
|
364 |
|
365 |
|
366 |
|
367 | if ( sortedChannels[ 2 ] >= 256 ) {
|
368 |
|
369 | avg = ( sortedChannels[ 0 ] + sortedChannels[ 1 ] + sortedChannels[ 2 ] ) / 3 ;
|
370 |
|
371 | if ( preserveLOverC ) {
|
372 |
|
373 | c = chromaColor.get( 'hcl.c' ) ;
|
374 | c /= FIX_STEP ;
|
375 | chromaColor = chromaColor.set( 'hcl.c' , c ) ;
|
376 | }
|
377 | else {
|
378 |
|
379 | l = chromaColor.get( 'hcl.l' ) ;
|
380 | l /= FIX_STEP ;
|
381 | chromaColor = chromaColor.set( 'hcl.l' , l ) ;
|
382 | }
|
383 |
|
384 |
|
385 | if ( avg > 255 ) { return chromaColor ; }
|
386 | }
|
387 | else if ( sortedChannels[ 1 ] < 0 ) {
|
388 |
|
389 | avg = ( sortedChannels[ 0 ] + sortedChannels[ 1 ] + sortedChannels[ 2 ] ) / 3 ;
|
390 |
|
391 | if ( preserveLOverC ) {
|
392 |
|
393 | c = chromaColor.get( 'hcl.c' ) ;
|
394 | c /= FIX_STEP ;
|
395 | chromaColor = chromaColor.set( 'hcl.c' , c ) ;
|
396 | }
|
397 | else {
|
398 |
|
399 | l = chromaColor.get( 'hcl.l' ) ;
|
400 | l *= FIX_STEP ;
|
401 | chromaColor = chromaColor.set( 'hcl.l' , l ) ;
|
402 | }
|
403 |
|
404 |
|
405 | if ( avg < 0 ) { return chromaColor ; }
|
406 | }
|
407 | else {
|
408 |
|
409 | return chromaColor ;
|
410 | }
|
411 | }
|
412 | } ;
|
413 |
|