terminal-state.go 4.5 KB

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