ui.go

  1package main
  2
  3import (
  4	"os"
  5	"path/filepath"
  6
  7	tea "github.com/charmbracelet/bubbletea"
  8	"github.com/charmbracelet/lipgloss"
  9	"github.com/charmbracelet/log"
 10	"github.com/charmbracelet/soft-serve/server/access"
 11	"github.com/charmbracelet/soft-serve/server/backend"
 12	"github.com/charmbracelet/soft-serve/server/config"
 13	"github.com/charmbracelet/soft-serve/server/errors"
 14	"github.com/charmbracelet/soft-serve/server/ui"
 15	"github.com/charmbracelet/soft-serve/server/ui/common"
 16	"github.com/mattn/go-tty"
 17	"github.com/muesli/termenv"
 18	"github.com/spf13/cobra"
 19)
 20
 21var uiCmd = &cobra.Command{
 22	Use: "ui",
 23	RunE: func(cmd *cobra.Command, args []string) error {
 24		ctx := cmd.Context()
 25		be := backend.FromContext(ctx)
 26		cfg := config.FromContext(ctx)
 27
 28		logPath := filepath.Join(cfg.DataPath, "log", "ui.log")
 29		f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 30		if err != nil {
 31			return err
 32		}
 33
 34		defer f.Close() // nolint:errcheck
 35
 36		logger := log.FromContext(ctx).WithPrefix("ui")
 37		logger.SetOutput(f)
 38		ctx = log.WithContext(ctx, logger)
 39
 40		lipgloss.SetColorProfile(termenv.Ascii)
 41
 42		logger.Infof("SSH_TTY %s", os.Getenv("SSH_TTY"))
 43		tty, err := tty.OpenDevice(os.Getenv("SSH_TTY"))
 44		// tty, err := tty.Open()
 45		if err != nil {
 46			return err
 47		}
 48
 49		// stdin := tty.Input()
 50		// stdout := cmd.OutOrStdout()
 51		stdin := tty.Input()
 52		stdout := tty.Output()
 53		// if tty := os.Getenv("SSH_TTY"); tty != "" {
 54		// 	logger.Infof("SSH_TTY %s", tty)
 55		// 	f, err := os.OpenFile(tty, os.O_RDWR, 0)
 56		// 	if err != nil {
 57		// 		return err
 58		// 	}
 59		// 	defer f.Close() // nolint:errcheck
 60		//
 61		// 	logger.Infof("using %s", tty)
 62		// 	stdin = f
 63		// 	stdout = f
 64		// }
 65
 66		// if !isatty.IsTerminal(stdout.(interface {
 67		// 	Fd() uintptr
 68		// }).Fd()) {
 69		// 	return fmt.Errorf("stdout is not a terminal")
 70		// }
 71
 72		var initialRepo string
 73		if len(args) == 1 {
 74			user, _ := be.Authenticate(ctx, nil)
 75			initialRepo = args[0]
 76			auth, _ := be.AccessLevel(ctx, initialRepo, user)
 77			if auth < access.ReadOnlyAccess {
 78				return errors.ErrUnauthorized
 79			}
 80		}
 81
 82		re := lipgloss.NewRenderer(stdout, termenv.WithColorCache(true), termenv.WithUnsafe(), termenv.WithTTY(true))
 83		// FIXME: detect color profile and dark background
 84		re.SetColorProfile(termenv.Ascii)
 85		re.SetHasDarkBackground(false)
 86		termenv.SetDefaultOutput(re.Output())
 87		c := common.NewCommon(ctx, re, 0, 0)
 88		m := ui.New(c, initialRepo)
 89		p := tea.NewProgram(m,
 90			tea.WithInput(stdin),
 91			tea.WithOutput(re.Output()),
 92			tea.WithAltScreen(),
 93			tea.WithoutCatchPanics(),
 94			tea.WithMouseCellMotion(),
 95		)
 96
 97		if _, err := p.Run(); err != nil {
 98			return err
 99		}
100
101		return nil
102	},
103}