common.go

  1package common
  2
  3import (
  4	"context"
  5	"fmt"
  6
  7	"github.com/alecthomas/chroma/v2/lexers"
  8	"github.com/charmbracelet/lipgloss"
  9	"github.com/charmbracelet/log"
 10	"github.com/charmbracelet/soft-serve/git"
 11	"github.com/charmbracelet/soft-serve/pkg/backend"
 12	"github.com/charmbracelet/soft-serve/pkg/config"
 13	"github.com/charmbracelet/soft-serve/pkg/ui/keymap"
 14	"github.com/charmbracelet/soft-serve/pkg/ui/styles"
 15	"github.com/charmbracelet/ssh"
 16	zone "github.com/lrstanley/bubblezone"
 17	"github.com/muesli/termenv"
 18)
 19
 20type contextKey struct {
 21	name string
 22}
 23
 24// Keys to use for context.Context.
 25var (
 26	ConfigKey = &contextKey{"config"}
 27	RepoKey   = &contextKey{"repo"}
 28)
 29
 30// Common is a struct all components should embed.
 31type Common struct {
 32	ctx           context.Context
 33	Width, Height int
 34	Styles        *styles.Styles
 35	KeyMap        *keymap.KeyMap
 36	Zone          *zone.Manager
 37	Output        *termenv.Output
 38	Logger        *log.Logger
 39	HideCloneCmd  bool
 40}
 41
 42// NewCommon returns a new Common struct.
 43func NewCommon(ctx context.Context, out *lipgloss.Renderer, width, height int) Common {
 44	if ctx == nil {
 45		ctx = context.TODO()
 46	}
 47	return Common{
 48		ctx:    ctx,
 49		Width:  width,
 50		Height: height,
 51		Output: out.Output(),
 52		Styles: styles.DefaultStyles(),
 53		KeyMap: keymap.DefaultKeyMap(),
 54		Zone:   zone.New(),
 55		Logger: log.FromContext(ctx).WithPrefix("ui"),
 56	}
 57}
 58
 59// SetValue sets a value in the context.
 60func (c *Common) SetValue(key, value interface{}) {
 61	c.ctx = context.WithValue(c.ctx, key, value)
 62}
 63
 64// SetSize sets the width and height of the common struct.
 65func (c *Common) SetSize(width, height int) {
 66	c.Width = width
 67	c.Height = height
 68}
 69
 70// Context returns the context.
 71func (c *Common) Context() context.Context {
 72	return c.ctx
 73}
 74
 75// Config returns the server config.
 76func (c *Common) Config() *config.Config {
 77	return config.FromContext(c.ctx)
 78}
 79
 80// Backend returns the Soft Serve backend.
 81func (c *Common) Backend() *backend.Backend {
 82	return backend.FromContext(c.ctx)
 83}
 84
 85// Repo returns the repository.
 86func (c *Common) Repo() *git.Repository {
 87	v := c.ctx.Value(RepoKey)
 88	if r, ok := v.(*git.Repository); ok {
 89		return r
 90	}
 91	return nil
 92}
 93
 94// PublicKey returns the public key.
 95func (c *Common) PublicKey() ssh.PublicKey {
 96	v := c.ctx.Value(ssh.ContextKeyPublicKey)
 97	if p, ok := v.(ssh.PublicKey); ok {
 98		return p
 99	}
100	return nil
101}
102
103// CloneCmd returns the clone command string.
104func (c *Common) CloneCmd(publicURL, name string) string {
105	if c.HideCloneCmd {
106		return ""
107	}
108	return fmt.Sprintf("git clone %s", RepoURL(publicURL, name))
109}
110
111// IsFileMarkdown returns true if the file is markdown.
112// It uses chroma lexers to analyze and determine the language.
113func IsFileMarkdown(content, ext string) bool {
114	var lang string
115	lexer := lexers.Match(ext)
116	if lexer == nil {
117		lexer = lexers.Analyse(content)
118	}
119	if lexer != nil && lexer.Config() != nil {
120		lang = lexer.Config().Name
121	}
122	return lang == "markdown"
123}