Skip to content

Commit

Permalink
Add support to parse todo timeline
Browse files Browse the repository at this point in the history
The todo parser is now able to read the todo timeline from
comments like in below examples:

  - [ ] Add item
  - [ ] Add item  # 2020-06-30
  - [x] Add item  # 2020-06-30T11:04:55Z

This allows parsing and updating the current format of the
Markdown formatted todo content which has the timeline in
the right hard side comment.

Signed-off-by: Heikki Laaksonen <laaksonen.heikki.j@gmail.com>
  • Loading branch information
heilaaks committed Jul 6, 2020
1 parent c4bd419 commit e0ed75b
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 18 deletions.
40 changes: 23 additions & 17 deletions snippy/content/parsers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,40 @@ class ContentParserBase(object):
"""Base class for text content parser."""

# Regexp patterns.
RE_MATCH_TODO_TIMELINE = re.compile(r'''
RE_TODO_TIMELINE = r"""
No\sTimeline | # Match timeline special string.
Today | # Match timeline special string.
Tomorrow | # Match timeline special string.
\d{4}-\d{2}-\d{2} # Match simplified ISO8601 date.
(?:
No\sTimelin | # Match timeline special string.
Today | # Match timeline special string.
Tomorrow | # Match timeline special string.
\d{4}-\d{2}-\d{2} # Match simplified ISO8601 date.
T # Match simplified ISO8601 date and time separator.
\d{2}\:\d{2}\:\d{2} # Match Simplified ISO8601 time.
(?:
T # Match simplified ISO8601 date and time separator.
\d{2}\:\d{2}\:\d{2} # Match Simplified ISO8601 time.
(?:
[+-]\d{2}\:\d{2} # Match timezone offset.
|
Z # Match UTC timezone.
)
[+-]\d{2}\:\d{2} # Match timezone offset.
|
$
Z # Match UTC timezone.
)
|
$
)
''', re.VERBOSE)
"""

RE_MATCH_TODO_TIMELINE = re.compile(r'''
(?:%s)
''' % RE_TODO_TIMELINE, re.VERBOSE)

RE_CATCH_TODO_ITEMS = re.compile(r'''
\s* # Match optional spaces before item.
[-]*\s* # Match optional hyphen followed by optional space.
[\[]{1} # Match mandatory opening bracket.
(?P<done>[xX\s]{0,1}) # Catch done status.
[\]\s]+ # Match closing bracket for done status.
(?P<item>\s.*) # Catch todo item.
''', re.VERBOSE)
[\]\s]+ # Match closing bracket followed by spaces for done status.
(?P<item>.+?) # Catch todo item.
(?:
\s+[#]{1}\s+ # Match optional timeline which starts with space(s) and a hash.
(?P<timeline>%s) # Catch timeline if it exists.
)?$ # Match optional timeline.
''' % RE_TODO_TIMELINE, re.MULTILINE | re.VERBOSE)

# Defined in subclasses.
REGEXP = {}
Expand Down
5 changes: 4 additions & 1 deletion snippy/content/parsers/mkdn.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,10 @@ def _todo_data(self, text):
match_todo = self.RE_CATCH_TODO_ITEMS.finditer(todo.group('todos'))
if match_todo:
for item in match_todo:
data.append('[{:1s}] {} # {}'.format(item.group('done').strip(), item.group('item').strip(), timeline))
if item.group('timeline'):
data.append('[{:1s}] {} # {}'.format(item.group('done').strip(), item.group('item').strip(), item.group('timeline'))) # noqa pylint: disable=line-too-long
else:
data.append('[{:1s}] {} # {}'.format(item.group('done').strip(), item.group('item').strip(), timeline))
else:
self._logger.debug('parsed todo data: %s', data)
if not match:
Expand Down
76 changes: 76 additions & 0 deletions tests/test_ut_content_parser_mkdn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2090,3 +2090,79 @@ def test_parser_todo_003(self):
assert resource.updated == '2020-07-01T11:23:50.244185+00:00'
assert resource.uuid == '361f7a5c-4863-4ee9-af1c-4f911fe864d1'
assert resource.digest == '15a085e068a8fbc70b239d83150db1fc6cbc6714d993f4936d945ba64f0f364e'

def test_parser_todo_004(self):
"""Test parsing todo.
Test case verifies that parsing TODO from filled template is parsed
correct. The timeline in the comment must not be part of the todo
item.
"""

text = Const.NEWLINE.join((
'# Test todo @snippy',
'',
'>',
'',
'## Todo',
'',
'[ ] Add todo item 1. # No Timeline',
'[ ] Add todo item 2. # No Timeline',
'[ ] Add testing 3 # Today',
'[ ] Add testing 4',
'[ ] Add testing 5 # Today',
'[ ] Add testing 6 # Tomorrow',
'[x] Add tests 7 # 2020-06-30',
'[ ] Add tests 8 # 2020-06-30',
'[x] Add tests 9 # 2020-06-30T11:04:55Z',
'[x] Add tests 10 # 2020-07-30T11:04:55+00:00',
'[x] Add tests 11 # 2020-07-30T11:04:55+00:00',
'',
'## Whiteboard',
'',
'## Meta',
'',
'> category : todo',
'created : 2020-07-01T11:17:34.512824+00:00',
'digest : 9d212abf8b48c8753738eac00eeed79c3f7a3bbb9b094b2aa8ee554195d320d8',
'filename :',
'languages :',
'name :',
'source :',
'tags :',
'updated : 2020-07-01T11:23:50.244185+00:00',
'uuid : 361f7a5c-4863-4ee9-af1c-4f911fe864d1',
'versions :',
'', ))
data = (
'[ ] Add todo item 1. # No Timeline',
'[ ] Add todo item 2. # No Timeline',
'[ ] Add testing 3 # Today',
'[ ] Add testing 4 # No Timeline',
'[ ] Add testing 5 # Today',
'[ ] Add testing 6 # Tomorrow',
'[x] Add tests 7 # 2020-06-30',
'[ ] Add tests 8 # 2020-06-30',
'[x] Add tests 9 # 2020-06-30T11:04:55Z',
'[x] Add tests 10 # 2020-07-30T11:04:55+00:00',
'[x] Add tests 11 # 2020-07-30T11:04:55+00:00',
)
collection = Collection()
Parser(self.TIMESTAMP, text, collection).read_collection()
resource = next(collection.resources())
assert resource.category == Const.TODO
assert resource.data == data
assert resource.brief == 'Test todo'
assert resource.description == ''
assert resource.name == ''
assert resource.groups == ('snippy',)
assert resource.tags == ()
assert resource.links == ()
assert resource.source == ''
assert resource.versions == ()
assert resource.languages == ()
assert resource.filename == ''
assert resource.created == '2020-07-01T11:17:34.512824+00:00'
assert resource.updated == '2020-07-01T11:23:50.244185+00:00'
assert resource.uuid == '361f7a5c-4863-4ee9-af1c-4f911fe864d1'
assert resource.digest == '01c6ca3a21e72a5650fe3b7a128326c0f44dbd013164039698acc984d68b24de'

0 comments on commit e0ed75b

Please sign in to comment.