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}