escape_sequences.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. r"""
  2. Terminal escape sequence patterns.
  3. This module provides regex patterns for matching terminal escape sequences. All patterns match
  4. sequences that begin with ESC (\\x1b). Before calling re.match with these patterns, callers should
  5. first check that the character at the current position is ESC for optimal performance.
  6. """
  7. # std imports
  8. import re
  9. # Zero-width escape sequences (SGR, OSC, CSI, etc.). This table, like INDETERMINATE_EFFECT_SEQUENCE,
  10. # originated from the 'blessed' library.
  11. ZERO_WIDTH_PATTERN = re.compile(
  12. # CSI sequences
  13. r'\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]|'
  14. # OSC sequences
  15. r'\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|'
  16. # APC sequences
  17. r'\x1b_[^\x1b\x07]*(?:\x07|\x1b\\)|'
  18. # DCS sequences
  19. r'\x1bP[^\x1b\x07]*(?:\x07|\x1b\\)|'
  20. # PM sequences
  21. r'\x1b\^[^\x1b\x07]*(?:\x07|\x1b\\)|'
  22. # Character set designation
  23. r'\x1b[()].|'
  24. # Fe sequences
  25. r'\x1b[\x40-\x5f]|'
  26. # Fp sequences
  27. r'\x1b[78=>g]'
  28. )
  29. # Cursor right movement: CSI [n] C, parameter may be parsed by width()
  30. CURSOR_RIGHT_SEQUENCE = re.compile(r'\x1b\[(\d*)C')
  31. # Cursor left movement: CSI [n] D, parameter may be parsed by width()
  32. CURSOR_LEFT_SEQUENCE = re.compile(r'\x1b\[(\d*)D')
  33. # Indeterminate effect sequences - raise ValueError in 'strict' mode. The effects of these sequences
  34. # are likely to be undesirable, moving the cursor vertically or to any unknown position, and
  35. # otherwise not managed by the 'width' method of this library.
  36. #
  37. # This table was created initially with code generation by extraction of termcap library with
  38. # techniques used at 'blessed' library runtime for 'xterm', 'alacritty', 'kitty', ghostty',
  39. # 'screen', 'tmux', and others. Then, these common capabilities were merged into the list below.
  40. INDETERMINATE_EFFECT_SEQUENCE = re.compile(
  41. '|'.join(f'(?:{_pattern})' for _pattern in (
  42. r'\x1b\[\d+;\d+r', # change_scroll_region
  43. r'\x1b\[\d*K', # erase_in_line (clr_eol, clr_bol)
  44. r'\x1b\[\d*J', # erase_in_display (clr_eos, erase_display)
  45. r'\x1b\[\d*G', # column_address
  46. r'\x1b\[\d+;\d+H', # cursor_address
  47. r'\x1b\[\d*H', # cursor_home
  48. r'\x1b\[\d*A', # cursor_up
  49. r'\x1b\[\d*B', # cursor_down
  50. r'\x1b\[\d*P', # delete_character
  51. r'\x1b\[\d*M', # delete_line
  52. r'\x1b\[\d*L', # insert_line
  53. r'\x1b\[\d*@', # insert_character
  54. r'\x1b\[\d+X', # erase_chars
  55. r'\x1b\[\d*S', # scroll_up (parm_index)
  56. r'\x1b\[\d*T', # scroll_down (parm_rindex)
  57. r'\x1b\[\d*d', # row_address
  58. r'\x1b\[\?1049[hl]', # alternate screen buffer
  59. r'\x1b\[\?47[hl]', # alternate screen (legacy)
  60. r'\x1b8', # restore_cursor
  61. r'\x1bD', # scroll_forward (index)
  62. r'\x1bM', # scroll_reverse (reverse index)
  63. ))
  64. )