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}