diff --git a/pytermgui/markup/parsing.py b/pytermgui/markup/parsing.py index b54d9c12..eadeba43 100644 --- a/pytermgui/markup/parsing.py +++ b/pytermgui/markup/parsing.py @@ -201,20 +201,21 @@ def tokenize_ansi( # pylint: disable=too-many-locals, too-many-branches, too-ma csi = matchobj.groups()[0:2] link_osc = matchobj.groups()[2:4] + if cursor < start: + yield PlainToken(text[cursor:start]) + if link_osc != (None, None): cursor = end uri, label = link_osc yield HLinkToken(uri) yield PlainToken(label) + yield ClearToken("/~") continue full, content = csi - if cursor < start: - yield PlainToken(text[cursor:start]) - cursor = end code = "" @@ -380,6 +381,9 @@ def parse_alias( def parse_clear(token: ClearToken, _: ContextDict, get_full: Callable[[], str]) -> str: """Parses a clearer token.""" + if token.value == "/~": + return "\x1b]8;;\x1b\\" + index = CLEARERS.get(token.value) if index is None: raise MarkupSyntaxError( @@ -513,6 +517,7 @@ def tokens_to_markup(tokens: list[Token]) -> str: markup += f"[{' '.join(tag.markup for tag in tags)}]" markup += token.value + tags = [] else: @@ -704,6 +709,9 @@ def parse_tokens( # pylint: disable=too-many-branches, too-many-locals, too-man if token.value in ("/", "/~"): link = None + if token.value == "/~": + continue + found = False for macro in macros.copy(): if token.targets(macro): diff --git a/pytermgui/regex.py b/pytermgui/regex.py index f39279ea..47c945fd 100644 --- a/pytermgui/regex.py +++ b/pytermgui/regex.py @@ -3,7 +3,7 @@ import re from functools import lru_cache -RE_LINK = re.compile(r"(?:\x1b\]8;;([^\\]*)\x1b\\([^\\]*)\x1b\]8;;\x1b\\)") +RE_LINK = re.compile(r"(?:\x1b\]8;;([^\\]*)\x1b\\([^\\]*?)\x1b\]8;;\x1b\\)") RE_ANSI_NEW = re.compile(rf"(\x1b\[(.*?)[mH])|{RE_LINK.pattern}|(\x1b_G(.*?)\x1b\\)") RE_ANSI = re.compile(r"(?:\x1b\[(.*?)[mH])|(?:\x1b\](.*?)\x1b\\)|(?:\x1b_G(.*?)\x1b\\)") RE_MACRO = re.compile(r"(![a-z0-9_\-]+)(?:\(([\w\/\.?\-=:]+)\))?") diff --git a/tests/test_parser.py b/tests/test_parser.py index e869d180..8ed332eb 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -6,10 +6,18 @@ import pytest -from pytermgui import StyledText, pretty, tim, tokenize_ansi, tokens_to_markup +from pytermgui import ( + StyledText, + pretty, + tim, + tokenize_ansi, + tokens_to_markup, + tokenize_markup, +) from pytermgui.colors import Color, str_to_color from pytermgui.markup import StyledText, Token from pytermgui.markup import tokens as tkns +from pytermgui.markup.parsing import parse_tokens from pytermgui.markup.style_maps import CLEARERS, STYLES @@ -98,6 +106,20 @@ def test_get_markup(self): markup = tim.get_markup(ansi) assert base == markup + def test_mutiline_markup(self): + base = "[141 @61 bold]Hello[/]\nWhat a beautifull day to look a this [~https://example.com]website[/~] !\nOh and this [~https://example.com]website also[/~]\nHave a nice day !" + opti_base = "[141 @61 bold]Hello[/]\nWhat a beautifull day to look a this [~https://example.com]website[/~] !\nOh and this [~https://example.com]website also[/~]\nHave a nice day ![/]" + + tokens = tokenize_markup(base) + ansi = parse_tokens(list(tokens)) + tokens2 = tokenize_ansi(ansi) + markup = tokens_to_markup(list(tokens2)) + assert opti_base == markup + + ansi = tim.parse(base) + markup = tim.get_markup(ansi) + assert opti_base == markup + def test_parse(self): assert ( tim.parse("[141 @61 bold !upper]Hello")