diff --git a/cmd/soft/browse/browse.go b/cmd/soft/browse/browse.go
index ff1a1d061..c430630cf 100644
--- a/cmd/soft/browse/browse.go
+++ b/cmd/soft/browse/browse.go
@@ -13,7 +13,6 @@ import (
"github.com/charmbracelet/soft-serve/pkg/ui/common"
"github.com/charmbracelet/soft-serve/pkg/ui/components/footer"
"github.com/charmbracelet/soft-serve/pkg/ui/pages/repo"
- "github.com/muesli/termenv"
"github.com/spf13/cobra"
)
@@ -40,7 +39,7 @@ var Command = &cobra.Command{
// Bubble Tea uses Termenv default output so we have to use the same
// thing here.
- output := termenv.DefaultOutput()
+ output := lipgloss.DefaultRenderer()
ctx := cmd.Context()
c := common.NewCommon(ctx, output, 0, 0)
c.HideCloneCmd = true
diff --git a/cmd/soft/main.go b/cmd/soft/main.go
index 8264abee8..9849e8a26 100644
--- a/cmd/soft/main.go
+++ b/cmd/soft/main.go
@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"runtime/debug"
+ "strconv"
"github.com/charmbracelet/log"
"github.com/charmbracelet/soft-serve/cmd/soft/admin"
@@ -13,9 +14,11 @@ import (
"github.com/charmbracelet/soft-serve/cmd/soft/serve"
"github.com/charmbracelet/soft-serve/pkg/config"
logr "github.com/charmbracelet/soft-serve/pkg/log"
+ "github.com/charmbracelet/soft-serve/pkg/ui/common"
"github.com/charmbracelet/soft-serve/pkg/version"
mcobra "github.com/muesli/mango-cobra"
"github.com/muesli/roff"
+ "github.com/muesli/termenv"
"github.com/spf13/cobra"
"go.uber.org/automaxprocs/maxprocs"
)
@@ -63,6 +66,10 @@ var (
)
func init() {
+ if noColor, _ := strconv.ParseBool(os.Getenv("SOFT_SERVE_NO_COLOR")); noColor {
+ common.DefaultColorProfile = termenv.Ascii
+ }
+
rootCmd.AddCommand(
manCmd,
serve.Command,
diff --git a/pkg/ssh/session.go b/pkg/ssh/session.go
index 5ccd9062b..99c8489ef 100644
--- a/pkg/ssh/session.go
+++ b/pkg/ssh/session.go
@@ -5,6 +5,7 @@ import (
"time"
tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/soft-serve/pkg/access"
"github.com/charmbracelet/soft-serve/pkg/backend"
"github.com/charmbracelet/soft-serve/pkg/config"
@@ -54,7 +55,7 @@ func SessionHandler(s ssh.Session) *tea.Program {
}
envs := &sessionEnv{s}
- output := termenv.NewOutput(s, termenv.WithColorCache(true), termenv.WithEnvironment(envs))
+ output := lipgloss.NewRenderer(s, termenv.WithColorCache(true), termenv.WithEnvironment(envs))
c := common.NewCommon(ctx, output, pty.Window.Width, pty.Window.Height)
c.SetValue(common.ConfigKey, cfg)
m := NewUI(c, initialRepo)
diff --git a/pkg/ui/common/common.go b/pkg/ui/common/common.go
index ceee1f58e..3c3eddd30 100644
--- a/pkg/ui/common/common.go
+++ b/pkg/ui/common/common.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
+ "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/log"
"github.com/charmbracelet/soft-serve/git"
"github.com/charmbracelet/soft-serve/pkg/backend"
@@ -38,7 +39,7 @@ type Common struct {
}
// NewCommon returns a new Common struct.
-func NewCommon(ctx context.Context, out *termenv.Output, width, height int) Common {
+func NewCommon(ctx context.Context, out *lipgloss.Renderer, width, height int) Common {
if ctx == nil {
ctx = context.TODO()
}
@@ -46,7 +47,7 @@ func NewCommon(ctx context.Context, out *termenv.Output, width, height int) Comm
ctx: ctx,
Width: width,
Height: height,
- Output: out,
+ Output: out.Output(),
Styles: styles.DefaultStyles(),
KeyMap: keymap.DefaultKeyMap(),
Zone: zone.New(),
diff --git a/testscript/script_test.go b/testscript/script_test.go
index f7dd22eec..0b1b619e2 100644
--- a/testscript/script_test.go
+++ b/testscript/script_test.go
@@ -15,6 +15,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"testing"
"time"
@@ -92,6 +93,8 @@ func TestScript(t *testing.T) {
"new-webhook": cmdNewWebhook,
"waitforserver": cmdWaitforserver,
"stopserver": cmdStopserver,
+ "ui": cmdUI(admin1.Signer()),
+ "uui": cmdUI(user1.Signer()),
},
Setup: func(e *testscript.Env) error {
// Add binPath to PATH
@@ -120,6 +123,9 @@ func TestScript(t *testing.T) {
// This is used to set up test specific configuration and http endpoints
e.Setenv("SOFT_SERVE_TESTRUN", "1")
+ // This will disable the default lipgloss renderer colors
+ e.Setenv("SOFT_SERVE_NO_COLOR", "1")
+
// Soft Serve debug environment variables
for _, env := range []string{
"SOFT_SERVE_DEBUG",
@@ -199,6 +205,64 @@ func cmdSoft(key ssh.Signer) func(ts *testscript.TestScript, neg bool, args []st
}
}
+func cmdUI(key ssh.Signer) func(ts *testscript.TestScript, neg bool, args []string) {
+ return func(ts *testscript.TestScript, neg bool, args []string) {
+ if len(args) < 1 {
+ ts.Fatalf("usage: ui ")
+ return
+ }
+
+ cli, err := ssh.Dial(
+ "tcp",
+ net.JoinHostPort("localhost", ts.Getenv("SSH_PORT")),
+ &ssh.ClientConfig{
+ User: "git",
+ Auth: []ssh.AuthMethod{ssh.PublicKeys(key)},
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ },
+ )
+ check(ts, err, neg)
+ defer cli.Close()
+
+ sess, err := cli.NewSession()
+ check(ts, err, neg)
+ defer sess.Close()
+
+ // XXX: this is a hack to make the UI tests work
+ // cmp command always complains about an extra newline
+ // in the output
+ defer ts.Stdout().Write([]byte("\n"))
+
+ sess.Stdout = ts.Stdout()
+ sess.Stderr = ts.Stderr()
+
+ stdin, err := sess.StdinPipe()
+ check(ts, err, neg)
+
+ in, err := strconv.Unquote(args[0])
+ check(ts, err, neg)
+ reader := strings.NewReader(in)
+ go func() {
+ defer stdin.Close()
+ for {
+ r, _, err := reader.ReadRune()
+ if err == io.EOF {
+ break
+ }
+ check(ts, err, neg)
+ stdin.Write([]byte(string(r))) // nolint: errcheck
+
+ // Wait for the UI to process the input
+ time.Sleep(100 * time.Millisecond)
+ }
+ }()
+
+ err = sess.RequestPty("dumb", 40, 80, ssh.TerminalModes{})
+ check(ts, err, neg)
+ check(ts, sess.Run(""), neg)
+ }
+}
+
// P.S. Windows sucks!
func cmdDos2Unix(ts *testscript.TestScript, neg bool, args []string) {
if neg {
diff --git a/testscript/testdata/repo-blob.txtar b/testscript/testdata/repo-blob.txtar
index 040160b17..e2712acfe 100644
--- a/testscript/testdata/repo-blob.txtar
+++ b/testscript/testdata/repo-blob.txtar
@@ -54,6 +54,6 @@ stderr 'revision does not exist'
-- blob1.txt --
# Hello\n\nwelcome
-- blob2.txt --
- [38;5;239m1[0m [38;5;236m│[0m [38;5;204m[0m[38;5;204mpackage[0m main[38;5;255m\[0mnconst foo [38;5;187m=[0m [38;5;85m2[0m[38;5;255m\[0mn
+ 1 │ package main\nconst foo = 2\n
-- blob3.txt --
1 │ //#include
diff --git a/testscript/testdata/ui-home.txtar b/testscript/testdata/ui-home.txtar
new file mode 100644
index 000000000..e7203fb0d
--- /dev/null
+++ b/testscript/testdata/ui-home.txtar
@@ -0,0 +1,53 @@
+# vi: set ft=conf
+
+# start soft serve
+exec soft serve &
+# wait for server to start
+waitforserver
+
+# test repositories tab
+ui '" q"'
+cp stdout home.txt
+grep 'Test Soft Serve' home.txt
+grep '• Repositories' home.txt
+grep 'No items found' home.txt
+
+# test about tab
+ui '"\t q"'
+cp stdout about.txt
+grep 'Create a `.soft-serve` repository and add a `README.md` file' about.txt
+
+# add a new repo
+soft repo create .soft-serve -n 'Config' -d '"Test Soft Serve"'
+soft repo description .soft-serve
+stdout 'Test Soft Serve'
+soft repo project-name .soft-serve
+stdout 'Config'
+
+# clone repo
+git clone ssh://localhost:$SSH_PORT/.soft-serve config
+
+# create readme file
+mkfile ./config/README.md '# Hello World\nTest Soft Serve'
+git -C config add -A
+git -C config commit -m 'Initial commit'
+git -C config push origin HEAD
+
+# test repositories tab
+ui '" q"'
+cp stdout home2.txt
+grep 'Config' home2.txt
+grep 'Test Soft Serve' home2.txt
+grep 'git clone ssh://localhost:.*/.soft-serve' home2.txt
+
+# test about tab
+ui '"\t q"'
+cp stdout about2.txt
+grep '• About' about2.txt
+grep 'Hello World' about2.txt
+grep 'Test Soft Serve' about2.txt
+
+# stop the server
+[windows] stopserver
+[windows] ! stderr .
+