pytermgui.helpers
Helper methods and functions for pytermgui.
View Source
0"""Helper methods and functions for pytermgui.""" 1 2from __future__ import annotations 3 4from typing import Iterator 5 6from .colors import Color 7from .ansi_interface import reset 8from .parser import markup, TokenType, Token 9 10__all__ = [ 11 "get_applied_sequences", 12 "break_line", 13] 14 15 16def get_applied_sequences(text: str) -> str: 17 """Extracts ANSI sequences from text. 18 19 Args: 20 text: The text to operate on. 21 22 Returns: 23 All sequences found. 24 """ 25 26 tokens: list[Token] = [] 27 reset_char = reset() 28 for token in markup.tokenize_ansi(text): 29 if not token.ttype is TokenType.UNSETTER: 30 tokens.append(token) 31 continue 32 33 assert token.sequence is not None 34 if token.sequence == reset_char: 35 tokens = [] 36 continue 37 38 name = token.name.lstrip("/") 39 for style in tokens.copy(): 40 if name in ["fg", "bg"] and style.ttype is TokenType.COLOR: 41 color = style.data 42 assert isinstance(color, Color) 43 44 if name == "fg" and not color.background: 45 tokens.remove(style) 46 elif name == "bg" and color.background: 47 tokens.remove(style) 48 49 elif style.name == name: 50 tokens.remove(style) 51 52 continue 53 54 return "".join(token.sequence or "" for token in tokens) 55 56 57def break_line( 58 line: str, limit: int, non_first_limit: int | None = None 59) -> Iterator[str]: 60 """Breaks a line into a `list[str]` with maximum `limit` length per line. 61 62 It keeps ongoing ANSI sequences between lines, and inserts a reset sequence 63 at the end of each style-containing line. 64 65 At the moment it splits strings exactly on the limit, and not on word 66 boundaries. That functionality would be preferred, so it will end up being 67 implemented at some point. 68 69 Args: 70 line: The line to split. May or may not contain ANSI sequences. 71 limit: The maximum amount of characters allowed in each line, excluding 72 non-printing sequences. 73 non_first_limit: The limit after the first line. If not given, defaults 74 to `limit`. 75 """ 76 77 used = 0 78 current = "" 79 sequences = "" 80 81 if non_first_limit is None: 82 non_first_limit = limit 83 84 for token in markup.tokenize_ansi(line): 85 if token.sequence is None: 86 assert isinstance(token.data, str) 87 for char in token.data: 88 if char == "\n" or used >= limit: 89 if sequences != "": 90 current += "\x1b[0m" 91 92 yield current 93 94 current = sequences 95 used = 0 96 97 limit = non_first_limit 98 99 if char != "\n": 100 current += char 101 used += 1 102 103 continue 104 105 if token.sequence == "\x1b[0m": 106 sequences = "\x1b[0m" 107 108 if len(current) > 0: 109 current += sequences 110 111 continue 112 113 sequences += token.sequence 114 current += token.sequence 115 116 if current == "": 117 return 118 119 if sequences != "" and not current.endswith("\x1b[0m"): 120 current += "\x1b[0m" 121 122 yield current
View Source
17def get_applied_sequences(text: str) -> str: 18 """Extracts ANSI sequences from text. 19 20 Args: 21 text: The text to operate on. 22 23 Returns: 24 All sequences found. 25 """ 26 27 tokens: list[Token] = [] 28 reset_char = reset() 29 for token in markup.tokenize_ansi(text): 30 if not token.ttype is TokenType.UNSETTER: 31 tokens.append(token) 32 continue 33 34 assert token.sequence is not None 35 if token.sequence == reset_char: 36 tokens = [] 37 continue 38 39 name = token.name.lstrip("/") 40 for style in tokens.copy(): 41 if name in ["fg", "bg"] and style.ttype is TokenType.COLOR: 42 color = style.data 43 assert isinstance(color, Color) 44 45 if name == "fg" and not color.background: 46 tokens.remove(style) 47 elif name == "bg" and color.background: 48 tokens.remove(style) 49 50 elif style.name == name: 51 tokens.remove(style) 52 53 continue 54 55 return "".join(token.sequence or "" for token in tokens)
Extracts ANSI sequences from text.
Args
- text: The text to operate on.
Returns
All sequences found.
#  
def
break_line(
line: str,
limit: int,
non_first_limit: int | None = None
) -> Iterator[str]:
View Source
58def break_line( 59 line: str, limit: int, non_first_limit: int | None = None 60) -> Iterator[str]: 61 """Breaks a line into a `list[str]` with maximum `limit` length per line. 62 63 It keeps ongoing ANSI sequences between lines, and inserts a reset sequence 64 at the end of each style-containing line. 65 66 At the moment it splits strings exactly on the limit, and not on word 67 boundaries. That functionality would be preferred, so it will end up being 68 implemented at some point. 69 70 Args: 71 line: The line to split. May or may not contain ANSI sequences. 72 limit: The maximum amount of characters allowed in each line, excluding 73 non-printing sequences. 74 non_first_limit: The limit after the first line. If not given, defaults 75 to `limit`. 76 """ 77 78 used = 0 79 current = "" 80 sequences = "" 81 82 if non_first_limit is None: 83 non_first_limit = limit 84 85 for token in markup.tokenize_ansi(line): 86 if token.sequence is None: 87 assert isinstance(token.data, str) 88 for char in token.data: 89 if char == "\n" or used >= limit: 90 if sequences != "": 91 current += "\x1b[0m" 92 93 yield current 94 95 current = sequences 96 used = 0 97 98 limit = non_first_limit 99 100 if char != "\n": 101 current += char 102 used += 1 103 104 continue 105 106 if token.sequence == "\x1b[0m": 107 sequences = "\x1b[0m" 108 109 if len(current) > 0: 110 current += sequences 111 112 continue 113 114 sequences += token.sequence 115 current += token.sequence 116 117 if current == "": 118 return 119 120 if sequences != "" and not current.endswith("\x1b[0m"): 121 current += "\x1b[0m" 122 123 yield current
Breaks a line into a list[str]
with maximum limit
length per line.
It keeps ongoing ANSI sequences between lines, and inserts a reset sequence at the end of each style-containing line.
At the moment it splits strings exactly on the limit, and not on word boundaries. That functionality would be preferred, so it will end up being implemented at some point.
Args
- line: The line to split. May or may not contain ANSI sequences.
- limit: The maximum amount of characters allowed in each line, excluding non-printing sequences.
- non_first_limit: The limit after the first line. If not given, defaults
to
limit
.