Add the --colormap option to build adhoc colormaps

Use the given list of comma-separated colors as a colormap (cycle the colors at each match).
Support of 256 colors mode colormaps.
This commit is contained in:
nojhan 2013-03-05 21:53:38 +01:00
commit c891bda94a
2 changed files with 55 additions and 20 deletions

View file

@ -28,10 +28,13 @@ rapid_blink, reverse, conceal or random.
`Random` will color each matching pattern with a random color among the 255 `Random` will color each matching pattern with a random color among the 255
available in the ANSI table. `random` will do the same in 8 colors mode. available in the ANSI table. `random` will do the same in 8 colors mode.
`rainbow` will cycle over a 8 colors rainbow at each matching pattern.
When not specified, a *COLOR* defaults to _red_ and a *STYLE* defaults to _bold_. When not specified, a *COLOR* defaults to _red_ and a *STYLE* defaults to _bold_.
`colout` is released under the GNU Public License v3. `colout` is released under the GNU Public License v3.
## OPTIONS ## OPTIONS
* `-h`, `--help`: * `-h`, `--help`:
@ -43,14 +46,17 @@ When not specified, a *COLOR* defaults to _red_ and a *STYLE* defaults to _bold_
* `-g`, `--groups`: * `-g`, `--groups`:
For color maps (like "rainbow"), iterate over matching groups in the pattern instead of over patterns. For color maps (like "rainbow"), iterate over matching groups in the pattern instead of over patterns.
* `-c`, `--colormap`:
Use the given list of comma-separated colors as a colormap (cycle the colors at each match).
## REGULAR EXPRESSIONS ## REGULAR EXPRESSIONS
A regular expression (or _regex_) is a pattern that describes a set of strings A regular expression (or _regex_) is a pattern that describes a set of strings
that matches it. that matches it.
`colout` understands regex as specifed in the _re_ python module. Given that `colout` understands regex as specifed in the _re_ python module. Given that
`colout` is generally called by the command line, you may have to escape `colout` is generally called by the command line, you may have to escape
special characters that would be recognize by your shell. special characters that would be recognize by your shell.
@ -87,6 +93,9 @@ special characters that would be recognize by your shell.
`make 2>&1 | colout :\([0-9]+\):[0-9]* yellow normal | colout error | colout warning magenta | colout pragma green normal | colout /\(\\w+\)*\.\(h\|cpp\) cyan normal` `make 2>&1 | colout :\([0-9]+\):[0-9]* yellow normal | colout error | colout warning magenta | colout pragma green normal | colout /\(\\w+\)*\.\(h\|cpp\) cyan normal`
* Color each word in the head of auth.log with a rainbow color map, starting a new colormap at each new line (the * Color each word in the head of auth.log with a rainbow color map, starting a new colormap at each new line (the
begining of the command is just bash magic to repeat the string "(\w+ begining of the command is just bash magic to repeat the string "(\\w+)\\W+":
`L=$(seq 10) ; P=${L//??/(\\w+)\\W+} ; head /var/log/auth.log | ./colout.py -g "^${P}(.*)$" rainbow` `L=$(seq 10) ; P=${L//??/(\\w+)\\W+} ; head /var/log/auth.log | ./colout.py -g "^${P}(.*)$" rainbow`
* Color each line of a file with a different color among a 256 color gradient from cyan to green:
`head /var/log/auth.log | ./colout.py -c "^.*$" 39,38,37,36,35,34`

View file

@ -26,7 +26,8 @@ colors = {
} }
rainbow = [ "red", "yellow", "green", "cyan", "blue", "magenta" ] rainbow = [ "red", "yellow", "green", "cyan", "blue", "magenta" ]
rainbow_idx = 0 colormap = rainbow # default colormap to rainbow
colormap_idx = 0
# Escaped end markers for given color modes # Escaped end markers for given color modes
endmarks = {8:";", 256:";38;5;"} endmarks = {8:";", 256:";38;5;"}
@ -45,7 +46,7 @@ def colorin( text, color = "red", style = "normal" ):
>>> colout.colorin("Faites chier la vache", 41, "normal") >>> colout.colorin("Faites chier la vache", 41, "normal")
'\x1b[0;38;5;41mFaites chier la vache\x1b[0m' '\x1b[0;38;5;41mFaites chier la vache\x1b[0m'
""" """
global rainbow_idx global colormap_idx
# Special characters. # Special characters.
start = "\033[" start = "\033["
@ -71,13 +72,29 @@ def colorin( text, color = "red", style = "normal" ):
elif color == "rainbow": elif color == "rainbow":
mode = 8 mode = 8
color = rainbow[rainbow_idx] color = colormap[colormap_idx]
color_code = str( 30 + colors[color] ) color_code = str( 30 + colors[color] )
if rainbow_idx < len(rainbow)-1: if colormap_idx < len(colormap)-1:
rainbow_idx += 1 colormap_idx += 1
else: else:
rainbow_idx = 0 colormap_idx = 0
elif color == "colormap":
color = colormap[colormap_idx]
if color in colors:
mode = 8
color_code = str( 30 + colors[color] )
else:
mode = 256
color_nb = int( color )
assert( 0 <= color_nb <= 255 )
color_code = str( color_nb )
if colormap_idx < len(colormap)-1:
colormap_idx += 1
else:
colormap_idx = 0
# 8 colors modes # 8 colors modes
elif color in colors: elif color in colors:
@ -107,7 +124,7 @@ def colorout( text, match, prev_end, color = "red", style = "normal", group=0 ):
return colored_text,end return colored_text,end
def colorup( text, pattern, color = "red", style = "normal", on_groups=False ): def colorup( text, pattern, color = "red", style = "normal", on_groups=False):
""" """
Color up every characters that match the given regexp patterns. Color up every characters that match the given regexp patterns.
If groups are specified, only color up them and not the whole pattern. If groups are specified, only color up them and not the whole pattern.
@ -130,7 +147,7 @@ def colorup( text, pattern, color = "red", style = "normal", on_groups=False ):
>>> colorup("Faites Chier la Vache", "([A-Z])(\S+)\s", "blue", "bold,italic") >>> colorup("Faites Chier la Vache", "([A-Z])(\S+)\s", "blue", "bold,italic")
'\x1b[1;34mF\x1b[0m\x1b[3;34maites\x1b[0m \x1b[1;34mC\x1b[0m\x1b[3;34mhier\x1b[0m la Vache' '\x1b[1;34mF\x1b[0m\x1b[3;34maites\x1b[0m \x1b[1;34mC\x1b[0m\x1b[3;34mhier\x1b[0m la Vache'
""" """
global rainbow_idx global colormap_idx
regex = re.compile(pattern)#, re.IGNORECASE) regex = re.compile(pattern)#, re.IGNORECASE)
# Prepare the colored text. # Prepare the colored text.
@ -160,7 +177,7 @@ def colorup( text, pattern, color = "red", style = "normal", on_groups=False ):
# If we want to iterate colormaps on groups instead of patterns # If we want to iterate colormaps on groups instead of patterns
if on_groups: if on_groups:
# Reset the counter at the beginning of each match # Reset the counter at the beginning of each match
rainbow_idx = 0 colormap_idx = 0
# For each group index. # For each group index.
# Note that match.groups returns a tuple (thus being indexed in [0,n[), # Note that match.groups returns a tuple (thus being indexed in [0,n[),
@ -176,7 +193,7 @@ def colorup( text, pattern, color = "red", style = "normal", on_groups=False ):
return colored_text return colored_text
def colorgen( items, pattern, color = "red", style = "normal", on_groups=False ): def colorgen( items, pattern, color = "red", style = "normal", on_groups=False):
""" """
A generator that colors the items given in an iterable input. A generator that colors the items given in an iterable input.
@ -186,7 +203,7 @@ def colorgen( items, pattern, color = "red", style = "normal", on_groups=False )
'2.7\x1b[0;31m1\x1b[0m828\x1b[0;31m1\x1b[0m82846'] '2.7\x1b[0;31m1\x1b[0m828\x1b[0;31m1\x1b[0m82846']
""" """
for item in items: for item in items:
yield colorup( item, pattern, color, style, on_groups ) yield colorup( item, pattern, color, style, on_groups)
###################### ######################
@ -239,8 +256,10 @@ def __args_dirty__(argv,usage=""):
on_stderr = bool(argv[4]) on_stderr = bool(argv[4])
if len(argv) == 6: if len(argv) == 6:
on_groups = bool(argv[5]) on_groups = bool(argv[5])
if len(argv) == 7:
as_colormap = bool(argv[6])
return pattern,color,style,on_stderr,on_groups return pattern,color,style,on_stderr,on_groups,as_colormap
def __args_parse__(argv,usage=""): def __args_parse__(argv,usage=""):
@ -268,11 +287,14 @@ def __args_parse__(argv,usage=""):
help="Output on the stderr instead of stdout") help="Output on the stderr instead of stdout")
parser.add_argument("-g", "--groups", action="store_true", parser.add_argument("-g", "--groups", action="store_true",
help="For color maps (random, rainbows), iterate over matching groups in the pattern instead of over patterns") help="For color maps (random, rainbow), iterate over matching groups in the pattern instead of over patterns")
parser.add_argument("-c", "--colormap", action="store_true",
help="Use the given colors as a colormap (cycle the colors at each match)")
args = parser.parse_args() args = parser.parse_args()
return args.pattern[0], args.color, args.style, args.stderr, args.groups return args.pattern[0], args.color, args.style, args.stderr, args.groups, args.colormap
if __name__ == "__main__": if __name__ == "__main__":
@ -285,14 +307,18 @@ if __name__ == "__main__":
# if argparse is not installed # if argparse is not installed
except ImportError: except ImportError:
pattern,color,style,on_stderr,on_groups = __args_dirty__(sys.argv,usage) pattern,color,style,on_stderr,on_groups,as_colormap = __args_dirty__(sys.argv,usage)
# if argparse is available # if argparse is available
else: else:
pattern,color,style,on_stderr,on_groups = __args_parse__(sys.argv,usage) pattern,color,style,on_stderr,on_groups,as_colormap = __args_parse__(sys.argv,usage)
# use the generator: output lines as they come # use the generator: output lines as they come
for colored in colorgen( sys.stdin, pattern, color, style, on_groups ): if as_colormap == True and color != "rainbow":
colormap = color.split(",") # replace the colormap by the given colors
color = "colormap" # use the keyword to switch to colormap instead of list of colors
for colored in colorgen( sys.stdin, pattern, color, style, on_groups):
if on_stderr: if on_stderr:
sys.stderr.write(colored) sys.stderr.write(colored)
sys.stderr.flush() sys.stderr.flush()