From 94788c7671da71a83e52872a24efa3507a4b46ec Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 21 Aug 2024 15:35:47 -0400 Subject: [PATCH] fix(tea): query bg color --- bubbletea/query.go | 95 +++++++++++++++++++++++++++++++++++++++++++ bubbletea/tea_unix.go | 11 +++-- 2 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 bubbletea/query.go diff --git a/bubbletea/query.go b/bubbletea/query.go new file mode 100644 index 0000000..c69de2e --- /dev/null +++ b/bubbletea/query.go @@ -0,0 +1,95 @@ +package bubbletea + +import ( + "image/color" + "io" + "time" + + "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/input" +) + +// queryBackgroundColor queries the terminal for the background color. +// If the terminal does not support querying the background color, nil is +// returned. +// +// Note: you will need to set the input to raw mode before calling this +// function. +// +// state, _ := term.MakeRaw(in.Fd()) +// defer term.Restore(in.Fd(), state) +// +// copied from x/term@v0.1.3. +func queryBackgroundColor(in io.Reader, out io.Writer) (c color.Color, err error) { + // nolint: errcheck + err = queryTerminal(in, out, defaultQueryTimeout, + func(events []input.Event) bool { + for _, e := range events { + switch e := e.(type) { + case input.BackgroundColorEvent: + c = e.Color + continue // we need to consume the next DA1 event + case input.PrimaryDeviceAttributesEvent: + return false + } + } + return true + }, ansi.RequestBackgroundColor+ansi.RequestPrimaryDeviceAttributes) + return +} + +const defaultQueryTimeout = time.Second * 2 + +// QueryTerminalFilter is a function that filters input events using a type +// switch. If false is returned, the QueryTerminal function will stop reading +// input. +type QueryTerminalFilter func(events []input.Event) bool + +// queryTerminal queries the terminal for support of various features and +// returns a list of response events. +// Most of the time, you will need to set stdin to raw mode before calling this +// function. +// Note: This function will block until the terminal responds or the timeout +// is reached. +// copied from x/term@v0.1.3. +func queryTerminal( + in io.Reader, + out io.Writer, + timeout time.Duration, + filter QueryTerminalFilter, + query string, +) error { + rd, err := input.NewDriver(in, "", 0) + if err != nil { + return err + } + + defer rd.Close() // nolint: errcheck + + done := make(chan struct{}, 1) + defer close(done) + go func() { + select { + case <-done: + case <-time.After(timeout): + rd.Cancel() + } + }() + + if _, err := io.WriteString(out, query); err != nil { + return err + } + + for { + events, err := rd.ReadEvents() + if err != nil { + return err + } + + if !filter(events) { + break + } + } + + return nil +} diff --git a/bubbletea/tea_unix.go b/bubbletea/tea_unix.go index fd0d216..114150c 100644 --- a/bubbletea/tea_unix.go +++ b/bubbletea/tea_unix.go @@ -12,7 +12,6 @@ import ( "github.com/charmbracelet/ssh" "github.com/charmbracelet/x/ansi" "github.com/charmbracelet/x/input" - "github.com/charmbracelet/x/term" "github.com/lucasb-eyer/go-colorful" "github.com/muesli/termenv" ) @@ -46,7 +45,7 @@ func newRenderer(s ssh.Session) *lipgloss.Renderer { termenv.WithEnvironment(env), termenv.WithColorCache(true), ) - bg, _ = term.QueryBackgroundColor(pty.Slave, pty.Slave) + bg, _ = queryBackgroundColor(pty.Slave, pty.Slave) } else { r = lipgloss.NewRenderer( s, @@ -54,7 +53,7 @@ func newRenderer(s ssh.Session) *lipgloss.Renderer { termenv.WithUnsafe(), termenv.WithColorCache(true), ) - bg = queryBackgroundColor(s) + bg = querySessionBackgroundColor(s) } if bg != nil { c, ok := colorful.MakeColor(bg) @@ -66,9 +65,9 @@ func newRenderer(s ssh.Session) *lipgloss.Renderer { return r } -// copied from x/exp/term. -func queryBackgroundColor(s ssh.Session) (bg color.Color) { - _ = term.QueryTerminal(s, s, time.Second, func(events []input.Event) bool { +// copied from x/term@v0.1.3. +func querySessionBackgroundColor(s ssh.Session) (bg color.Color) { + _ = queryTerminal(s, s, time.Second, func(events []input.Event) bool { for _, e := range events { switch e := e.(type) { case input.BackgroundColorEvent: