Skip to content

Commit

Permalink
bubbletea testing, improve termuiimg api
Browse files Browse the repository at this point in the history
  • Loading branch information
srlehn committed Nov 23, 2023
1 parent f303a41 commit 17b220a
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 212 deletions.
119 changes: 20 additions & 99 deletions cmd/bubbletea_test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,21 @@
package main

import (
"context"
"image"
"log"
"log/slog"
"os"
"time"

"github.com/srlehn/termimg"
_ "github.com/srlehn/termimg/drawers/all"
"github.com/srlehn/termimg/internal/assets"
"github.com/srlehn/termimg/internal/logx"
"github.com/srlehn/termimg/term"
_ "github.com/srlehn/termimg/terminals"
"github.com/srlehn/termimg/tui/bubbleteaimg"

// "github.com/srlehn/termimg/tty/contdtty"
"github.com/srlehn/termimg/tty/bubbleteatty"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

var testImg []byte = assets.SnakePic
Expand All @@ -43,114 +38,40 @@ func main() {
}

func m() error {
// create termimg terminal
opts := []term.Option{
mdl := newTestModel1()
// mdl := newTestModel2()

//ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
//defer cancel()
teaOpts := []tea.ProgramOption{
//tea.WithContext(ctx),
// tea.WithAltScreen(),
}
var prog *tea.Program
timgOpts := []term.Option{
term.SetLogFile(`log_termimg.log`, true),
termimg.DefaultConfig,
term.SetTTYProvider(bubbleteatty.New, true),
bubbleteatty.BubbleTeaProgram(mdl, &prog, teaOpts...),
}
tm, err := term.NewTerminal(opts...)

tm, err := term.NewTerminal(timgOpts...)
if err != nil {
return err
}
defer tm.Close()

bounds := image.Rect(10, 10, 60, 35)
text := `Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`
style := lipgloss.NewStyle().
Border(lipgloss.NormalBorder(), true).Margin(2).Padding(0, 1).
Width(bounds.Dx()).Height(bounds.Dy())
mdl, err := newModel(&style, bounds, text)
if err != nil {
return err
if stp, ok := any(mdl).(interface{ Setup(*term.Terminal) error }); ok {
log.Println("SETUP", tm != nil)
if err := stp.Setup(tm); err != nil {
log.Println("SETUP", err)
return err
}
}

// finish "tty" setup
teaOpts := []tea.ProgramOption{tea.WithAltScreen()}
tty, err := bubbleteatty.TTYOf(tm)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
prog, err := tty.SetProgram(ctx, mdl, teaOpts...)
if err != nil {
return err
}
defer prog.Quit()

// image setup
if err := mdl.img.Setup(tm, termimg.NewImageBytes(testImg)); err != nil {
return err
}

//go func() {
if _, err = prog.Run(); logx.IsErr(err, tm, slog.LevelError) {
return err
}
//}()

// time.Sleep(5 * time.Second)

return nil
}

var _ tea.Model = (*model)(nil)

type model struct {
img *bubbleteaimg.Image
styleText lipgloss.Style
text string
}

func newModel(style *lipgloss.Style, bounds image.Rectangle, text string) (*model, error) {
styleText := style.Copy().Width(bounds.Dx() / 2).Height(bounds.Dy())
styleImg := style.Copy().Width(bounds.Dx()).Height(bounds.Dy())
img, err := bubbleteaimg.NewImage(&styleImg)
if err != nil {
return nil, err
}
mdl := &model{
styleText: styleText,
img: img,
text: text,
}
return mdl, nil
}

func (m *model) Init() tea.Cmd {
return func() tea.Msg {
if m != nil && m.img != nil {
return m.img.Init()
}
return nil
}
}

func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
log.Printf("tea.Quit called\n")
return m, tea.Quit
}
default:
log.Printf("tea msg: %T %+#[1]v\n", msg)
if m != nil && m.img != nil {
mImg, cmd := m.img.Update(msg)
m.img = mImg.(*bubbleteaimg.Image)
return m, cmd
}
}

cmd := func() tea.Msg { return msg }
return m, cmd
}

func (m *model) View() string {
if m == nil {
return `<nil bubbletea.Model>`
}
return lipgloss.JoinHorizontal(lipgloss.Bottom, m.styleText.Render(m.text), m.img.View())
}
115 changes: 115 additions & 0 deletions cmd/bubbletea_test/model1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//go:build dev

package main

import (
"image"
"log"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
"github.com/srlehn/termimg"
"github.com/srlehn/termimg/internal/errors"
"github.com/srlehn/termimg/term"
"github.com/srlehn/termimg/tty/bubbleteatty"
"github.com/srlehn/termimg/tui/bubbleteaimg"
)

func newTestModel1() *model1 {
bounds := image.Rect(10, 10, 60, 30)
text := `Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`
style := lipgloss.NewStyle().
Border(lipgloss.DoubleBorder(), true).Margin(2).Padding(0, 1).
Width(bounds.Dx()).Height(bounds.Dy())
return newModel1(&style, bounds, text)
}

var _ tea.Model = (*model1)(nil)

type model1 struct {
img *bubbleteaimg.Image
styleText lipgloss.Style
styleImg lipgloss.Style
text string
}

func newModel1(style *lipgloss.Style, bounds image.Rectangle, text string) *model1 {
styleText := style.Copy().Width(bounds.Dx() / 2).Height(bounds.Dy())
styleImg := style.Copy().Width(bounds.Dx()).Height(bounds.Dy())
mdl := &model1{
styleText: styleText,
styleImg: styleImg,
text: text,
}
return mdl
}

func (m *model1) Setup(tm *term.Terminal) error {
if err := errors.NilReceiver(m); err != nil {
return err
}
if err := errors.NilParam(tm); err != nil {
return err
}
img, err := bubbleteaimg.NewImage(tm, termimg.NewImageBytes(testImg), &m.styleImg)
if err != nil {
return err
}
m.img = img

tty, ok := tm.TTY().(*bubbleteatty.TTYBubbleTea)
if !ok || tty == nil {
log.Println(`unsupported tty`)
return errors.New(`unsupported tty`)
}
renderer := tty.LipGlossRenderer()
log.Printf("REND %+#v\n", renderer)
log.Printf("REND color profile %v\n", renderer.ColorProfile())
log.Printf("REND output %+#v\n", renderer.Output())
renderer.SetColorProfile(termenv.ANSI256)
// lipgloss.SetDefaultRenderer(renderer)
m.styleText = m.styleText.
Copy().
Renderer(renderer).
BorderForeground(lipgloss.Color(`32`)) // 63, 228
// BorderBackground(lipgloss.Color(`34`)) // 63, 228
return nil
}

func (m *model1) Init() tea.Cmd {
return func() tea.Msg {
if m != nil && m.img != nil {
return m.img.Init()
}
return nil
}
}

func (m *model1) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
}
default:
log.Printf("tea msg: %T %+#[1]v\n", msg)
if m != nil && m.img != nil {
mImg, cmd := m.img.Update(msg)
m.img = mImg.(*bubbleteaimg.Image)
return m, cmd
}
}

// cmd := func() tea.Msg { return msg }
// return m, cmd
return m, nil
}

func (m *model1) View() string {
if m == nil || m.img == nil {
return `<nil bubbletea.Model>`
}
return lipgloss.JoinHorizontal(lipgloss.Bottom, m.styleText.Render(m.text), m.img.View())
}
Loading

0 comments on commit 17b220a

Please sign in to comment.