From 3ad4f6da1f70dd7a489f5b3448f7f7de433463e6 Mon Sep 17 00:00:00 2001 From: Fede Luzzi Date: Tue, 12 May 2026 13:19:35 -0300 Subject: [PATCH] add utils file --- connpy/utils.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 connpy/utils.py diff --git a/connpy/utils.py b/connpy/utils.py new file mode 100644 index 0000000..d82d92b --- /dev/null +++ b/connpy/utils.py @@ -0,0 +1,47 @@ +import re + +def log_cleaner(data: str) -> str: + """ + Stateless utility to remove ANSI sequences and process cursor movements. + """ + if not data: + return "" + + lines = data.split('\n') + cleaned_lines = [] + + # Regex to capture: ANSI sequences, control characters (\r, \b, etc), and plain text chunks + token_re = re.compile(r'(\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/ ]*[@-~])|\r|\b|\x7f|[\x00-\x1F]|[^\x1B\r\b\x7f\x00-\x1F]+)') + + for line in lines: + buffer = [] + cursor = 0 + + for token in token_re.findall(line): + if token == '\r': + cursor = 0 + elif token in ('\b', '\x7f'): + if cursor > 0: + cursor -= 1 + elif token == '\x1B[D': # Left Arrow + if cursor > 0: + cursor -= 1 + elif token == '\x1B[C': # Right Arrow + if cursor < len(buffer): + cursor += 1 + elif token == '\x1B[K': # Clear to end of line + buffer = buffer[:cursor] + elif token.startswith('\x1B'): + continue + elif len(token) == 1 and ord(token) < 32: + continue + else: + for char in token: + if cursor == len(buffer): + buffer.append(char) + else: + buffer[cursor] = char + cursor += 1 + cleaned_lines.append("".join(buffer)) + + return "\n".join(cleaned_lines).replace('\n\n', '\n').strip()