common.go

 1package common
 2
 3import (
 4	"fmt"
 5	"image"
 6	"os"
 7
 8	tea "charm.land/bubbletea/v2"
 9	"github.com/atotto/clipboard"
10	"github.com/charmbracelet/crush/internal/app"
11	"github.com/charmbracelet/crush/internal/config"
12	"github.com/charmbracelet/crush/internal/ui/styles"
13	"github.com/charmbracelet/crush/internal/uiutil"
14	uv "github.com/charmbracelet/ultraviolet"
15)
16
17// MaxAttachmentSize defines the maximum allowed size for file attachments (5 MB).
18const MaxAttachmentSize = int64(5 * 1024 * 1024)
19
20// AllowedImageTypes defines the permitted image file types.
21var AllowedImageTypes = []string{".jpg", ".jpeg", ".png"}
22
23// Common defines common UI options and configurations.
24type Common struct {
25	App    *app.App
26	Styles *styles.Styles
27}
28
29// Config returns the configuration associated with this [Common] instance.
30func (c *Common) Config() *config.Config {
31	return c.App.Config()
32}
33
34// DefaultCommon returns the default common UI configurations.
35func DefaultCommon(app *app.App) *Common {
36	s := styles.DefaultStyles()
37	return &Common{
38		App:    app,
39		Styles: &s,
40	}
41}
42
43// CenterRect returns a new [Rectangle] centered within the given area with the
44// specified width and height.
45func CenterRect(area uv.Rectangle, width, height int) uv.Rectangle {
46	centerX := area.Min.X + area.Dx()/2
47	centerY := area.Min.Y + area.Dy()/2
48	minX := centerX - width/2
49	minY := centerY - height/2
50	maxX := minX + width
51	maxY := minY + height
52	return image.Rect(minX, minY, maxX, maxY)
53}
54
55// IsFileTooBig checks if the file at the given path exceeds the specified size
56// limit.
57func IsFileTooBig(filePath string, sizeLimit int64) (bool, error) {
58	fileInfo, err := os.Stat(filePath)
59	if err != nil {
60		return false, fmt.Errorf("error getting file info: %w", err)
61	}
62
63	if fileInfo.Size() > sizeLimit {
64		return true, nil
65	}
66
67	return false, nil
68}
69
70// CopyToClipboard copies the given text to the clipboard using both OSC 52
71// (terminal escape sequence) and native clipboard for maximum compatibility.
72// Returns a command that reports success to the user with the given message.
73func CopyToClipboard(text, successMessage string) tea.Cmd {
74	return CopyToClipboardWithCallback(text, successMessage, nil)
75}
76
77// CopyToClipboardWithCallback copies text to clipboard and executes a callback
78// before showing the success message.
79// This is useful when you need to perform additional actions like clearing UI state.
80func CopyToClipboardWithCallback(text, successMessage string, callback tea.Cmd) tea.Cmd {
81	return tea.Sequence(
82		tea.SetClipboard(text),
83		func() tea.Msg {
84			_ = clipboard.WriteAll(text)
85			return nil
86		},
87		callback,
88		uiutil.ReportInfo(successMessage),
89	)
90}