[PR #1270] [CLOSED] fix: fix index shifting issue with attachment restoration #9873

Closed
opened 2026-02-16 18:14:18 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/anomalyco/opencode/pull/1270
Author: @rstacruz
Created: 7/23/2025
Status: Closed

Base: devHead: fix-attachment-issue


📝 Commits (7)

  • 05a43b1 fix: fix index shifting issue with attachment restoration
  • b3ec300 fix: update test cases to use new AppPath struct
  • 3d4e99e fix: adjust attachment end indices in editor test
  • 88cec0f fix: remove redundant test cases for bug fixes
  • c3c9a0e feat: refactor test setup to use factory methods for editor and attachments
  • 1696a62 fix: remove redundant bug reproduction test
  • 5bb8f8a Merge remote-tracking branch 'upstream/dev' into fix-attachment-issue

📊 Changes

4 files changed (+577 additions, -3 deletions)

View changed files

📝 packages/tui/internal/components/chat/editor.go (+4 -3)
packages/tui/internal/components/chat/editor_test.go (+202 -0)
📝 packages/tui/internal/components/textarea/textarea.go (+120 -0)
packages/tui/internal/components/textarea/textarea_test.go (+251 -0)

📄 Description

hopefully fixes #1266:

When navigating message history using the "Up" arrow key, messages containing attachments and line breaks become corrupted, resulting in duplicated attachment paths within the text.

Disclaimer: I'm not familiar with the opencode codebase, and this PR was done with the help of opencode. Mostly this is me trying to test out how much OpenCode can help me with a new codebase :)

How I tested this

I used cd packages/tui && go test -v ./... to run tests.

Test output
?   	github.com/sst/opencode/cmd/opencode	[no test files]
?   	github.com/sst/opencode/internal/api	[no test files]
?   	github.com/sst/opencode/internal/app	[no test files]
?   	github.com/sst/opencode/internal/attachment	[no test files]
?   	github.com/sst/opencode/internal/clipboard	[no test files]
?   	github.com/sst/opencode/internal/commands	[no test files]
?   	github.com/sst/opencode/internal/completions	[no test files]
=== RUN   TestRestoreFromPromptWithMultilineAttachments
--- PASS: TestRestoreFromPromptWithMultilineAttachments (0.00s)
=== RUN   TestRestoreFromPromptMultipleAttachments
--- PASS: TestRestoreFromPromptMultipleAttachments (0.00s)
=== RUN   TestRestoreFromPromptAttachmentsAtLineBoundaries
--- PASS: TestRestoreFromPromptAttachmentsAtLineBoundaries (0.00s)
=== RUN   TestRestoreFromPromptEmptyLinesWithAttachments
--- PASS: TestRestoreFromPromptEmptyLinesWithAttachments (0.00s)
=== RUN   TestRestoreFromHistoryIndex
--- PASS: TestRestoreFromHistoryIndex (0.00s)
PASS
ok  	github.com/sst/opencode/internal/components/chat	(cached)
?   	github.com/sst/opencode/internal/components/commands	[no test files]
?   	github.com/sst/opencode/internal/components/dialog	[no test files]
?   	github.com/sst/opencode/internal/components/diff	[no test files]
?   	github.com/sst/opencode/internal/components/fileviewer	[no test files]
=== RUN   TestArrowKeyNavigation
--- PASS: TestArrowKeyNavigation (0.00s)
=== RUN   TestJKKeyNavigation
--- PASS: TestJKKeyNavigation (0.00s)
=== RUN   TestCtrlNavigation
--- PASS: TestCtrlNavigation (0.00s)
=== RUN   TestNavigationBoundaries
--- PASS: TestNavigationBoundaries (0.00s)
=== RUN   TestEmptyList
--- PASS: TestEmptyList (0.00s)
PASS
ok  	github.com/sst/opencode/internal/components/list	(cached)
?   	github.com/sst/opencode/internal/components/modal	[no test files]
?   	github.com/sst/opencode/internal/components/qr	[no test files]
?   	github.com/sst/opencode/internal/components/status	[no test files]
=== RUN   TestReplaceRangeAbsolute
=== RUN   TestReplaceRangeAbsolute/replace_spanning_multiple_lines
=== RUN   TestReplaceRangeAbsolute/replace_across_newlines
=== RUN   TestReplaceRangeAbsolute/replace_spanning_multiple_lines#01
=== RUN   TestReplaceRangeAbsolute/replace_at_start
=== RUN   TestReplaceRangeAbsolute/replace_at_end
=== RUN   TestReplaceRangeAbsolute/empty_replacement
--- PASS: TestReplaceRangeAbsolute (0.00s)
    --- PASS: TestReplaceRangeAbsolute/replace_spanning_multiple_lines (0.00s)
    --- PASS: TestReplaceRangeAbsolute/replace_across_newlines (0.00s)
    --- PASS: TestReplaceRangeAbsolute/replace_spanning_multiple_lines#01 (0.00s)
    --- PASS: TestReplaceRangeAbsolute/replace_at_start (0.00s)
    --- PASS: TestReplaceRangeAbsolute/replace_at_end (0.00s)
    --- PASS: TestReplaceRangeAbsolute/empty_replacement (0.00s)
=== RUN   TestReplaceRangeAbsoluteWithAttachments
--- PASS: TestReplaceRangeAbsoluteWithAttachments (0.00s)
=== RUN   TestAbsolutePosToRowCol
=== RUN   TestAbsolutePosToRowCol/single_line_start
=== RUN   TestAbsolutePosToRowCol/single_line_middle
=== RUN   TestAbsolutePosToRowCol/single_line_end
=== RUN   TestAbsolutePosToRowCol/multi-line_first_line
=== RUN   TestAbsolutePosToRowCol/multi-line_second_line_start
=== RUN   TestAbsolutePosToRowCol/multi-line_second_line_middle
=== RUN   TestAbsolutePosToRowCol/multi-line_third_line
=== RUN   TestAbsolutePosToRowCol/beyond_end
--- PASS: TestAbsolutePosToRowCol (0.00s)
    --- PASS: TestAbsolutePosToRowCol/single_line_start (0.00s)
    --- PASS: TestAbsolutePosToRowCol/single_line_middle (0.00s)
    --- PASS: TestAbsolutePosToRowCol/single_line_end (0.00s)
    --- PASS: TestAbsolutePosToRowCol/multi-line_first_line (0.00s)
    --- PASS: TestAbsolutePosToRowCol/multi-line_second_line_start (0.00s)
    --- PASS: TestAbsolutePosToRowCol/multi-line_second_line_middle (0.00s)
    --- PASS: TestAbsolutePosToRowCol/multi-line_third_line (0.00s)
    --- PASS: TestAbsolutePosToRowCol/beyond_end (0.00s)
=== RUN   TestReplaceRangeAbsoluteEdgeCases
=== RUN   TestReplaceRangeAbsoluteEdgeCases/invalid_positions
=== RUN   TestReplaceRangeAbsoluteEdgeCases/empty_text
=== RUN   TestReplaceRangeAbsoluteEdgeCases/zero-length_replacement
--- PASS: TestReplaceRangeAbsoluteEdgeCases (0.00s)
    --- PASS: TestReplaceRangeAbsoluteEdgeCases/invalid_positions (0.00s)
    --- PASS: TestReplaceRangeAbsoluteEdgeCases/empty_text (0.00s)
    --- PASS: TestReplaceRangeAbsoluteEdgeCases/zero-length_replacement (0.00s)
PASS
ok  	github.com/sst/opencode/internal/components/textarea	(cached)
?   	github.com/sst/opencode/internal/components/toast	[no test files]
?   	github.com/sst/opencode/internal/id	[no test files]
?   	github.com/sst/opencode/internal/layout	[no test files]
?   	github.com/sst/opencode/internal/styles	[no test files]
=== RUN   TestLoadThemesFromJSON
--- PASS: TestLoadThemesFromJSON (0.00s)
=== RUN   TestColorReferenceResolution
--- PASS: TestColorReferenceResolution (0.01s)
=== RUN   TestLoadThemesFromDirectories
--- PASS: TestLoadThemesFromDirectories (0.01s)
PASS
ok  	github.com/sst/opencode/internal/theme	(cached)
?   	github.com/sst/opencode/internal/tui	[no test files]
=== RUN   TestWriteStringsPar
--- PASS: TestWriteStringsPar (0.01s)
PASS
ok  	github.com/sst/opencode/internal/util	(cached)
?   	github.com/sst/opencode/internal/viewport	[no test files]

I used cd packages/opencode && bun run src/index.ts to manually verify.

Left shows the release version (v0.3.57), right shows dev version.

image

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/anomalyco/opencode/pull/1270 **Author:** [@rstacruz](https://github.com/rstacruz) **Created:** 7/23/2025 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `fix-attachment-issue` --- ### 📝 Commits (7) - [`05a43b1`](https://github.com/anomalyco/opencode/commit/05a43b193014a4a6add38be6087eaf4a5a380bb7) fix: fix index shifting issue with attachment restoration - [`b3ec300`](https://github.com/anomalyco/opencode/commit/b3ec30096714268ef98d673a2b4d725f9ce05ff8) fix: update test cases to use new AppPath struct - [`3d4e99e`](https://github.com/anomalyco/opencode/commit/3d4e99e76004ee08291a92b3d153b5e6430c1726) fix: adjust attachment end indices in editor test - [`88cec0f`](https://github.com/anomalyco/opencode/commit/88cec0f8df169fd618cbcfc58c2f75045cfa9af0) fix: remove redundant test cases for bug fixes - [`c3c9a0e`](https://github.com/anomalyco/opencode/commit/c3c9a0e829bff28c46225d33dc0a0a9b40210a16) feat: refactor test setup to use factory methods for editor and attachments - [`1696a62`](https://github.com/anomalyco/opencode/commit/1696a62f5b611aaa210740fb173799daaa7483e0) fix: remove redundant bug reproduction test - [`5bb8f8a`](https://github.com/anomalyco/opencode/commit/5bb8f8a4530510f3128a98177dc47dcdf39037b5) Merge remote-tracking branch 'upstream/dev' into fix-attachment-issue ### 📊 Changes **4 files changed** (+577 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `packages/tui/internal/components/chat/editor.go` (+4 -3) ➕ `packages/tui/internal/components/chat/editor_test.go` (+202 -0) 📝 `packages/tui/internal/components/textarea/textarea.go` (+120 -0) ➕ `packages/tui/internal/components/textarea/textarea_test.go` (+251 -0) </details> ### 📄 Description hopefully fixes #1266: > When navigating message history using the "Up" arrow key, messages containing attachments and line breaks become corrupted, resulting in duplicated attachment paths within the text. *Disclaimer:* I'm not familiar with the opencode codebase, and this PR was done with the help of opencode. Mostly this is me trying to test out how much OpenCode can help me with a new codebase :) ## How I tested this I used `cd packages/tui && go test -v ./...` to run tests. <details> <summary>Test output</summary> ``` ? github.com/sst/opencode/cmd/opencode [no test files] ? github.com/sst/opencode/internal/api [no test files] ? github.com/sst/opencode/internal/app [no test files] ? github.com/sst/opencode/internal/attachment [no test files] ? github.com/sst/opencode/internal/clipboard [no test files] ? github.com/sst/opencode/internal/commands [no test files] ? github.com/sst/opencode/internal/completions [no test files] === RUN TestRestoreFromPromptWithMultilineAttachments --- PASS: TestRestoreFromPromptWithMultilineAttachments (0.00s) === RUN TestRestoreFromPromptMultipleAttachments --- PASS: TestRestoreFromPromptMultipleAttachments (0.00s) === RUN TestRestoreFromPromptAttachmentsAtLineBoundaries --- PASS: TestRestoreFromPromptAttachmentsAtLineBoundaries (0.00s) === RUN TestRestoreFromPromptEmptyLinesWithAttachments --- PASS: TestRestoreFromPromptEmptyLinesWithAttachments (0.00s) === RUN TestRestoreFromHistoryIndex --- PASS: TestRestoreFromHistoryIndex (0.00s) PASS ok github.com/sst/opencode/internal/components/chat (cached) ? github.com/sst/opencode/internal/components/commands [no test files] ? github.com/sst/opencode/internal/components/dialog [no test files] ? github.com/sst/opencode/internal/components/diff [no test files] ? github.com/sst/opencode/internal/components/fileviewer [no test files] === RUN TestArrowKeyNavigation --- PASS: TestArrowKeyNavigation (0.00s) === RUN TestJKKeyNavigation --- PASS: TestJKKeyNavigation (0.00s) === RUN TestCtrlNavigation --- PASS: TestCtrlNavigation (0.00s) === RUN TestNavigationBoundaries --- PASS: TestNavigationBoundaries (0.00s) === RUN TestEmptyList --- PASS: TestEmptyList (0.00s) PASS ok github.com/sst/opencode/internal/components/list (cached) ? github.com/sst/opencode/internal/components/modal [no test files] ? github.com/sst/opencode/internal/components/qr [no test files] ? github.com/sst/opencode/internal/components/status [no test files] === RUN TestReplaceRangeAbsolute === RUN TestReplaceRangeAbsolute/replace_spanning_multiple_lines === RUN TestReplaceRangeAbsolute/replace_across_newlines === RUN TestReplaceRangeAbsolute/replace_spanning_multiple_lines#01 === RUN TestReplaceRangeAbsolute/replace_at_start === RUN TestReplaceRangeAbsolute/replace_at_end === RUN TestReplaceRangeAbsolute/empty_replacement --- PASS: TestReplaceRangeAbsolute (0.00s) --- PASS: TestReplaceRangeAbsolute/replace_spanning_multiple_lines (0.00s) --- PASS: TestReplaceRangeAbsolute/replace_across_newlines (0.00s) --- PASS: TestReplaceRangeAbsolute/replace_spanning_multiple_lines#01 (0.00s) --- PASS: TestReplaceRangeAbsolute/replace_at_start (0.00s) --- PASS: TestReplaceRangeAbsolute/replace_at_end (0.00s) --- PASS: TestReplaceRangeAbsolute/empty_replacement (0.00s) === RUN TestReplaceRangeAbsoluteWithAttachments --- PASS: TestReplaceRangeAbsoluteWithAttachments (0.00s) === RUN TestAbsolutePosToRowCol === RUN TestAbsolutePosToRowCol/single_line_start === RUN TestAbsolutePosToRowCol/single_line_middle === RUN TestAbsolutePosToRowCol/single_line_end === RUN TestAbsolutePosToRowCol/multi-line_first_line === RUN TestAbsolutePosToRowCol/multi-line_second_line_start === RUN TestAbsolutePosToRowCol/multi-line_second_line_middle === RUN TestAbsolutePosToRowCol/multi-line_third_line === RUN TestAbsolutePosToRowCol/beyond_end --- PASS: TestAbsolutePosToRowCol (0.00s) --- PASS: TestAbsolutePosToRowCol/single_line_start (0.00s) --- PASS: TestAbsolutePosToRowCol/single_line_middle (0.00s) --- PASS: TestAbsolutePosToRowCol/single_line_end (0.00s) --- PASS: TestAbsolutePosToRowCol/multi-line_first_line (0.00s) --- PASS: TestAbsolutePosToRowCol/multi-line_second_line_start (0.00s) --- PASS: TestAbsolutePosToRowCol/multi-line_second_line_middle (0.00s) --- PASS: TestAbsolutePosToRowCol/multi-line_third_line (0.00s) --- PASS: TestAbsolutePosToRowCol/beyond_end (0.00s) === RUN TestReplaceRangeAbsoluteEdgeCases === RUN TestReplaceRangeAbsoluteEdgeCases/invalid_positions === RUN TestReplaceRangeAbsoluteEdgeCases/empty_text === RUN TestReplaceRangeAbsoluteEdgeCases/zero-length_replacement --- PASS: TestReplaceRangeAbsoluteEdgeCases (0.00s) --- PASS: TestReplaceRangeAbsoluteEdgeCases/invalid_positions (0.00s) --- PASS: TestReplaceRangeAbsoluteEdgeCases/empty_text (0.00s) --- PASS: TestReplaceRangeAbsoluteEdgeCases/zero-length_replacement (0.00s) PASS ok github.com/sst/opencode/internal/components/textarea (cached) ? github.com/sst/opencode/internal/components/toast [no test files] ? github.com/sst/opencode/internal/id [no test files] ? github.com/sst/opencode/internal/layout [no test files] ? github.com/sst/opencode/internal/styles [no test files] === RUN TestLoadThemesFromJSON --- PASS: TestLoadThemesFromJSON (0.00s) === RUN TestColorReferenceResolution --- PASS: TestColorReferenceResolution (0.01s) === RUN TestLoadThemesFromDirectories --- PASS: TestLoadThemesFromDirectories (0.01s) PASS ok github.com/sst/opencode/internal/theme (cached) ? github.com/sst/opencode/internal/tui [no test files] === RUN TestWriteStringsPar --- PASS: TestWriteStringsPar (0.01s) PASS ok github.com/sst/opencode/internal/util (cached) ? github.com/sst/opencode/internal/viewport [no test files] ``` </details> I used `cd packages/opencode && bun run src/index.ts` to manually verify. Left shows the release version (v0.3.57), right shows dev version. <img width="3000" height="1064" alt="image" src="https://github.com/user-attachments/assets/e4e3ebfc-411a-4298-ab3f-28b2d3aea0a5" /> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-16 18:14:18 -05:00
yindo closed this issue 2026-02-16 18:14:18 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#9873