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}