feat: add refile heading

This commit is contained in:
Lyz 2025-01-26 12:03:47 +01:00
parent 8280949f23
commit 8ecccb8b24
No known key found for this signature in database
GPG Key ID: 6C7D7C1612CDE02F
2 changed files with 226 additions and 1 deletions

View File

@ -329,7 +329,7 @@ class Headline:
closed: Optional[Time] = None,
):
self.start_line = start_line
self.depth = depth
self._depth = depth
self.orig = orig
self.properties = properties
self.keywords = keywords
@ -762,6 +762,16 @@ class Headline:
pass
self._state = new_state
@property
def depth(self):
return self._depth
@depth.setter
def depth(self, value):
self._depth = value
for child in self.children:
child.depth = value + 1
@property
def clock(self):
times = []
@ -1066,6 +1076,38 @@ class Headline:
self.children.append(headline)
return headline
def refile(
self, destination: Union["Headline", OrgDoc], top: bool = False
) -> Union["Headline", OrgDoc]:
"""Refile this headline to a new destination.
Args:
destination: The headline to which this headline will be moved
top: Whether to append to bottom or insert at top of destination's children
Returns:
The destination headline
"""
# Remove from the parent
if self.parent:
if isinstance(self.parent, Headline):
self.parent.children.remove(self)
else:
self.parent.headlines.remove(self)
# Add ourselves to the destination
if top:
destination.children.insert(0, self)
else:
destination.children.append(self)
# Adjust the depth
self.depth = destination.depth + 1
# Adjust our parent
self.parent = destination
return destination
RawLine = collections.namedtuple("RawLine", ("linenum", "line"))
Keyword = collections.namedtuple(
@ -2366,6 +2408,24 @@ class OrgDoc:
def shallow_tags(self) -> list[str]:
return self.tags
@property
def depth(self):
"""
Attribute to be compatible with the signature of the Headlines.
Useful when doing operations across the headline hierarchy
"""
return 0
@property
def children(self):
"""
Attribute to be compatible with the signature of the Headlines.
Useful when doing operations across the headline hierarchy
"""
return self.headlines
## Querying
def get_links(self):
for headline in self.headlines:

View File

@ -1024,6 +1024,171 @@ class TestSerde(unittest.TestCase):
self.assertEqual(dumps(doc), "* TODO First entry")
def test_refile_headline_down_to_bottom(self) -> None:
orig = """* Source Headline
** Child of Source
* Destination Headline
** Existing Child"""
doc = loads(orig)
source_headline = doc.headlines[0]
destination_headline = doc.headlines[1]
result = source_headline.refile(destination_headline)
assert result == destination_headline
assert source_headline.parent == destination_headline
assert source_headline in destination_headline.children
assert destination_headline.children[-1] == source_headline
assert (
dumps(doc)
== """* Destination Headline
** Existing Child
** Source Headline
*** Child of Source"""
)
def test_refile_headline_down_to_top(self) -> None:
orig = """* Source Headline
** Child of Source
* Destination Headline
** Existing Child"""
doc = loads(orig)
source_headline = doc.headlines[0]
destination_headline = doc.headlines[1]
result = source_headline.refile(destination_headline, top=True)
assert result == destination_headline
assert source_headline.parent == destination_headline
assert source_headline in destination_headline.children
assert destination_headline.children[0] == source_headline
assert (
dumps(doc)
== """* Destination Headline
** Source Headline
*** Child of Source
** Existing Child"""
)
def test_refile_headline_down_to_existing_child(self) -> None:
orig = """* Source Headline
** Child of Source
* Destination Parent
** Destination Headline"""
doc = loads(orig)
source_headline = doc.headlines[0]
destination_headline = doc.headlines[1]
destination_child = destination_headline.children[0]
result = source_headline.refile(destination_child)
assert result == destination_child
assert source_headline.parent == destination_child
assert source_headline in destination_child.children
assert destination_child.children[-1] == source_headline
assert (
dumps(doc)
== """* Destination Parent
** Destination Headline
*** Source Headline
**** Child of Source"""
)
def test_refile_headline_from_child_to_parent_bottom(self) -> None:
orig = """* Destination Headline
** Existing Child
*** Source Headline
**** Source Child"""
doc = loads(orig)
source_headline = doc.headlines[0].children[0].children[0]
destination_headline = doc.headlines[0]
result = source_headline.refile(destination_headline)
assert result == destination_headline
assert source_headline.parent == destination_headline
assert source_headline in destination_headline.children
assert destination_headline.children[-1] == source_headline
assert (
dumps(doc)
== """* Destination Headline
** Existing Child
** Source Headline
*** Source Child"""
)
def test_refile_headline_from_child_to_parent_top(self) -> None:
orig = """* Destination Headline
** Existing Child
*** Source Headline
**** Source Child"""
doc = loads(orig)
source_headline = doc.headlines[0].children[0].children[0]
destination_headline = doc.headlines[0]
result = source_headline.refile(destination_headline, top=True)
assert result == destination_headline
assert source_headline.parent == destination_headline
assert source_headline in destination_headline.children
assert destination_headline.children[0] == source_headline
assert (
dumps(doc)
== """* Destination Headline
** Source Headline
*** Source Child
** Existing Child"""
)
def test_refile_headline_from_child_to_first_level_at_bottom(self) -> None:
orig = """* Destination Headline
** Existing Child
*** Source Headline
**** Source Child"""
doc = loads(orig)
source_headline = doc.headlines[0].children[0].children[0]
destination_headline = doc.headlines[0].parent
result = source_headline.refile(destination_headline)
assert result == destination_headline
assert source_headline.parent == destination_headline
assert source_headline in destination_headline.children
assert destination_headline.children[-1] == source_headline
assert (
dumps(doc)
== """* Destination Headline
** Existing Child
* Source Headline
** Source Child"""
)
def test_refile_headline_from_child_to_first_level_at_top(self) -> None:
orig = """* Destination Headline
** Existing Child
*** Source Headline
**** Source Child"""
doc = loads(orig)
source_headline = doc.headlines[0].children[0].children[0]
destination_headline = doc.headlines[0].parent
result = source_headline.refile(destination_headline, top=True)
assert result == destination_headline
assert source_headline.parent == destination_headline
assert source_headline in destination_headline.children
assert destination_headline.children[0] == source_headline
assert (
dumps(doc)
== """* Source Headline
** Source Child
* Destination Headline
** Existing Child"""
)
def print_tree(tree, indentation=0, headline=None):
for element in tree: