Skip to content

Commit

Permalink
feat: display files middleware
Browse files Browse the repository at this point in the history
sshing with a filepath in a non-interactive terminal spits out the file
content with the option of syntax highlighting and line numbers
  • Loading branch information
aymanbagabas committed Feb 8, 2022
1 parent 4fab795 commit 9ea2a7e
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
144 changes: 144 additions & 0 deletions server/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package server

import (
"fmt"
"path/filepath"
"strings"

"github.com/alecthomas/chroma/lexers"
gansi "github.com/charmbracelet/glamour/ansi"
"github.com/charmbracelet/lipgloss"
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"
"github.com/gliderlabs/ssh"
gg "github.com/go-git/go-git/v5"
"github.com/muesli/termenv"
)

// softServeMiddleware is a middleware that handles displaying files with the
// option of syntax highlighting and line numbers.
func softServeMiddleware(ac *appCfg.Config) wish.Middleware {
return func(sh ssh.Handler) ssh.Handler {
return func(s ssh.Session) {
_, _, active := s.Pty()
cmds := s.Command()
if !active && len(cmds) > 0 {
func() {
formatting := false
lineno := false
fp := filepath.Clean(cmds[0])
ps := strings.Split(fp, "/")
repo := ps[0]
repoExists := false
for _, rp := range ac.Source.AllRepos() {
if rp.Name == repo {
repoExists = true
}
}
if !repoExists {
return
}
auth := ac.AuthRepo(repo, s.PublicKey())
if auth < git.ReadOnlyAccess {
s.Write([]byte("unauthorized"))
s.Exit(1)
return
}
for _, op := range cmds[1:] {
if op == "formatting" {
formatting = true
} else if op == "lineno" || op == "linenumber" {
lineno = true
}
}
rs, err := ac.Source.GetRepo(repo)
if err != nil {
_, _ = s.Write([]byte(err.Error()))
_ = s.Exit(1)
return
}
fc, err := readFile(rs.Repository, strings.Join(ps[1:], "/"))
if err != nil {
_, _ = s.Write([]byte(err.Error()))
_ = s.Exit(1)
return
}
if formatting {
ffc, err := withFormatting(fp, fc)
if err != nil {
s.Write([]byte(err.Error()))
s.Exit(1)
return
}
fc = ffc
}
if lineno {
fc = withLineNumber(fc, formatting)
}
s.Write([]byte(fc))
}()
}
sh(s)
}
}
}

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, formatting bool) string {
st := lipgloss.NewStyle().Foreground(lipgloss.Color("15"))
lines := strings.Split(s, "\n")
mll := fmt.Sprintf("%d", len(fmt.Sprintf("%d", len(lines))))
for i, l := range lines {
lines[i] = fmt.Sprintf("%-"+mll+"d │ %s", i+1, l)
if formatting {
lines[i] = st.Render(lines[i])
}
}
return strings.Join(lines, "\n")
}

func withFormatting(p, c string) (string, error) {
zero := uint(0)
lang := ""
lexer := lexers.Match(p)
if lexer != nil && lexer.Config() != nil {
lang = lexer.Config().Name
}
formatter := &gansi.CodeBlockElement{
Code: c,
Language: lang,
}
r := strings.Builder{}
styles := types.DefaultStyles()
styles.CodeBlock.Margin = &zero
rctx := gansi.NewRenderContext(gansi.Options{
Styles: styles,
ColorProfile: termenv.TrueColor,
})
err := formatter.Render(&r, rctx)
if err != nil {
return "", err
}
return r.String(), nil
}
1 change: 1 addition & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func NewServer(cfg *config.Config) *Server {
mw := []wish.Middleware{
rm.MiddlewareWithLogger(
cfg.ErrorLog,
softServeMiddleware(ac),
bm.Middleware(tui.SessionHandler(ac)),
gm.Middleware(cfg.RepoPath, ac),
lm.Middleware(),
Expand Down

0 comments on commit 9ea2a7e

Please sign in to comment.