common.go 3.1 KB

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