on main help sign in
chore: update vendors
commit935e7135bb300e739cd38920a1484bf171bc9e4f authorAyman Bagabas <ayman.bagabas@gmail.com> dateTue 8 Jul 2025, 11:07 (1 year ago) parent2fd0eb5
13 files changed+172−60
vendor/github.com/charmbracelet/bubbletea/v2/.golangci.yml−1 vendor/github.com/charmbracelet/bubbletea/v2/README.md−1 vendor/github.com/charmbracelet/bubbletea/v2/cursed_renderer.go+15 vendor/github.com/charmbracelet/bubbletea/v2/exec.go+4 vendor/github.com/charmbracelet/bubbletea/v2/nil_renderer.go+2−1 vendor/github.com/charmbracelet/bubbletea/v2/renderer.go+3 vendor/github.com/charmbracelet/bubbletea/v2/standard_renderer.go+3 vendor/github.com/charmbracelet/bubbletea/v2/tea.go+15−6 vendor/github.com/charmbracelet/ultraviolet/event.go+36 vendor/github.com/charmbracelet/ultraviolet/parse.go+5−3 vendor/github.com/charmbracelet/ultraviolet/terminal_reader.go+24−19 vendor/github.com/charmbracelet/ultraviolet/terminal_reader_windows.go+60−24 vendor/modules.txt+5−5
vendor/github.com/charmbracelet/bubbletea/v2/.golangci.yml−1
@@ -7,7 +7,6 @@ linters:
77 - exhaustive
88 - goconst
99 - godot
10− - godox
1110 - gomoddirectives
1211 - goprintffuncname
1312 - gosec
vendor/github.com/charmbracelet/bubbletea/v2/README.md−1
@@ -10,7 +10,6 @@
1010 <a href="https://github.com/charmbracelet/bubbletea/releases"><img src="https://img.shields.io/github/release/charmbracelet/bubbletea.svg" alt="Latest Release"></a>
1111 <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>
1212 <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>
1413</p>
1514
1615The 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) {
104104 return s.scr.WriteString(str)
105105}
106106
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+
107122// flush implements renderer.
108123func (s *cursedRenderer) flush(p *Program) error {
109124 s.mu.Lock()
vendor/github.com/charmbracelet/bubbletea/v2/exec.go+4
@@ -114,6 +114,7 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) {
114114
115115 // Execute system command.
116116 if err := c.Run(); err != nil {
117+ p.renderer.resetLinesRendered()
117118 _ = p.RestoreTerminal() // also try to restore the terminal.
118119 if fn != nil {
119120 go p.Send(fn(err))
@@ -121,6 +122,9 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) {
121122 return
122123 }
123124
125+ // Maintain the existing output from the command
126+ p.renderer.resetLinesRendered()
127+
124128 // Have the program re-capture input.
125129 err := p.RestoreTerminal()
126130 if fn != nil {
vendor/github.com/charmbracelet/bubbletea/v2/nil_renderer.go+2−1
@@ -67,4 +67,5 @@ func (n nilRenderer) setBackgroundColor(color.Color) {}
6767func (n nilRenderer) setWindowTitle(string) {}
6868
6969// 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 {
7171 repaint()
7272
7373 writeString(string) (int, error)
74+
75+ // resetLinesRendered ensures exec output remains on screen on exit
76+ resetLinesRendered()
7477}
7578
7679// 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) {}
382382func (r *standardRenderer) setBackgroundColor(c color.Color) {}
383383func (r *standardRenderer) setWindowTitle(s string) {}
384384func (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) {
12201220 default:
12211221 }
12221222 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)
12291223 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+ }
12301239}
12311240
12321241// 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 {
131131 return Key(k).String()
132132}
133133
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+
134152// Key returns the underlying key event. This is a syntactic sugar for casting
135153// the key event to a [Key].
136154func (k KeyPressEvent) Key() Key {
@@ -163,6 +181,24 @@ func (k KeyReleaseEvent) String() string {
163181 return Key(k).String()
164182}
165183
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+
166202// Key returns the underlying key event. This is a convenience method and
167203// syntactic sugar to satisfy the [KeyEvent] interface, and cast the key event to
168204// [Key].
vendor/github.com/charmbracelet/ultraviolet/parse.go+5−3
@@ -748,10 +748,12 @@ func (p *SequenceParser) parseSs3(b []byte) (int, Event) {
748748}
749749
750750func (p *SequenceParser) parseOsc(b []byte) (int, Event) {
751− defaultKey := KeyPressEvent{Code: rune(b[1]), Mod: ModAlt}
751+ defaultKey := func() KeyPressEvent {
752+ return KeyPressEvent{Code: rune(b[1]), Mod: ModAlt}
753+ }
752754 if len(b) == 2 && b[0] == ansi.ESC {
753755 // short cut if this is an alt+] key
754− return 2, defaultKey
756+ return 2, defaultKey()
755757 }
756758
757759 var i int
@@ -802,7 +804,7 @@ func (p *SequenceParser) parseOsc(b []byte) (int, Event) {
802804 case ansi.ESC:
803805 if i >= len(b) || b[i] != '\\' {
804806 if cmd == -1 || (start == 0 && end == 2) {
805− return 2, defaultKey
807+ return 2, defaultKey()
806808 }
807809
808810 // 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 {
5555 // Windows Console API.
5656 MouseMode *MouseMode
5757
58− // Timeout is the escape character timeout duration. Most escape sequences
59− // start with an escape character [ansi.ESC] and are followed by one or
60− // more characters. If the next character is not received within this
61− // timeout, the reader will assume that the escape sequence is complete and
62− // will process the received characters as a complete escape sequence.
58+ // EscTimeout is the escape character timeout duration. Most escape
59+ // sequences start with an escape character [ansi.ESC] and are followed by
60+ // one or more characters. If the next character is not received within
61+ // this timeout, the reader will assume that the escape sequence is
62+ // complete and will process the received characters as a complete escape
63+ // sequence.
6364 //
6465 // By default, this is set to [DefaultEscTimeout] (50 milliseconds).
65− Timeout time.Duration
66+ EscTimeout time.Duration
6667
6768 r io.Reader
6869 rd cancelreader.CancelReader
@@ -85,6 +86,7 @@ type TerminalReader struct {
8586 // prevent multiple calls to the Close() method.
8687 closed bool
8788 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.
8890 close chan struct{} // close is a channel used to signal the reader to close.
8991 closeOnce sync.Once
9092 notify chan []byte // notify is a channel used to notify the reader of new input events.
@@ -113,10 +115,10 @@ type TerminalReader struct {
113115// }
114116func NewTerminalReader(r io.Reader, termType string) *TerminalReader {
115117 return &TerminalReader{
116− Timeout: DefaultEscTimeout,
117− r: r,
118− term: termType,
119− lookup: true, // Use lookup table by default.
118+ EscTimeout: DefaultEscTimeout,
119+ r: r,
120+ term: termType,
121+ lookup: true, // Use lookup table by default.
120122 }
121123}
122124
@@ -131,22 +133,20 @@ func (d *TerminalReader) SetLogger(logger Logger) {
131133// lookup table for key sequences if it is not already set. This function
132134// should be called before reading input events.
133135func (d *TerminalReader) Start() (err error) {
134− if d.rd == nil {
135− d.rd, err = newCancelreader(d.r)
136− if err != nil {
137− return err
138− }
136+ d.rd, err = newCancelreader(d.r)
137+ if err != nil {
138+ return err
139139 }
140140 if d.table == nil {
141141 d.table = buildKeysTable(d.Legacy, d.term, d.UseTerminfo)
142142 }
143143 d.started = true
144144 d.esc.Store(false)
145− d.timeout = time.NewTimer(d.Timeout)
145+ d.timeout = time.NewTimer(d.EscTimeout)
146146 d.notify = make(chan []byte)
147147 d.close = make(chan struct{}, 1)
148148 d.closeOnce = sync.Once{}
149− go d.run()
149+ d.runOnce = sync.Once{}
150150 return nil
151151}
152152
@@ -194,6 +194,11 @@ func (d *TerminalReader) receiveEvents(ctx context.Context, events chan<- Event)
194194 return ErrReaderNotStarted
195195 }
196196
197+ // Start the reader loop if it hasn't been started yet.
198+ d.runOnce.Do(func() {
199+ go d.run()
200+ })
201+
197202 closingFunc := func() error {
198203 // If we're closing, make sure to send any remaining events even if
199204 // they are incomplete.
@@ -255,7 +260,7 @@ func (d *TerminalReader) run() {
255260 esc := n > 0 && n <= 2 && readBuf[0] == ansi.ESC
256261 if esc {
257262 d.esc.Store(true)
258− d.timeout.Reset(d.Timeout)
263+ d.timeout.Reset(d.EscTimeout)
259264 }
260265
261266 d.notify <- readBuf[:n]
@@ -305,7 +310,7 @@ LOOP:
305310 ansi.ESC, ansi.CSI, ansi.OSC, ansi.DCS, ansi.APC, ansi.SOS, ansi.PM,
306311 }, d.buf[0]) {
307312 d.esc.Store(true)
308− d.timeout.Reset(d.Timeout)
313+ d.timeout.Reset(d.EscTimeout)
309314 }
310315 }
311316 // 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 (
88 "errors"
99 "fmt"
1010 "strings"
11+ "time"
1112 "unicode"
1213 "unicode/utf16"
1314 "unicode/utf8"
@@ -22,7 +23,7 @@ import (
2223// given event channel.
2324func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event) error {
2425 for {
25− evs, err := d.handleConInput(readConsoleInput)
26+ evs, err := d.handleConInput()
2627 if errors.Is(err, errNotConInputReader) {
2728 return d.receiveEvents(ctx, events)
2829 }
@@ -41,31 +42,45 @@ func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event)
4142
4243var errNotConInputReader = fmt.Errorf("handleConInput: not a conInputReader")
4344
44−func (d *TerminalReader) handleConInput(
45− finput func(windows.Handle, []xwindows.InputRecord) (uint32, error),
46−) ([]Event, error) {
45+func (d *TerminalReader) handleConInput() ([]Event, error) {
4746 cc, ok := d.rd.(*conInputReader)
4847 if !ok {
4948 return nil, errNotConInputReader
5049 }
5150
52− // read up to 256 events, this is to allow for sequences events reported as
53− // key events.
54− var events [256]xwindows.InputRecord
55− _, err := finput(cc.conin, events[:])
56− if err != nil {
51+ var (
52+ events []xwindows.InputRecord
53+ err error
54+ )
55+ for {
56+ // Peek up to 256 events, this is to allow for sequences events reported as
57+ // key events.
58+ events, err = peekNConsoleInputs(cc.conin, 256)
5759 if cc.isCanceled() {
5860 return nil, cancelreader.ErrCanceled
5961 }
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 {
6078 return nil, fmt.Errorf("read coninput events: %w", err)
6179 }
6280
6381 var evs []Event
6482 for _, event := range events {
6583 if e := d.SequenceParser.parseConInputEvent(event, &d.keyState, d.MouseMode, d.logger); e != nil {
66− if e == nil {
67− continue
68− }
6984 if multi, ok := e.(MultiEvent); ok {
7085 if d.logger != nil {
7186 for _, ev := range multi {
@@ -223,6 +238,16 @@ func highWord(data uint32) uint16 {
223238 return uint16((data & 0xFFFF0000) >> 16) //nolint:gosec
224239}
225240
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+
226251func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
227252 if len(inputRecords) == 0 {
228253 return 0, fmt.Errorf("size of input record buffer cannot be zero")
@@ -235,7 +260,6 @@ func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecor
235260 return read, err //nolint:wrapcheck
236261}
237262
238−//nolint:unused
239263func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
240264 if len(inputRecords) == 0 {
241265 return 0, fmt.Errorf("size of input record buffer cannot be zero")
@@ -248,6 +272,16 @@ func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecor
248272 return read, err //nolint:wrapcheck
249273}
250274
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+
251285// parseWin32InputKeyEvent parses a single key event from either the Windows
252286// Console API or win32-input-mode events. When state is nil, it means this is
253287// 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
506540
507541 var text string
508542 keyCode := baseCode
509− if !unicode.IsControl(r) {
543+ if unicode.IsControl(r) {
544+ return p.parseControl(byte(r))
545+ } else {
510546 rw := utf8.EncodeRune(utf8Buf[:], r)
511547 keyCode, _ = utf8.DecodeRune(utf8Buf[:rw])
512548 if unicode.IsPrint(keyCode) && (cks == 0 ||
@@ -517,18 +553,18 @@ func (p *SequenceParser) parseWin32InputKeyEvent(state *win32InputState, vkc uin
517553 // then the key event is a printable event i.e. [text] is not empty.
518554 text = string(keyCode)
519555 }
520− }
521556
522− key.Code = keyCode
523− key.Text = text
524− key.Mod = translateControlKeyState(cks)
525− key.BaseCode = baseCode
526− key = ensureKeyCase(key, cks)
527− if keyDown {
528− return KeyPressEvent(key)
529− }
557+ key.Code = keyCode
558+ key.Text = text
559+ key.Mod = translateControlKeyState(cks)
560+ key.BaseCode = baseCode
561+ key = ensureKeyCase(key, cks)
562+ if keyDown {
563+ return KeyPressEvent(key)
564+ }
530565
531− return KeyReleaseEvent(key)
566+ return KeyReleaseEvent(key)
567+ }
532568}
533569
534570// 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
254254github.com/charmbracelet/bubbles/v2/textarea
255255github.com/charmbracelet/bubbles/v2/textinput
256256github.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
258258## explicit; go 1.24.3
259259github.com/charmbracelet/bubbletea/v2
260260# github.com/charmbracelet/colorprofile v0.3.1
@@ -269,7 +269,7 @@ github.com/charmbracelet/glamour/v2
269269github.com/charmbracelet/glamour/v2/ansi
270270github.com/charmbracelet/glamour/v2/internal/autolink
271271github.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
273273## explicit; go 1.24.2
274274github.com/charmbracelet/lipgloss/v2
275275github.com/charmbracelet/lipgloss/v2/table
@@ -277,7 +277,7 @@ github.com/charmbracelet/lipgloss/v2/tree
277277# github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706
278278## explicit; go 1.19
279279github.com/charmbracelet/log/v2
280−# github.com/charmbracelet/ultraviolet v0.0.0-20250707134318-0fdaa64b8c5e
280+# github.com/charmbracelet/ultraviolet v0.0.0-20250708144633-4a8e4329a1a0
281281## explicit; go 1.24.0
282282github.com/charmbracelet/ultraviolet
283283# github.com/charmbracelet/x/ansi v0.9.3
@@ -838,5 +838,5 @@ mvdan.cc/sh/v3/fileutil
838838mvdan.cc/sh/v3/interp
839839mvdan.cc/sh/v3/pattern
840840mvdan.cc/sh/v3/syntax
841−# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250703182356-a42fb608faaf
842−# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250703152138-ff346e83e819
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-20250708150236-b6de769f3a51