1package uv
2
3import (
4 "fmt"
5 "image"
6 "image/color"
7 "strings"
8
9 "github.com/charmbracelet/x/ansi"
10 "github.com/charmbracelet/x/ansi/kitty"
11)
12
13// Event represents an input event that can be received from an input source.
14type Event interface{}
15
16// UnknownEvent represents an unknown event.
17type UnknownEvent string
18
19// String returns a string representation of the unknown event.
20func (e UnknownEvent) String() string {
21 return fmt.Sprintf("%q", string(e))
22}
23
24// UnknownCsiEvent represents an unknown CSI (Control Sequence Introducer) event.
25type UnknownCsiEvent string
26
27// String returns a string representation of the unknown CSI event.
28func (e UnknownCsiEvent) String() string {
29 return fmt.Sprintf("%q", string(e))
30}
31
32// UnknownSs3Event represents an unknown SS3 (Single Shift 3) event.
33type UnknownSs3Event string
34
35// String returns a string representation of the unknown SS3 event.
36func (e UnknownSs3Event) String() string {
37 return fmt.Sprintf("%q", string(e))
38}
39
40// UnknownOscEvent represents an unknown OSC (Operating System Command) event.
41type UnknownOscEvent string
42
43// String returns a string representation of the unknown OSC event.
44func (e UnknownOscEvent) String() string {
45 return fmt.Sprintf("%q", string(e))
46}
47
48// UnknownDcsEvent represents an unknown DCS (Device Control String) event.
49type UnknownDcsEvent string
50
51// String returns a string representation of the unknown DCS event.
52func (e UnknownDcsEvent) String() string {
53 return fmt.Sprintf("%q", string(e))
54}
55
56// UnknownSosEvent represents an unknown SOS (Start of String) event.
57type UnknownSosEvent string
58
59// String returns a string representation of the unknown SOS event.
60func (e UnknownSosEvent) String() string {
61 return fmt.Sprintf("%q", string(e))
62}
63
64// UnknownPmEvent represents an unknown PM (Privacy Message) event.
65type UnknownPmEvent string
66
67// String returns a string representation of the unknown PM event.
68func (e UnknownPmEvent) String() string {
69 return fmt.Sprintf("%q", string(e))
70}
71
72// UnknownApcEvent represents an unknown APC (Application Program Command) event.
73type UnknownApcEvent string
74
75// String returns a string representation of the unknown APC event.
76func (e UnknownApcEvent) String() string {
77 return fmt.Sprintf("%q", string(e))
78}
79
80// MultiEvent represents multiple messages event.
81type MultiEvent []Event
82
83// String returns a string representation of the multiple messages event.
84func (e MultiEvent) String() string {
85 var sb strings.Builder
86 for _, ev := range e {
87 sb.WriteString(fmt.Sprintf("%v\n", ev))
88 }
89 return sb.String()
90}
91
92// WindowSizeEvent represents the window size in cells.
93type WindowSizeEvent Size
94
95// Bounds returns the bounds corresponding to the size.
96func (s WindowSizeEvent) Bounds() Rectangle {
97 return Size(s).Bounds()
98}
99
100// WindowPixelSizeEvent represents the window size in pixels.
101type WindowPixelSizeEvent Size
102
103// Bounds returns the bounds corresponding to the size.
104func (s WindowPixelSizeEvent) Bounds() Rectangle {
105 return Size(s).Bounds()
106}
107
108// KeyPressEvent represents a key press event.
109type KeyPressEvent Key
110
111// MatchString returns true if the [Key] matches the given string. The string
112// can be a key name like "enter", "tab", "a", or a printable character like
113// "1" or " ". It can also have combinations of modifiers like "ctrl+a",
114// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
115func (k KeyPressEvent) MatchString(s string) bool {
116 return Key(k).MatchString(s)
117}
118
119// MatchStrings returns true if the [Key] matches any of the given strings. The
120// strings can be key names like "enter", "tab", "a", or a printable character
121// like "1" or " ". It can also have combinations of modifiers like "ctrl+a",
122// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
123// See [Key.MatchString] for more details.
124func (k KeyPressEvent) MatchStrings(ss ...string) bool {
125 return Key(k).MatchStrings(ss...)
126}
127
128// String implements [fmt.Stringer] and is quite useful for matching key
129// events. For details, on what this returns see [Key.String].
130func (k KeyPressEvent) String() string {
131 return Key(k).String()
132}
133
134// Key returns the underlying key event. This is a syntactic sugar for casting
135// the key event to a [Key].
136func (k KeyPressEvent) Key() Key {
137 return Key(k)
138}
139
140// KeyReleaseEvent represents a key release event.
141type KeyReleaseEvent Key
142
143// MatchString returns true if the [Key] matches the given string. The string
144// can be a key name like "enter", "tab", "a", or a printable character like
145// "1" or " ". It can also have combinations of modifiers like "ctrl+a",
146// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
147func (k KeyReleaseEvent) MatchString(s string) bool {
148 return Key(k).MatchString(s)
149}
150
151// MatchStrings returns true if the [Key] matches any of the given strings. The
152// strings can be key names like "enter", "tab", "a", or a printable character
153// like "1" or " ". It can also have combinations of modifiers like "ctrl+a",
154// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
155// See [Key.MatchString] for more details.
156func (k KeyReleaseEvent) MatchStrings(ss ...string) bool {
157 return Key(k).MatchStrings(ss...)
158}
159
160// String implements [fmt.Stringer] and is quite useful for matching key
161// events. For details, on what this returns see [Key.String].
162func (k KeyReleaseEvent) String() string {
163 return Key(k).String()
164}
165
166// Key returns the underlying key event. This is a convenience method and
167// syntactic sugar to satisfy the [KeyEvent] interface, and cast the key event to
168// [Key].
169func (k KeyReleaseEvent) Key() Key {
170 return Key(k)
171}
172
173// KeyEvent represents a key event. This can be either a key press or a key
174// release event.
175type KeyEvent interface {
176 fmt.Stringer
177
178 // Text returns the text representation of the key event. This is useful
179 // for matching key events along with [Key.String].
180 // TODO: Use this instead of storing Text in the [Key] struct.
181 // Text() string
182
183 // Key returns the underlying key event.
184 Key() Key
185}
186
187// MouseEvent represents a mouse message. This is a generic mouse message that
188// can represent any kind of mouse event.
189type MouseEvent interface {
190 fmt.Stringer
191
192 // Mouse returns the underlying mouse event.
193 Mouse() Mouse
194}
195
196// MouseClickEvent represents a mouse button click event.
197type MouseClickEvent Mouse
198
199// String returns a string representation of the mouse click event.
200func (e MouseClickEvent) String() string {
201 return Mouse(e).String()
202}
203
204// Mouse returns the underlying mouse event. This is a convenience method and
205// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
206// event to [Mouse].
207func (e MouseClickEvent) Mouse() Mouse {
208 return Mouse(e)
209}
210
211// MouseReleaseEvent represents a mouse button release event.
212type MouseReleaseEvent Mouse
213
214// String returns a string representation of the mouse release event.
215func (e MouseReleaseEvent) String() string {
216 return Mouse(e).String()
217}
218
219// Mouse returns the underlying mouse event. This is a convenience method and
220// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
221// event to [Mouse].
222func (e MouseReleaseEvent) Mouse() Mouse {
223 return Mouse(e)
224}
225
226// MouseWheelEvent represents a mouse wheel message event.
227type MouseWheelEvent Mouse
228
229// String returns a string representation of the mouse wheel event.
230func (e MouseWheelEvent) String() string {
231 return Mouse(e).String()
232}
233
234// Mouse returns the underlying mouse event. This is a convenience method and
235// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
236// event to [Mouse].
237func (e MouseWheelEvent) Mouse() Mouse {
238 return Mouse(e)
239}
240
241// MouseMotionEvent represents a mouse motion event.
242type MouseMotionEvent Mouse
243
244// String returns a string representation of the mouse motion event.
245func (e MouseMotionEvent) String() string {
246 m := Mouse(e)
247 if m.Button != 0 {
248 return m.String() + "+motion"
249 }
250 return m.String() + "motion"
251}
252
253// Mouse returns the underlying mouse event. This is a convenience method and
254// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
255// event to [Mouse].
256func (e MouseMotionEvent) Mouse() Mouse {
257 return Mouse(e)
258}
259
260// CursorPositionEvent represents a cursor position event. Where X is the
261// zero-based column and Y is the zero-based row.
262type CursorPositionEvent image.Point
263
264// FocusEvent represents a terminal focus event.
265// This occurs when the terminal gains focus.
266type FocusEvent struct{}
267
268// BlurEvent represents a terminal blur event.
269// This occurs when the terminal loses focus.
270type BlurEvent struct{}
271
272// DarkColorSchemeEvent is sent when the operating system is using a dark color
273// scheme. This is typically used to notify applications of the current or new
274// system color scheme.
275type DarkColorSchemeEvent struct{}
276
277// LightColorSchemeEvent is sent when the operating system is using a light color
278// scheme. This is typically used to notify applications of the current or new
279// system color scheme.
280type LightColorSchemeEvent struct{}
281
282// PasteEvent is an message that is emitted when a terminal receives pasted text
283// using bracketed-paste.
284type PasteEvent string
285
286// PasteStartEvent is an message that is emitted when the terminal starts the
287// bracketed-paste text.
288type PasteStartEvent struct{}
289
290// PasteEndEvent is an message that is emitted when the terminal ends the
291// bracketed-paste text.
292type PasteEndEvent struct{}
293
294// TerminalVersionEvent is a message that represents the terminal version.
295type TerminalVersionEvent string
296
297// ModifyOtherKeysEvent represents a modifyOtherKeys event.
298//
299// 0: disable
300// 1: enable mode 1
301// 2: enable mode 2
302//
303// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
304// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
305type ModifyOtherKeysEvent uint8
306
307// KittyGraphicsEvent represents a Kitty Graphics response event.
308//
309// See https://sw.kovidgoyal.net/kitty/graphics-protocol/
310type KittyGraphicsEvent struct {
311 Options kitty.Options
312 Payload []byte
313}
314
315// KittyEnhancementsEvent represents a Kitty enhancements event.
316type KittyEnhancementsEvent int
317
318// Contains reports whether m contains the given enhancements.
319func (e KittyEnhancementsEvent) Contains(enhancements int) bool {
320 return int(e)&enhancements == enhancements
321}
322
323// PrimaryDeviceAttributesEvent is an event that represents the terminal
324// primary device attributes.
325//
326// Common attributes include:
327// - 1 132 columns
328// - 2 Printer port
329// - 4 Sixel
330// - 6 Selective erase
331// - 7 Soft character set (DRCS)
332// - 8 User-defined keys (UDKs)
333// - 9 National replacement character sets (NRCS) (International terminal only)
334// - 12 Yugoslavian (SCS)
335// - 15 Technical character set
336// - 18 Windowing capability
337// - 21 Horizontal scrolling
338// - 23 Greek
339// - 24 Turkish
340// - 42 ISO Latin-2 character set
341// - 44 PCTerm
342// - 45 Soft key map
343// - 46 ASCII emulation
344//
345// See [ansi.PrimaryDeviceAttributes] for more details.
346type PrimaryDeviceAttributesEvent []int
347
348// ModeReportEvent is a message that represents a mode report event (DECRPM).
349//
350// See: https://vt100.net/docs/vt510-rm/DECRPM.html
351type ModeReportEvent struct {
352 // Mode is the mode number.
353 Mode ansi.Mode
354
355 // Value is the mode value.
356 Value ansi.ModeSetting
357}
358
359// ForegroundColorEvent represents a foreground color event. This event is
360// emitted when the terminal requests the terminal foreground color using
361// [ansi.RequestForegroundColor].
362type ForegroundColorEvent struct{ color.Color }
363
364// String returns the hex representation of the color.
365func (e ForegroundColorEvent) String() string {
366 return colorToHex(e.Color)
367}
368
369// IsDark returns whether the color is dark.
370func (e ForegroundColorEvent) IsDark() bool {
371 return isDarkColor(e.Color)
372}
373
374// BackgroundColorEvent represents a background color event. This event is
375// emitted when the terminal requests the terminal background color using
376// [ansi.RequestBackgroundColor].
377type BackgroundColorEvent struct{ color.Color }
378
379// String returns the hex representation of the color.
380func (e BackgroundColorEvent) String() string {
381 return colorToHex(e)
382}
383
384// IsDark returns whether the color is dark.
385func (e BackgroundColorEvent) IsDark() bool {
386 return isDarkColor(e.Color)
387}
388
389// CursorColorEvent represents a cursor color change event. This event is
390// emitted when the program requests the terminal cursor color using
391// [ansi.RequestCursorColor].
392type CursorColorEvent struct{ color.Color }
393
394// String returns the hex representation of the color.
395func (e CursorColorEvent) String() string {
396 return colorToHex(e)
397}
398
399// IsDark returns whether the color is dark.
400func (e CursorColorEvent) IsDark() bool {
401 return isDarkColor(e)
402}
403
404// WindowOpEvent is a window operation (XTWINOPS) report event. This is used to
405// report various window operations such as reporting the window size or cell
406// size.
407type WindowOpEvent struct {
408 Op int
409 Args []int
410}
411
412// CapabilityEvent represents a Termcap/Terminfo response event. Termcap
413// responses are generated by the terminal in response to RequestTermcap
414// (XTGETTCAP) requests.
415//
416// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
417type CapabilityEvent string
418
419// ClipboardSelection represents a clipboard selection. The most common
420// clipboard selections are "system" and "primary" and selections.
421type ClipboardSelection = byte
422
423// Clipboard selections.
424const (
425 SystemClipboard ClipboardSelection = ansi.SystemClipboard
426 PrimaryClipboard ClipboardSelection = ansi.PrimaryClipboard
427)
428
429// ClipboardEvent is a clipboard read message event. This message is emitted when
430// a terminal receives an OSC52 clipboard read message event.
431type ClipboardEvent struct {
432 Content string
433 Selection ClipboardSelection
434}
435
436// String returns the string representation of the clipboard message.
437func (e ClipboardEvent) String() string {
438 return e.Content
439}
440
441// ignoredEvent represents a sequence event that is ignored by the terminal
442// reader. This is used to ignore certain sequences that can be canceled.
443type ignoredEvent string