orgmunge 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orgmunge-0.2.0/README.org → orgmunge-0.2.2/PKG-INFO +49 -15
- orgmunge-0.2.0/PKG-INFO → orgmunge-0.2.2/README.org +32 -31
- {orgmunge-0.2.0 → orgmunge-0.2.2}/pyproject.toml +1 -1
- {orgmunge-0.2.0 → orgmunge-0.2.2}/src/orgmunge/__init__.py +20 -1
- {orgmunge-0.2.0 → orgmunge-0.2.2}/src/orgmunge/classes.py +36 -11
- {orgmunge-0.2.0 → orgmunge-0.2.2}/src/orgmunge/lexer.py +2 -2
- orgmunge-0.2.2/src/orgmunge/parser.out +1912 -0
- {orgmunge-0.2.0 → orgmunge-0.2.2}/src/orgmunge/parser.py +17 -7
- orgmunge-0.2.2/src/orgmunge/parsetab.py +108 -0
- orgmunge-0.2.0/src/orgmunge/parser.out +0 -1793
- orgmunge-0.2.0/src/orgmunge/parsetab.py +0 -176
- {orgmunge-0.2.0 → orgmunge-0.2.2}/LICENSE +0 -0
- {orgmunge-0.2.0 → orgmunge-0.2.2}/src/orgmunge/Untitled Document +0 -0
- {orgmunge-0.2.0 → orgmunge-0.2.2}/src/orgmunge/todos.json +0 -0
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: orgmunge
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Programmatically modify Orgmode documents
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: durableOne
|
|
7
|
+
Author-email: era31asj@gmail.com
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: ply (>=3.11,<4.0)
|
|
15
|
+
Description-Content-Type: text/plain
|
|
16
|
+
|
|
1
17
|
#+title:Orgmunge
|
|
2
18
|
* Motivation and scope
|
|
3
19
|
Orgmunge was born out of the desire to modify Org documents
|
|
@@ -120,21 +136,25 @@ compromising your information. See [[https://github.com/durableOne/redactOrg][re
|
|
|
120
136
|
values. The properties are parsed from the =PROPERTIES= drawer if
|
|
121
137
|
it exists. This attribute can also be set by the user (the value
|
|
122
138
|
supplied must be a dict).
|
|
123
|
-
2. =
|
|
139
|
+
2. =inherited_properties=. Same format as the =properties= dict but
|
|
140
|
+
contains only properties inherited from ancestors.
|
|
141
|
+
3. =tags= returns a list of all tags (those explicitly defined for
|
|
142
|
+
this heading and those inherited)
|
|
143
|
+
4. =headline= returns the heading's headline. This attribute can also
|
|
124
144
|
be set by a user (the value must be a [[*Headline Objects][Headline]] instance).
|
|
125
|
-
|
|
145
|
+
5. =scheduling= is a [[*Scheduling Objects][Scheduling]] object containing information about
|
|
126
146
|
=SCHEDULED/DEADLINE/CLOSED= timestamps of the heading, if any. Can
|
|
127
147
|
also be set by the user (the value must be a Scheduling instance).
|
|
128
|
-
|
|
148
|
+
6. =drawers= is a list of [[*Drawer Objects][Drawer]] objects containing the drawers
|
|
129
149
|
associated with this heading. When you update the heading's
|
|
130
150
|
=properties= attribute, the =PROPERTIES= drawer is updated the next
|
|
131
151
|
time you access it.
|
|
132
|
-
|
|
152
|
+
7. =children= returns a list of Heading objects that are the direct
|
|
133
153
|
children of this heading.
|
|
134
|
-
|
|
154
|
+
8. =parent= returns the parent heading of the current one. If the
|
|
135
155
|
current heading is a top-level heading, the root heading will be
|
|
136
156
|
returned.
|
|
137
|
-
|
|
157
|
+
9. =sibling= returns the sibling heading of the current one that comes
|
|
138
158
|
before it in the tree, if any. The reason this is the sibling
|
|
139
159
|
heading that is formally tracked is because it's the one that
|
|
140
160
|
would adopt the current heading whenever the current heading is
|
|
@@ -143,34 +163,37 @@ compromising your information. See [[https://github.com/durableOne/redactOrg][re
|
|
|
143
163
|
#+begin_src python
|
|
144
164
|
siblings = [c for c in current_heading.parent.children if c is not current_heading]
|
|
145
165
|
#+end_src
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
166
|
+
10. =level= is the heading's level, with 1 being the top level and each
|
|
167
|
+
sub-level after that being incremented by 1 (the heading's level
|
|
168
|
+
is the number of "stars" before its headline).
|
|
149
169
|
- Important methods:
|
|
150
170
|
1. =clocking=. This returns a list of [[*Clocking Objects][Clocking]] objects, parsed
|
|
151
171
|
from the heading's =LOGBOOK= drawer, if any. You can also pass the
|
|
152
172
|
optional boolean parameter =include_children=, which, when True,
|
|
153
173
|
includes clocking information of this heading's children as well.
|
|
154
|
-
2. =
|
|
174
|
+
2. =get_all_properties=. This returns a dict of all properties of the
|
|
175
|
+
heading, whether directly defined or inherited from the heading's
|
|
176
|
+
ancestors. The latest-defined value of a property wins over.
|
|
177
|
+
3. =add_child= accepts a Heading object to add as a child to the
|
|
155
178
|
current heading. The optional boolean parameter =new= should be set
|
|
156
179
|
to =True= when this is a new heading that was created and needs to
|
|
157
180
|
be assigned a parent. It should be set to =False= (default) when
|
|
158
181
|
the addition of a child is due to a promotion/demotion operation.
|
|
159
|
-
|
|
182
|
+
4. =remove_child= accepts a heading object and deletes it from the
|
|
160
183
|
current heading's children if it's a child of the current
|
|
161
184
|
heading.
|
|
162
|
-
|
|
185
|
+
5. =promote= promotes the current heading one level. If the heading has
|
|
163
186
|
children, they would be orphaned so this raises a
|
|
164
187
|
=ValueError=. Technically, Org allows you to have, say, level 3
|
|
165
188
|
headings under a level 1 heading, but =orgmunge= does not allow
|
|
166
189
|
this to make parsing the tree easier.
|
|
167
|
-
|
|
190
|
+
6. =promote_tree= promotes the current heading and all its
|
|
168
191
|
descendants. Use this if the heading you want to promote has
|
|
169
192
|
children.
|
|
170
|
-
|
|
193
|
+
7. =demote= demotes the current heading one level. If the current
|
|
171
194
|
heading has no sibling to adopt it, the demotion attempt fails
|
|
172
195
|
and raises a =ValueError=.
|
|
173
|
-
|
|
196
|
+
8. =demote_tree= is the equivalent of =promote_tree= for demotion.
|
|
174
197
|
*** Headline Objects
|
|
175
198
|
- Important attributes:
|
|
176
199
|
1. =done= is a boolean attribute that determines whether the headline
|
|
@@ -295,6 +318,16 @@ ignored if =exact= is =True=.
|
|
|
295
318
|
Uses =filter_headings= under the hood so will return a generator of
|
|
296
319
|
matching headings.
|
|
297
320
|
|
|
321
|
+
*** Search for Headings by Path
|
|
322
|
+
Use =Org.get_heading_by_path= to search for a heading with the given path:
|
|
323
|
+
#+begin_src python
|
|
324
|
+
Org.get_heading_by_path(path, exact=False, re_flags=0)
|
|
325
|
+
#+end_src
|
|
326
|
+
=path= is a list of heading titles. Each member is interpreted the same
|
|
327
|
+
way the =search_string= argument of =get_headings_by_title= is
|
|
328
|
+
interpreted. This function returns the first heading of the tree that
|
|
329
|
+
matches the given path or =None= if no such heading is found.
|
|
330
|
+
|
|
298
331
|
* License
|
|
299
332
|
#+INCLUDE: ./LICENSE
|
|
300
333
|
|
|
@@ -312,3 +345,4 @@ Thanks to these wonderful people for contributing time and code:
|
|
|
312
345
|
- [[https://github.com/Nalisarc][Nalisarc]]
|
|
313
346
|
- [[https://github.com/ispringle][ispringle]]
|
|
314
347
|
- [[https://github.com/crdoconnor][crdoconnor]]
|
|
348
|
+
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: orgmunge
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: Programmatically modify Orgmode documents
|
|
5
|
-
License: MIT
|
|
6
|
-
Author: durableOne
|
|
7
|
-
Author-email: era31asj@gmail.com
|
|
8
|
-
Requires-Python: >=3.10,<4.0
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Requires-Dist: ply (>=3.11,<4.0)
|
|
14
|
-
Description-Content-Type: text/plain
|
|
15
|
-
|
|
16
1
|
#+title:Orgmunge
|
|
17
2
|
* Motivation and scope
|
|
18
3
|
Orgmunge was born out of the desire to modify Org documents
|
|
@@ -135,21 +120,25 @@ compromising your information. See [[https://github.com/durableOne/redactOrg][re
|
|
|
135
120
|
values. The properties are parsed from the =PROPERTIES= drawer if
|
|
136
121
|
it exists. This attribute can also be set by the user (the value
|
|
137
122
|
supplied must be a dict).
|
|
138
|
-
2. =
|
|
123
|
+
2. =inherited_properties=. Same format as the =properties= dict but
|
|
124
|
+
contains only properties inherited from ancestors.
|
|
125
|
+
3. =tags= returns a list of all tags (those explicitly defined for
|
|
126
|
+
this heading and those inherited)
|
|
127
|
+
4. =headline= returns the heading's headline. This attribute can also
|
|
139
128
|
be set by a user (the value must be a [[*Headline Objects][Headline]] instance).
|
|
140
|
-
|
|
129
|
+
5. =scheduling= is a [[*Scheduling Objects][Scheduling]] object containing information about
|
|
141
130
|
=SCHEDULED/DEADLINE/CLOSED= timestamps of the heading, if any. Can
|
|
142
131
|
also be set by the user (the value must be a Scheduling instance).
|
|
143
|
-
|
|
132
|
+
6. =drawers= is a list of [[*Drawer Objects][Drawer]] objects containing the drawers
|
|
144
133
|
associated with this heading. When you update the heading's
|
|
145
134
|
=properties= attribute, the =PROPERTIES= drawer is updated the next
|
|
146
135
|
time you access it.
|
|
147
|
-
|
|
136
|
+
7. =children= returns a list of Heading objects that are the direct
|
|
148
137
|
children of this heading.
|
|
149
|
-
|
|
138
|
+
8. =parent= returns the parent heading of the current one. If the
|
|
150
139
|
current heading is a top-level heading, the root heading will be
|
|
151
140
|
returned.
|
|
152
|
-
|
|
141
|
+
9. =sibling= returns the sibling heading of the current one that comes
|
|
153
142
|
before it in the tree, if any. The reason this is the sibling
|
|
154
143
|
heading that is formally tracked is because it's the one that
|
|
155
144
|
would adopt the current heading whenever the current heading is
|
|
@@ -158,34 +147,37 @@ compromising your information. See [[https://github.com/durableOne/redactOrg][re
|
|
|
158
147
|
#+begin_src python
|
|
159
148
|
siblings = [c for c in current_heading.parent.children if c is not current_heading]
|
|
160
149
|
#+end_src
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
150
|
+
10. =level= is the heading's level, with 1 being the top level and each
|
|
151
|
+
sub-level after that being incremented by 1 (the heading's level
|
|
152
|
+
is the number of "stars" before its headline).
|
|
164
153
|
- Important methods:
|
|
165
154
|
1. =clocking=. This returns a list of [[*Clocking Objects][Clocking]] objects, parsed
|
|
166
155
|
from the heading's =LOGBOOK= drawer, if any. You can also pass the
|
|
167
156
|
optional boolean parameter =include_children=, which, when True,
|
|
168
157
|
includes clocking information of this heading's children as well.
|
|
169
|
-
2. =
|
|
158
|
+
2. =get_all_properties=. This returns a dict of all properties of the
|
|
159
|
+
heading, whether directly defined or inherited from the heading's
|
|
160
|
+
ancestors. The latest-defined value of a property wins over.
|
|
161
|
+
3. =add_child= accepts a Heading object to add as a child to the
|
|
170
162
|
current heading. The optional boolean parameter =new= should be set
|
|
171
163
|
to =True= when this is a new heading that was created and needs to
|
|
172
164
|
be assigned a parent. It should be set to =False= (default) when
|
|
173
165
|
the addition of a child is due to a promotion/demotion operation.
|
|
174
|
-
|
|
166
|
+
4. =remove_child= accepts a heading object and deletes it from the
|
|
175
167
|
current heading's children if it's a child of the current
|
|
176
168
|
heading.
|
|
177
|
-
|
|
169
|
+
5. =promote= promotes the current heading one level. If the heading has
|
|
178
170
|
children, they would be orphaned so this raises a
|
|
179
171
|
=ValueError=. Technically, Org allows you to have, say, level 3
|
|
180
172
|
headings under a level 1 heading, but =orgmunge= does not allow
|
|
181
173
|
this to make parsing the tree easier.
|
|
182
|
-
|
|
174
|
+
6. =promote_tree= promotes the current heading and all its
|
|
183
175
|
descendants. Use this if the heading you want to promote has
|
|
184
176
|
children.
|
|
185
|
-
|
|
177
|
+
7. =demote= demotes the current heading one level. If the current
|
|
186
178
|
heading has no sibling to adopt it, the demotion attempt fails
|
|
187
179
|
and raises a =ValueError=.
|
|
188
|
-
|
|
180
|
+
8. =demote_tree= is the equivalent of =promote_tree= for demotion.
|
|
189
181
|
*** Headline Objects
|
|
190
182
|
- Important attributes:
|
|
191
183
|
1. =done= is a boolean attribute that determines whether the headline
|
|
@@ -310,6 +302,16 @@ ignored if =exact= is =True=.
|
|
|
310
302
|
Uses =filter_headings= under the hood so will return a generator of
|
|
311
303
|
matching headings.
|
|
312
304
|
|
|
305
|
+
*** Search for Headings by Path
|
|
306
|
+
Use =Org.get_heading_by_path= to search for a heading with the given path:
|
|
307
|
+
#+begin_src python
|
|
308
|
+
Org.get_heading_by_path(path, exact=False, re_flags=0)
|
|
309
|
+
#+end_src
|
|
310
|
+
=path= is a list of heading titles. Each member is interpreted the same
|
|
311
|
+
way the =search_string= argument of =get_headings_by_title= is
|
|
312
|
+
interpreted. This function returns the first heading of the tree that
|
|
313
|
+
matches the given path or =None= if no such heading is found.
|
|
314
|
+
|
|
313
315
|
* License
|
|
314
316
|
#+INCLUDE: ./LICENSE
|
|
315
317
|
|
|
@@ -327,4 +329,3 @@ Thanks to these wonderful people for contributing time and code:
|
|
|
327
329
|
- [[https://github.com/Nalisarc][Nalisarc]]
|
|
328
330
|
- [[https://github.com/ispringle][ispringle]]
|
|
329
331
|
- [[https://github.com/crdoconnor][crdoconnor]]
|
|
330
|
-
|
|
@@ -7,7 +7,7 @@ import platform
|
|
|
7
7
|
from .parser import Parser
|
|
8
8
|
from .lexer import Lexer
|
|
9
9
|
from .classes import *
|
|
10
|
-
from typing import List, Dict, Optional, Generator, Callable
|
|
10
|
+
from typing import List, Dict, Optional, Generator, Callable, Iterable
|
|
11
11
|
|
|
12
12
|
class Org:
|
|
13
13
|
def _parse_todos(self, inp: str) -> Optional[Dict[str, Dict[str, str]]]:
|
|
@@ -164,6 +164,25 @@ class Org:
|
|
|
164
164
|
condition = lambda h: bool(re.search(fr'{search_string}', h.title, flags=re_flags))
|
|
165
165
|
return self.filter_headings(condition)
|
|
166
166
|
|
|
167
|
+
def get_heading_by_path(self, path: List[str], exact: bool = False, re_flags: int = 0) -> Optional[Heading]:
|
|
168
|
+
"""Return a heading by its given path. If exact is True, interpret the given path
|
|
169
|
+
as strings to match node titles exactly; otherwise, interpret them as regexes. If
|
|
170
|
+
no heading matches the given path, return None"""
|
|
171
|
+
if exact:
|
|
172
|
+
condition = lambda heading: heading.title == path[-1]
|
|
173
|
+
else:
|
|
174
|
+
condition = lambda heading: bool(re.search(fr'{path[-1]}', heading.title, flags=re_flags))
|
|
175
|
+
if not path:
|
|
176
|
+
return self.root
|
|
177
|
+
else:
|
|
178
|
+
headings_at_this_level = self.filter_headings(lambda h: h.level == len(path) and condition(h))
|
|
179
|
+
candidates = (h for h in headings_at_this_level
|
|
180
|
+
if h.parent is self.get_heading_by_path(path[:-1], exact=exact, re_flags=re_flags))
|
|
181
|
+
try:
|
|
182
|
+
return next(candidates)
|
|
183
|
+
except StopIteration:
|
|
184
|
+
return None
|
|
185
|
+
|
|
167
186
|
def __repr__(self):
|
|
168
187
|
result = ''
|
|
169
188
|
for keyword in self.metadata:
|
|
@@ -135,7 +135,6 @@ class Priority:
|
|
|
135
135
|
return False
|
|
136
136
|
else:
|
|
137
137
|
return str(self) == str(other)
|
|
138
|
-
|
|
139
138
|
class Headline:
|
|
140
139
|
def __init__(self, todos, level: str, comment: bool = False,
|
|
141
140
|
todo: Optional[str] = None, priority: Optional[str] = None,
|
|
@@ -159,10 +158,10 @@ class Headline:
|
|
|
159
158
|
raise AttributeError("Can't set the 'done' attribute")
|
|
160
159
|
|
|
161
160
|
def _is_done(self):
|
|
162
|
-
if self.todo in self.
|
|
163
|
-
return True
|
|
164
|
-
elif self.todo is None or self.todo in self._todo_states:
|
|
161
|
+
if self.todo is None or self.todo in self._todo_states:
|
|
165
162
|
return False
|
|
163
|
+
elif self.todo in self._done_states:
|
|
164
|
+
return True
|
|
166
165
|
else:
|
|
167
166
|
raise ValueError(f"Uncategorized todo state {self.todo}")
|
|
168
167
|
|
|
@@ -252,7 +251,6 @@ class Headline:
|
|
|
252
251
|
return False
|
|
253
252
|
else:
|
|
254
253
|
return str(self) == str(other)
|
|
255
|
-
|
|
256
254
|
class TimeStamp:
|
|
257
255
|
def __init__(self, timestamp_str: str):
|
|
258
256
|
is_active = re.search(Lexer.ATIMESTAMP, timestamp_str)
|
|
@@ -376,7 +374,6 @@ class TimeStamp:
|
|
|
376
374
|
return False
|
|
377
375
|
else:
|
|
378
376
|
return str(self) == str(other)
|
|
379
|
-
|
|
380
377
|
class Scheduling:
|
|
381
378
|
_closed = None
|
|
382
379
|
_scheduled = None
|
|
@@ -442,7 +439,6 @@ class Scheduling:
|
|
|
442
439
|
return False
|
|
443
440
|
else:
|
|
444
441
|
return str(self) == str(other)
|
|
445
|
-
|
|
446
442
|
class Drawer:
|
|
447
443
|
def __init__(self, drawer_string: str):
|
|
448
444
|
self.name = re.sub(r':', '', drawer_string.split('\n')[0])
|
|
@@ -458,7 +454,6 @@ class Drawer:
|
|
|
458
454
|
return False
|
|
459
455
|
else:
|
|
460
456
|
return str(self) == str(other)
|
|
461
|
-
|
|
462
457
|
class Clocking:
|
|
463
458
|
def __init__(self, start_time: str, end_time: Optional[str] = None):
|
|
464
459
|
self._start_time = dt.strptime(start_time, ORG_TIME_FORMAT)
|
|
@@ -526,7 +521,6 @@ class Clocking:
|
|
|
526
521
|
return False
|
|
527
522
|
else:
|
|
528
523
|
return str(self) == str(other)
|
|
529
|
-
|
|
530
524
|
class Heading():
|
|
531
525
|
def __init__(self, headline: Headline, contents: Tuple[Scheduling, List[Drawer], str]):
|
|
532
526
|
self._headline = headline
|
|
@@ -534,6 +528,7 @@ class Heading():
|
|
|
534
528
|
self._children = []
|
|
535
529
|
self._parent = None
|
|
536
530
|
self._sibling = None
|
|
531
|
+
self._inherited_properties = dict()
|
|
537
532
|
if self.body:
|
|
538
533
|
self.timestamps = [TimeStamp(t[0]) for t in re.findall(fr'({Lexer.ATIMESTAMP}|{Lexer.ITIMESTAMP})', self.body)]
|
|
539
534
|
if self._drawers:
|
|
@@ -567,9 +562,9 @@ class Heading():
|
|
|
567
562
|
def _get_clocking_info(self) -> List[Clocking]:
|
|
568
563
|
if not self.drawers:
|
|
569
564
|
return []
|
|
570
|
-
logbook =
|
|
565
|
+
logbook = self.get_drawer_by_name('LOGBOOK')
|
|
571
566
|
if logbook:
|
|
572
|
-
return [self._parse_clock_line(l) for l in logbook
|
|
567
|
+
return [self._parse_clock_line(l) for l in logbook.contents if re.search(r'^\s*CLOCK:', l)]
|
|
573
568
|
else:
|
|
574
569
|
return []
|
|
575
570
|
|
|
@@ -580,6 +575,27 @@ class Heading():
|
|
|
580
575
|
def _get_properties_string(self) -> str:
|
|
581
576
|
return "\n".join([f":{k}:{' '*7}{v}" for k, v in self.properties.items()])
|
|
582
577
|
|
|
578
|
+
@property
|
|
579
|
+
def inherited_properties(self):
|
|
580
|
+
if not self._inherited_properties:
|
|
581
|
+
if self.parent:
|
|
582
|
+
self._inherited_properties = {**self.parent.inherited_properties, **self.parent.properties}
|
|
583
|
+
return self._inherited_properties
|
|
584
|
+
|
|
585
|
+
@inherited_properties.setter
|
|
586
|
+
def inherited_properties(self, _):
|
|
587
|
+
raise AttributeError("Can't set the inherited properties of a heading")
|
|
588
|
+
|
|
589
|
+
@property
|
|
590
|
+
def tags(self):
|
|
591
|
+
self_tags = self.headline.tags or []
|
|
592
|
+
parent_tags = (self.parent.tags if self.parent else None) or []
|
|
593
|
+
return list(set(self_tags + parent_tags))
|
|
594
|
+
|
|
595
|
+
@tags.setter
|
|
596
|
+
def tags(self, _):
|
|
597
|
+
raise AttributeError("Can't set the tags of a heading, use headline instead.")
|
|
598
|
+
|
|
583
599
|
@property
|
|
584
600
|
def properties(self):
|
|
585
601
|
return self._properties
|
|
@@ -593,6 +609,8 @@ class Heading():
|
|
|
593
609
|
for key in val:
|
|
594
610
|
self._properties[key] = val[key]
|
|
595
611
|
|
|
612
|
+
def get_all_properties(self) -> Dict[str, str]:
|
|
613
|
+
return {**self.inherited_properties, **self.properties}
|
|
596
614
|
|
|
597
615
|
def clocking(self, include_children: bool = False) -> List[Clocking]:
|
|
598
616
|
"Return the clocking information of the given headline and possibly its children."
|
|
@@ -602,6 +620,13 @@ class Heading():
|
|
|
602
620
|
else:
|
|
603
621
|
return own_clocking
|
|
604
622
|
|
|
623
|
+
def get_drawer_by_name(self, name: str) -> Optional[Drawer]:
|
|
624
|
+
"Return the named drawer if it exists, or None if it doesn't"
|
|
625
|
+
try:
|
|
626
|
+
return next(d for d in self.drawers if d.name == name)
|
|
627
|
+
except StopIteration:
|
|
628
|
+
return None
|
|
629
|
+
|
|
605
630
|
@property
|
|
606
631
|
def headline(self):
|
|
607
632
|
return self._headline
|
|
@@ -34,7 +34,7 @@ class Lexer:
|
|
|
34
34
|
|
|
35
35
|
def t_error(t):
|
|
36
36
|
print(f"Illegal character encountered: {t.value[0]}")
|
|
37
|
-
|
|
37
|
+
raise ValueError("Lexer error!")
|
|
38
38
|
|
|
39
39
|
self.todos = todos
|
|
40
40
|
all_todo_keywords = {**todos['todo_states'], **todos['done_states']}
|
|
@@ -94,7 +94,7 @@ class Lexer:
|
|
|
94
94
|
return t
|
|
95
95
|
|
|
96
96
|
def t_SPACE(t):
|
|
97
|
-
r'[
|
|
97
|
+
r'[^\S\r\n]+'
|
|
98
98
|
return t
|
|
99
99
|
|
|
100
100
|
def t_TEXT(t):
|