From c891bda94ae16f0531d12477f613dbc266415693 Mon Sep 17 00:00:00 2001 From: nojhan Date: Tue, 5 Mar 2013 21:53:38 +0100 Subject: [PATCH] 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. --- README.md | 15 +++++++++++--- colout.py | 60 +++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 3877aa6..d6eafbf 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,13 @@ rapid_blink, reverse, conceal or random. `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. +`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_. `colout` is released under the GNU Public License v3. + ## OPTIONS * `-h`, `--help`: @@ -43,14 +46,17 @@ When not specified, a *COLOR* defaults to _red_ and a *STYLE* defaults to _bold_ * `-g`, `--groups`: 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 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` 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. @@ -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` * 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` +* 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` + diff --git a/colout.py b/colout.py index 44e92b1..b698c84 100755 --- a/colout.py +++ b/colout.py @@ -26,7 +26,8 @@ colors = { } 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 endmarks = {8:";", 256:";38;5;"} @@ -45,7 +46,7 @@ def colorin( text, color = "red", style = "normal" ): >>> colout.colorin("Faites chier la vache", 41, "normal") '\x1b[0;38;5;41mFaites chier la vache\x1b[0m' """ - global rainbow_idx + global colormap_idx # Special characters. start = "\033[" @@ -71,13 +72,29 @@ def colorin( text, color = "red", style = "normal" ): elif color == "rainbow": mode = 8 - color = rainbow[rainbow_idx] + color = colormap[colormap_idx] color_code = str( 30 + colors[color] ) - if rainbow_idx < len(rainbow)-1: - rainbow_idx += 1 + if colormap_idx < len(colormap)-1: + colormap_idx += 1 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 elif color in colors: @@ -107,7 +124,7 @@ def colorout( text, match, prev_end, color = "red", style = "normal", group=0 ): 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. 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") '\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) # 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 on_groups: # Reset the counter at the beginning of each match - rainbow_idx = 0 + colormap_idx = 0 # For each group index. # 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 -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. @@ -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'] """ 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]) if len(argv) == 6: 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=""): @@ -268,11 +287,14 @@ def __args_parse__(argv,usage=""): help="Output on the stderr instead of stdout") 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() - 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__": @@ -285,14 +307,18 @@ if __name__ == "__main__": # if argparse is not installed 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 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 - 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: sys.stderr.write(colored) sys.stderr.flush()