@@ -40,6 +40,7 @@ type EditorComponent interface {
4040 Paste () (tea.Model , tea.Cmd )
4141 Newline () (tea.Model , tea.Cmd )
4242 SetValue (value string )
43+ SetValueWithAttachments (value string )
4344 SetInterruptKeyInDebounce (inDebounce bool )
4445 SetExitKeyInDebounce (inDebounce bool )
4546}
@@ -94,51 +95,13 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
9495 }
9596
9697 filePath := text
97- ext := strings .ToLower (filepath .Ext (filePath ))
98-
99- mediaType := ""
100- switch ext {
101- case ".jpg" :
102- mediaType = "image/jpeg"
103- case ".png" , ".jpeg" , ".gif" , ".webp" :
104- mediaType = "image/" + ext [1 :]
105- case ".pdf" :
106- mediaType = "application/pdf"
107- default :
108- attachment := & textarea.Attachment {
109- ID : uuid .NewString (),
110- Display : "@" + filePath ,
111- URL : fmt .Sprintf ("file://./%s" , filePath ),
112- Filename : filePath ,
113- MediaType : "text/plain" ,
114- }
115- m .textarea .InsertAttachment (attachment )
116- m .textarea .InsertString (" " )
117- return m , nil
118- }
11998
120- fileBytes , err := os .ReadFile (filePath )
121- if err != nil {
122- slog .Error ("Failed to read file" , "error" , err )
99+ attachment := m .createAttachmentFromFile (filePath )
100+ if attachment == nil {
123101 m .textarea .InsertRunesFromUserInput ([]rune (msg ))
124102 return m , nil
125103 }
126- base64EncodedFile := base64 .StdEncoding .EncodeToString (fileBytes )
127- url := fmt .Sprintf ("data:%s;base64,%s" , mediaType , base64EncodedFile )
128- attachmentCount := len (m .textarea .GetAttachments ())
129- attachmentIndex := attachmentCount + 1
130- label := "File"
131- if strings .HasPrefix (mediaType , "image/" ) {
132- label = "Image"
133- }
134104
135- attachment := & textarea.Attachment {
136- ID : uuid .NewString (),
137- MediaType : mediaType ,
138- Display : fmt .Sprintf ("[%s #%d]" , label , attachmentIndex ),
139- URL : url ,
140- Filename : filePath ,
141- }
142105 m .textarea .InsertAttachment (attachment )
143106 m .textarea .InsertString (" " )
144107 case tea.ClipboardMsg :
@@ -173,25 +136,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
173136 // Now, insert the attachment at the position where the '@' was.
174137 // The cursor is now at `atIndex` after the replacement.
175138 filePath := msg .Item .Value
176- extension := filepath .Ext (filePath )
177- mediaType := ""
178- switch extension {
179- case ".jpg" :
180- mediaType = "image/jpeg"
181- case ".png" , ".jpeg" , ".gif" , ".webp" :
182- mediaType = "image/" + extension [1 :]
183- case ".pdf" :
184- mediaType = "application/pdf"
185- default :
186- mediaType = "text/plain"
187- }
188- attachment := & textarea.Attachment {
189- ID : uuid .NewString (),
190- Display : "@" + filePath ,
191- URL : fmt .Sprintf ("file://./%s" , url .PathEscape (filePath )),
192- Filename : filePath ,
193- MediaType : mediaType ,
194- }
139+ attachment := m .createAttachmentFromPath (filePath )
195140 m .textarea .InsertAttachment (attachment )
196141 m .textarea .InsertString (" " )
197142 return m , nil
@@ -424,6 +369,38 @@ func (m *editorComponent) SetValue(value string) {
424369 m .textarea .SetValue (value )
425370}
426371
372+ func (m * editorComponent ) SetValueWithAttachments (value string ) {
373+ m .textarea .Reset ()
374+
375+ i := 0
376+ for i < len (value ) {
377+ // Check if filepath and add attachment
378+ if value [i ] == '@' {
379+ start := i + 1
380+ end := start
381+ for end < len (value ) && value [end ] != ' ' && value [end ] != '\t' && value [end ] != '\n' && value [end ] != '\r' {
382+ end ++
383+ }
384+
385+ if end > start {
386+ filePath := value [start :end ]
387+ if _ , err := os .Stat (filePath ); err == nil {
388+ attachment := m .createAttachmentFromFile (filePath )
389+ if attachment != nil {
390+ m .textarea .InsertAttachment (attachment )
391+ i = end
392+ continue
393+ }
394+ }
395+ }
396+ }
397+
398+ // Not a valid file path, insert the character normally
399+ m .textarea .InsertRune (rune (value [i ]))
400+ i ++
401+ }
402+ }
403+
427404func (m * editorComponent ) SetExitKeyInDebounce (inDebounce bool ) {
428405 m .exitKeyInDebounce = inDebounce
429406}
@@ -504,3 +481,69 @@ func NewEditorComponent(app *app.App) EditorComponent {
504481
505482 return m
506483}
484+
485+ func getMediaTypeFromExtension (ext string ) string {
486+ switch strings .ToLower (ext ) {
487+ case ".jpg" :
488+ return "image/jpeg"
489+ case ".png" , ".jpeg" , ".gif" , ".webp" :
490+ return "image/" + ext [1 :]
491+ case ".pdf" :
492+ return "application/pdf"
493+ default :
494+ return "text/plain"
495+ }
496+ }
497+
498+ func (m * editorComponent ) createAttachmentFromFile (filePath string ) * textarea.Attachment {
499+ ext := strings .ToLower (filepath .Ext (filePath ))
500+ mediaType := getMediaTypeFromExtension (ext )
501+
502+ // For text files, create a simple file reference
503+ if mediaType == "text/plain" {
504+ return & textarea.Attachment {
505+ ID : uuid .NewString (),
506+ Display : "@" + filePath ,
507+ URL : fmt .Sprintf ("file://./%s" , filePath ),
508+ Filename : filePath ,
509+ MediaType : mediaType ,
510+ }
511+ }
512+
513+ // For binary files (images, PDFs), read and encode
514+ fileBytes , err := os .ReadFile (filePath )
515+ if err != nil {
516+ slog .Error ("Failed to read file" , "error" , err )
517+ return nil
518+ }
519+
520+ base64EncodedFile := base64 .StdEncoding .EncodeToString (fileBytes )
521+ url := fmt .Sprintf ("data:%s;base64,%s" , mediaType , base64EncodedFile )
522+ attachmentCount := len (m .textarea .GetAttachments ())
523+ attachmentIndex := attachmentCount + 1
524+ label := "File"
525+ if strings .HasPrefix (mediaType , "image/" ) {
526+ label = "Image"
527+ }
528+
529+ return & textarea.Attachment {
530+ ID : uuid .NewString (),
531+ MediaType : mediaType ,
532+ Display : fmt .Sprintf ("[%s #%d]" , label , attachmentIndex ),
533+ URL : url ,
534+ Filename : filePath ,
535+ }
536+ }
537+
538+ func (m * editorComponent ) createAttachmentFromPath (filePath string ) * textarea.Attachment {
539+ extension := filepath .Ext (filePath )
540+ mediaType := getMediaTypeFromExtension (extension )
541+
542+ return & textarea.Attachment {
543+ ID : uuid .NewString (),
544+ Display : "@" + filePath ,
545+ URL : fmt .Sprintf ("file://./%s" , url .PathEscape (filePath )),
546+ Filename : filePath ,
547+ MediaType : mediaType ,
548+ }
549+ }
0 commit comments