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}