Commit 55a04e20 authored by Michał Góral's avatar Michał Góral

Fixed pylint. Moved grouping algorithms outside of widget's code.

parent 85621e54
Pipeline #56840526 passed with stage
in 1 minute and 21 seconds
......@@ -30,7 +30,6 @@ process() should accept either a list of markup elements or a single markup
element (string or tuple).
import itertools
from collections import deque
from html.parser import HTMLParser
import attr
......@@ -51,7 +50,7 @@ class _M:
# <m>) won't have any effect because URWID will only process the
# inner-most markup element. Plus my tests showed that URWID quickly
# starts bugging with markup nested multiple times.
if isinstance(data, str) or isinstance(data, list):
if isinstance(data, (list, str)):
return (, data)
return data
......@@ -67,7 +66,7 @@ class _Sr:
def process(self, data):
if isinstance(data, str):
return '{0}{1}{2}'.format(self.beg, data, self.end)
elif isinstance(data, list):
if isinstance(data, list):
return [self.beg] + data + [self.end]
return [self.beg, data, self.end]
......@@ -102,9 +101,11 @@ class Parser(HTMLParser):
if not ctor:
if not self.tags:
return eprint(_('Unexpected end tag: </{}>'.format(tag)))
eprint(_('Unexpected end tag: </{}>'.format(tag)))
if not isinstance(self.tags[-1], ctor):
return eprint(_('End tag in incorrect order: </{}>'.format(tag)))
eprint(_('End tag in incorrect order: </{}>'.format(tag)))
def handle_data(self, data):
......@@ -19,6 +19,7 @@
import shlex
import functools
from collections import OrderedDict, deque
class TaskComparer:
......@@ -86,3 +87,37 @@ def sort_tasks(tasks, sort_string):
cmp = _process_sort_string(sort_string)
comparer = functools.partial(TaskComparer, cmp=cmp)
def group_tasks(tasks):
'''Groups tasks by creating parent-child relationship. This allows creating subtasks
even if TaskWarrior doesn't natively supports that.
Tasks are grouped by their `depends` field: parent tasks depend on
grouped = OrderedDict([(t['uuid'], t) for t in tasks])
alldeps = set()
for t in tasks:
depth = t.setdefault('_depth', 0)
if 'depends' in t:
deps = t['depends'].split(',')
for dep_uuid in deps:
dep = grouped.get(dep_uuid)
if dep:
dep['_depth'] = depth + 1
t.setdefault('_children', []).append(dep)
for dep in alldeps:
del grouped[dep]
return grouped
def dfs(tasks):
'''Depth-first-search walk through tasks grouped by group_tasks()'''
stack = deque(list(tasks.values()))
while stack:
task = stack.pop()
yield task
stack.extend(task.get('_children', []))
......@@ -17,7 +17,7 @@
'''Widgets used by TWC'''
from collections import defaultdict, OrderedDict, deque
from collections import defaultdict
import urwid
......@@ -45,7 +45,6 @@ class TaskView(urwid.Text):
parser = markup.Parser()
......@@ -58,44 +57,26 @@ class BlockView(urwid.BoxAdapter):
'''View of a single agenda block, i.e. a list of tasks'''
def __init__(self, screen, cfg, tw, block):
self.block = block
self.tasks = twutils.filter_tasks(block.filter, tw)
twutils.sort_tasks(self.tasks, block.sort)
tasks = twutils.filter_tasks(block.filter, tw)
twutils.sort_tasks(tasks, block.sort)
if block.limit is not None:
self.tasks = self.tasks[:block.limit]
od = OrderedDict([(t['uuid'], t) for t in self.tasks])
alldeps = set()
for t in self.tasks:
depth = t.setdefault('depth', 0)
if 'depends' in t:
deps = t['depends'].split(',')
for dep_uuid in deps:
dep = od.get(dep_uuid)
if dep:
dep['depth'] = depth + 1
t.setdefault('children', []).append(dep)
for dep in alldeps:
del od[dep]
tasks = tasks[:block.limit]
self.tasks = twutils.group_tasks(tasks)
focus_map = {c: '{}-focus'.format(c)
for c in cfg.colors if not c.endswith('-focus')}
focus_map[None] = 'text-focus'
textboxes = []
stack = deque(list(od.values()))
while len(stack) > 0:
task = stack.pop()
indent = ' ' * task['depth'] * 2
for task in twutils.dfs(self.tasks):
indent = ' ' * task['_depth'] * 2
fmt = indent + self.block.fmt
urwid.AttrMap(TaskView(task, fmt), None, focus_map))
stack.extend(task.get('children', []))
lw = urwid.ListBox(urwid.SimpleFocusListWalker(textboxes))
lb = urwid.LineBox(lw,
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