1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
package bubbletea
import (
"log"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/wish"
"github.com/gliderlabs/ssh"
"github.com/muesli/termenv"
)
// BubbleTeaHander is the function Bubble Tea apps implement to hook into the
// SSH Middleware. This will create a new tea.Program for every connection and
// start it with the tea.ProgramOptions returned.
type BubbleTeaHandler func(ssh.Session) (tea.Model, []tea.ProgramOption)
// Middleware takes a BubbleTeaHandler and hooks the input and output for the
// ssh.Session into the tea.Program. It also captures window resize events and
// sends them to the tea.Program as tea.WindowSizeMsgs. By default a 256 color
// profile will be used when rendering with Lip Gloss.
func Middleware(bth BubbleTeaHandler) wish.Middleware {
return MiddlewareWithColorProfile(bth, termenv.ANSI256)
}
// MiddlewareWithColorProfile allows you to specify the number of colors
// returned by the server when using Lip Gloss. The number of colors supported
// by an SSH client's terminal cannot be detected by the server but this will
// allow for manually setting the color profile on all SSH connections.
func MiddlewareWithColorProfile(bth BubbleTeaHandler, cp termenv.Profile) wish.Middleware {
return func(sh ssh.Handler) ssh.Handler {
lipgloss.SetColorProfile(cp)
return func(s ssh.Session) {
errc := make(chan error, 1)
m, opts := bth(s)
if m != nil {
opts = append(opts, tea.WithInput(s), tea.WithOutput(s))
p := tea.NewProgram(m, opts...)
_, windowChanges, _ := s.Pty()
go func() {
for {
select {
case <-s.Context().Done():
if p != nil {
p.Quit()
}
case w := <-windowChanges:
if p != nil {
p.Send(tea.WindowSizeMsg{Width: w.Width, Height: w.Height})
}
case err := <-errc:
if err != nil {
log.Print(err)
}
}
}
}()
errc <- p.Start()
}
sh(s)
}
}
}
|