From 83710a4fc1d45bfd27fd334922f12ce0dd956a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Sun, 20 Dec 2020 12:14:58 +0100 Subject: [PATCH] Support updating ranges with contents with different size. --- org_dom/org_dom.py | 36 +++++++++++++++++------- org_dom/utils.py | 15 ++-------- tests/03-links.org | 4 +++ tests/test_dom.py | 53 +++++++++++++++++++++++++++++++++-- tests/utils/dom_assertions.py | 18 ++++-------- 5 files changed, 89 insertions(+), 37 deletions(-) diff --git a/org_dom/org_dom.py b/org_dom/org_dom.py index 888d989..2ba1ba4 100644 --- a/org_dom/org_dom.py +++ b/org_dom/org_dom.py @@ -76,17 +76,33 @@ def get_tokens(value): class RangeInRaw: - def __init__(self, content, start, end): + def __init__(self, content, start_token, end_token): self._content = content - self._start = start - self._end = end + self._start_id = id(start_token) + self._end_id = id(end_token) - def update_range(self, contents): - if len(contents) == (self._end) - self._start: - for i in range(self._start, self._end): - self._content.contents[i] = contents[i - self._start] + def update_range(self, new_contents): + # Find start token + for start_idx, tok in enumerate(self._content.contents): + if id(tok) == self._start_id: + break else: - raise NotImplementedError() + raise Exception("Start token not found") + + # Find end token + for offset, tok in enumerate(self._content.contents[start_idx:]): + if id(tok) == self._end_id: + break + else: + raise Exception("End token not found") + + # Remove old contents + for i in range(1, offset): + self._content.contents.pop(start_idx + 1) + + # Add new ones + for i, element in enumerate(new_contents): + self._content.contents.insert(start_idx + i + 1, element) def get_links_from_content(content): @@ -99,11 +115,11 @@ def get_links_from_content(content): if isinstance(tok, LinkToken): if tok.tok_type == LinkTokenType.OPEN_LINK: in_link = True - open_link_token = i + 1 + open_link_token = tok elif tok.tok_type == LinkTokenType.OPEN_DESCRIPTION: in_description = True elif tok.tok_type == LinkTokenType.CLOSE: - rng = RangeInRaw(content, open_link_token, i) + rng = RangeInRaw(content, open_link_token, tok) yield Link( "".join(link_value), "".join(link_description) if in_description else None, diff --git a/org_dom/utils.py b/org_dom/utils.py index afa0849..ef507c3 100644 --- a/org_dom/utils.py +++ b/org_dom/utils.py @@ -1,20 +1,9 @@ -from .org_dom import ( - Bold, - Code, - Headline, - Italic, - Line, - RawLine, - Strike, - Text, - Underlined, - Verbatim, -) +from .org_dom import (Bold, Code, Headline, Italic, Line, RawLine, Strike, + Text, Underlined, Verbatim) def get_hl_raw_contents(doc: Headline) -> str: lines = [] - for content in doc.contents: lines.append(get_raw_contents(content)) diff --git a/tests/03-links.org b/tests/03-links.org index cea26fb..0e1c978 100644 --- a/tests/03-links.org +++ b/tests/03-links.org @@ -11,3 +11,7 @@ This is a [[https://codigoparallevar.com/1][web link]]. This is a /italized [[https://codigoparallevar.com/2][web link]]/. + + This is a link with no description to [[* First level]]. + + This is [[id:03-markup-first-level-id][a link to a section by id]]. diff --git a/tests/test_dom.py b/tests/test_dom.py index dfde750..95fd778 100644 --- a/tests/test_dom.py +++ b/tests/test_dom.py @@ -200,12 +200,19 @@ class TestSerde(unittest.TestCase): doc = load(f) links = list(doc.get_links()) - self.assertEqual(len(links), 2) + self.assertEqual(len(links), 4) self.assertEqual(links[0].value, "https://codigoparallevar.com/1") self.assertEqual(links[0].description, "web link") self.assertEqual(links[1].value, "https://codigoparallevar.com/2") self.assertEqual(links[1].description, "web link") + + self.assertEqual(links[2].value, "* First level") + self.assertEqual(links[2].description, None) + + self.assertEqual(links[3].value, "id:03-markup-first-level-id") + self.assertEqual(links[3].description, "a link to a section by id") + ex = Dom( props=[ ("TITLE", "03-Links"), @@ -238,17 +245,34 @@ class TestSerde(unittest.TestCase): ), ".\n", ), + SPAN("\n"), + SPAN( + " This is a link with no description to ", + WEB_LINK(None, "* First level"), + ".\n", + ), + SPAN("\n"), + SPAN( + " This is ", + WEB_LINK( + "a link to a section by id", + "id:03-markup-first-level-id", + ), + ".\n", + ), ], ) ), ) + ex.assert_matches(self, doc) + def test_update_links_file_03(self): with open(os.path.join(DIR, "03-links.org")) as f: doc = load(f) links = list(doc.get_links()) - self.assertEqual(len(links), 2) + self.assertEqual(len(links), 4) self.assertEqual(links[0].value, "https://codigoparallevar.com/1") self.assertEqual(links[0].description, "web link") links[0].value = "https://codigoparallevar.com/1-updated" @@ -259,6 +283,16 @@ class TestSerde(unittest.TestCase): links[1].value = "https://codigoparallevar.com/2-updated" links[1].description = "web link #2 with update" + self.assertEqual(links[2].value, "* First level") + self.assertEqual(links[2].description, None) + links[2].value = "* Non-existent level" + links[2].description = "a description now" + + self.assertEqual(links[3].value, "id:03-markup-first-level-id") + self.assertEqual(links[3].description, "a link to a section by id") + links[3].value = "id:03-markup-non-existent-level-id" + links[3].description = None + ex = Dom( props=[ ("TITLE", "03-Links"), @@ -295,6 +329,21 @@ class TestSerde(unittest.TestCase): ), ".\n", ), + SPAN("\n"), + SPAN( + " This is a link with no description to ", + WEB_LINK("a description now", "* Non-existent level"), + ".\n", + ), + SPAN("\n"), + SPAN( + " This is ", + WEB_LINK( + None, + "id:03-markup-non-existent-level-id", + ), + ".\n", + ), ], ) ), diff --git a/tests/utils/dom_assertions.py b/tests/utils/dom_assertions.py index 35539f5..2494a26 100644 --- a/tests/utils/dom_assertions.py +++ b/tests/utils/dom_assertions.py @@ -2,17 +2,8 @@ import collections import unittest from datetime import datetime -from org_dom import ( - Bold, - Code, - Italic, - Line, - Strike, - Text, - Underlined, - Verbatim, - get_raw_contents, -) +from org_dom import (Bold, Code, Italic, Line, Strike, Text, Underlined, + Verbatim, get_raw_contents) def timestamp_to_datetime(ts): @@ -209,7 +200,10 @@ class WEB_LINK: self.link = link def get_raw(self): - return "[[{}][{}]]".format(self.link, self.text) + if self.text: + return "[[{}][{}]]".format(self.link, self.text) + else: + return "[[{}]]".format(self.link) def assertEqual(self, test_case, other): test_case.assertTrue(isinstance(other, WebLink))