File: terminal-state.go

package info (click to toggle)
kitty 0.45.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 27,476 kB
  • sloc: ansic: 84,285; python: 57,992; objc: 5,432; sh: 1,333; xml: 364; makefile: 144; javascript: 78
file content (201 lines) | stat: -rw-r--r-- 6,068 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>

package loop

import (
	"fmt"
	"strings"

	"github.com/kovidgoyal/kitty"
)

type KeyboardStateBits uint8

const (
	LEGACY_KEYS                     KeyboardStateBits = 0
	DISAMBIGUATE_KEYS                                 = 1
	REPORT_KEY_EVENT_TYPES                            = 2
	REPORT_ALTERNATE_KEYS                             = 4
	REPORT_ALL_KEYS_AS_ESCAPE_CODES                   = 8
	REPORT_TEXT_WITH_KEYS                             = 16
	FULL_KEYBOARD_PROTOCOL                            = DISAMBIGUATE_KEYS | REPORT_ALTERNATE_KEYS | REPORT_ALL_KEYS_AS_ESCAPE_CODES | REPORT_TEXT_WITH_KEYS | REPORT_KEY_EVENT_TYPES
	NO_KEYBOARD_STATE_CHANGE                          = 32
)

const (
	SAVE_CURSOR                   = "\0337"
	RESTORE_CURSOR                = "\0338"
	SAVE_PRIVATE_MODE_VALUES      = "\033[?s"
	RESTORE_PRIVATE_MODE_VALUES   = "\033[?r"
	SAVE_COLORS                   = "\033[#P"
	RESTORE_COLORS                = "\033[#Q"
	DECSACE_DEFAULT_REGION_SELECT = "\033[*x"
	CLEAR_SCREEN                  = "\033[H\033[2J"
)

type CursorShapes uint

const (
	BLOCK_CURSOR     CursorShapes = 1
	UNDERLINE_CURSOR CursorShapes = 3
	BAR_CURSOR       CursorShapes = 5
)

type Mode uint32

const private Mode = 1 << 31

const (
	LNM                              Mode = 20
	IRM                              Mode = 4
	DECKM                            Mode = 1 | private
	DECSCNM                          Mode = 5 | private
	DECOM                            Mode = 6 | private
	DECAWM                           Mode = 7 | private
	DECARM                           Mode = 8 | private
	DECTCEM                          Mode = 25 | private
	MOUSE_BUTTON_TRACKING            Mode = 1000 | private
	MOUSE_MOTION_TRACKING            Mode = 1002 | private
	MOUSE_MOVE_TRACKING              Mode = 1003 | private
	FOCUS_TRACKING                   Mode = 1004 | private
	MOUSE_UTF8_MODE                  Mode = 1005 | private
	MOUSE_SGR_MODE                   Mode = 1006 | private
	MOUSE_URXVT_MODE                 Mode = 1015 | private
	MOUSE_SGR_PIXEL_MODE             Mode = 1016 | private
	ALTERNATE_SCREEN                 Mode = 1049 | private
	BRACKETED_PASTE                  Mode = 2004 | private
	PENDING_UPDATE                   Mode = 2026 | private
	COLOR_SCHEME_CHANGE_NOTIFICATION Mode = 2031 | private
	INBAND_RESIZE_NOTIFICATION       Mode = 2048 | private
	HANDLE_TERMIOS_SIGNALS           Mode = kitty.HandleTermiosSignals | private
)

func (self Mode) escape_code(which string) string {
	num := self
	priv := ""
	if num&private > 0 {
		priv = "?"
		num &^= private
	}
	return fmt.Sprintf("\033[%s%d%s", priv, uint32(num), which)
}

func (self Mode) EscapeCodeToSet() string {
	return self.escape_code("h")
}

func (self Mode) EscapeCodeToReset() string {
	return self.escape_code("l")
}

type MouseTracking uint8

const (
	NO_MOUSE_TRACKING MouseTracking = iota
	BUTTONS_ONLY_MOUSE_TRACKING
	BUTTONS_AND_DRAG_MOUSE_TRACKING
	FULL_MOUSE_TRACKING
)

