on main help sign in
chore: update vendors
935e713Ayman Bagabas
vendor/github.com/charmbracelet/bubbletea/v2/.golangci.yml−1
@@ -7,7 +7,6 @@ linters:
7 - exhaustive
7 - exhaustive
8 - goconst
8 - goconst
9 - godot
9 - godot
10− - godox
11 - gomoddirectives
10 - gomoddirectives
12 - goprintffuncname
11 - goprintffuncname
13 - gosec
12 - gosec
vendor/github.com/charmbracelet/bubbletea/v2/README.md−1
@@ -10,7 +10,6 @@
10 <a href="https://github.com/charmbracelet/bubbletea/releases"><img src="https://img.shields.io/github/release/charmbracelet/bubbletea.svg" alt="Latest Release"></a>
10 <a href="https://github.com/charmbracelet/bubbletea/releases"><img src="https://img.shields.io/github/release/charmbracelet/bubbletea.svg" alt="Latest Release"></a>
11 <a href="https://pkg.go.dev/github.com/charmbracelet/bubbletea?tab=doc"><img src="https://godoc.org/github.com/charmbracelet/bubbletea?status.svg" alt="GoDoc"></a>
11 <a href="https://pkg.go.dev/github.com/charmbracelet/bubbletea?tab=doc"><img src="https://godoc.org/github.com/charmbracelet/bubbletea?status.svg" alt="GoDoc"></a>
12 <a href="https://github.com/charmbracelet/bubbletea/actions"><img src="https://github.com/charmbracelet/bubbletea/actions/workflows/build.yml/badge.svg" alt="Build Status"></a>
12 <a href="https://github.com/charmbracelet/bubbletea/actions"><img src="https://github.com/charmbracelet/bubbletea/actions/workflows/build.yml/badge.svg" alt="Build Status"></a>
13− <a href="https://www.phorm.ai/query?projectId=a0e324b6-b706-4546-b951-6671ea60c13f"><img src="https://stuff.charm.sh/misc/phorm-badge.svg" alt="phorm.ai"></a>
14</p>
13</p>
15
14
16The fun, functional and stateful way to build terminal apps. A Go framework
15The fun, functional and stateful way to build terminal apps. A Go framework
vendor/github.com/charmbracelet/bubbletea/v2/cursed_renderer.go+15
@@ -104,6 +104,21 @@ func (s *cursedRenderer) writeString(str string) (int, error) {
104 return s.scr.WriteString(str)
104 return s.scr.WriteString(str)
105}
105}
106
106
107+// resetLinesRendered implements renderer.
108+func (s *cursedRenderer) resetLinesRendered() {
109+ s.mu.Lock()
110+ defer s.mu.Unlock()
111+
112+ if !s.altScreen {
113+ var frameHeight int
114+ if s.lastFrame != nil {
115+ frameHeight = strings.Count(*s.lastFrame, "\n") + 1
116+ }
117+
118+ io.WriteString(s.w, strings.Repeat("\n", max(0, frameHeight-1))) //nolint:errcheck,gosec
119+ }
120+}
121+
107// flush implements renderer.
122// flush implements renderer.
108func (s *cursedRenderer) flush(p *Program) error {
123func (s *cursedRenderer) flush(p *Program) error {
109 s.mu.Lock()
124 s.mu.Lock()
vendor/github.com/charmbracelet/bubbletea/v2/exec.go+4
@@ -114,6 +114,7 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) {
114
114
115 // Execute system command.
115 // Execute system command.
116 if err := c.Run(); err != nil {
116 if err := c.Run(); err != nil {
117+ p.renderer.resetLinesRendered()
117 _ = p.RestoreTerminal() // also try to restore the terminal.
118 _ = p.RestoreTerminal() // also try to restore the terminal.
118 if fn != nil {
119 if fn != nil {
119 go p.Send(fn(err))
120 go p.Send(fn(err))
@@ -121,6 +122,9 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) {
121 return
122 return
122 }
123 }
123
124
125+ // Maintain the existing output from the command
126+ p.renderer.resetLinesRendered()
127+
124 // Have the program re-capture input.
128 // Have the program re-capture input.
125 err := p.RestoreTerminal()
129 err := p.RestoreTerminal()
126 if fn != nil {
130 if fn != nil {
vendor/github.com/charmbracelet/bubbletea/v2/nil_renderer.go+2−1
@@ -67,4 +67,5 @@ func (n nilRenderer) setBackgroundColor(color.Color) {}
67func (n nilRenderer) setWindowTitle(string) {}
67func (n nilRenderer) setWindowTitle(string) {}
68
68
69// hit implements the Renderer interface.
69// hit implements the Renderer interface.
70−func (n nilRenderer) hit(MouseMsg) []Msg { return nil }
70+func (n nilRenderer) hit(MouseMsg) []Msg { return nil }
71+func (n nilRenderer) resetLinesRendered() {}
vendor/github.com/charmbracelet/bubbletea/v2/renderer.go+3
@@ -71,6 +71,9 @@ type renderer interface {
71 repaint()
71 repaint()
72
72
73 writeString(string) (int, error)
73 writeString(string) (int, error)
74+
75+ // resetLinesRendered ensures exec output remains on screen on exit
76+ resetLinesRendered()
74}
77}
75
78
76// repaintMsg forces a full repaint.
79// repaintMsg forces a full repaint.
vendor/github.com/charmbracelet/bubbletea/v2/standard_renderer.go+3
@@ -382,3 +382,6 @@ func (r *standardRenderer) setForegroundColor(c color.Color) {}
382func (r *standardRenderer) setBackgroundColor(c color.Color) {}
382func (r *standardRenderer) setBackgroundColor(c color.Color) {}
383func (r *standardRenderer) setWindowTitle(s string) {}
383func (r *standardRenderer) setWindowTitle(s string) {}
384func (r *standardRenderer) hit(MouseMsg) []Msg { return nil }
384func (r *standardRenderer) hit(MouseMsg) []Msg { return nil }
385+func (r *standardRenderer) resetLinesRendered() {
386+ r.linesRendered = 0
387+}
vendor/github.com/charmbracelet/bubbletea/v2/tea.go+15−6
@@ -1220,13 +1220,22 @@ func (p *Program) recoverFromPanic(r any) {
1220 default:
1220 default:
1221 }
1221 }
1222 p.cancel() // Just in case a previous shutdown has failed.
1222 p.cancel() // Just in case a previous shutdown has failed.
1223− s := strings.ReplaceAll(
1224− fmt.Sprintf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r),
1225− "\n", "\r\n")
1226− fmt.Fprintln(os.Stderr, s)
1227− stack := strings.ReplaceAll(fmt.Sprintf("%s", debug.Stack()), "\n", "\r\n")
1228− fmt.Fprintln(os.Stderr, stack)
1229 p.shutdown(true)
1223 p.shutdown(true)
1224+ // We use "\r\n" to ensure the output is formatted even when restoring the
1225+ // terminal does not work or when raw mode is still active.
1226+ rec := strings.ReplaceAll(fmt.Sprintf("%s", r), "\n", "\r\n")
1227+ fmt.Fprintf(os.Stderr, "Caught panic:\r\n\r\n%s\r\n\r\nRestoring terminal...\r\n\r\n", rec)
1228+ stack := strings.ReplaceAll(fmt.Sprintf("%s\n", debug.Stack()), "\n", "\r\n")
1229+ fmt.Fprint(os.Stderr, stack)
1230+ if v, err := strconv.ParseBool(os.Getenv("TEA_DEBUG")); err == nil && v {
1231+ f, err := os.Create(fmt.Sprintf("bubbletea-panic-%d.log", time.Now().Unix()))
1232+ if err == nil {
1233+ defer f.Close() //nolint:errcheck
1234+ fmt.Fprintln(f, rec) //nolint:errcheck
1235+ fmt.Fprintln(f) //nolint:errcheck
1236+ fmt.Fprintln(f, stack) //nolint:errcheck
1237+ }
1238+ }
1230}
1239}
1231
1240
1232// ReleaseTerminal restores the original terminal state and cancels the input
1241// ReleaseTerminal restores the original terminal state and cancels the input
vendor/github.com/charmbracelet/ultraviolet/event.go+36
@@ -131,6 +131,24 @@ func (k KeyPressEvent) String() string {
131 return Key(k).String()
131 return Key(k).String()
132}
132}
133
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".
148+func (k KeyPressEvent) Keystroke() string {
149+ return Key(k).Keystroke()
150+}
151+
134// Key returns the underlying key event. This is a syntactic sugar for casting
152// Key returns the underlying key event. This is a syntactic sugar for casting
135// the key event to a [Key].
153// the key event to a [Key].
136func (k KeyPressEvent) Key() Key {
154func (k KeyPressEvent) Key() Key {
@@ -163,6 +181,24 @@ func (k KeyReleaseEvent) String() string {
163 return Key(k).String()
181 return Key(k).String()
164}
182}
165
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".
198+func (k KeyReleaseEvent) Keystroke() string {
199+ return Key(k).Keystroke()
200+}
201+
166// Key returns the underlying key event. This is a convenience method and
202// 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
203// syntactic sugar to satisfy the [KeyEvent] interface, and cast the key event to
168// [Key].
204// [Key].
vendor/github.com/charmbracelet/ultraviolet/parse.go+5−3
@@ -748,10 +748,12 @@ func (p *SequenceParser) parseSs3(b []byte) (int, Event) {
748}
748}
749
749
750func (p *SequenceParser) parseOsc(b []byte) (int, Event) {
750func (p *SequenceParser) parseOsc(b []byte) (int, Event) {
751+ defaultKey := func() KeyPressEvent {
751− defaultKey := KeyPressEvent{Code: rune(b[1]), Mod: ModAlt}
752+ return KeyPressEvent{Code: rune(b[1]), Mod: ModAlt}
753+ }
752 if len(b) == 2 && b[0] == ansi.ESC {
754 if len(b) == 2 && b[0] == ansi.ESC {
753 // short cut if this is an alt+] key
755 // short cut if this is an alt+] key
754− return 2, defaultKey
756+ return 2, defaultKey()
755 }
757 }
756
758
757 var i int
759 var i int
@@ -802,7 +804,7 @@ func (p *SequenceParser) parseOsc(b []byte) (int, Event) {
802 case ansi.ESC:
804 case ansi.ESC:
803 if i >= len(b) || b[i] != '\\' {
805 if i >= len(b) || b[i] != '\\' {
804 if cmd == -1 || (start == 0 && end == 2) {
806 if cmd == -1 || (start == 0 && end == 2) {
805− return 2, defaultKey
807+ return 2, defaultKey()
806 }
808 }
807
809
808 // If we don't have a valid ST terminator, then this is a
810 // If we don't have a valid ST terminator, then this is a
vendor/github.com/charmbracelet/ultraviolet/terminal_reader.go+24−19
@@ -55,14 +55,15 @@ type TerminalReader struct {
55 // Windows Console API.
55 // Windows Console API.
56 MouseMode *MouseMode
56 MouseMode *MouseMode
57
57
58− // Timeout is the escape character timeout duration. Most escape sequences
58+ // EscTimeout is the escape character timeout duration. Most escape
59− // start with an escape character [ansi.ESC] and are followed by one or
59+ // sequences start with an escape character [ansi.ESC] and are followed by
60− // more characters. If the next character is not received within this
60+ // one or more characters. If the next character is not received within
61− // timeout, the reader will assume that the escape sequence is complete and
61+ // this timeout, the reader will assume that the escape sequence is
62− // will process the received characters as a complete escape sequence.
62+ // complete and will process the received characters as a complete escape
63+ // sequence.
63 //
64 //
64 // By default, this is set to [DefaultEscTimeout] (50 milliseconds).
65 // By default, this is set to [DefaultEscTimeout] (50 milliseconds).
65− Timeout time.Duration
66+ EscTimeout time.Duration
66
67
67 r io.Reader
68 r io.Reader
68 rd cancelreader.CancelReader
69 rd cancelreader.CancelReader
@@ -85,6 +86,7 @@ type TerminalReader struct {
85 // prevent multiple calls to the Close() method.
86 // prevent multiple calls to the Close() method.
86 closed bool
87 closed bool
87 started bool // started indicates whether the reader has been started.
88 started bool // started indicates whether the reader has been started.
89+ runOnce sync.Once // runOnce is used to ensure that the reader is only started once.
88 close chan struct{} // close is a channel used to signal the reader to close.
90 close chan struct{} // close is a channel used to signal the reader to close.
89 closeOnce sync.Once
91 closeOnce sync.Once
90 notify chan []byte // notify is a channel used to notify the reader of new input events.
92 notify chan []byte // notify is a channel used to notify the reader of new input events.
@@ -113,10 +115,10 @@ type TerminalReader struct {
113// }
115// }
114func NewTerminalReader(r io.Reader, termType string) *TerminalReader {
116func NewTerminalReader(r io.Reader, termType string) *TerminalReader {
115 return &TerminalReader{
117 return &TerminalReader{
116− Timeout: DefaultEscTimeout,
118+ EscTimeout: DefaultEscTimeout,
117− r: r,
119+ r: r,
118− term: termType,
120+ term: termType,
119− lookup: true, // Use lookup table by default.
121+ lookup: true, // Use lookup table by default.
120 }
122 }
121}
123}
122
124
@@ -131,22 +133,20 @@ func (d *TerminalReader) SetLogger(logger Logger) {
131// lookup table for key sequences if it is not already set. This function
133// lookup table for key sequences if it is not already set. This function
132// should be called before reading input events.
134// should be called before reading input events.
133func (d *TerminalReader) Start() (err error) {
135func (d *TerminalReader) Start() (err error) {
134− if d.rd == nil {
135− d.rd, err = newCancelreader(d.r)
136+ d.rd, err = newCancelreader(d.r)
136− if err != nil {
137+ if err != nil {
137− return err
138+ return err
138− }
139 }
139 }
140 if d.table == nil {
140 if d.table == nil {
141 d.table = buildKeysTable(d.Legacy, d.term, d.UseTerminfo)
141 d.table = buildKeysTable(d.Legacy, d.term, d.UseTerminfo)
142 }
142 }
143 d.started = true
143 d.started = true
144 d.esc.Store(false)
144 d.esc.Store(false)
145− d.timeout = time.NewTimer(d.Timeout)
145+ d.timeout = time.NewTimer(d.EscTimeout)
146 d.notify = make(chan []byte)
146 d.notify = make(chan []byte)
147 d.close = make(chan struct{}, 1)
147 d.close = make(chan struct{}, 1)
148 d.closeOnce = sync.Once{}
148 d.closeOnce = sync.Once{}
149− go d.run()
149+ d.runOnce = sync.Once{}
150 return nil
150 return nil
151}
151}
152
152
@@ -194,6 +194,11 @@ func (d *TerminalReader) receiveEvents(ctx context.Context, events chan<- Event)
194 return ErrReaderNotStarted
194 return ErrReaderNotStarted
195 }
195 }
196
196
197+ // Start the reader loop if it hasn't been started yet.
198+ d.runOnce.Do(func() {
199+ go d.run()
200+ })
201+
197 closingFunc := func() error {
202 closingFunc := func() error {
198 // If we're closing, make sure to send any remaining events even if
203 // If we're closing, make sure to send any remaining events even if
199 // they are incomplete.
204 // they are incomplete.
@@ -255,7 +260,7 @@ func (d *TerminalReader) run() {
255 esc := n > 0 && n <= 2 && readBuf[0] == ansi.ESC
260 esc := n > 0 && n <= 2 && readBuf[0] == ansi.ESC
256 if esc {
261 if esc {
257 d.esc.Store(true)
262 d.esc.Store(true)
258− d.timeout.Reset(d.Timeout)
263+ d.timeout.Reset(d.EscTimeout)
259 }
264 }
260
265
261 d.notify <- readBuf[:n]
266 d.notify <- readBuf[:n]
@@ -305,7 +310,7 @@ LOOP:
305 ansi.ESC, ansi.CSI, ansi.OSC, ansi.DCS, ansi.APC, ansi.SOS, ansi.PM,
310 ansi.ESC, ansi.CSI, ansi.OSC, ansi.DCS, ansi.APC, ansi.SOS, ansi.PM,
306 }, d.buf[0]) {
311 }, d.buf[0]) {
307 d.esc.Store(true)
312 d.esc.Store(true)
308− d.timeout.Reset(d.Timeout)
313+ d.timeout.Reset(d.EscTimeout)
309 }
314 }
310 }
315 }
311 // If this is the entire buffer, we can break and assume this
316 // If this is the entire buffer, we can break and assume this
vendor/github.com/charmbracelet/ultraviolet/terminal_reader_windows.go+60−24
@@ -8,6 +8,7 @@ import (
8 "errors"
8 "errors"
9 "fmt"
9 "fmt"
10 "strings"
10 "strings"
11+ "time"
11 "unicode"
12 "unicode"
12 "unicode/utf16"
13 "unicode/utf16"
13 "unicode/utf8"
14 "unicode/utf8"
@@ -22,7 +23,7 @@ import (
22// given event channel.
23// given event channel.
23func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event) error {
24func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event) error {
24 for {
25 for {
25− evs, err := d.handleConInput(readConsoleInput)
26+ evs, err := d.handleConInput()
26 if errors.Is(err, errNotConInputReader) {
27 if errors.Is(err, errNotConInputReader) {
27 return d.receiveEvents(ctx, events)
28 return d.receiveEvents(ctx, events)
28 }
29 }
@@ -41,31 +42,45 @@ func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event)
41
42
42var errNotConInputReader = fmt.Errorf("handleConInput: not a conInputReader")
43var errNotConInputReader = fmt.Errorf("handleConInput: not a conInputReader")
43
44
44−func (d *TerminalReader) handleConInput(
45+func (d *TerminalReader) handleConInput() ([]Event, error) {
45− finput func(windows.Handle, []xwindows.InputRecord) (uint32, error),
46−) ([]Event, error) {
47 cc, ok := d.rd.(*conInputReader)
46 cc, ok := d.rd.(*conInputReader)
48 if !ok {
47 if !ok {
49 return nil, errNotConInputReader
48 return nil, errNotConInputReader
50 }
49 }
51
50
51+ var (
52+ events []xwindows.InputRecord
53+ err error
54+ )
55+ for {
52− // read up to 256 events, this is to allow for sequences events reported as
56+ // Peek up to 256 events, this is to allow for sequences events reported as
53− // key events.
57+ // key events.
54− var events [256]xwindows.InputRecord
58+ events, err = peekNConsoleInputs(cc.conin, 256)
55− _, err := finput(cc.conin, events[:])
56− if err != nil {
57 if cc.isCanceled() {
59 if cc.isCanceled() {
58 return nil, cancelreader.ErrCanceled
60 return nil, cancelreader.ErrCanceled
59 }
61 }
62+ if err != nil {
63+ return nil, fmt.Errorf("peek coninput events: %w", err)
64+ }
65+ if len(events) > 0 {
66+ break
67+ }
68+
69+ // Sleep for a bit to avoid busy waiting.
70+ time.Sleep(10 * time.Millisecond)
71+ }
72+
73+ events, err = readNConsoleInputs(cc.conin, uint32(len(events)))
74+ if cc.isCanceled() {
75+ return nil, cancelreader.ErrCanceled
76+ }
77+ if err != nil {
60 return nil, fmt.Errorf("read coninput events: %w", err)
78 return nil, fmt.Errorf("read coninput events: %w", err)
61 }
79 }
62
80
63 var evs []Event
81 var evs []Event
64 for _, event := range events {
82 for _, event := range events {
65 if e := d.SequenceParser.parseConInputEvent(event, &d.keyState, d.MouseMode, d.logger); e != nil {
83 if e := d.SequenceParser.parseConInputEvent(event, &d.keyState, d.MouseMode, d.logger); e != nil {
66− if e == nil {
67− continue
68− }
69 if multi, ok := e.(MultiEvent); ok {
84 if multi, ok := e.(MultiEvent); ok {
70 if d.logger != nil {
85 if d.logger != nil {
71 for _, ev := range multi {
86 for _, ev := range multi {
@@ -223,6 +238,16 @@ func highWord(data uint32) uint16 {
223 return uint16((data & 0xFFFF0000) >> 16) //nolint:gosec
238 return uint16((data & 0xFFFF0000) >> 16) //nolint:gosec
224}
239}
225
240
241+func readNConsoleInputs(console windows.Handle, maxEvents uint32) ([]xwindows.InputRecord, error) {
242+ if maxEvents == 0 {
243+ return nil, fmt.Errorf("maxEvents cannot be zero")
244+ }
245+
246+ records := make([]xwindows.InputRecord, maxEvents)
247+ n, err := readConsoleInput(console, records)
248+ return records[:n], err
249+}
250+
226func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
251func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
227 if len(inputRecords) == 0 {
252 if len(inputRecords) == 0 {
228 return 0, fmt.Errorf("size of input record buffer cannot be zero")
253 return 0, fmt.Errorf("size of input record buffer cannot be zero")
@@ -235,7 +260,6 @@ func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecor
235 return read, err //nolint:wrapcheck
260 return read, err //nolint:wrapcheck
236}
261}
237
262
238−//nolint:unused
239func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
263func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
240 if len(inputRecords) == 0 {
264 if len(inputRecords) == 0 {
241 return 0, fmt.Errorf("size of input record buffer cannot be zero")
265 return 0, fmt.Errorf("size of input record buffer cannot be zero")
@@ -248,6 +272,16 @@ func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecor
248 return read, err //nolint:wrapcheck
272 return read, err //nolint:wrapcheck
249}
273}
250
274
275+func peekNConsoleInputs(console windows.Handle, maxEvents uint32) ([]xwindows.InputRecord, error) {
276+ if maxEvents == 0 {
277+ return nil, fmt.Errorf("maxEvents cannot be zero")
278+ }
279+
280+ records := make([]xwindows.InputRecord, maxEvents)
281+ n, err := peekConsoleInput(console, records)
282+ return records[:n], err
283+}
284+
251// parseWin32InputKeyEvent parses a single key event from either the Windows
285// parseWin32InputKeyEvent parses a single key event from either the Windows
252// Console API or win32-input-mode events. When state is nil, it means this is
286// Console API or win32-input-mode events. When state is nil, it means this is
253// an event from win32-input-mode. Otherwise, it's a key event from the Windows
287// an event from win32-input-mode. Otherwise, it's a key event from the Windows
@@ -506,7 +540,9 @@ func (p *SequenceParser) parseWin32InputKeyEvent(state *win32InputState, vkc uin
506
540
507 var text string
541 var text string
508 keyCode := baseCode
542 keyCode := baseCode
509− if !unicode.IsControl(r) {
543+ if unicode.IsControl(r) {
544+ return p.parseControl(byte(r))
545+ } else {
510 rw := utf8.EncodeRune(utf8Buf[:], r)
546 rw := utf8.EncodeRune(utf8Buf[:], r)
511 keyCode, _ = utf8.DecodeRune(utf8Buf[:rw])
547 keyCode, _ = utf8.DecodeRune(utf8Buf[:rw])
512 if unicode.IsPrint(keyCode) && (cks == 0 ||
548 if unicode.IsPrint(keyCode) && (cks == 0 ||
@@ -517,18 +553,18 @@ func (p *SequenceParser) parseWin32InputKeyEvent(state *win32InputState, vkc uin
517 // then the key event is a printable event i.e. [text] is not empty.
553 // then the key event is a printable event i.e. [text] is not empty.
518 text = string(keyCode)
554 text = string(keyCode)
519 }
555 }
520− }
521
556
522− key.Code = keyCode
557+ key.Code = keyCode
523− key.Text = text
558+ key.Text = text
524− key.Mod = translateControlKeyState(cks)
559+ key.Mod = translateControlKeyState(cks)
525− key.BaseCode = baseCode
560+ key.BaseCode = baseCode
526− key = ensureKeyCase(key, cks)
561+ key = ensureKeyCase(key, cks)
527− if keyDown {
562+ if keyDown {
528− return KeyPressEvent(key)
563+ return KeyPressEvent(key)
529− }
564+ }
530
565
531− return KeyReleaseEvent(key)
566+ return KeyReleaseEvent(key)
567+ }
532}
568}
533
569
534// ensureKeyCase ensures that the key's text is in the correct case based on the
570// ensureKeyCase ensures that the key's text is in the correct case based on the
vendor/modules.txt+5−5
@@ -254,7 +254,7 @@ github.com/charmbracelet/bubbles/v2/spinner
254github.com/charmbracelet/bubbles/v2/textarea
254github.com/charmbracelet/bubbles/v2/textarea
255github.com/charmbracelet/bubbles/v2/textinput
255github.com/charmbracelet/bubbles/v2/textinput
256github.com/charmbracelet/bubbles/v2/viewport
256github.com/charmbracelet/bubbles/v2/viewport
257−# github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250703182356-a42fb608faaf
257+# github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708145940-f4b2ad3636f9
258## explicit; go 1.24.3
258## explicit; go 1.24.3
259github.com/charmbracelet/bubbletea/v2
259github.com/charmbracelet/bubbletea/v2
260# github.com/charmbracelet/colorprofile v0.3.1
260# github.com/charmbracelet/colorprofile v0.3.1
@@ -269,7 +269,7 @@ github.com/charmbracelet/glamour/v2
269github.com/charmbracelet/glamour/v2/ansi
269github.com/charmbracelet/glamour/v2/ansi
270github.com/charmbracelet/glamour/v2/internal/autolink
270github.com/charmbracelet/glamour/v2/internal/autolink
271github.com/charmbracelet/glamour/v2/styles
271github.com/charmbracelet/glamour/v2/styles
272−# github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.2.0.20250703152125-8e1c474f8a71 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250703152138-ff346e83e819
272+# github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.2.0.20250703152125-8e1c474f8a71 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708150236-b6de769f3a51
273## explicit; go 1.24.2
273## explicit; go 1.24.2
274github.com/charmbracelet/lipgloss/v2
274github.com/charmbracelet/lipgloss/v2
275github.com/charmbracelet/lipgloss/v2/table
275github.com/charmbracelet/lipgloss/v2/table
@@ -277,7 +277,7 @@ github.com/charmbracelet/lipgloss/v2/tree
277# github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706
277# github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706
278## explicit; go 1.19
278## explicit; go 1.19
279github.com/charmbracelet/log/v2
279github.com/charmbracelet/log/v2
280−# github.com/charmbracelet/ultraviolet v0.0.0-20250707134318-0fdaa64b8c5e
280+# github.com/charmbracelet/ultraviolet v0.0.0-20250708144633-4a8e4329a1a0
281## explicit; go 1.24.0
281## explicit; go 1.24.0
282github.com/charmbracelet/ultraviolet
282github.com/charmbracelet/ultraviolet
283# github.com/charmbracelet/x/ansi v0.9.3
283# github.com/charmbracelet/x/ansi v0.9.3
@@ -838,5 +838,5 @@ mvdan.cc/sh/v3/fileutil
838mvdan.cc/sh/v3/interp
838mvdan.cc/sh/v3/interp
839mvdan.cc/sh/v3/pattern
839mvdan.cc/sh/v3/pattern
840mvdan.cc/sh/v3/syntax
840mvdan.cc/sh/v3/syntax
841−# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250703182356-a42fb608faaf
841+# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708145940-f4b2ad3636f9
842−# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250703152138-ff346e83e819
842+# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708150236-b6de769f3a51