common.go

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