common.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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 configuration associated with this [Common] instance.
  24. func (c *Common) Config() *config.Config {
  25. return c.App.Config()
  26. }
  27. // DefaultCommon returns the default common UI configurations.
  28. func DefaultCommon(app *app.App) *Common {
  29. s := styles.DefaultStyles()
  30. return &Common{
  31. App: app,
  32. Styles: &s,
  33. }
  34. }
  35. // CenterRect returns a new [Rectangle] centered within the given area with the
  36. // specified width and height.
  37. func CenterRect(area uv.Rectangle, width, height int) uv.Rectangle {
  38. centerX := area.Min.X + area.Dx()/2
  39. centerY := area.Min.Y + area.Dy()/2
  40. minX := centerX - width/2
  41. minY := centerY - height/2
  42. maxX := minX + width
  43. maxY := minY + height
  44. return image.Rect(minX, minY, maxX, maxY)
  45. }
  46. // BottomLeftRect returns a new [Rectangle] positioned at the bottom-left within the given area with the
  47. // specified width and height.
  48. func BottomLeftRect(area uv.Rectangle, width, height int) uv.Rectangle {
  49. minX := area.Min.X
  50. maxX := minX + width
  51. maxY := area.Max.Y
  52. minY := maxY - height
  53. return image.Rect(minX, minY, maxX, maxY)
  54. }
  55. // IsFileTooBig checks if the file at the given path exceeds the specified size
  56. // limit.
  57. func 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. if fileInfo.Size() > sizeLimit {
  63. return true, nil
  64. }
  65. return false, nil
  66. }
  67. // CopyToClipboard copies the given text to the clipboard using both OSC 52
  68. // (terminal escape sequence) and native clipboard for maximum compatibility.
  69. // Returns a command that reports success to the user with the given message.
  70. func CopyToClipboard(text, successMessage string) tea.Cmd {
  71. return CopyToClipboardWithCallback(text, successMessage, nil)
  72. }
  73. // CopyToClipboardWithCallback copies text to clipboard and executes a callback
  74. // before showing the success message.
  75. // This is useful when you need to perform additional actions like clearing UI state.
  76. func CopyToClipboardWithCallback(text, successMessage string, callback tea.Cmd) tea.Cmd {
  77. return tea.Sequence(
  78. tea.SetClipboard(text),
  79. func() tea.Msg {
  80. _ = clipboard.WriteAll(text)
  81. return nil
  82. },
  83. callback,
  84. util.ReportInfo(successMessage),
  85. )
  86. }