terminal-state.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package loop
  3. import (
  4. "fmt"
  5. "strings"
  6. "kitty"
  7. )
  8. type KeyboardStateBits uint8
  9. const (
  10. LEGACY_KEYS KeyboardStateBits = 0
  11. DISAMBIGUATE_KEYS = 1
  12. REPORT_KEY_EVENT_TYPES = 2
  13. REPORT_ALTERNATE_KEYS = 4
  14. REPORT_ALL_KEYS_AS_ESCAPE_CODES = 8
  15. REPORT_TEXT_WITH_KEYS = 16
  16. FULL_KEYBOARD_PROTOCOL = DISAMBIGUATE_KEYS | REPORT_ALTERNATE_KEYS | REPORT_ALL_KEYS_AS_ESCAPE_CODES | REPORT_TEXT_WITH_KEYS | REPORT_KEY_EVENT_TYPES
  17. NO_KEYBOARD_STATE_CHANGE = 32
  18. )
  19. const (
  20. SAVE_CURSOR = "\0337"
  21. RESTORE_CURSOR = "\0338"
  22. SAVE_PRIVATE_MODE_VALUES = "\033[?s"
  23. RESTORE_PRIVATE_MODE_VALUES = "\033[?r"
  24. SAVE_COLORS = "\033[#P"
  25. RESTORE_COLORS = "\033[#Q"
  26. DECSACE_DEFAULT_REGION_SELECT = "\033[*x"
  27. CLEAR_SCREEN = "\033[H\033[2J"
  28. )
  29. type CursorShapes uint
  30. const (
  31. BLOCK_CURSOR CursorShapes = 1
  32. UNDERLINE_CURSOR CursorShapes = 3
  33. BAR_CURSOR CursorShapes = 5
  34. )
  35. type Mode uint32
  36. const private Mode = 1 << 31
  37. const (
  38. LNM Mode = 20
  39. IRM Mode = 4
  40. DECKM Mode = 1 | private
  41. DECSCNM Mode = 5 | private
  42. DECOM Mode = 6 | private
  43. DECAWM Mode = 7 | private
  44. DECARM Mode = 8 | private
  45. DECTCEM Mode = 25 | private
  46. MOUSE_BUTTON_TRACKING Mode = 1000 | private
  47. MOUSE_MOTION_TRACKING Mode = 1002 | private
  48. MOUSE_MOVE_TRACKING Mode = 1003 | private
  49. FOCUS_TRACKING Mode = 1004 | private
  50. MOUSE_UTF8_MODE Mode = 1005 | private
  51. MOUSE_SGR_MODE Mode = 1006 | private
  52. MOUSE_URXVT_MODE Mode = 1015 | private
  53. MOUSE_SGR_PIXEL_MODE Mode = 1016 | private
  54. ALTERNATE_SCREEN Mode = 1049 | private
  55. BRACKETED_PASTE Mode = 2004 | private
  56. PENDING_UPDATE Mode = 2026 | private
  57. INBAND_RESIZE_NOTIFICATION Mode = 2048 | private
  58. HANDLE_TERMIOS_SIGNALS Mode = kitty.HandleTermiosSignals | private
  59. )
  60. func (self Mode) escape_code(which string) string {
  61. num := self
  62. priv := ""
  63. if num&private > 0 {
  64. priv = "?"
  65. num &^= private
  66. }
  67. return fmt.Sprintf("\033[%s%d%s", priv, uint32(num), which)
  68. }
  69. func (self Mode) EscapeCodeToSet() string {
  70. return self.escape_code("h")
  71. }
  72. func (self Mode) EscapeCodeToReset() string {
  73. return self.escape_code("l")
  74. }
  75. type MouseTracking uint8
  76. const (
  77. NO_MOUSE_TRACKING MouseTracking = iota
  78. BUTTONS_ONLY_MOUSE_TRACKING
  79. BUTTONS_AND_DRAG_MOUSE_TRACKING
  80. FULL_MOUSE_TRACKING
  81. )
  82. type TerminalStateOptions struct {
  83. Alternate_screen, restore_colors bool
  84. mouse_tracking MouseTracking
  85. kitty_keyboard_mode KeyboardStateBits
  86. in_band_resize_notification bool
  87. }
  88. func set_modes(sb *strings.Builder, modes ...Mode) {
  89. for _, m := range modes {
  90. sb.WriteString(m.EscapeCodeToSet())
  91. }
  92. }
  93. func reset_modes(sb *strings.Builder, modes ...Mode) {
  94. for _, m := range modes {
  95. sb.WriteString(m.EscapeCodeToReset())
  96. }
  97. }
  98. func (self *TerminalStateOptions) SetStateEscapeCodes() string {
  99. var sb strings.Builder
  100. sb.Grow(256)
  101. if self.Alternate_screen {
  102. sb.WriteString(SAVE_CURSOR)
  103. }
  104. sb.WriteString(SAVE_PRIVATE_MODE_VALUES)
  105. if self.restore_colors {
  106. sb.WriteString(SAVE_COLORS)
  107. }
  108. sb.WriteString(DECSACE_DEFAULT_REGION_SELECT)
  109. reset_modes(&sb,
  110. IRM, DECKM, DECSCNM, BRACKETED_PASTE, FOCUS_TRACKING,
  111. MOUSE_BUTTON_TRACKING, MOUSE_MOTION_TRACKING, MOUSE_MOVE_TRACKING, MOUSE_UTF8_MODE, MOUSE_SGR_MODE)
  112. set_modes(&sb, DECARM, DECAWM, DECTCEM)
  113. if self.in_band_resize_notification {
  114. set_modes(&sb, INBAND_RESIZE_NOTIFICATION)
  115. }
  116. if self.Alternate_screen {
  117. set_modes(&sb, ALTERNATE_SCREEN)
  118. sb.WriteString(CLEAR_SCREEN)
  119. }
  120. switch self.kitty_keyboard_mode {
  121. case LEGACY_KEYS:
  122. sb.WriteString("\033[>u")
  123. case NO_KEYBOARD_STATE_CHANGE:
  124. default:
  125. sb.WriteString(fmt.Sprintf("\033[>%du", self.kitty_keyboard_mode))
  126. }
  127. if self.mouse_tracking != NO_MOUSE_TRACKING {
  128. sb.WriteString(MOUSE_SGR_PIXEL_MODE.EscapeCodeToSet())
  129. switch self.mouse_tracking {
  130. case BUTTONS_ONLY_MOUSE_TRACKING:
  131. sb.WriteString(MOUSE_BUTTON_TRACKING.EscapeCodeToSet())
  132. case BUTTONS_AND_DRAG_MOUSE_TRACKING:
  133. sb.WriteString(MOUSE_MOTION_TRACKING.EscapeCodeToSet())
  134. case FULL_MOUSE_TRACKING:
  135. sb.WriteString(MOUSE_MOVE_TRACKING.EscapeCodeToSet())
  136. }
  137. }
  138. return sb.String()
  139. }
  140. func (self *TerminalStateOptions) ResetStateEscapeCodes() string {
  141. var sb strings.Builder
  142. sb.Grow(64)
  143. if self.kitty_keyboard_mode != NO_KEYBOARD_STATE_CHANGE {
  144. sb.WriteString("\033[<u")
  145. }
  146. if self.Alternate_screen {
  147. sb.WriteString(ALTERNATE_SCREEN.EscapeCodeToReset())
  148. } else {
  149. sb.WriteString(SAVE_CURSOR)
  150. }
  151. sb.WriteString(RESTORE_PRIVATE_MODE_VALUES)
  152. if self.restore_colors {
  153. sb.WriteString(RESTORE_COLORS)
  154. }
  155. sb.WriteString(RESTORE_CURSOR)
  156. return sb.String()
  157. }
  158. func CursorShape(shape CursorShapes, blink bool) string {
  159. if !blink {
  160. shape += 1
  161. }
  162. return fmt.Sprintf("\x1b[%d q", shape)
  163. }