diff --git a/internal/fsext/paste.go b/internal/fsext/paste.go index 7e89a6443e09a2c5831ce8a072945cf7d1c4fd95..4996473acf41355e391ba6e9bf2547abfbbea9cb 100644 --- a/internal/fsext/paste.go +++ b/internal/fsext/paste.go @@ -1,20 +1,36 @@ package fsext import ( - "runtime" + "os" "strings" ) -func PasteStringToPaths(s string) []string { - switch runtime.GOOS { - case "windows": - return windowsPasteStringToPaths(s) +func ParsePastedFiles(s string) []string { + s = strings.TrimSpace(s) + + // NOTE: Rio on Windows adds NULL chars for some reason. + s = strings.ReplaceAll(s, "\x00", "") + + switch { + case attemptStat(s): + return strings.Split(s, "\n") + case os.Getenv("WT_SESSION") != "": + return windowsTerminalParsePastedFiles(s) default: - return unixPasteStringToPaths(s) + return unixParsePastedFiles(s) + } +} + +func attemptStat(s string) bool { + for path := range strings.SplitSeq(s, "\n") { + if info, err := os.Stat(path); err != nil || info.IsDir() { + return false + } } + return true } -func windowsPasteStringToPaths(s string) []string { +func windowsTerminalParsePastedFiles(s string) []string { if strings.TrimSpace(s) == "" { return nil } @@ -42,8 +58,10 @@ func windowsPasteStringToPaths(s string) []string { } case inQuotes: current.WriteByte(ch) + case ch != ' ': + // Text outside quotes is not allowed + return nil } - // Skip characters outside quotes and spaces between quoted sections } // Add any remaining content if quotes were properly closed @@ -59,7 +77,7 @@ func windowsPasteStringToPaths(s string) []string { return paths } -func unixPasteStringToPaths(s string) []string { +func unixParsePastedFiles(s string) []string { if strings.TrimSpace(s) == "" { return nil } diff --git a/internal/fsext/paste_test.go b/internal/fsext/paste_test.go index 09f8ad4d5bebbc993193d38a7ebbb31778aba7f6..c1c4d4adfba0eca44586f55f2a23dd882038522e 100644 --- a/internal/fsext/paste_test.go +++ b/internal/fsext/paste_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" ) -func TestPasteStringToPaths(t *testing.T) { - t.Run("Windows", func(t *testing.T) { +func TestParsePastedFiles(t *testing.T) { + t.Run("WindowsTerminal", func(t *testing.T) { tests := []struct { name string input string @@ -24,7 +24,7 @@ func TestPasteStringToPaths(t *testing.T) { expected: []string{`C:\path\my-screenshot-one.png`, `C:\path\my-screenshot-two.png`, `C:\path\my-screenshot-three.png`}, }, { - name: "sigle with spaces", + name: "single with spaces", input: `"C:\path\my screenshot one.png"`, expected: []string{`C:\path\my screenshot one.png`}, }, @@ -46,7 +46,7 @@ func TestPasteStringToPaths(t *testing.T) { { name: "text outside quotes", input: `"C:\path\file.png" some random text "C:\path\file2.png"`, - expected: []string{`C:\path\file.png`, `C:\path\file2.png`}, + expected: nil, }, { name: "multiple spaces between paths", @@ -66,7 +66,7 @@ func TestPasteStringToPaths(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := windowsPasteStringToPaths(tt.input) + result := windowsTerminalParsePastedFiles(tt.input) require.Equal(t, tt.expected, result) }) } @@ -141,7 +141,7 @@ func TestPasteStringToPaths(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := unixPasteStringToPaths(tt.input) + result := unixParsePastedFiles(tt.input) require.Equal(t, tt.expected, result) }) } diff --git a/internal/ui/model/ui.go b/internal/ui/model/ui.go index 6231c82c514ee021e7e8f47272c8f606ec54ff09..806ce0bcdf4bf0217f759aa97d361b1e60a824b7 100644 --- a/internal/ui/model/ui.go +++ b/internal/ui/model/ui.go @@ -2915,7 +2915,7 @@ func (m *UI) handlePasteMsg(msg tea.PasteMsg) tea.Cmd { // Attempt to parse pasted content as file paths. If possible to parse, // all files exist and are valid, add as attachments. // Otherwise, paste as text. - paths := fsext.PasteStringToPaths(msg.Content) + paths := fsext.ParsePastedFiles(msg.Content) allExistsAndValid := func() bool { for _, path := range paths { if _, err := os.Stat(path); os.IsNotExist(err) { @@ -2956,6 +2956,9 @@ func (m *UI) handleFilePathPaste(path string) tea.Cmd { if err != nil { return uiutil.ReportError(err) } + if fileInfo.IsDir() { + return uiutil.ReportWarn("Cannot attach a directory") + } if fileInfo.Size() > common.MaxAttachmentSize { return uiutil.ReportWarn("File is too big (>5mb)") }