event.go

  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// Keystroke returns the keystroke representation of the [Key]. While less type
135// safe than looking at the individual fields, it will usually be more
136// convenient and readable to use this method when matching against keys.
137//
138// Note that modifier keys are always printed in the following order:
139//   - ctrl
140//   - alt
141//   - shift
142//   - meta
143//   - hyper
144//   - super
145//
146// For example, you'll always see "ctrl+shift+alt+a" and never
147// "shift+ctrl+alt+a".
148func (k KeyPressEvent) Keystroke() string {
149	return Key(k).Keystroke()
150}
151
152// Key returns the underlying key event. This is a syntactic sugar for casting
153// the key event to a [Key].
154func (k KeyPressEvent) Key() Key {
155	return Key(k)
156}
157
158// KeyReleaseEvent represents a key release event.
159type KeyReleaseEvent Key
160
161// MatchString returns true if the [Key] matches the given string. The string
162// can be a key name like "enter", "tab", "a", or a printable character like
163// "1" or " ". It can also have combinations of modifiers like "ctrl+a",
164// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
165func (k KeyReleaseEvent) MatchString(s string) bool {
166	return Key(k).MatchString(s)
167}
168
169// MatchStrings returns true if the [Key] matches any of the given strings. The
170// strings can be key names like "enter", "tab", "a", or a printable character
171// like "1" or " ". It can also have combinations of modifiers like "ctrl+a",
172// "shift+enter", "alt+tab", "ctrl+shift+enter", etc.
173// See [Key.MatchString] for more details.
174func (k KeyReleaseEvent) MatchStrings(ss ...string) bool {
175	return Key(k).MatchStrings(ss...)
176}
177
178// String implements [fmt.Stringer] and is quite useful for matching key
179// events. For details, on what this returns see [Key.String].
180func (k KeyReleaseEvent) String() string {
181	return Key(k).String()
182}
183
184// Keystroke returns the keystroke representation of the [Key]. While less type
185// safe than looking at the individual fields, it will usually be more
186// convenient and readable to use this method when matching against keys.
187//
188// Note that modifier keys are always printed in the following order:
189//   - ctrl
190//   - alt
191//   - shift
192//   - meta
193//   - hyper
194//   - super
195//
196// For example, you'll always see "ctrl+shift+alt+a" and never
197// "shift+ctrl+alt+a".
198func (k KeyReleaseEvent) Keystroke() string {
199	return Key(k).Keystroke()
200}
201
202// Key returns the underlying key event. This is a convenience method and
203// syntactic sugar to satisfy the [KeyEvent] interface, and cast the key event to
204// [Key].
205func (k KeyReleaseEvent) Key() Key {
206	return Key(k)
207}
208
209// KeyEvent represents a key event. This can be either a key press or a key
210// release event.
211type KeyEvent interface {
212	fmt.Stringer
213
214	// Text returns the text representation of the key event. This is useful
215	// for matching key events along with [Key.String].
216	// TODO: Use this instead of storing Text in the [Key] struct.
217	// Text() string
218
219	// Key returns the underlying key event.
220	Key() Key
221}
222
223// MouseEvent represents a mouse message. This is a generic mouse message that
224// can represent any kind of mouse event.
225type MouseEvent interface {
226	fmt.Stringer
227
228	// Mouse returns the underlying mouse event.
229	Mouse() Mouse
230}
231
232// MouseClickEvent represents a mouse button click event.
233type MouseClickEvent Mouse
234
235// String returns a string representation of the mouse click event.
236func (e MouseClickEvent) String() string {
237	return Mouse(e).String()
238}
239
240// Mouse returns the underlying mouse event. This is a convenience method and
241// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
242// event to [Mouse].
243func (e MouseClickEvent) Mouse() Mouse {
244	return Mouse(e)
245}
246
247// MouseReleaseEvent represents a mouse button release event.
248type MouseReleaseEvent Mouse
249
250// String returns a string representation of the mouse release event.
251func (e MouseReleaseEvent) String() string {
252	return Mouse(e).String()
253}
254
255// Mouse returns the underlying mouse event. This is a convenience method and
256// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
257// event to [Mouse].
258func (e MouseReleaseEvent) Mouse() Mouse {
259	return Mouse(e)
260}
261
262// MouseWheelEvent represents a mouse wheel message event.
263type MouseWheelEvent Mouse
264
265// String returns a string representation of the mouse wheel event.
266func (e MouseWheelEvent) String() string {
267	return Mouse(e).String()
268}
269
270// Mouse returns the underlying mouse event. This is a convenience method and
271// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
272// event to [Mouse].
273func (e MouseWheelEvent) Mouse() Mouse {
274	return Mouse(e)
275}
276
277// MouseMotionEvent represents a mouse motion event.
278type MouseMotionEvent Mouse
279
280// String returns a string representation of the mouse motion event.
281func (e MouseMotionEvent) String() string {
282	m := Mouse(e)
283	if m.Button != 0 {
284		return m.String() + "+motion"
285	}
286	return m.String() + "motion"
287}
288
289// Mouse returns the underlying mouse event. This is a convenience method and
290// syntactic sugar to satisfy the [MouseEvent] interface, and cast the mouse
291// event to [Mouse].
292func (e MouseMotionEvent) Mouse() Mouse {
293	return Mouse(e)
294}
295
296// CursorPositionEvent represents a cursor position event. Where X is the
297// zero-based column and Y is the zero-based row.
298type CursorPositionEvent image.Point
299
300// FocusEvent represents a terminal focus event.
301// This occurs when the terminal gains focus.
302type FocusEvent struct{}
303
304// BlurEvent represents a terminal blur event.
305// This occurs when the terminal loses focus.
306type BlurEvent struct{}
307
308// DarkColorSchemeEvent is sent when the operating system is using a dark color
309// scheme. This is typically used to notify applications of the current or new
310// system color scheme.
311type DarkColorSchemeEvent struct{}
312
313// LightColorSchemeEvent is sent when the operating system is using a light color
314// scheme. This is typically used to notify applications of the current or new
315// system color scheme.
316type LightColorSchemeEvent struct{}
317
318// PasteEvent is an message that is emitted when a terminal receives pasted text
319// using bracketed-paste.
320type PasteEvent string
321
322// PasteStartEvent is an message that is emitted when the terminal starts the
323// bracketed-paste text.
324type PasteStartEvent struct{}
325
326// PasteEndEvent is an message that is emitted when the terminal ends the
327// bracketed-paste text.
328type PasteEndEvent struct{}
329
330// TerminalVersionEvent is a message that represents the terminal version.
331type TerminalVersionEvent string
332
333// ModifyOtherKeysEvent represents a modifyOtherKeys event.
334//
335//	0: disable
336//	1: enable mode 1
337//	2: enable mode 2
338//
339// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
340// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
341type ModifyOtherKeysEvent uint8
342
343// KittyGraphicsEvent represents a Kitty Graphics response event.
344//
345// See https://sw.kovidgoyal.net/kitty/graphics-protocol/
346type KittyGraphicsEvent struct {
347	Options kitty.Options
348	Payload []byte
349}
350
351// KittyEnhancementsEvent represents a Kitty enhancements event.
352type KittyEnhancementsEvent int
353
354// Contains reports whether m contains the given enhancements.
355func (e KittyEnhancementsEvent) Contains(enhancements int) bool {
356	return int(e)&enhancements == enhancements
357}
358
359// PrimaryDeviceAttributesEvent is an event that represents the terminal
360// primary device attributes.
361//
362// Common attributes include:
363//   - 1	132 columns
364//   - 2	Printer port
365//   - 4	Sixel
366//   - 6	Selective erase
367//   - 7	Soft character set (DRCS)
368//   - 8	User-defined keys (UDKs)
369//   - 9	National replacement character sets (NRCS) (International terminal only)
370//   - 12	Yugoslavian (SCS)
371//   - 15	Technical character set
372//   - 18	Windowing capability
373//   - 21	Horizontal scrolling
374//   - 23	Greek
375//   - 24	Turkish
376//   - 42	ISO Latin-2 character set
377//   - 44	PCTerm
378//   - 45	Soft key map
379//   - 46	ASCII emulation
380//
381// See [ansi.PrimaryDeviceAttributes] for more details.
382type PrimaryDeviceAttributesEvent []int
383
384// ModeReportEvent is a message that represents a mode report event (DECRPM).
385//
386// See: https://vt100.net/docs/vt510-rm/DECRPM.html
387type ModeReportEvent struct {
388	// Mode is the mode number.
389	Mode ansi.Mode
390
391	// Value is the mode value.
392	Value ansi.ModeSetting
393}
394
395// ForegroundColorEvent represents a foreground color event. This event is
396// emitted when the terminal requests the terminal foreground color using
397// [ansi.RequestForegroundColor].
398type ForegroundColorEvent struct{ color.Color }
399
400// String returns the hex representation of the color.
401func (e ForegroundColorEvent) String() string {
402	return colorToHex(e.Color)
403}
404
405// IsDark returns whether the color is dark.
406func (e ForegroundColorEvent) IsDark() bool {
407	return isDarkColor(e.Color)
408}
409
410// BackgroundColorEvent represents a background color event. This event is
411// emitted when the terminal requests the terminal background color using
412// [ansi.RequestBackgroundColor].
413type BackgroundColorEvent struct{ color.Color }
414
415// String returns the hex representation of the color.
416func (e BackgroundColorEvent) String() string {
417	return colorToHex(e)
418}
419
420// IsDark returns whether the color is dark.
421func (e BackgroundColorEvent) IsDark() bool {
422	return isDarkColor(e.Color)
423}
424
425// CursorColorEvent represents a cursor color change event. This event is
426// emitted when the program requests the terminal cursor color using
427// [ansi.RequestCursorColor].
428type CursorColorEvent struct{ color.Color }
429
430// String returns the hex representation of the color.
431func (e CursorColorEvent) String() string {
432	return colorToHex(e)
433}
434
435// IsDark returns whether the color is dark.
436func (e CursorColorEvent) IsDark() bool {
437	return isDarkColor(e)
438}
439
440// WindowOpEvent is a window operation (XTWINOPS) report event. This is used to
441// report various window operations such as reporting the window size or cell
442// size.
443type WindowOpEvent struct {
444	Op   int
445	Args []int
446}
447
448// CapabilityEvent represents a Termcap/Terminfo response event. Termcap
449// responses are generated by the terminal in response to RequestTermcap
450// (XTGETTCAP) requests.
451//
452// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
453type CapabilityEvent string
454
455// ClipboardSelection represents a clipboard selection. The most common
456// clipboard selections are "system" and "primary" and selections.
457type ClipboardSelection = byte
458
459// Clipboard selections.
460const (
461	SystemClipboard  ClipboardSelection = ansi.SystemClipboard
462	PrimaryClipboard ClipboardSelection = ansi.PrimaryClipboard
463)
464
465// ClipboardEvent is a clipboard read message event. This message is emitted when
466// a terminal receives an OSC52 clipboard read message event.
467type ClipboardEvent struct {
468	Content   string
469	Selection ClipboardSelection
470}
471
472// String returns the string representation of the clipboard message.
473func (e ClipboardEvent) String() string {
474	return e.Content
475}
476
477// ignoredEvent represents a sequence event that is ignored by the terminal
478// reader. This is used to ignore certain sequences that can be canceled.
479type ignoredEvent string