on main help sign in
chore: support clipboard past image
commita069e8a0dff3f1dffb520693182eacef4f49815b authorKujtim Hoxha <kujtimii.h@gmail.com> dateMon 28 Jul 2025, 21:12 (1 year ago) parente218c2a
2 files changed+47−4
internal/tui/components/chat/editor/editor.go+41 internal/tui/components/dialogs/filepicker/filepicker.go+6−4
internal/tui/components/chat/editor/editor.go+41
@@ -2,8 +2,10 @@ package editor
22
33import (
44 "fmt"
5+ "net/http"
56 "os"
67 "os/exec"
8+ "path/filepath"
79 "runtime"
810 "slices"
911 "strings"
@@ -207,6 +209,45 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
207209 case OpenEditorMsg:
208210 m.textarea.SetValue(msg.Text)
209211 m.textarea.MoveToEnd()
212+ case tea.PasteMsg:
213+ path := strings.ReplaceAll(string(msg), "\\ ", " ")
214+ // try to get an image
215+ path, err := filepath.Abs(path)
216+ if err != nil {
217+ m.textarea, cmd = m.textarea.Update(msg)
218+ return m, cmd
219+ }
220+ isAllowedType := false
221+ for _, ext := range filepicker.AllowedTypes {
222+ if strings.HasSuffix(path, ext) {
223+ isAllowedType = true
224+ break
225+ }
226+ }
227+ if !isAllowedType {
228+
229+ m.textarea, cmd = m.textarea.Update(msg)
230+ return m, cmd
231+ }
232+ tooBig, _ := filepicker.IsFileTooBig(path, filepicker.MaxAttachmentSize)
233+ if tooBig {
234+ m.textarea, cmd = m.textarea.Update(msg)
235+ return m, cmd
236+ }
237+
238+ content, err := os.ReadFile(path)
239+ if err != nil {
240+ m.textarea, cmd = m.textarea.Update(msg)
241+ return m, cmd
242+ }
243+ mimeBufferSize := min(512, len(content))
244+ mimeType := http.DetectContentType(content[:mimeBufferSize])
245+ fileName := filepath.Base(path)
246+ attachment := message.Attachment{FilePath: path, FileName: fileName, MimeType: mimeType, Content: content}
247+ return m, util.CmdHandler(filepicker.FilePickedMsg{
248+ Attachment: attachment,
249+ })
250+
210251 case tea.KeyPressMsg:
211252 cur := m.textarea.Cursor()
212253 curIdx := m.textarea.Width()*cur.Y + cur.X
internal/tui/components/dialogs/filepicker/filepicker.go+6−4
@@ -21,7 +21,7 @@ import (
2121)
2222
2323const (
24− maxAttachmentSize = int64(5 * 1024 * 1024) // 5MB
24+ MaxAttachmentSize = int64(5 * 1024 * 1024) // 5MB
2525 FilePickerID = "filepicker"
2626 fileSelectionHight = 10
2727)
@@ -45,10 +45,12 @@ type model struct {
4545 help help.Model
4646}
4747
48+var AllowedTypes = []string{".jpg", ".jpeg", ".png"}
49+
4850func NewFilePickerCmp(workingDir string) FilePicker {
4951 t := styles.CurrentTheme()
5052 fp := filepicker.New()
51− fp.AllowedTypes = []string{".jpg", ".jpeg", ".png"}
53+ fp.AllowedTypes = AllowedTypes
5254
5355 if workingDir != "" {
5456 fp.CurrentDirectory = workingDir
@@ -127,7 +129,7 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
127129 return m, tea.Sequence(
128130 util.CmdHandler(dialogs.CloseDialogMsg{}),
129131 func() tea.Msg {
130− isFileLarge, err := ValidateFileSize(path, maxAttachmentSize)
132+ isFileLarge, err := IsFileTooBig(path, MaxAttachmentSize)
131133 if err != nil {
132134 return util.ReportError(fmt.Errorf("unable to read the image: %w", err))
133135 }
@@ -222,7 +224,7 @@ func (m *model) Position() (int, int) {
222224 return row, col
223225}
224226
225−func ValidateFileSize(filePath string, sizeLimit int64) (bool, error) {
227+func IsFileTooBig(filePath string, sizeLimit int64) (bool, error) {
226228 fileInfo, err := os.Stat(filePath)
227229 if err != nil {
228230 return false, fmt.Errorf("error getting file info: %w", err)