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	Renderer      *lipgloss.Renderer
 38	Output        *termenv.Output
 39	Logger        *log.Logger
 40	HideCloneCmd  bool
 41}
 42
 43// NewCommon returns a new Common struct.
 44func NewCommon(ctx context.Context, out *lipgloss.Renderer, width, height int) Common {
 45	if ctx == nil {
 46		ctx = context.TODO()
 47	}
 48	return Common{
 49		ctx:      ctx,
 50		Width:    width,
 51		Height:   height,
 52		Renderer: out,
 53		Output:   out.Output(),
 54		Styles:   styles.DefaultStyles(out),
 55		KeyMap:   keymap.DefaultKeyMap(),
 56		Zone:     zone.New(),
 57		Logger:   log.FromContext(ctx).WithPrefix("ui"),
 58	}
 59}
 60
 61// SetValue sets a value in the context.
 62func (c *Common) SetValue(key, value interface{}) {
 63	c.ctx = context.WithValue(c.ctx, key, value)
 64}
 65
 66// SetSize sets the width and height of the common struct.
 67func (c *Common) SetSize(width, height int) {
 68	c.Width = width
 69	c.Height = height
 70}
 71
 72// Context returns the context.
 73func (c *Common) Context() context.Context {
 74	return c.ctx
 75}
 76
 77// Config returns the server config.
 78func (c *Common) Config() *config.Config {
 79	return config.FromContext(c.ctx)
 80}
 81
 82// Backend returns the Soft Serve backend.
 83func (c *Common) Backend() *backend.Backend {
 84	return backend.FromContext(c.ctx)
 85}
 86
 87// Repo returns the repository.
 88func (c *Common) Repo() *git.Repository {
 89	v := c.ctx.Value(RepoKey)
 90	if r, ok := v.(*git.Repository); ok {
 91		return r
 92	}
 93	return nil
 94}
 95
 96// PublicKey returns the public key.
 97func (c *Common) PublicKey() ssh.PublicKey {
 98	v := c.ctx.Value(ssh.ContextKeyPublicKey)
 99	if p, ok := v.(ssh.PublicKey); ok {
100		return p
101	}
102	return nil
103}
104
105// CloneCmd returns the clone command string.
106func (c *Common) CloneCmd(publicURL, name string) string {
107	if c.HideCloneCmd {
108		return ""
109	}
110	return fmt.Sprintf("git clone %s", RepoURL(publicURL, name))
111}
112
113// IsFileMarkdown returns true if the file is markdown.
114// It uses chroma lexers to analyze and determine the language.
115func IsFileMarkdown(content, ext string) bool {
116	var lang string
117	lexer := lexers.Match(ext)
118	if lexer == nil {
119		lexer = lexers.Analyse(content)
120	}
121	if lexer != nil && lexer.Config() != nil {
122		lang = lexer.Config().Name
123	}
124	return lang == "markdown"
125}