920e4a75d11de2f06010d23aab444ab2f02d5d70

Author
Ayman Bagabas <ayman.bagabas@gmail.com>
Committer
Ayman Bagabas <ayman.bagabas@gmail.com>
Date

Message

fix: use lipgloss renderers

Fixes: https://github.com/charmbracelet/soft-serve/pull/468

Diff

This diff is truncated to protect this page.

  1diff --git a/pkg/jobs/mirror.go b/pkg/jobs/mirror.go
  2index 6d5d91685b0dd7bd8caaade35a1f73d1d8a92427..6c7f2e756eb442df58d6bc6797f66d23e5f44197 100644
  3--- a/pkg/jobs/mirror.go
  4+++ b/pkg/jobs/mirror.go
  5@@ -5,6 +5,7 @@ import (
  6 	"fmt"
  7 	"path/filepath"
  8 	"runtime"
  9+	"strings"
 10 
 11 	"github.com/charmbracelet/log"
 12 	"github.com/charmbracelet/soft-serve/git"
 13@@ -62,16 +63,26 @@ func (m mirrorPull) Func(ctx context.Context) func() {
 14 				name := repo.Name()
 15 				wq.Add(name, func() {
 16 					repo := repo
 17-					cmd := git.NewCommand("remote", "update", "--prune").WithContext(ctx)
 18-					cmd.AddEnvs(
 19-						fmt.Sprintf(`GIT_SSH_COMMAND=ssh -o UserKnownHostsFile="%s" -o StrictHostKeyChecking=no -i "%s"`,
 20-							filepath.Join(cfg.DataPath, "ssh", "known_hosts"),
 21-							cfg.SSH.ClientKeyPath,
 22-						),
 23-					)
 24-
 25-					if _, err := cmd.RunInDir(r.Path); err != nil {
 26-						logger.Error("error running git remote update", "repo", name, "err", err)
 27+
 28+					cmds := []string{
 29+						"fetch --prune",               // fetch prune before updating remote
 30+						"gc --aggressive --prune=now", // aggressive garbage collection
 31+						"remote update --prune",       // update remote and prune remote refs
 32+					}
 33+
 34+					for _, c := range cmds {
 35+						args := strings.Split(c, " ")
 36+						cmd := git.NewCommand(args...).WithContext(ctx)
 37+						cmd.AddEnvs(
 38+							fmt.Sprintf(`GIT_SSH_COMMAND=ssh -o UserKnownHostsFile="%s" -o StrictHostKeyChecking=no -i "%s"`,
 39+								filepath.Join(cfg.DataPath, "ssh", "known_hosts"),
 40+								cfg.SSH.ClientKeyPath,
 41+							),
 42+						)
 43+
 44+						if _, err := cmd.RunInDir(r.Path); err != nil {
 45+							logger.Error("error running git remote update", "repo", name, "err", err)
 46+						}
 47 					}
 48 
 49 					if cfg.LFS.Enabled {
 50diff --git a/pkg/ssh/cmd/blob.go b/pkg/ssh/cmd/blob.go
 51index 45e0affb2ad7c0cc9b9a82efecf0fc8e177e63d7..9678a37a49ce426f3e6a910c04a7f804159d95ee 100644
 52--- a/pkg/ssh/cmd/blob.go
 53+++ b/pkg/ssh/cmd/blob.go
 54@@ -3,6 +3,7 @@ package cmd
 55 import (
 56 	"fmt"
 57 
 58+	"github.com/charmbracelet/lipgloss"
 59 	"github.com/charmbracelet/soft-serve/git"
 60 	"github.com/charmbracelet/soft-serve/pkg/backend"
 61 	"github.com/charmbracelet/soft-serve/pkg/ui/common"
 62@@ -11,12 +12,12 @@ import (
 63 )
 64 
 65 // blobCommand returns a command that prints the contents of a file.
 66-func blobCommand() *cobra.Command {
 67+func blobCommand(renderer *lipgloss.Renderer) *cobra.Command {
 68 	var linenumber bool
 69 	var color bool
 70 	var raw bool
 71 
 72-	styles := styles.DefaultStyles()
 73+	styles := styles.DefaultStyles(renderer)
 74 	cmd := &cobra.Command{
 75 		Use:               "blob REPOSITORY [REFERENCE] [PATH]",
 76 		Aliases:           []string{"cat", "show"},
 77diff --git a/pkg/ssh/cmd/commit.go b/pkg/ssh/cmd/commit.go
 78index 4f91b2fed9ef2ca334d266ee4c43b8770ac73a06..52af6725a53692f7310a75cc6efbce33d0c8492b 100644
 79--- a/pkg/ssh/cmd/commit.go
 80+++ b/pkg/ssh/cmd/commit.go
 81@@ -6,6 +6,7 @@ import (
 82 	"time"
 83 
 84 	gansi "github.com/charmbracelet/glamour/ansi"
 85+	"github.com/charmbracelet/lipgloss"
 86 	"github.com/charmbracelet/soft-serve/git"
 87 	"github.com/charmbracelet/soft-serve/pkg/backend"
 88 	"github.com/charmbracelet/soft-serve/pkg/ui/common"
 89@@ -14,7 +15,7 @@ import (
 90 )
 91 
 92 // commitCommand returns a command that prints the contents of a commit.
 93-func commitCommand() *cobra.Command {
 94+func commitCommand(renderer *lipgloss.Renderer) *cobra.Command {
 95 	var color bool
 96 	var patchOnly bool
 97 
 98@@ -54,7 +55,7 @@ func commitCommand() *cobra.Command {
 99 				return err
100 			}
101 
102-			commonStyle := styles.DefaultStyles()
103+			commonStyle := styles.DefaultStyles(renderer)
104 			style := commonStyle.Log
105 
106 			s := strings.Builder{}
107diff --git a/pkg/ssh/cmd/repo.go b/pkg/ssh/cmd/repo.go
108index fa3e72ff9a3098b40314acbca119c86628f9850c..6a2bb541e62e5ac97da0516bb28440a91ccfbe19 100644
109--- a/pkg/ssh/cmd/repo.go
110+++ b/pkg/ssh/cmd/repo.go
111@@ -4,13 +4,14 @@ import (
112 	"fmt"
113 	"strings"
114 
115+	"github.com/charmbracelet/lipgloss"
116 	"github.com/charmbracelet/soft-serve/pkg/backend"
117 	"github.com/charmbracelet/soft-serve/pkg/proto"
118 	"github.com/spf13/cobra"
119 )
120 
121 // RepoCommand returns a command for managing repositories.
122-func RepoCommand() *cobra.Command {
123+func RepoCommand(renderer *lipgloss.Renderer) *cobra.Command {
124 	cmd := &cobra.Command{
125 		Use:     "repo",
126 		Aliases: []string{"repos", "repository", "repositories"},
127@@ -18,10 +19,10 @@ func RepoCommand() *cobra.Command {
128 	}
129 
130 	cmd.AddCommand(
131-		blobCommand(),
132+		blobCommand(renderer),
133 		branchCommand(),
134 		collabCommand(),
135-		commitCommand(),
136+		commitCommand(renderer),
137 		createCommand(),
138 		deleteCommand(),
139 		descriptionCommand(),
140diff --git a/pkg/ssh/middleware.go b/pkg/ssh/middleware.go
141index 5fbbaa6631fa072feb3a26d7b93a65aa61ed127a..638e1f78a4e38513376423f8c8a7d9a4b4ab18b0 100644
142--- a/pkg/ssh/middleware.go
143+++ b/pkg/ssh/middleware.go
144@@ -2,6 +2,7 @@ package ssh
145 
146 import (
147 	"fmt"
148+	"os"
149 	"time"
150 
151 	"github.com/charmbracelet/log"
152@@ -14,6 +15,8 @@ import (
153 	"github.com/charmbracelet/soft-serve/pkg/store"
154 	"github.com/charmbracelet/ssh"
155 	"github.com/charmbracelet/wish"
156+	bm "github.com/charmbracelet/wish/bubbletea"
157+	"github.com/muesli/termenv"
158 	"github.com/prometheus/client_golang/prometheus"
159 	"github.com/prometheus/client_golang/prometheus/promauto"
160 	"github.com/spf13/cobra"
161@@ -87,6 +90,12 @@ func CommandMiddleware(sh ssh.Handler) ssh.Handler {
162 		ctx := s.Context()
163 		cfg := config.FromContext(ctx)
164 
165+		renderer := bm.MakeRenderer(s)
166+		if testrun, ok := os.LookupEnv("SOFT_SERVE_NO_COLOR"); ok && testrun == "1" {
167+			// Disable colors when running tests.
168+			renderer.SetColorProfile(termenv.Ascii)
169+		}
170+
171 		args := s.Command()
172 		cliCommandCounter.WithLabelValues(cmd.CommandName(args)).Inc()
173 		rootCmd := &cobra.Command{
174@@ -101,7 +110,7 @@ func CommandMiddleware(sh ssh.Handler) ssh.Handler {
175 			cmd.GitUploadPackCommand(),
176 			cmd.GitUploadArchiveCommand(),
177 			cmd.GitReceivePackCommand(),
178-			cmd.RepoCommand(),
179+			cmd.RepoCommand(renderer),
180 			cmd.SettingsCommand(),
181 			cmd.UserCommand(),
182 			cmd.InfoCommand(),
183diff --git a/pkg/ssh/session.go b/pkg/ssh/session.go
184index 9907649725434cea3ae675527be6a3c91228059e..290436ca984f2e40e3831145b35331852740aa9f 100644
185--- a/pkg/ssh/session.go
186+++ b/pkg/ssh/session.go
187@@ -1,6 +1,7 @@
188 package ssh
189 
190 import (
191+	"os"
192 	"time"
193 
194 	tea "github.com/charmbracelet/bubbletea"
195@@ -12,6 +13,7 @@ import (
196 	"github.com/charmbracelet/ssh"
197 	"github.com/charmbracelet/wish"
198 	bm "github.com/charmbracelet/wish/bubbletea"
199+	"github.com/muesli/termenv"
200 	"github.com/prometheus/client_golang/prometheus"
201 	"github.com/prometheus/client_golang/prometheus/promauto"
202 )
203@@ -52,8 +54,13 @@ func SessionHandler(s ssh.Session) *tea.Program {
204 		}
205 	}
206 
207-	output := bm.MakeRenderer(s)
208-	c := common.NewCommon(ctx, output, pty.Window.Width, pty.Window.Height)
209+	renderer := bm.MakeRenderer(s)
210+	if testrun, ok := os.LookupEnv("SOFT_SERVE_NO_COLOR"); ok && testrun == "1" {
211+		// Disable colors when running tests.
212+		renderer.SetColorProfile(termenv.Ascii)
213+	}
214+
215+	c := common.NewCommon(ctx, renderer, pty.Window.Width, pty.Window.Height)
216 	c.SetValue(common.ConfigKey, cfg)
217 	m := NewUI(c, initialRepo)
218 	opts := bm.MakeOptions(s)
219diff --git a/pkg/ui/common/common.go b/pkg/ui/common/common.go
220index c5e2319599e5d876e27cb27fb8c5afc079b4bf22..93d40f57328aa1d191dc5115e12b16f1f86d0c9d 100644
221--- a/pkg/ui/common/common.go
222+++ b/pkg/ui/common/common.go
223@@ -34,6 +34,7 @@ type Common struct {
224 	Styles        *styles.Styles
225 	KeyMap        *keymap.KeyMap
226 	Zone          *zone.Manager
227+	Renderer      *lipgloss.Renderer
228 	Output        *termenv.Output
229 	Logger        *log.Logger
230 	HideCloneCmd  bool
231@@ -45,14 +46,15 @@ func NewCommon(ctx context.Context, out *lipgloss.Renderer, width, height int) C
232 		ctx = context.TODO()
233 	}
234 	return Common{
235-		ctx:    ctx,
236-		Width:  width,
237-		Height: height,
238-		Output: out.Output(),
239-		Styles: styles.DefaultStyles(),
240-		KeyMap: keymap.DefaultKeyMap(),
241-		Zone:   zone.New(),
242-		Logger: log.FromContext(ctx).WithPrefix("ui"),
243+		ctx:      ctx,
244+		Width:    width,
245+		Height:   height,
246+		Renderer: out,
247+		Output:   out.Output(),
248+		Styles:   styles.DefaultStyles(out),
249+		KeyMap:   keymap.DefaultKeyMap(),
250+		Zone:     zone.New(),
251+		Logger:   log.FromContext(ctx).WithPrefix("ui"),
252 	}
253 }
254 
255diff --git a/pkg/ui/components/code/code.go b/pkg/ui/components/code/code.go
256index 5dd0ff83249eb77993aee64e399aa62af8b0c3fe..3673eb4caa1de0b8192dcdc0197fb9aaca20ddcf 100644
257--- a/pkg/ui/components/code/code.go
258+++ b/pkg/ui/components/code/code.go
259@@ -121,7 +121,7 @@ func (r *Code) Init() tea.Cmd {
260 	// https://github.com/muesli/reflow/issues/43
261 	//
262 	// TODO: solve this upstream in Glamour/Reflow.
263-	content = lipgloss.NewStyle().Width(w).Render(content)
264+	content = r.common.Renderer.NewStyle().Width(w).Render(content)
265 
266 	r.Viewport.Model.SetContent(content)
267 
268diff --git a/pkg/ui/components/statusbar/statusbar.go b/pkg/ui/components/statusbar/statusbar.go
269index 2ac1fa47e671c4e29b8d009d81bd7ac1ce58a971..2b9e18849df6682813756940e01d666608c3199c 100644
270--- a/pkg/ui/components/statusbar/statusbar.go
271+++ b/pkg/ui/components/statusbar/statusbar.go
272@@ -80,7 +80,7 @@ func (s *Model) View() string {
273 		Width(maxWidth).
274 		Render(v)
275 
276-	return lipgloss.NewStyle().MaxWidth(s.common.Width).
277+	return s.common.Renderer.NewStyle().MaxWidth(s.common.Width).
278 		Render(
279 			lipgloss.JoinHorizontal(lipgloss.Top,
280 				key,
281diff --git a/pkg/ui/components/tabs/tabs.go b/pkg/ui/components/tabs/tabs.go
282index d5132e7f8be01fff7b6490f4ec76f2baf37bb3d8..ac3a780725b4031fa084a73e69a826784c7493f6 100644
283--- a/pkg/ui/components/tabs/tabs.go
284+++ b/pkg/ui/components/tabs/tabs.go
285@@ -105,7 +105,7 @@ func (t *Tabs) View() string {
286 			s.WriteString(sep.String())
287 		}
288 	}
289-	return lipgloss.NewStyle().
290+	return t.common.Renderer.NewStyle().
291 		MaxWidth(t.common.Width).
292 		Render(s.String())
293 }
294diff --git a/pkg/ui/pages/repo/filesitem.go b/pkg/ui/pages/repo/filesitem.go
295index 04b6715e3446a7d0406d0cfdb21482730e68fe88..fde57de8c380a22932cf3992d6cc3b2cfd1f0e11 100644
296--- a/pkg/ui/pages/repo/filesitem.go
297+++ b/pkg/ui/pages/repo/filesitem.go
298@@ -4,6 +4,7 @@ import (
299 	"fmt"
300 	"io"
301 	"io/fs"
302+	"strconv"
303 	"strings"
304 
305 	"github.com/charmbracelet/bubbles/key"
306@@ -22,7 +23,11 @@ type FileItem struct {
307 
308 // ID returns the ID of the file item.
309 func (i FileItem) ID() string {
310-	return i.entry.Name()
311+	name := i.entry.Name()
312+	if n, err := strconv.Unquote(name); err == nil {
313+		name = n
314+	}
315+	return name
316 }
317 
318 // Title returns the title of the file item.
319@@ -139,7 +144,7 @@ func (d FileItemDelegate) Render(w io.Writer, m list.Model, index int, listItem
320 	name = nameStyle.Render(name)
321 	size = sizeStyle.Render(size)
322 	modeStr := modeStyle.Render(mode.String())
323-	truncate := lipgloss.NewStyle().MaxWidth(m.Width() -
324+	truncate := d.common.Renderer.NewStyle().MaxWidth(m.Width() -
325 		s.Selector.GetHorizontalFrameSize() -
326 		s.Selector.GetWidth())
327 	fmt.Fprint(w,
328diff --git a/pkg/ui/pages/repo/repo.go b/pkg/ui/pages/repo/repo.go
329index 535937d4e46bc6cee34ab01aa3b47cf35dbd866f..5d4105bf65172e4d4467096efa0bccb44c7bfa8e 100644
330--- a/pkg/ui/pages/repo/repo.go
331+++ b/pkg/ui/pages/repo/repo.go
332@@ -323,7 +323,7 @@ func (r *Repo) headerView() string {
333 	if r.selectedRepo == nil {
334 		return ""
335 	}
336-	truncate := lipgloss.NewStyle().MaxWidth(r.common.Width)
337+	truncate := r.common.Renderer.NewStyle().MaxWidth(r.common.Width)
338 	header := r.selectedRepo.ProjectName()
339 	if header == "" {
340 		header = r.selectedRepo.Name()
341diff --git a/pkg/ui/pages/selection/selection.go b/pkg/ui/pages/selection/selection.go
342index 4b9b72a17ddd5ea0c37e2622f26f53e0b6b08567..8dd56e66c4cd4689f2dc0cb9ee5995b50aee125d 100644
343--- a/pkg/ui/pages/selection/selection.go
344+++ b/pkg/ui/pages/selection/selection.go
345@@ -51,7 +51,7 @@ func New(c common.Common) *Selection {
346 		ts[i] = b.String()
347 	}
348 	t := tabs.New(c, ts)
349-	t.TabSeparator = lipgloss.NewStyle()
350+	t.TabSeparator = c.Renderer.NewStyle()
351 	t.TabInactive = c.Styles.TopLevelNormalTab.Copy()
352 	t.TabActive = c.Styles.TopLevelActiveTab.Copy()
353 	t.TabDot = c.Styles.TopLevelActiveTabDot.Copy()
354@@ -289,15 +289,15 @@ func (s *Selection) View() string {
355 	wm, hm := s.getMargins()
356 	switch s.activePane {
357 	case selectorPane:
358-		ss := lipgloss.NewStyle().
359+		ss := s.common.Renderer.NewStyle().
360 			Width(s.common.Width - wm).
361 			Height(s.common.Height - hm)
362 		view = ss.Render(s.selector.View())
363 	case readmePane:
364-		rs := lipgloss.NewStyle().
365+		rs := s.common.Renderer.NewStyle().
366 			Height(s.common.Height - hm)
367 		status := fmt.Sprintf("☰ %.f%%", s.readme.ScrollPercent()*100)
368-		readmeStatus := lipgloss.NewStyle().
369+		readmeStatus := s.common.Renderer.NewStyle().
370 			Align(lipgloss.Right).
371 			Width(s.common.Width - wm).
372 			Foreground(s.common.Styles.InactiveBorderColor).
373diff --git a/pkg/ui/styles/styles.go b/pkg/ui/styles/styles.go
374index c8bc0aa53dfa4dae0d4b813f8211dcd772396fa6..5874d2cdf563914cf06554830b6683a37cc3a3f9 100644
375--- a/pkg/ui/styles/styles.go
376+++ b/pkg/ui/styles/styles.go
377@@ -165,7 +165,7 @@ type Styles struct {
378 }
379 
380 // DefaultStyles returns default styles for the UI.
381-func DefaultStyles() *Styles {
382+func DefaultStyles(r *lipgloss.Renderer) *Styles {
383 	highlightColor := lipgloss.Color("210")
384 	highlightColorDim := lipgloss.Color("174")
385 	selectorColor := lipgloss.Color("167")
386@@ -176,10 +176,10 @@ func DefaultStyles() *Styles {
387 	s.ActiveBorderColor = lipgloss.Color("62")
388 	s.InactiveBorderColor = lipgloss.Color("241")
389 
390-	s.App = lipgloss.NewStyle().
391+	s.App = r.NewStyle().
392 		Margin(1, 2)
393 
394-	s.ServerName = lipgloss.NewStyle().
395+	s.ServerName = r.NewStyle().
396 		Height(1).
397 		MarginLeft(1).
398 		MarginBottom(1).
399@@ -188,29 +188,29 @@ func DefaultStyles() *Styles {
400 		Foreground(lipgloss.Color("229")).
401 		Bold(true)
402 
403-	s.TopLevelNormalTab = lipgloss.NewStyle().
404+	s.TopLevelNormalTab = r.NewStyle().
405 		MarginRight(2)
406 
407 	s.TopLevelActiveTab = s.TopLevelNormalTab.Copy().
408 		Foreground(lipgloss.Color("36"))
409 
410-	s.TopLevelActiveTabDot = lipgloss.NewStyle().
411+	s.TopLevelActiveTabDot = r.NewStyle().
412 		Foreground(lipgloss.Color("36"))
413 
414-	s.RepoSelector.Normal.Base = lipgloss.NewStyle().
415+	s.RepoSelector.Normal.Base = r.NewStyle().
416 		PaddingLeft(1).
417 		Border(lipgloss.Border{Left: " "}, false, false, false, true).
418 		Height(3)
419 
420-	s.RepoSelector.Normal.Title = lipgloss.NewStyle().Bold(true)
421+	s.RepoSelector.Normal.Title = r.NewStyle().Bold(true)
422 
423-	s.RepoSelector.Normal.Desc = lipgloss.NewStyle().
424+	s.RepoSelector.Normal.Desc = r.NewStyle().
425 		Foreground(lipgloss.Color("243"))
426 
427-	s.RepoSelector.Normal.Command = lipgloss.NewStyle().
428+	s.RepoSelector.Normal.Command = r.NewStyle().
429 		Foreground(lipgloss.Color("132"))
430 
431-	s.RepoSelector.Normal.Updated = lipgloss.NewStyle().
432+	s.RepoSelector.Normal.Updated = r.NewStyle().
433 		Foreground(lipgloss.Color("243"))
434 
435 	s.RepoSelector.Active.Base = s.RepoSelector.Normal.Base.Copy().
436@@ -229,78 +229,78 @@ func DefaultStyles() *Styles {
437 	s.RepoSelector.Active.Command = s.RepoSelector.Normal.Command.Copy().
438 		Foreground(lipgloss.Color("204"))
439 
440-	s.MenuItem = lipgloss.NewStyle().
441+	s.MenuItem = r.NewStyle().
442 		PaddingLeft(1).
443 		Border(lipgloss.Border{
444 			Left: " ",
445 		}, false, false, false, true).
446 		Height(3)
447 
448-	s.MenuLastUpdate = lipgloss.NewStyle().
449+	s.MenuLastUpdate = r.NewStyle().
450 		Foreground(lipgloss.Color("241")).
451 		Align(lipgloss.Right)
452 
453-	s.Repo.Base = lipgloss.NewStyle()
454+	s.Repo.Base = r.NewStyle()
455 
456-	s.Repo.Title = lipgloss.NewStyle().
457+	s.Repo.Title = r.NewStyle().
458 		Padding(0, 2)
459 
460-	s.Repo.Command = lipgloss.NewStyle().
461+	s.Repo.Command = r.NewStyle().
462 		Foreground(lipgloss.Color("168"))
463 
464-	s.Repo.Body = lipgloss.NewStyle().
465+	s.Repo.Body = r.NewStyle().
466 		Margin(1, 0)
467 
468-	s.Repo.Header = lipgloss.NewStyle().
469+	s.Repo.Header = r.NewStyle().
470 		MaxHeight(2).
471 		Border(lipgloss.NormalBorder(), false, false, true, false).
472 		BorderForeground(lipgloss.Color("236"))
473 
474-	s.Repo.HeaderName = lipgloss.NewStyle().
475+	s.Repo.HeaderName = r.NewStyle().
476 		Foreground(lipgloss.Color("212")).