Refactor headline state parsing.
- Add separate function to parse states. - Handle edge case when no `|` is used to split TODO and DONE states. - Add typing to the states to future-proof for handling keyboard shortcuts and actions on state changes.
This commit is contained in:
parent
da2d8c8c6d
commit
b174405c90
@ -9,7 +9,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import cast, Iterator, List, Literal, Optional, Tuple, Union
|
from typing import cast, Iterator, List, Literal, Optional, Tuple, TypedDict, Union
|
||||||
|
|
||||||
from .types import HeadlineDict
|
from .types import HeadlineDict
|
||||||
|
|
||||||
@ -107,6 +107,15 @@ CodeSnippet = collections.namedtuple("CodeSnippet", ("name", "content", "result"
|
|||||||
NON_FINISHED_GROUPS = (type(None), dom.ListGroupNode, dom.ResultsDrawerNode, dom.PropertyDrawerNode)
|
NON_FINISHED_GROUPS = (type(None), dom.ListGroupNode, dom.ResultsDrawerNode, dom.PropertyDrawerNode)
|
||||||
FREE_GROUPS = (dom.CodeBlock,)
|
FREE_GROUPS = (dom.CodeBlock,)
|
||||||
|
|
||||||
|
# States
|
||||||
|
class HeadlineState(TypedDict):
|
||||||
|
# To be extended to handle keyboard shortcuts
|
||||||
|
name: str
|
||||||
|
|
||||||
|
class OrgDocDeclaredStates(TypedDict):
|
||||||
|
not_completed: List[HeadlineState]
|
||||||
|
completed: List[HeadlineState]
|
||||||
|
|
||||||
|
|
||||||
class NonReproducibleDocument(Exception):
|
class NonReproducibleDocument(Exception):
|
||||||
"""
|
"""
|
||||||
@ -1759,16 +1768,16 @@ def parse_headline(hl, doc, parent) -> Headline:
|
|||||||
title = line
|
title = line
|
||||||
is_done = is_todo = False
|
is_done = is_todo = False
|
||||||
for state in doc.todo_keywords or []:
|
for state in doc.todo_keywords or []:
|
||||||
if title.startswith(state + " "):
|
if title.startswith(state['name'] + " "):
|
||||||
hl_state = state
|
hl_state = state
|
||||||
title = title[len(state + " ") :]
|
title = title[len(state['name'] + " ") :]
|
||||||
is_todo = True
|
is_todo = True
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
for state in doc.done_keywords or []:
|
for state in doc.done_keywords or []:
|
||||||
if title.startswith(state + " "):
|
if title.startswith(state['name'] + " "):
|
||||||
hl_state = state
|
hl_state = state
|
||||||
title = title[len(state + " ") :]
|
title = title[len(state['name'] + " ") :]
|
||||||
is_done = True
|
is_done = True
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -1863,29 +1872,53 @@ def dump_delimiters(line: DelimiterLine):
|
|||||||
return (line.linenum, line.line)
|
return (line.linenum, line.line)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_todo_done_keywords(line: str) -> OrgDocDeclaredStates:
|
||||||
|
clean_line = re.sub(r"\([^)]+\)", "", line)
|
||||||
|
if '|' in clean_line:
|
||||||
|
todo_kws, done_kws = clean_line.split("|", 1)
|
||||||
|
has_split = True
|
||||||
|
else:
|
||||||
|
# Standard behavior in this case is: the last state is the one considered as DONE
|
||||||
|
todo_kws = clean_line
|
||||||
|
|
||||||
|
todo_keywords = re.sub(r"\s{2,}", " ", todo_kws.strip()).split()
|
||||||
|
if has_split:
|
||||||
|
done_keywords = re.sub(r"\s{2,}", " ", done_kws.strip()).split()
|
||||||
|
else:
|
||||||
|
done_keywods = [todo_keywords[-1]]
|
||||||
|
todo_keywords = todo_keywords[:-1]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"not_completed": [
|
||||||
|
HeadlineState(name=keyword)
|
||||||
|
for keyword in todo_keywords
|
||||||
|
],
|
||||||
|
"completed": [
|
||||||
|
HeadlineState(name=keyword)
|
||||||
|
for keyword in done_keywords
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class OrgDoc:
|
class OrgDoc:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, headlines, keywords, contents, list_items, structural, properties,
|
self, headlines, keywords, contents, list_items, structural, properties,
|
||||||
environment=BASE_ENVIRONMENT,
|
environment=BASE_ENVIRONMENT,
|
||||||
):
|
):
|
||||||
self.todo_keywords = DEFAULT_TODO_KEYWORDS
|
self.todo_keywords = [HeadlineState(name=kw) for kw in DEFAULT_TODO_KEYWORDS]
|
||||||
self.done_keywords = DEFAULT_DONE_KEYWORDS
|
self.done_keywords = [HeadlineState(name=kw) for kw in DEFAULT_DONE_KEYWORDS]
|
||||||
|
|
||||||
keywords_set_in_file = False
|
keywords_set_in_file = False
|
||||||
for keyword in keywords:
|
for keyword in keywords:
|
||||||
if keyword.key in ("TODO", "SEQ_TODO"):
|
if keyword.key in ("TODO", "SEQ_TODO"):
|
||||||
todo_kws, done_kws = re.sub(r"\([^)]+\)", "", keyword.value).split("|", 1)
|
states = parse_todo_done_keywords(keyword.value)
|
||||||
|
self.todo_keywords, self.done_keywords = states['not_completed'], states['completed']
|
||||||
self.todo_keywords = re.sub(r"\s{2,}", " ", todo_kws.strip()).split()
|
|
||||||
self.done_keywords = re.sub(r"\s{2,}", " ", done_kws.strip()).split()
|
|
||||||
keywords_set_in_file = True
|
keywords_set_in_file = True
|
||||||
|
|
||||||
if not keywords_set_in_file and 'org-todo-keywords' in environment:
|
if not keywords_set_in_file and 'org-todo-keywords' in environment:
|
||||||
# Read keywords from environment
|
# Read keywords from environment
|
||||||
todo_kws, done_kws = re.sub(r"\([^)]+\)", "", environment['org-todo-keywords']).split("|", 1)
|
states = parse_todo_done_keywords(environment['org-todo-keywords'])
|
||||||
|
self.todo_keywords, self.done_keywords = states['not_completed'], states['completed']
|
||||||
self.todo_keywords = re.sub(r"\s{2,}", " ", todo_kws.strip()).split()
|
|
||||||
self.done_keywords = re.sub(r"\s{2,}", " ", done_kws.strip()).split()
|
|
||||||
|
|
||||||
self.keywords: List[Property] = keywords
|
self.keywords: List[Property] = keywords
|
||||||
self.contents: List[RawLine] = contents
|
self.contents: List[RawLine] = contents
|
||||||
@ -1960,7 +1993,7 @@ class OrgDoc:
|
|||||||
|
|
||||||
state = ""
|
state = ""
|
||||||
if headline.state:
|
if headline.state:
|
||||||
state = headline.state + " "
|
state = headline.state['name'] + " "
|
||||||
|
|
||||||
raw_title = token_list_to_raw(headline.title.contents)
|
raw_title = token_list_to_raw(headline.title.contents)
|
||||||
tags_padding = ""
|
tags_padding = ""
|
||||||
|
Loading…
Reference in New Issue
Block a user