Commit afcf61cb authored by Bram Schoenmakers's avatar Bram Schoenmakers

Add preliminary support to grouping to the pretty printer

parent a6e3dc95
...@@ -24,7 +24,9 @@ from topydo.lib.Filter import HiddenTagFilter, InstanceFilter ...@@ -24,7 +24,9 @@ from topydo.lib.Filter import HiddenTagFilter, InstanceFilter
from topydo.lib.printers.PrettyPrinter import pretty_printer_factory from topydo.lib.printers.PrettyPrinter import pretty_printer_factory
from topydo.lib.prettyprinters.Format import PrettyPrinterFormatFilter from topydo.lib.prettyprinters.Format import PrettyPrinterFormatFilter
from topydo.lib.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
from topydo.lib.Sorter import Sorter
from topydo.lib.Utils import get_terminal_size from topydo.lib.Utils import get_terminal_size
from topydo.lib.View import View
class ListCommand(ExpressionCommand): class ListCommand(ExpressionCommand):
...@@ -37,6 +39,7 @@ class ListCommand(ExpressionCommand): ...@@ -37,6 +39,7 @@ class ListCommand(ExpressionCommand):
self.printer = None self.printer = None
self.sort_expression = config().sort_string() self.sort_expression = config().sort_string()
self.group_expression = config().group_string()
self.show_all = False self.show_all = False
self.ids = None self.ids = None
self.format = config().list_format() self.format = config().list_format()
...@@ -55,7 +58,7 @@ class ListCommand(ExpressionCommand): ...@@ -55,7 +58,7 @@ class ListCommand(ExpressionCommand):
return True return True
def _process_flags(self): def _process_flags(self):
opts, args = self.getopt('f:F:i:n:Ns:x') opts, args = self.getopt('f:F:g:i:n:Ns:x')
for opt, value in opts: for opt, value in opts:
if opt == '-x': if opt == '-x':
...@@ -81,6 +84,8 @@ class ListCommand(ExpressionCommand): ...@@ -81,6 +84,8 @@ class ListCommand(ExpressionCommand):
self.printer = None self.printer = None
elif opt == '-F': elif opt == '-F':
self.format = value self.format = value
elif opt == '-g':
self.group_expression = value
elif opt == '-N': elif opt == '-N':
# 2 lines are assumed to be taken up by printing the next prompt # 2 lines are assumed to be taken up by printing the next prompt
# display at least one item # display at least one item
...@@ -143,8 +148,17 @@ class ListCommand(ExpressionCommand): ...@@ -143,8 +148,17 @@ class ListCommand(ExpressionCommand):
self.printer = pretty_printer_factory(self.todolist, filters) self.printer = pretty_printer_factory(self.todolist, filters)
if self.group_expression:
self.out(self.printer.print_groups(self._view().groups))
else:
self.out(self.printer.print_list(self._view().todos)) self.out(self.printer.print_list(self._view().todos))
def _view(self):
sorter = Sorter(self.sort_expression, self.group_expression)
filters = self._filters()
return View(sorter, filters, self.todolist)
def _N_lines(self): def _N_lines(self):
''' Determine how many lines to print, such that the number of items ''' Determine how many lines to print, such that the number of items
displayed will fit on the terminal (i.e one 'screen-ful' of items) displayed will fit on the terminal (i.e one 'screen-ful' of items)
......
...@@ -92,6 +92,7 @@ class _Config: ...@@ -92,6 +92,7 @@ class _Config:
'sort': { 'sort': {
'keep_sorted': '0', 'keep_sorted': '0',
'sort_string': 'desc:importance,due,desc:priority', 'sort_string': 'desc:importance,due,desc:priority',
'group_string': '',
'ignore_weekends': '1', 'ignore_weekends': '1',
}, },
...@@ -270,6 +271,9 @@ class _Config: ...@@ -270,6 +271,9 @@ class _Config:
def sort_string(self): def sort_string(self):
return self.cp.get('sort', 'sort_string') return self.cp.get('sort', 'sort_string')
def group_string(self):
return self.cp.get('sort', 'group_string')
def ignore_weekends(self): def ignore_weekends(self):
try: try:
return self.cp.getboolean('sort', 'ignore_weekends') return self.cp.getboolean('sort', 'ignore_weekends')
......
...@@ -34,13 +34,33 @@ def get_field_function(p_field): ...@@ -34,13 +34,33 @@ def get_field_function(p_field):
access that property. If the property could not be located, return the access that property. If the property could not be located, return the
identity function. identity function.
""" """
def priority_key(p_todo):
priority = p_todo.priority()
return (priority or 'ZZ', priority or '')
def projects_key(p_todo):
projects = sorted(p_todo.projects())
return ([p.lower() for p in projects], ", ".join(projects))
def contexts_key(p_todo):
contexts = sorted(p_todo.contexts())
return ([p.lower() for p in contexts], ", ".join(contexts))
def get_tag_key(p_todo):
if p_todo.has_tag(p_field):
return ("0" + p_todo.tag_value(p_field), p_todo.tag_value(p_field))
else:
return ("1", "")
# default result
result = lambda a: a result = lambda a: a
if is_priority_field(p_field): if is_priority_field(p_field):
# assign dummy priority when a todo has no priority # assign dummy priority when a todo has no priority
result = lambda a: a.priority() or 'ZZ' result = priority_key
elif p_field == 'context' or p_field == 'contexts': elif p_field == 'context' or p_field == 'contexts':
result = lambda a: sorted([c.lower() for c in a.contexts()]) result = contexts_key
elif p_field == 'creationdate' or p_field == 'creation': elif p_field == 'creationdate' or p_field == 'creation':
# when a task has no creation date, push it to the end by assigning it # when a task has no creation date, push it to the end by assigning it
# the maximum possible date. # the maximum possible date.
...@@ -56,15 +76,14 @@ def get_field_function(p_field): ...@@ -56,15 +76,14 @@ def get_field_function(p_field):
elif p_field == 'length': elif p_field == 'length':
result = lambda a: a.length() result = lambda a: a.length()
elif p_field == 'project' or p_field == 'projects': elif p_field == 'project' or p_field == 'projects':
result = lambda a: sorted([c.lower() for c in a.projects()]) result = projects_key
elif p_field == 'text': elif p_field == 'text':
result = lambda a: a.text() result = lambda a: a.text()
else: else:
# try to find the corresponding tag # try to find the corresponding tag
# when a tag is not present, push it to the end of the list by giving # when a tag is not present, push it to the end of the list by giving
# it an artificially higher value # it an artificially higher value
result = (lambda a: "0" + a.tag_value(p_field) if a.has_tag(p_field) result = get_tag_key
else "1")
return result return result
...@@ -115,7 +134,11 @@ class Sorter(object): ...@@ -115,7 +134,11 @@ class Sorter(object):
return sorted_todos return sorted_todos
def group(self, p_todos): def group(self, p_todos):
result = [([], self.sort(p_todos))] """
Groups the todos according to the given group string. Assumes that the
given todos have already been sorted with self.sort().
"""
result = [([], p_todos)]
for function, _ in self.groupfunctions: for function, _ in self.groupfunctions:
oldresult = result oldresult = result
......
...@@ -38,3 +38,8 @@ class View(object): ...@@ -38,3 +38,8 @@ class View(object):
result = _filter.filter(result) result = _filter.filter(result)
return result return result
@property
def groups(self):
todos = self.todos
return self._sorter.group(self.todos)
...@@ -76,6 +76,15 @@ class PrettyPrinter(Printer): ...@@ -76,6 +76,15 @@ class PrettyPrinter(Printer):
""" """
return [self.print_todo(todo) for todo in p_todos] return [self.print_todo(todo) for todo in p_todos]
def print_groups(self, p_groups):
result = []
for key, todos in p_groups:
result.append(TopydoString(key))
result.append(TopydoString("\n===\n"))
result += self.print_list(todos)
return result
def pretty_printer_factory(p_todolist, p_additional_filters=None): def pretty_printer_factory(p_todolist, p_additional_filters=None):
""" Returns a pretty printer suitable for the ls and dep subcommands. """ """ Returns a pretty printer suitable for the ls and dep subcommands. """
......
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