Bug #2: Search Line Handling
Status: RESOLVED in v3.12.0 Category: Search & Replace Severity: Medium (Accuracy issue) Resolution Date: December 2025
Problem
Section titled “Problem”When a search pattern appeared multiple times on the same line, the search functions returned incorrect character positions. This caused edit operations to target the wrong text.
Example
Section titled “Example”Line content: "This test tests testing"Pattern: "test"Expected positions:
- “test” at column 5 (first occurrence)
- “test” at column 10 (in “tests”)
- “test” at column 16 (in “testing”)
Actual behavior (bug):
- All three matches reported column 5 (first occurrence)
- Edits targeting the 2nd or 3rd occurrence would incorrectly modify the 1st
Impact
Section titled “Impact”- Incorrect edit positions when targeting specific occurrences
- Users had to manually verify and correct edit locations
- Required workarounds like using more specific patterns
- Broke the precision of coordinate-based editing workflow
Symptoms
Section titled “Symptoms”// User wants to change "tests" to "verifies"smart_search({pattern: "test", include_content: true})
// Response (BUG):// Line 1, Column 5: "test" <- First occurrence// Line 1, Column 5: "test" <- WRONG! Should be column 10// Line 1, Column 5: "test" <- WRONG! Should be column 16
// Edit targeting column 5 changes wrong occurrence!Root Cause
Section titled “Root Cause”The original implementation used strings.Index() which always finds the first occurrence:
// BUGGY CODEfunc calculateCharacterOffset(line, pattern string) (int, int) { startOffset := strings.Index(line, pattern) // Always returns first match! if startOffset == -1 { return 0, 0 } endOffset := startOffset + len(pattern) return startOffset, endOffset}When processing multiple matches on the same line, each match was assigned the position of the first occurrence.
Solution
Section titled “Solution”Using regex.FindStringIndex()
Section titled “Using regex.FindStringIndex()”Replaced strings.Index() with regexp.FindStringIndex() which correctly identifies the position of the actual match being processed:
// FIXED CODE (core/search_operations.go:707-721)func calculateCharacterOffset(line string, regexPattern *regexp.Regexp) (int, int) { if regexPattern == nil { return 0, 0 }
// FindStringIndex returns [start, end] of the FIRST match // But we call this for each match found during iteration, // so we process the line progressively loc := regexPattern.FindStringIndex(line) if loc == nil { return 0, 0 }
return loc[0], loc[1] // Correct positions for THIS match}Enhanced Search Processing
Section titled “Enhanced Search Processing”The search functions now track position correctly by processing matches progressively:
// In performAdvancedTextSearchfor scanner.Scan() { line := scanner.Text() lineNum++
// Find ALL matches on this line matches := regexPattern.FindAllStringIndex(line, -1)
for _, match := range matches { startOffset := match[0] endOffset := match[1]
result := SearchMatch{ Line: lineNum, MatchStart: startOffset, // Correct position for THIS match MatchEnd: endOffset, Content: line, } results = append(results, result) }}Test Case
Section titled “Test Case”Added specific test for this bug in tests/coordinate_tracking_test.go:
// TestMultipleOccurrencesOnSameLine - Bug #2 regression testfunc TestMultipleOccurrencesOnSameLine(t *testing.T) { content := `This test tests testing`
// Create test file testFile := filepath.Join(t.TempDir(), "test_multiple.txt") os.WriteFile(testFile, []byte(content), 0644)
// Search for "test" which appears 3 times resp, err := engine.AdvancedTextSearch(ctx, request)
// Verify we find all occurrences with CORRECT positions // Before fix: All would show column 5 // After fix: Columns 5, 10, 16}New Behavior
Section titled “New Behavior”Correct Position Reporting
Section titled “Correct Position Reporting”smart_search({pattern: "test", include_content: true})
// Response (FIXED):// Line 1, Column 5-9: "test" <- First occurrence// Line 1, Column 10-14: "test" <- In "tests" (correct!)// Line 1, Column 16-20: "test" <- In "testing" (correct!)Accurate Editing
Section titled “Accurate Editing”// Target specific occurrence using coordinatesreplace_nth_occurrence({ path: "file.txt", pattern: "test", occurrence: 2, // Target second occurrence replacement: "verify"})
// Result: "This test verifies testing"// (Correctly changes "tests" to "verifies")Files Modified
Section titled “Files Modified”-
core/search_operations.go
- Lines 707-721: New
calculateCharacterOffset()function using regex - Lines 310, 502, 520: Updated callers to pass regex pattern
- Lines 707-721: New
-
tests/coordinate_tracking_test.go (NEW)
TestMultipleOccurrencesOnSameLine- Specific regression test- 6 additional coordinate accuracy tests
- 384 lines total
Test Results
Section titled “Test Results”=== RUN TestMultipleOccurrencesOnSameLine--- PASS: TestMultipleOccurrencesOnSameLine (0.01s)=== RUN TestCoordinateAccuracy--- PASS: TestCoordinateAccuracy (0.01s)=== RUN TestCoordinateEdgeCases--- PASS: TestCoordinateEdgeCases (0.01s)=== RUN TestSmartSearchWithCoordinates--- PASS: TestSmartSearchWithCoordinates (0.02s)=== RUN TestAdvancedTextSearchCoordinates--- PASS: TestAdvancedTextSearchCoordinates (0.01s)=== RUN TestCoordinatesWithContext--- PASS: TestCoordinatesWithContext (0.01s)=== RUN TestBackwardCompatibility--- PASS: TestBackwardCompatibility (0.01s)PASSBackward Compatibility
Section titled “Backward Compatibility”100% backward compatible:
- Same function signatures
- Same response format (with more accurate data)
- No breaking changes to existing workflows
Resolution Timeline
Section titled “Resolution Timeline”- Discovered: During Phase 1 of v3.12.0 development
- Root cause identified:
strings.Index()limitation - Fixed: December 2025
- Released: v3.12.0 (Phase 1)
- Status: Production Ready
Related Work
Section titled “Related Work”This fix was part of the “Code Editing Excellence” initiative (v3.12.0):
- Phase 1 (completed): Coordinate tracking - This bug fix
- Phase 2 (planned): Diff-based editing - Uses accurate coordinates
- Phase 3 (planned): Preview mode - Depends on accurate positioning
The coordinate accuracy from this fix enables future phases that rely on precise text positioning.
Lessons Learned
Section titled “Lessons Learned”- Regex is more powerful than string functions -
FindStringIndexhandles complex matching correctly - Test edge cases explicitly - Multiple occurrences on same line wasn’t tested initially
- Coordinate accuracy matters - Small position errors compound into wrong edits
- Regression tests prevent reintroduction - The specific test case guards against future breaks