diff --git a/taskwiki/regexp.py b/taskwiki/regexp.py index 495146779..692e7c6dd 100644 --- a/taskwiki/regexp.py +++ b/taskwiki/regexp.py @@ -17,7 +17,7 @@ DUE = r'(?P{0})'.format(DUE_UNNAMED) TEXT = r'(?P.+?)' COMPLETION_MARK = r'(?P.)' -PRIORITY = r'(?P!{1,3})' +PRIORITY = r'(?P!+|¡+)' GENERIC_TASK = re.compile(''.join([ '^', diff --git a/taskwiki/store.py b/taskwiki/store.py index 4e3dcd40a..d2e532d2c 100644 --- a/taskwiki/store.py +++ b/taskwiki/store.py @@ -22,10 +22,32 @@ def __init__(self, default_rc, default_data, extra_warrior_defs): current_kwargs.update(extra_warrior_defs[key]) self.warriors[key] = TaskWarrior(**current_kwargs) - # Make sure context is not respected in any TaskWarrior for tw in self.warriors.values(): + # Make sure context is not respected in any TaskWarrior tw.overrides.update({'context':''}) + # Read urgency levels once instead of at every task processing. + _urgency_levels = tw.config.get("uda.priority.values") or "H,M,L," + tw._config = None # unset the config cache + _urgency_levels = _urgency_levels.split(",") + _urgency_levels.reverse() + + # The empty urgency (priority:) is considered the zero point. + # Priorities left of it in taskwarrior's conf are considered values + # of insignificance, i.e. they have a negative weight. + zero_point = _urgency_levels.index('') + keys = [i - zero_point for i in range(0, len(_urgency_levels))] + + urgency_levels = {k:_urgency_levels[i] for i, k in enumerate(keys)} + urgency_levels[0] = None + # urgency_levels[None] = None + # For the default urgency levels, this will be: + # {0: None, 1: 'L', 2: 'M', 3: 'H'} + + # Urgency levels need to be stored in the respective TaskWarrior + # instance as they are specific to it. + tw.urgency_levels = urgency_levels + def __getitem__(self, key): try: return self.warriors[key] diff --git a/taskwiki/vwtask.py b/taskwiki/vwtask.py index d725d09e6..c80852a2f 100644 --- a/taskwiki/vwtask.py +++ b/taskwiki/vwtask.py @@ -11,14 +11,6 @@ from taskwiki.short import ShortUUID -def convert_priority_from_tw_format(priority): - return {None: None, 'L': 1, 'M': 2, 'H': 3}[priority] - - -def convert_priority_to_tw_format(priority): - return {0: None, 1: 'L', 2: 'M', 3: 'H'}[priority] - - class VimwikiTask(object): # Lists all data keys that are reflected in Vim representation buffer_keys = ('indent', 'description', 'uuid', 'completed_mark', @@ -106,9 +98,11 @@ def from_line(cls, cache, number): else: self.task['description'] = match.group('text') - self.task['priority'] = convert_priority_to_tw_format( - len(match.group('priority') or [])) # This is either 0,1,2 or 3 - + self.task['priority'] = tw.urgency_levels.get( + 0 if match.group('priority') is None + else len(match.group('priority')) if '!' in match.group('priority') + else -len(match.group('priority')) # if '¡' in match.group('priority') + ) # Also make sure changes in the progress field are reflected if self['completed_mark'] == 'X': self.task['status'] = 'completed' @@ -241,11 +235,13 @@ def task(self, task): @property def priority_from_tw_format(self): - return convert_priority_from_tw_format(self.task['priority']) + return list(self.tw.urgency_levels.keys())[ + list(self.tw.urgency_levels.values()).index(self.task["priority"]) + ] @property def priority_to_tw_format(self): - return convert_priority_to_tw_format(self['priority']) + return self.tw.urgency_levels[self['priority']] def save_to_tw(self): # This method persumes all the dependencies have been created at the @@ -328,6 +324,14 @@ def __str__(self): self['due'].strftime(regexp.DATE_FORMAT) ) if self['due'] else '' + priority_str = ( + " " + "!" * self.priority_from_tw_format + if self["priority"] and self.priority_from_tw_format > 0 + else " " + "¡" * self.priority_from_tw_format + if self["priority"] and self.priority_from_tw_format < 0 + else "" + ) + return ''.join([ self['indent'], '* [', @@ -335,7 +339,7 @@ def __str__(self): '] ', (self['description'].encode('utf-8') if six.PY2 else self['description']) if self['description'] else 'TEXT MISSING?', - ' ' + '!' * self.priority_from_tw_format if self['priority'] else '', + priority_str, due_str, ' #' + self.uuid.vim_representation(self.cache) if self.uuid else '', ]) diff --git a/tests/base.py b/tests/base.py index 92a777171..f6eaacf96 100644 --- a/tests/base.py +++ b/tests/base.py @@ -387,3 +387,32 @@ def reset(self): self.warriors.clear() self.warriors.update({'default': 'default'}) self.buffer_has_authority = True + +class MockCacheWithPriorities(object): + default_urgency_levels = {0: None, 1: 'L', 2: 'M', 3: 'H'} + + # Create a warrior object on the fly + warriors = {"default": type("", (object,), {"urgency_levels": {}},)()} + + buffer_has_authority = True + + def __init__(self, urgency_levels=None): + from taskwiki import store + self.urgency_levels = urgency_levels + self.warriors['default'].urgency_levels = urgency_levels or self.default_urgency_levels + self.buffer = MockBuffer() + self.line = store.LineStore(self) + self.vwtask = dict() + self.task = dict() + self.viewport = dict() + + def reset(self): + self.warriors.clear() + self.warriors.update( + { + "default": type( + "", (object,), {"urgency_levels": self.urgency_levels} + )() + } + ) + self.buffer_has_authority = True diff --git a/tests/test_vwtask_parsing.py b/tests/test_vwtask_parsing.py index 704dfb8b9..bb6572b22 100644 --- a/tests/test_vwtask_parsing.py +++ b/tests/test_vwtask_parsing.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from datetime import datetime -from tests.base import MockVim, MockCache +from tests.base import MockVim, MockCacheWithPriorities import sys from tasklib import local_zone @@ -8,7 +8,7 @@ class TestParsingVimwikiTask(object): def setup(self): self.mockvim = MockVim() - self.cache = MockCache() + self.cache = MockCacheWithPriorities() sys.modules['vim'] = self.mockvim from taskwiki.vwtask import VimwikiTask self.VimwikiTask = VimwikiTask @@ -56,7 +56,7 @@ def test_due_short(self): assert vwtask['priority'] == None assert vwtask['indent'] == '' - def test_priority_low(self): + def test_default_priority_low(self): self.cache.buffer[0] = "* [ ] Semi-Important task !" vwtask = self.VimwikiTask.from_line(self.cache, 0) @@ -64,7 +64,7 @@ def test_priority_low(self): assert vwtask['priority'] == 'L' assert vwtask['uuid'] == None - def test_priority_medium(self): + def test_default_priority_medium(self): self.cache.buffer[0] = "* [ ] Important task !!" vwtask = self.VimwikiTask.from_line(self.cache, 0) @@ -72,7 +72,7 @@ def test_priority_medium(self): assert vwtask['priority'] == 'M' assert vwtask['uuid'] == None - def test_priority_high(self): + def test_default_priority_high(self): self.cache.buffer[0] = "* [ ] Very important task !!!" vwtask = self.VimwikiTask.from_line(self.cache, 0) @@ -81,6 +81,78 @@ def test_priority_high(self): assert vwtask['uuid'] == None assert vwtask['due'] == None + def test_custom_priority_0(self): + self.cache = MockCacheWithPriorities({ + -2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H' + }) + self.cache.buffer[0] = "* [ ] Very important task ¡¡" + vwtask = self.VimwikiTask.from_line(self.cache, 0) + + assert vwtask['description'] == u"Very important task" + assert vwtask['priority'] == 0 + assert vwtask['uuid'] == None + assert vwtask['due'] == None + + def test_custom_priority_L(self): + self.cache = MockCacheWithPriorities({ + -2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H' + }) + self.cache.buffer[0] = "* [ ] Very important task ¡" + vwtask = self.VimwikiTask.from_line(self.cache, 0) + + assert vwtask['description'] == u"Very important task" + assert vwtask['priority'] == 'L' + assert vwtask['uuid'] == None + assert vwtask['due'] == None + + def test_custom_priority_none(self): + self.cache = MockCacheWithPriorities({ + -2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H' + }) + self.cache.buffer[0] = "* [ ] Very important task" + vwtask = self.VimwikiTask.from_line(self.cache, 0) + + assert vwtask['description'] == u"Very important task" + assert vwtask['priority'] == None + assert vwtask['uuid'] == None + assert vwtask['due'] == None + + def test_custom_priority_M(self): + self.cache = MockCacheWithPriorities({ + -2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H' + }) + self.cache.buffer[0] = "* [ ] Very important task !" + vwtask = self.VimwikiTask.from_line(self.cache, 0) + + assert vwtask['description'] == u"Very important task" + assert vwtask['priority'] == 'M' + assert vwtask['uuid'] == None + assert vwtask['due'] == None + + def test_custom_priority_H(self): + self.cache = MockCacheWithPriorities({ + -2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H' + }) + self.cache.buffer[0] = "* [ ] Very important task !!" + vwtask = self.VimwikiTask.from_line(self.cache, 0) + + assert vwtask['description'] == u"Very important task" + assert vwtask['priority'] == 'H' + assert vwtask['uuid'] == None + assert vwtask['due'] == None + + def test_custom_priority_no_three_exclamations(self): + self.cache = MockCacheWithPriorities({ + -2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H' + }) + self.cache.buffer[0] = "* [ ] Very important task !!!" + vwtask = self.VimwikiTask.from_line(self.cache, 0) + + assert vwtask['description'] == u"Very important task" + assert vwtask['priority'] == None + assert vwtask['uuid'] == None + assert vwtask['due'] == None + def test_priority_and_due(self): self.cache.buffer[0] = "* [ ] Due today !!! (2015-08-08)" vwtask = self.VimwikiTask.from_line(self.cache, 0)