type TerminalStateOptions struct {
	Alternate_screen, restore_colors bool
	mouse_tracking                   MouseTracking
	kitty_keyboard_mode              KeyboardStateBits
	in_band_resize_notification      bool
	focus_tracking                   bool
	color_scheme_change_notification bool
}

func set_modes(sb *strings.Builder, modes ...Mode) {
	for _, m := range modes {
		sb.WriteString(m.EscapeCodeToSet())
	}
}

func reset_modes(sb *strings.Builder, modes ...Mode) {
	for _, m := range modes {
		sb.WriteString(m.EscapeCodeToReset())
	}
}

func (self *TerminalStateOptions) SetStateEscapeCodes() string {
	var sb strings.Builder
	sb.Grow(256)
	if self.Alternate_screen {
		sb.WriteString(SAVE_CURSOR)
	}
	sb.WriteString(SAVE_PRIVATE_MODE_VALUES)
	if self.restore_colors {
		sb.WriteString(SAVE_COLORS)
	}
	sb.WriteString(DECSACE_DEFAULT_REGION_SELECT)
	reset_modes(&sb,
		IRM, DECKM, DECSCNM, BRACKETED_PASTE,
		MOUSE_BUTTON_TRACKING, MOUSE_MOTION_TRACKING, MOUSE_MOVE_TRACKING, MOUSE_UTF8_MODE, MOUSE_SGR_MODE)
	set_modes(&sb, DECARM, DECAWM, DECTCEM)
	if self.focus_tracking {
		set_modes(&sb, FOCUS_TRACKING)
	}
	if self.in_band_resize_notification {
		set_modes(&sb, INBAND_RESIZE_NOTIFICATION)
	}
	if self.color_scheme_change_notification {
		set_modes(&sb, COLOR_SCHEME_CHANGE_NOTIFICATION)
	}
	if self.Alternate_screen {
		set_modes(&sb, ALTERNATE_SCREEN)
		sb.WriteString(CLEAR_SCREEN)
	}
	switch self.kitty_keyboard_mode {
	case LEGACY_KEYS:
		sb.WriteString("\033[>u")
	case NO_KEYBOARD_STATE_CHANGE:
	default:
		sb.WriteString(fmt.Sprintf("\033[>%du", self.kitty_keyboard_mode))
	}
	if self.mouse_tracking != NO_MOUSE_TRACKING {
		sb.WriteString(MOUSE_SGR_PIXEL_MODE.EscapeCodeToSet())
		switch self.mouse_tracking {
		case BUTTONS_ONLY_MOUSE_TRACKING:
			sb.WriteString(MOUSE_BUTTON_TRACKING.EscapeCodeToSet())
		case BUTTONS_AND_DRAG_MOUSE_TRACKING:
			sb.WriteString(MOUSE_MOTION_TRACKING.EscapeCodeToSet())
		case FULL_MOUSE_TRACKING:
			sb.WriteString(MOUSE_MOVE_TRACKING.EscapeCodeToSet())
		}
	}
	return sb.String()
}

func (self *TerminalStateOptions) ResetStateEscapeCodes() string {
	var sb strings.Builder
	sb.Grow(64)
	if self.kitty_keyboard_mode != NO_KEYBOARD_STATE_CHANGE {
		sb.WriteString("\033[<u")
	}
	if self.Alternate_screen {
		sb.WriteString(ALTERNATE_SCREEN.EscapeCodeToReset())
	} else {
		sb.WriteString(SAVE_CURSOR)
	}
	// Explictly turn off this mode as there are some terminals that dont
	// support restoring all modes and people tend to use the show-key kitten
	// in other terminals. Since I do want to encourage adoption of the kitty
	// keyboard protocol, the extra bytes are worth it in this case.
	if self.in_band_resize_notification {
		reset_modes(&sb, INBAND_RESIZE_NOTIFICATION)
	}
	sb.WriteString(RESTORE_PRIVATE_MODE_VALUES)
	if self.restore_colors {
		sb.WriteString(RESTORE_COLORS)
	}
	sb.WriteString(RESTORE_CURSOR)
	return sb.String()
}

func CursorShape(shape CursorShapes, blink bool) string {
	if !blink {
		shape += 1
	}
	return fmt.Sprintf("\x1b[%d q", shape)
}