...

Source file src/github.com/logrusorgru/aurora/v3/color.go

Documentation: github.com/logrusorgru/aurora/v3

     1  //
     2  // Copyright (c) 2016-2020 The Aurora Authors. All rights reserved.
     3  // This program is free software. It comes without any warranty,
     4  // to the extent permitted by applicable law. You can redistribute
     5  // it and/or modify it under the terms of the Unlicense. See LICENSE
     6  // file for more details or see below.
     7  //
     8  
     9  //
    10  // This is free and unencumbered software released into the public domain.
    11  //
    12  // Anyone is free to copy, modify, publish, use, compile, sell, or
    13  // distribute this software, either in source code form or as a compiled
    14  // binary, for any purpose, commercial or non-commercial, and by any
    15  // means.
    16  //
    17  // In jurisdictions that recognize copyright laws, the author or authors
    18  // of this software dedicate any and all copyright interest in the
    19  // software to the public domain. We make this dedication for the benefit
    20  // of the public at large and to the detriment of our heirs and
    21  // successors. We intend this dedication to be an overt act of
    22  // relinquishment in perpetuity of all present and future rights to this
    23  // software under copyright law.
    24  //
    25  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    26  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    27  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    28  // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
    29  // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    30  // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    31  // OTHER DEALINGS IN THE SOFTWARE.
    32  //
    33  // For more information, please refer to <http://unlicense.org/>
    34  //
    35  
    36  package aurora
    37  
    38  // A Color type is a color. It can contain
    39  // one background color, one foreground color
    40  // and a format, including ideogram related
    41  // formats.
    42  type Color uint
    43  
    44  /*
    45  
    46  	Developer note.
    47  
    48  	The int type is architecture depended and can be
    49  	represented as int32 or int64.
    50  
    51  	Thus, we can use 32-bits only to be fast and
    52  	cross-platform.
    53  
    54  	All supported formats requires 14 bits. It is
    55  	first 14 bits.
    56  
    57  	A foreground color requires 8 bit + 1 bit (presence flag).
    58  	And the same for background color.
    59  
    60  	The Color representations
    61  
    62  	[ bg 8 bit ] [fg 8 bit ] [ fg/bg 2 bits ] [ fm 14 bits ]
    63  
    64  	https://play.golang.org/p/fq2zcNstFoF
    65  
    66  */
    67  
    68  // Special formats
    69  const (
    70  	BoldFm       Color = 1 << iota // 1
    71  	FaintFm                        // 2
    72  	ItalicFm                       // 3
    73  	UnderlineFm                    // 4
    74  	SlowBlinkFm                    // 5
    75  	RapidBlinkFm                   // 6
    76  	ReverseFm                      // 7
    77  	ConcealFm                      // 8
    78  	CrossedOutFm                   // 9
    79  
    80  	FrakturFm         // 20
    81  	DoublyUnderlineFm // 21 or bold off for some systems
    82  
    83  	FramedFm    // 51
    84  	EncircledFm // 52
    85  	OverlinedFm // 53
    86  
    87  	InverseFm       = ReverseFm    // alias to ReverseFm
    88  	BlinkFm         = SlowBlinkFm  // alias to SlowBlinkFm
    89  	HiddenFm        = ConcealFm    // alias to ConcealFm
    90  	StrikeThroughFm = CrossedOutFm // alias to CrossedOutFm
    91  
    92  	maskFm = BoldFm | FaintFm |
    93  		ItalicFm | UnderlineFm |
    94  		SlowBlinkFm | RapidBlinkFm |
    95  		ReverseFm |
    96  		ConcealFm | CrossedOutFm |
    97  
    98  		FrakturFm | DoublyUnderlineFm |
    99  
   100  		FramedFm | EncircledFm | OverlinedFm
   101  
   102  	flagFg Color = 1 << 14 // presence flag (14th bit)
   103  	flagBg Color = 1 << 15 // presence flag (15th bit)
   104  
   105  	shiftFg = 16 // shift for foreground (starting from 16th bit)
   106  	shiftBg = 24 // shift for background (starting from 24th bit)
   107  )
   108  
   109  // Foreground colors and related formats
   110  const (
   111  
   112  	// 8 bits
   113  
   114  	// [  0;   7] - 30-37
   115  	// [  8;  15] - 90-97
   116  	// [ 16; 231] - RGB
   117  	// [232; 255] - grayscale
   118  
   119  	BlackFg   Color = (iota << shiftFg) | flagFg // 30, 90
   120  	RedFg                                        // 31, 91
   121  	GreenFg                                      // 32, 92
   122  	YellowFg                                     // 33, 93
   123  	BlueFg                                       // 34, 94
   124  	MagentaFg                                    // 35, 95
   125  	CyanFg                                       // 36, 96
   126  	WhiteFg                                      // 37, 97
   127  
   128  	BrightFg Color = ((1 << 3) << shiftFg) | flagFg // -> 90
   129  
   130  	// the BrightFg itself doesn't represent
   131  	// a color, thus it has not flagFg
   132  
   133  	// 5 bits
   134  
   135  	// BrownFg represents brown foreground color.
   136  	//
   137  	// Deprecated: use YellowFg instead, following specifications
   138  	BrownFg = YellowFg
   139  
   140  	//
   141  	maskFg = (0xff << shiftFg) | flagFg
   142  )
   143  
   144  // Background colors and related formats
   145  const (
   146  
   147  	// 8 bits
   148  
   149  	// [  0;   7] - 40-47
   150  	// [  8;  15] - 100-107
   151  	// [ 16; 231] - RGB
   152  	// [232; 255] - grayscale
   153  
   154  	BlackBg   Color = (iota << shiftBg) | flagBg // 40, 100
   155  	RedBg                                        // 41, 101
   156  	GreenBg                                      // 42, 102
   157  	YellowBg                                     // 43, 103
   158  	BlueBg                                       // 44, 104
   159  	MagentaBg                                    // 45, 105
   160  	CyanBg                                       // 46, 106
   161  	WhiteBg                                      // 47, 107
   162  
   163  	BrightBg Color = ((1 << 3) << shiftBg) | flagBg // -> 100
   164  
   165  	// the BrightBg itself doesn't represent
   166  	// a color, thus it has not flagBg
   167  
   168  	// 5 bits
   169  
   170  	// BrownBg represents brown foreground color.
   171  	//
   172  	// Deprecated: use YellowBg instead, following specifications
   173  	BrownBg = YellowBg
   174  
   175  	//
   176  	maskBg = (0xff << shiftBg) | flagBg
   177  )
   178  
   179  const (
   180  	availFlags = "-+# 0"
   181  	esc        = "\033["
   182  	clear      = esc + "0m"
   183  )
   184  
   185  // IsValid returns true always
   186  //
   187  // Deprecated: don't use this method anymore
   188  func (c Color) IsValid() bool {
   189  	return true
   190  }
   191  
   192  // Nos returns string like 1;7;31;45. It
   193  // may be an empty string for empty color.
   194  // If the zero is true, then the string
   195  // is prepended with 0;
   196  func (c Color) Nos(zero bool) string {
   197  	return string(c.appendNos(make([]byte, 0, 59), zero))
   198  }
   199  
   200  func appendCond(bs []byte, cond, semi bool, vals ...byte) []byte {
   201  	if !cond {
   202  		return bs
   203  	}
   204  	return appendSemi(bs, semi, vals...)
   205  }
   206  
   207  // if the semi is true, then prepend with semicolon
   208  func appendSemi(bs []byte, semi bool, vals ...byte) []byte {
   209  	if semi {
   210  		bs = append(bs, ';')
   211  	}
   212  	return append(bs, vals...)
   213  }
   214  
   215  func itoa(t byte) string {
   216  	var (
   217  		a [3]byte
   218  		j = 2
   219  	)
   220  	for i := 0; i < 3; i, j = i+1, j-1 {
   221  		a[j] = '0' + t%10
   222  		if t = t / 10; t == 0 {
   223  			break
   224  		}
   225  	}
   226  	return string(a[j:])
   227  }
   228  
   229  func (c Color) appendFg(bs []byte, zero bool) []byte {
   230  
   231  	if zero || c&maskFm != 0 {
   232  		bs = append(bs, ';')
   233  	}
   234  
   235  	// 0- 7 :  30-37
   236  	// 8-15 :  90-97
   237  	// > 15 : 38;5;val
   238  
   239  	switch fg := (c & maskFg) >> shiftFg; {
   240  	case fg <= 7:
   241  		// '3' and the value itself
   242  		bs = append(bs, '3', '0'+byte(fg))
   243  	case fg <= 15:
   244  		// '9' and the value itself
   245  		bs = append(bs, '9', '0'+byte(fg&^0x08)) // clear bright flag
   246  	default:
   247  		bs = append(bs, '3', '8', ';', '5', ';')
   248  		bs = append(bs, itoa(byte(fg))...)
   249  	}
   250  	return bs
   251  }
   252  
   253  func (c Color) appendBg(bs []byte, zero bool) []byte {
   254  
   255  	if zero || c&(maskFm|maskFg) != 0 {
   256  		bs = append(bs, ';')
   257  	}
   258  
   259  	// 0- 7 :  40- 47
   260  	// 8-15 : 100-107
   261  	// > 15 : 48;5;val
   262  
   263  	switch fg := (c & maskBg) >> shiftBg; {
   264  	case fg <= 7:
   265  		// '3' and the value itself
   266  		bs = append(bs, '4', '0'+byte(fg))
   267  	case fg <= 15:
   268  		// '1', '0' and the value itself
   269  		bs = append(bs, '1', '0', '0'+byte(fg&^0x08)) // clear bright flag
   270  	default:
   271  		bs = append(bs, '4', '8', ';', '5', ';')
   272  		bs = append(bs, itoa(byte(fg))...)
   273  	}
   274  	return bs
   275  }
   276  
   277  func (c Color) appendFm9(bs []byte, zero bool) []byte {
   278  
   279  	bs = appendCond(bs, c&ItalicFm != 0,
   280  		zero || c&(BoldFm|FaintFm) != 0,
   281  		'3')
   282  	bs = appendCond(bs, c&UnderlineFm != 0,
   283  		zero || c&(BoldFm|FaintFm|ItalicFm) != 0,
   284  		'4')
   285  	// don't combine slow and rapid blink using only
   286  	// on of them, preferring slow blink
   287  	if c&SlowBlinkFm != 0 {
   288  		bs = appendSemi(bs,
   289  			zero || c&(BoldFm|FaintFm|ItalicFm|UnderlineFm) != 0,
   290  			'5')
   291  	} else if c&RapidBlinkFm != 0 {
   292  		bs = appendSemi(bs,
   293  			zero || c&(BoldFm|FaintFm|ItalicFm|UnderlineFm) != 0,
   294  			'6')
   295  	}
   296  
   297  	// including 1-2
   298  	const mask6i = BoldFm | FaintFm |
   299  		ItalicFm | UnderlineFm |
   300  		SlowBlinkFm | RapidBlinkFm
   301  
   302  	bs = appendCond(bs, c&ReverseFm != 0,
   303  		zero || c&(mask6i) != 0,
   304  		'7')
   305  	bs = appendCond(bs, c&ConcealFm != 0,
   306  		zero || c&(mask6i|ReverseFm) != 0,
   307  		'8')
   308  	bs = appendCond(bs, c&CrossedOutFm != 0,
   309  		zero || c&(mask6i|ReverseFm|ConcealFm) != 0,
   310  		'9')
   311  
   312  	return bs
   313  }
   314  
   315  // append 1;3;38;5;216 like string that represents ANSI
   316  // color of the Color; the zero argument requires
   317  // appending of '0' before to reset previous format
   318  // and colors
   319  func (c Color) appendNos(bs []byte, zero bool) []byte {
   320  
   321  	if zero {
   322  		bs = append(bs, '0') // reset previous
   323  	}
   324  
   325  	// formats
   326  	//
   327  
   328  	if c&maskFm != 0 {
   329  
   330  		// 1-2
   331  
   332  		// don't combine bold and faint using only on of them, preferring bold
   333  
   334  		if c&BoldFm != 0 {
   335  			bs = appendSemi(bs, zero, '1')
   336  		} else if c&FaintFm != 0 {
   337  			bs = appendSemi(bs, zero, '2')
   338  		}
   339  
   340  		// 3-9
   341  
   342  		const mask9 = ItalicFm | UnderlineFm |
   343  			SlowBlinkFm | RapidBlinkFm |
   344  			ReverseFm | ConcealFm | CrossedOutFm
   345  
   346  		if c&mask9 != 0 {
   347  			bs = c.appendFm9(bs, zero)
   348  		}
   349  
   350  		// 20-21
   351  
   352  		const (
   353  			mask21 = FrakturFm | DoublyUnderlineFm
   354  			mask9i = BoldFm | FaintFm | mask9
   355  		)
   356  
   357  		if c&mask21 != 0 {
   358  			bs = appendCond(bs, c&FrakturFm != 0,
   359  				zero || c&mask9i != 0,
   360  				'2', '0')
   361  			bs = appendCond(bs, c&DoublyUnderlineFm != 0,
   362  				zero || c&(mask9i|FrakturFm) != 0,
   363  				'2', '1')
   364  		}
   365  
   366  		// 50-53
   367  
   368  		const (
   369  			mask53  = FramedFm | EncircledFm | OverlinedFm
   370  			mask21i = mask9i | mask21
   371  		)
   372  
   373  		if c&mask53 != 0 {
   374  			bs = appendCond(bs, c&FramedFm != 0,
   375  				zero || c&mask21i != 0,
   376  				'5', '1')
   377  			bs = appendCond(bs, c&EncircledFm != 0,
   378  				zero || c&(mask21i|FramedFm) != 0,
   379  				'5', '2')
   380  			bs = appendCond(bs, c&OverlinedFm != 0,
   381  				zero || c&(mask21i|FramedFm|EncircledFm) != 0,
   382  				'5', '3')
   383  		}
   384  
   385  	}
   386  
   387  	// foreground
   388  	if c&maskFg != 0 {
   389  		bs = c.appendFg(bs, zero)
   390  	}
   391  
   392  	// background
   393  	if c&maskBg != 0 {
   394  		bs = c.appendBg(bs, zero)
   395  	}
   396  
   397  	return bs
   398  }
   399  

View as plain text