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
  5. should 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. )