From c5fc8b2d8926db3bd8ed9fd928e3cb7a21d56ce3 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 22 Feb 2022 12:27:19 -0500 Subject: [PATCH] feat: cat middleware: list directory entries --- internal/git/git.go | 13 +++--- server/middleware.go | 98 ++++++++++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 42 deletions(-) diff --git a/internal/git/git.go b/internal/git/git.go index f7188c551ca3da69aafae773506b4a533dff345c..cf2b09d37bfdbb3bcea2ae0ec3daab12e26aa222 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -306,13 +306,7 @@ func (rs *RepoSource) loadRepo(name string, rg *git.Repository) (*Repo, error) { // LatestFile returns the latest file at the specified path in the repository. func (r *Repo) LatestFile(path string) (string, error) { - lg, err := r.repository.Log(&git.LogOptions{ - From: r.GetHEAD().Hash(), - }) - if err != nil { - return "", err - } - c, err := lg.Next() + c, err := r.commitForHash(r.head.Hash()) if err != nil { return "", err } @@ -326,3 +320,8 @@ func (r *Repo) LatestFile(path string) (string, error) { } return content, nil } + +// LatestTree returns the latest tree at the specified path in the repository. +func (r *Repo) LatestTree(path string) (*object.Tree, error) { + return r.Tree(r.head, path) +} diff --git a/server/middleware.go b/server/middleware.go index e60fd53b57648ce20db5722a217ae6a0d857f067..cdfc70d73a4a13cc35d1bd997632d811a1f9df32 100644 --- a/server/middleware.go +++ b/server/middleware.go @@ -3,6 +3,7 @@ package server import ( "fmt" "path/filepath" + "sort" "strings" "github.com/alecthomas/chroma/lexers" @@ -11,16 +12,36 @@ import ( appCfg "github.com/charmbracelet/soft-serve/internal/config" "github.com/charmbracelet/soft-serve/internal/tui/bubbles/git/types" "github.com/charmbracelet/wish" - "github.com/charmbracelet/wish/git" + gitwish "github.com/charmbracelet/wish/git" "github.com/gliderlabs/ssh" - gg "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/filemode" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/muesli/termenv" ) var ( - linenoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) + linenoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) + dirnameStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00AAFF")) + filenameStyle = lipgloss.NewStyle() + filemodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#777777")) ) +type entries []object.TreeEntry + +func (cl entries) Len() int { return len(cl) } +func (cl entries) Swap(i, j int) { cl[i], cl[j] = cl[j], cl[i] } +func (cl entries) Less(i, j int) bool { + if cl[i].Mode == filemode.Dir && cl[j].Mode == filemode.Dir { + return cl[i].Name < cl[j].Name + } else if cl[i].Mode == filemode.Dir { + return true + } else if cl[j].Mode == filemode.Dir { + return false + } else { + return cl[i].Name < cl[j].Name + } +} + // softServeMiddleware is a middleware that handles displaying files with the // option of syntax highlighting and line numbers. func softServeMiddleware(ac *appCfg.Config) wish.Middleware { @@ -48,7 +69,7 @@ func softServeMiddleware(ac *appCfg.Config) wish.Middleware { return } auth := ac.AuthRepo(repo, s.PublicKey()) - if auth < git.ReadOnlyAccess { + if auth < gitwish.ReadOnlyAccess { s.Write([]byte("unauthorized")) s.Exit(1) return @@ -66,25 +87,52 @@ func softServeMiddleware(ac *appCfg.Config) wish.Middleware { _ = s.Exit(1) return } - fc, err := readFile(rs.Repository(), strings.Join(ps[1:], "/")) - if err != nil { + p := strings.Join(ps[1:], "/") + t, err := rs.LatestTree(p) + if err != nil && err != object.ErrDirectoryNotFound { _, _ = s.Write([]byte(err.Error())) _ = s.Exit(1) return } - if color { - ffc, err := withFormatting(fp, fc) + if err == object.ErrDirectoryNotFound { + fc, err := rs.LatestFile(p) if err != nil { - s.Write([]byte(err.Error())) - s.Exit(1) + _, _ = s.Write([]byte(err.Error())) + _ = s.Exit(1) return } - fc = ffc - } - if lineno { - fc = withLineNumber(fc, color) + if color { + ffc, err := withFormatting(fp, fc) + if err != nil { + s.Write([]byte(err.Error())) + s.Exit(1) + return + } + fc = ffc + } + if lineno { + fc = withLineNumber(fc, color) + } + s.Write([]byte(fc)) + } else { + ents := entries(t.Entries) + sort.Sort(ents) + for _, e := range ents { + m, _ := e.Mode.ToOSFileMode() + if m == 0 { + s.Write([]byte(strings.Repeat(" ", 10))) + } else { + s.Write([]byte(filemodeStyle.Render(m.String()))) + } + s.Write([]byte(" ")) + if e.Mode.IsFile() { + s.Write([]byte(filenameStyle.Render(e.Name))) + } else { + s.Write([]byte(dirnameStyle.Render(e.Name))) + } + s.Write([]byte("\n")) + } } - s.Write([]byte(fc)) }() } sh(s) @@ -92,26 +140,6 @@ func softServeMiddleware(ac *appCfg.Config) wish.Middleware { } } -func readFile(r *gg.Repository, fp string) (string, error) { - l, err := r.Log(&gg.LogOptions{}) - if err != nil { - return "", err - } - c, err := l.Next() - if err != nil { - return "", err - } - f, err := c.File(fp) - if err != nil { - return "", err - } - fc, err := f.Contents() - if err != nil { - return "", err - } - return fc, nil -} - func withLineNumber(s string, color bool) string { lines := strings.Split(s, "\n") mll := fmt.Sprintf("%d", len(fmt.Sprintf("%d", len(lines))))