--- a/artemis.py Fri Apr 15 21:37:16 2011 -0700
+++ b/artemis.py Fri Apr 15 22:43:19 2011 -0700
@@ -14,6 +14,8 @@
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
+from termcolor import colored
+
state = {'new': 'new', 'fixed': ['fixed', 'resolved']}
state['default'] = state['new']
@@ -36,6 +38,8 @@
if opts['order']:
order = opts['order']
+ # Colors
+ colors = _read_colors(ui)
# Find issues
issues_dir = ui.config('artemis', 'issues', default = default_issues_dir)
@@ -61,7 +65,7 @@
list_properties_dict = {}
properties += filter(lambda p: len(p) > 1, cmd_properties)
- subjects = []
+ summaries = []
for issue in issues:
mbox = mailbox.Maildir(issue, factory=mailbox.MaildirMessage)
root = _find_root_key(mbox)
@@ -77,18 +81,15 @@
if match_date and not date_match(util.parsedate(mbox[root]['date'])[0]): continue
if not list_properties:
- subjects.append(("%s (%3d) [%s]: %s\n" % (issue[len(issues_path)+1:], # +1 for trailing /
- len(mbox)-1, # number of replies (-1 for self)
- _status_msg(mbox[root]),
- mbox[root]['Subject']),
- _find_mbox_date(mbox, root, order)))
+ summaries.append((_summary_line(mbox, root, issue[len(issues_path)+1:], colors), # +1 for trailing /
+ _find_mbox_date(mbox, root, order)))
else:
for lp in list_properties:
if lp in mbox[root]: list_properties_dict.setdefault(lp, set()).add(mbox[root][lp])
if not list_properties:
- subjects.sort(lambda (s1,d1),(s2,d2): cmp(d2,d1))
- for s,d in subjects:
+ summaries.sort(lambda (s1,d1),(s2,d2): cmp(d2,d1))
+ for s,d in summaries:
ui.write(s)
else:
for lp in list_properties_dict.keys():
@@ -421,6 +422,35 @@
else:
return msg['State']
+def _read_colors(ui):
+ colors = {}
+ # defaults
+ colors['new.color'] = 'red'
+ colors['new.on_color'] = 'on_grey'
+ colors['new.attrs'] = 'bold'
+ colors['resolved.color'] = 'white'
+ colors['resolved.on_color'] = ''
+ colors['resolved.attrs'] = ''
+ for v in colors:
+ colors[v] = ui.config('artemis', v, colors[v])
+ if v.endswith('attrs'): colors[v] = colors[v].split()
+ return colors
+
+def _color_summary(line, msg, colors):
+ if msg['State'] == 'new':
+ return colored(line, colors['new.color'], attrs = colors['new.attrs'])
+ elif msg['State'] in state['fixed']:
+ return colored(line, colors['resolved.color'], attrs = colors['resolved.attrs'])
+ else:
+ return line
+
+def _summary_line(mbox, root, issue, colors):
+ line = "%s (%3d) [%s]: %s\n" % (issue,
+ len(mbox)-1, # number of replies (-1 for self)
+ _status_msg(mbox[root]),
+ mbox[root]['Subject'])
+ return _color_summary(line, mbox[root], colors)
+
cmdtable = {
'ilist': (ilist,
[('a', 'all', False,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/termcolor.py Fri Apr 15 22:43:19 2011 -0700
@@ -0,0 +1,168 @@
+# coding: utf-8
+# Copyright (c) 2008-2011 Volvox Development Team
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# Author: Konstantin Lepa <konstantin.lepa@gmail.com>
+
+"""ANSII Color formatting for output in terminal."""
+
+from __future__ import print_function
+import os
+
+
+__ALL__ = [ 'colored', 'cprint' ]
+
+VERSION = (1, 1, 0)
+
+ATTRIBUTES = dict(
+ list(zip([
+ 'bold',
+ 'dark',
+ '',
+ 'underline',
+ 'blink',
+ '',
+ 'reverse',
+ 'concealed'
+ ],
+ list(range(1, 9))
+ ))
+ )
+del ATTRIBUTES['']
+
+
+HIGHLIGHTS = dict(
+ list(zip([
+ 'on_grey',
+ 'on_red',
+ 'on_green',
+ 'on_yellow',
+ 'on_blue',
+ 'on_magenta',
+ 'on_cyan',
+ 'on_white'
+ ],
+ list(range(40, 48))
+ ))
+ )
+
+
+COLORS = dict(
+ list(zip([
+ 'grey',
+ 'red',
+ 'green',
+ 'yellow',
+ 'blue',
+ 'magenta',
+ 'cyan',
+ 'white',
+ ],
+ list(range(30, 38))
+ ))
+ )
+
+
+RESET = '\033[0m'
+
+
+def colored(text, color=None, on_color=None, attrs=None):
+ """Colorize text.
+
+ Available text colors:
+ red, green, yellow, blue, magenta, cyan, white.
+
+ Available text highlights:
+ on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white.
+
+ Available attributes:
+ bold, dark, underline, blink, reverse, concealed.
+
+ Example:
+ colored('Hello, World!', 'red', 'on_grey', ['blue', 'blink'])
+ colored('Hello, World!', 'green')
+ """
+ if os.getenv('ANSI_COLORS_DISABLED') is None:
+ fmt_str = '\033[%dm%s'
+ if color is not None:
+ text = fmt_str % (COLORS[color], text)
+
+ if on_color is not None:
+ text = fmt_str % (HIGHLIGHTS[on_color], text)
+
+ if attrs is not None:
+ for attr in attrs:
+ text = fmt_str % (ATTRIBUTES[attr], text)
+
+ text += RESET
+ return text
+
+
+def cprint(text, color=None, on_color=None, attrs=None, **kwargs):
+ """Print colorize text.
+
+ It accepts arguments of print function.
+ """
+
+ print((colored(text, color, on_color, attrs)), **kwargs)
+
+
+if __name__ == '__main__':
+ print('Current terminal type: %s' % os.getenv('TERM'))
+ print('Test basic colors:')
+ cprint('Grey color', 'grey')
+ cprint('Red color', 'red')
+ cprint('Green color', 'green')
+ cprint('Yellow color', 'yellow')
+ cprint('Blue color', 'blue')
+ cprint('Magenta color', 'magenta')
+ cprint('Cyan color', 'cyan')
+ cprint('White color', 'white')
+ print(('-' * 78))
+
+ print('Test highlights:')
+ cprint('On grey color', on_color='on_grey')
+ cprint('On red color', on_color='on_red')
+ cprint('On green color', on_color='on_green')
+ cprint('On yellow color', on_color='on_yellow')
+ cprint('On blue color', on_color='on_blue')
+ cprint('On magenta color', on_color='on_magenta')
+ cprint('On cyan color', on_color='on_cyan')
+ cprint('On white color', color='grey', on_color='on_white')
+ print('-' * 78)
+
+ print('Test attributes:')
+ cprint('Bold grey color', 'grey', attrs=['bold'])
+ cprint('Dark red color', 'red', attrs=['dark'])
+ cprint('Underline green color', 'green', attrs=['underline'])
+ cprint('Blink yellow color', 'yellow', attrs=['blink'])
+ cprint('Reversed blue color', 'blue', attrs=['reverse'])
+ cprint('Concealed Magenta color', 'magenta', attrs=['concealed'])
+ cprint('Bold underline reverse cyan color', 'cyan',
+ attrs=['bold', 'underline', 'reverse'])
+ cprint('Dark blink concealed white color', 'white',
+ attrs=['dark', 'blink', 'concealed'])
+ print(('-' * 78))
+
+ print('Test mixing:')
+ cprint('Underline red on grey color', 'red', 'on_grey',
+ ['underline'])
+ cprint('Reversed green on red color', 'green', 'on_red', ['reverse'])
+