From 3ef6d864ef7378b64e56e088f07e6c52a7092f45 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 11 May 2023 12:47:38 -0700 Subject: [PATCH] fix(ui): UI regressions (#279) * fix(backend): wrap i/o operations in transactions when i/o errors, transaction rolls back * fix(lint): inefficient assignment * fix(ui): respect log settings * fix(ui): truncate command string after yanking * fix(git): make sure to use system git config in diff * fix(ui): move support goto top/bottom in viewport --- cmd/soft/root.go | 28 ++-------------- git/repo.go | 6 +++- internal/log/log.go | 39 +++++++++++++++++++++++ server/git/git.go | 1 + server/ssh/session.go | 6 +++- server/ui/components/code/code.go | 11 +------ server/ui/components/viewport/viewport.go | 10 ++++++ server/ui/pages/repo/log.go | 4 +++ server/ui/pages/selection/item.go | 13 +++++--- 9 files changed, 76 insertions(+), 42 deletions(-) create mode 100644 internal/log/log.go diff --git a/cmd/soft/root.go b/cmd/soft/root.go index edd7c21492974d1923c7cf8a6967237fa24bc09b..1dc8e1883c9bac8c1b38b00c422cbc4bb7037532 100644 --- a/cmd/soft/root.go +++ b/cmd/soft/root.go @@ -4,11 +4,9 @@ import ( "context" "os" "runtime/debug" - "strconv" - "strings" - "time" "github.com/charmbracelet/log" + . "github.com/charmbracelet/soft-serve/internal/log" "github.com/spf13/cobra" ) @@ -53,28 +51,8 @@ func init() { } func main() { - ctx := context.Background() - logger := log.NewWithOptions(os.Stderr, log.Options{ - ReportTimestamp: true, - TimeFormat: time.DateOnly, - }) - if debug, _ := strconv.ParseBool(os.Getenv("SOFT_SERVE_DEBUG")); debug { - logger.SetLevel(log.DebugLevel) - } - if tsfmt := os.Getenv("SOFT_SERVE_LOG_TIME_FORMAT"); tsfmt != "" { - logger.SetTimeFormat(tsfmt) - } - - switch strings.ToLower(os.Getenv("SOFT_SERVE_LOG_FORMAT")) { - case "json": - logger.SetFormatter(log.JSONFormatter) - case "logfmt": - logger.SetFormatter(log.LogfmtFormatter) - case "text": - logger.SetFormatter(log.TextFormatter) - } - - ctx = log.WithContext(ctx, logger) + logger := NewDefaultLogger() + ctx := log.WithContext(context.Background(), logger) if err := rootCmd.ExecuteContext(ctx); err != nil { os.Exit(1) } diff --git a/git/repo.go b/git/repo.go index 050d3f67fd85a53766ce7b7de5f4311bc3563b9e..67a0e286d45ce438102a9e793665f86745c1be8e 100644 --- a/git/repo.go +++ b/git/repo.go @@ -147,7 +147,11 @@ func (r *Repository) TreePath(ref *Reference, path string) (*Tree, error) { // Diff returns the diff for the given commit. func (r *Repository) Diff(commit *Commit) (*Diff, error) { - ddiff, err := r.Repository.Diff(commit.Hash.String(), DiffMaxFiles, DiffMaxFileLines, DiffMaxLineChars) + ddiff, err := r.Repository.Diff(commit.Hash.String(), DiffMaxFiles, DiffMaxFileLines, DiffMaxLineChars, git.DiffOptions{ + CommandOptions: git.CommandOptions{ + Envs: []string{"GIT_CONFIG_GLOBAL=/dev/null"}, + }, + }) if err != nil { return nil, err } diff --git a/internal/log/log.go b/internal/log/log.go new file mode 100644 index 0000000000000000000000000000000000000000..a1184153b81da766f76fc10ca7f533c0a486b710 --- /dev/null +++ b/internal/log/log.go @@ -0,0 +1,39 @@ +package log + +import ( + "os" + "strconv" + "strings" + "time" + + "github.com/charmbracelet/log" +) + +var contextKey = &struct{ string }{"logger"} + +// NewDefaultLogger returns a new logger with default settings. +func NewDefaultLogger() *log.Logger { + logger := log.NewWithOptions(os.Stderr, log.Options{ + ReportTimestamp: true, + TimeFormat: time.DateOnly, + }) + + if debug, _ := strconv.ParseBool(os.Getenv("SOFT_SERVE_DEBUG")); debug { + logger.SetLevel(log.DebugLevel) + } + + if tsfmt := os.Getenv("SOFT_SERVE_LOG_TIME_FORMAT"); tsfmt != "" { + logger.SetTimeFormat(tsfmt) + } + + switch strings.ToLower(os.Getenv("SOFT_SERVE_LOG_FORMAT")) { + case "json": + logger.SetFormatter(log.JSONFormatter) + case "logfmt": + logger.SetFormatter(log.LogfmtFormatter) + case "text": + logger.SetFormatter(log.TextFormatter) + } + + return logger +} diff --git a/server/git/git.go b/server/git/git.go index 0b14f0b5031901b2b4299d87981f43134509edb9..85e2cf068e5f24e141c0455db2d8a1a5aa01121c 100644 --- a/server/git/git.go +++ b/server/git/git.go @@ -88,6 +88,7 @@ func RunGit(ctx context.Context, in io.Reader, out io.Writer, er io.Writer, dir c.Env = append(c.Env, "SOFT_SERVE_DEBUG="+os.Getenv("SOFT_SERVE_DEBUG")) if cfg != nil { c.Env = append(c.Env, "SOFT_SERVE_LOG_FORMAT="+cfg.LogFormat) + c.Env = append(c.Env, "SOFT_SERVE_LOG_TIME_FORMAT="+cfg.LogTimeFormat) } stdin, err := c.StdinPipe() diff --git a/server/ssh/session.go b/server/ssh/session.go index e24bdc83a4cd9d453ae0acf3793c6c459fa5c6a3..b39e15e24cc305c14eac1f59c777c0baa5f20f52 100644 --- a/server/ssh/session.go +++ b/server/ssh/session.go @@ -4,6 +4,8 @@ import ( "strings" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/log" + . "github.com/charmbracelet/soft-serve/internal/log" "github.com/charmbracelet/soft-serve/server/backend" "github.com/charmbracelet/soft-serve/server/config" "github.com/charmbracelet/soft-serve/server/errors" @@ -48,7 +50,9 @@ func SessionHandler(cfg *config.Config) bm.ProgramHandler { envs := &sessionEnv{s} output := termenv.NewOutput(s, termenv.WithColorCache(true), termenv.WithEnvironment(envs)) - c := common.NewCommon(s.Context(), output, pty.Window.Width, pty.Window.Height) + logger := NewDefaultLogger() + ctx := log.WithContext(s.Context(), logger) + c := common.NewCommon(ctx, output, pty.Window.Width, pty.Window.Height) c.SetValue(common.ConfigKey, cfg) m := ui.New(c, initialRepo) p := tea.NewProgram(m, diff --git a/server/ui/components/code/code.go b/server/ui/components/code/code.go index bf3fc4c4d080159e478aac05280d22631e97a9b7..8291183349ee1059b6baa703f692014f0c55952c 100644 --- a/server/ui/components/code/code.go +++ b/server/ui/components/code/code.go @@ -6,7 +6,6 @@ import ( "sync" "github.com/alecthomas/chroma/lexers" - "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/glamour" gansi "github.com/charmbracelet/glamour/ansi" @@ -99,18 +98,10 @@ func (r *Code) Init() tea.Cmd { // Update implements tea.Model. func (r *Code) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds := make([]tea.Cmd, 0) - switch msg := msg.(type) { + switch msg.(type) { case tea.WindowSizeMsg: // Recalculate content width and line wrap. cmds = append(cmds, r.Init()) - case tea.KeyMsg: - // Viewport doesn't handle these keys, so we do it here. - switch { - case key.Matches(msg, r.common.KeyMap.GotoTop): - r.GotoTop() - case key.Matches(msg, r.common.KeyMap.GotoBottom): - r.GotoBottom() - } } v, cmd := r.Viewport.Update(msg) r.Viewport = v.(*vp.Viewport) diff --git a/server/ui/components/viewport/viewport.go b/server/ui/components/viewport/viewport.go index bdccc0f0ad5971938b6dc364b938e529c0c6248b..35fe8f24da7147bb2404d03af6fdeb6982c3514d 100644 --- a/server/ui/components/viewport/viewport.go +++ b/server/ui/components/viewport/viewport.go @@ -1,6 +1,7 @@ package viewport import ( + "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/soft-serve/server/ui/common" @@ -36,6 +37,15 @@ func (v *Viewport) Init() tea.Cmd { // Update implements tea.Model. func (v *Viewport) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch { + case key.Matches(msg, v.common.KeyMap.GotoTop): + v.GotoTop() + case key.Matches(msg, v.common.KeyMap.GotoBottom): + v.GotoBottom() + } + } vp, cmd := v.Model.Update(msg) v.Model = &vp return v, cmd diff --git a/server/ui/pages/repo/log.go b/server/ui/pages/repo/log.go index 0b1480b466840e9f6f6fb9ca09c4fbdaed0adb2a..21bbcdf9fe46cf8fec7738168fcdbb50d2efd3b1 100644 --- a/server/ui/pages/repo/log.go +++ b/server/ui/pages/repo/log.go @@ -105,6 +105,8 @@ func (l *Log) ShortHelp() []key.Binding { return []key.Binding{ l.common.KeyMap.UpDown, l.common.KeyMap.BackItem, + l.common.KeyMap.GotoTop, + l.common.KeyMap.GotoBottom, } default: return []key.Binding{} @@ -151,6 +153,8 @@ func (l *Log) FullHelp() [][]key.Binding { { k.Down, k.Up, + l.common.KeyMap.GotoTop, + l.common.KeyMap.GotoBottom, }, }...) } diff --git a/server/ui/pages/selection/item.go b/server/ui/pages/selection/item.go index bc06210738a1b4206ad794f53a86b0e5506ce864..6550497c78b954f03ce5dc9627aefce0d9ce66b4 100644 --- a/server/ui/pages/selection/item.go +++ b/server/ui/pages/selection/item.go @@ -83,7 +83,7 @@ func (i Item) Title() string { } // Description returns the item description. Implements list.DefaultItem. -func (i Item) Description() string { return i.repo.Description() } +func (i Item) Description() string { return strings.TrimSpace(i.repo.Description()) } // FilterValue implements list.Item. func (i Item) FilterValue() string { return i.Title() } @@ -199,13 +199,16 @@ func (d *ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem lis s.WriteRune('\n') s.WriteString(desc) s.WriteRune('\n') - cmd := common.TruncateString(i.Command(), m.Width()-styles.Base.GetHorizontalFrameSize()) - cmd = styles.Command.Render(cmd) + + cmd := i.Command() + cmdStyler := styles.Command.Render if d.copiedIdx == index { - cmd += " " + styles.Desc.Render("(copied to clipboard)") + cmd = "(copied to clipboard)" + cmdStyler = styles.Desc.Render d.copiedIdx = -1 } - s.WriteString(cmd) + cmd = common.TruncateString(cmd, m.Width()-styles.Base.GetHorizontalFrameSize()) + s.WriteString(cmdStyler(cmd)) fmt.Fprint(w, d.common.Zone.Mark(i.ID(), styles.Base.Render(s.String()),