Commit 239a275f authored by Bram Schoenmakers's avatar Bram Schoenmakers

Introduce -C flag to steer color output

The -C flag takes 0, 1, 16, 256, auto, yes, true, no, false as possible
values.

If auto, then colors are enabled unless the output is not connected to a
TTY and is likely not to understand ANSI escape codes. 'auto' is the
default value.

The config().colors() function either returns 0, 16 or 256 for the
possible colors that can be displayed.

These values are also recognized by the colors option in the
configuration file.

This fixes issue #111.
parent 163fdb91
...@@ -45,8 +45,7 @@ class ConfigTest(TopydoTest): ...@@ -45,8 +45,7 @@ class ConfigTest(TopydoTest):
""" Bad colour switch value. """ """ Bad colour switch value. """
# boolean settings must first be typecast to integers, because all # boolean settings must first be typecast to integers, because all
# strings evaulate to 'True' # strings evaulate to 'True'
self.assertEqual(config("test/data/ConfigTest4.conf").colors(), self.assertEqual(config("test/data/ConfigTest4.conf").colors(), 0)
bool(int(config().defaults["topydo"]["colors"])))
def test_config06(self): def test_config06(self):
""" Bad auto creation date switch value. """ """ Bad auto creation date switch value. """
......
...@@ -684,13 +684,9 @@ C - ...@@ -684,13 +684,9 @@ C -
self.maxDiff = None self.maxDiff = None
mock_terminal_size.return_value = self.terminal_size(100, 25) mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '%Z|%I| %x %p %S %k\\t%{(}h{)}'})
command1 = ListCommand(["-x"], self.todolist, self.out, self.error)
command1.execute()
config(p_overrides={('ls', 'list_format'): '%z|%I| %x %p %S %k\\t%{(}h{)}'}) config(p_overrides={('ls', 'list_format'): '%z|%I| %x %p %S %k\\t%{(}h{)}'})
command2 = ListCommand(["-x"], self.todolist, self.out, self.error) command = ListCommand(["-x"], self.todolist, self.out, self.error)
command2.execute() command.execute()
result = u""" | 1| D Bar @Context1 +Project2 (due a month ago, started a month ago) result = u""" | 1| D Bar @Context1 +Project2 (due a month ago, started a month ago)
| 2| Z Lorem ipsum dolorem sit amet. Red @fox +jumpe... lazy:bar (due in 2 days, starts in a day) | 2| Z Lorem ipsum dolorem sit amet. Red @fox +jumpe... lazy:bar (due in 2 days, starts in a day)
...@@ -699,7 +695,7 @@ C - ...@@ -699,7 +695,7 @@ C -
| 5| Drink beer @ home | 5| Drink beer @ home
| 6| x 2014-12-12 Completed but with date:2014-12-12 | 6| x 2014-12-12 Completed but with date:2014-12-12
""" """
self.assertEqual(self.output, result * 2) self.assertEqual(self.output, result)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
default_command = ls default_command = ls
; filename = todo.txt ; filename = todo.txt
; archive_filename = done.txt ; archive_filename = done.txt
colors = 1 colors = auto
; identifiers can be 'linenumber' or 'text' ; identifiers can be 'linenumber' or 'text'
identifiers = linenumber identifiers = linenumber
backup_count = 5 backup_count = 5
...@@ -42,6 +42,8 @@ append_parent_contexts = 0 ...@@ -42,6 +42,8 @@ append_parent_contexts = 0
; [light-]gray, darkgray or numbers from 0 to 255. When number is specified color ; [light-]gray, darkgray or numbers from 0 to 255. When number is specified color
; is matched from Xterm color chart available here: ; is matched from Xterm color chart available here:
; http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg ; http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
; When using values between 16 and 256, make sure to set colors = 256 in the
; [topydo] section.
; priority_colors = A:cyan,B:yellow,C:blue ; priority_colors = A:cyan,B:yellow,C:blue
; project_color = red ; project_color = red
......
...@@ -22,7 +22,7 @@ I/O on the command-line. ...@@ -22,7 +22,7 @@ I/O on the command-line.
import getopt import getopt
import sys import sys
MAIN_OPTS = "ac:d:ht:v" MAIN_OPTS = "ac:C:d:ht:v"
READ_ONLY_COMMANDS = ('List', 'ListContext', 'ListProject') READ_ONLY_COMMANDS = ('List', 'ListContext', 'ListProject')
...@@ -30,12 +30,14 @@ def usage(): ...@@ -30,12 +30,14 @@ def usage():
""" Prints the command-line usage of topydo. """ """ Prints the command-line usage of topydo. """
print("""\ print("""\
Synopsis: topydo [-a] [-c <config>] [-d <archive>] [-t <todo.txt>] subcommand [help|args] Synopsis: topydo [-a] [-c <config>] [-C <colormode>] [-d <archive>] [-t <todo.txt>] subcommand [help|args]
topydo -h topydo -h
topydo -v topydo -v
-a : Do not archive todo items on completion. -a : Do not archive todo items on completion.
-c : Specify an alternative configuration file. -c : Specify an alternative configuration file.
-C : Specify color mode (0 = disable, 1 = enable 16 colors,
16 = enable 16 colors, 256 = enable 256 colors, auto (default))
-d : Specify an alternative archive file (done.txt) -d : Specify an alternative archive file (done.txt)
-h : This help text -h : This help text
-t : Specify an alternative todo file -t : Specify an alternative todo file
...@@ -62,14 +64,14 @@ Available commands: ...@@ -62,14 +64,14 @@ Available commands:
Run `topydo help <subcommand>` for command-specific help. Run `topydo help <subcommand>` for command-specific help.
""") """)
def write(p_file, p_string): def write(p_file, p_string):
""" """
Write p_string to file p_file, trailed by a newline character. Write p_string to file p_file, trailed by a newline character.
ANSI codes are removed when the file is not a TTY. ANSI codes are removed when the file is not a TTY (and colors are
automatically determined).
""" """
if not p_file.isatty(): if not config().colors(16 if p_file.isatty() else 0):
p_string = escape_ansi(p_string) p_string = escape_ansi(p_string)
if p_string: if p_string:
...@@ -140,6 +142,8 @@ class CLIApplicationBase(object): ...@@ -140,6 +142,8 @@ class CLIApplicationBase(object):
self.do_archive = False self.do_archive = False
elif opt == "-c": elif opt == "-c":
alt_config_path = value alt_config_path = value
elif opt == "-C":
overrides[('topydo', 'colors')] = value
elif opt == "-t": elif opt == "-t":
overrides[('topydo', 'filename')] = value overrides[('topydo', 'filename')] = value
elif opt == "-d": elif opt == "-d":
......
...@@ -58,7 +58,7 @@ class _Config: ...@@ -58,7 +58,7 @@ class _Config:
self.defaults = { self.defaults = {
'topydo': { 'topydo': {
'default_command': 'ls', 'default_command': 'ls',
'colors': '1', 'colors': 'auto',
'filename': 'todo.txt', 'filename': 'todo.txt',
'archive_filename': 'done.txt', 'archive_filename': 'done.txt',
'identifiers': 'linenumber', 'identifiers': 'linenumber',
...@@ -152,11 +152,30 @@ class _Config: ...@@ -152,11 +152,30 @@ class _Config:
def default_command(self): def default_command(self):
return self.cp.get('topydo', 'default_command') return self.cp.get('topydo', 'default_command')
def colors(self): def colors(self, p_default=16):
"""
Returns 0, 16 or 256 representing the number of colors that should be
used in the output. When the configured value is 'auto', the default
value is used.
"""
lookup = {
'auto': p_default,
'false': 0,
'no': 0,
'0': 0,
'1': 16,
'true': 16,
'yes': 16,
'16': 16,
'256': 256,
}
try: try:
return self.cp.getboolean('topydo', 'colors') return lookup[self.cp.get('topydo', 'colors').lower()] # pylint: disable=no-member
except ValueError: except ValueError:
return self.defaults['topydo']['colors'] == '1' return lookup[self.defaults['topydo']['colors'].lower()] # pylint: disable=no-member
except KeyError:
return 0
def todotxt(self): def todotxt(self):
return os.path.expanduser(self.cp.get('topydo', 'filename')) return os.path.expanduser(self.cp.get('topydo', 'filename'))
......
...@@ -129,9 +129,9 @@ def _right_align(p_str): ...@@ -129,9 +129,9 @@ def _right_align(p_str):
return p_str return p_str
def color_block(p_todo, p_256_color): def color_block(p_todo):
return '{} {}'.format( return '{} {}'.format(
progress_color(p_todo, p_256_color).as_ansi(p_background=True), progress_color(p_todo).as_ansi(p_background=True),
config().priority_color(p_todo.priority()).as_ansi(), config().priority_color(p_todo.priority()).as_ansi(),
) )
...@@ -201,9 +201,7 @@ class ListFormatParser(object): ...@@ -201,9 +201,7 @@ class ListFormatParser(object):
# relative completion date # relative completion date
'X': lambda t: 'x ' + humanize_date(t.completion_date()) if t.is_completed() else '', 'X': lambda t: 'x ' + humanize_date(t.completion_date()) if t.is_completed() else '',
'z': lambda t: color_block(t, p_256_color=False) if config().colors() else ' ', 'z': lambda t: color_block(t) if config().colors() else ' ',
'Z': lambda t: color_block(t, p_256_color=True) if config().colors() else ' ',
} }
self.format_list = self._preprocess_format() self.format_list = self._preprocess_format()
......
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
import re import re
from topydo.lib.Color import Color from topydo.lib.Color import Color
from topydo.lib.Config import config
from topydo.lib.Recurrence import relative_date_to_date from topydo.lib.Recurrence import relative_date_to_date
def progress_color(p_todo, p_256color=False): def progress_color(p_todo):
color16_range = [ color16_range = [
10, # light green 10, # light green
2, # green 2, # green
...@@ -76,7 +77,7 @@ def progress_color(p_todo, p_256color=False): ...@@ -76,7 +77,7 @@ def progress_color(p_todo, p_256color=False):
else: else:
return 0 return 0
color_range = color256_range if p_256color else color16_range color_range = color256_range if config().colors() == 256 else color16_range
progress = get_progress() progress = get_progress()
# TODO: remove linear scale to exponential scale # TODO: remove linear scale to exponential scale
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment