MCPcopy Create free account
hub / github.com/coder/coder / fuzzyReplaceLines

Function fuzzyReplaceLines

agent/agentfiles/files.go:1489–1555  ·  view source on GitHub ↗

fuzzyReplaceLines handles fuzzy matching passes (2 and 3) for fuzzyReplace. When replaceAll is false and there are multiple matches, an error is returned. When replaceAll is true, all non-overlapping matches are replaced. Returns (result, true, nil) on success, ("", false, nil) when searchLines don

(
	contentLines, searchLines []string,
	replace string,
	eq func(a, b string) bool,
	replaceAll bool,
	forcedEnding string,
)

Source from the content-addressed store, hash-verified

1487//
1488//nolint:revive // replaceAll is a direct pass-through of the user's flag, not a control coupling.
1489func fuzzyReplaceLines(
1490 contentLines, searchLines []string,
1491 replace string,
1492 eq func(a, b string) bool,
1493 replaceAll bool,
1494 forcedEnding string,
1495) (string, bool, error) {
1496 start, end, ok := seekLines(contentLines, searchLines, eq)
1497 if !ok {
1498 return "", false, nil
1499 }
1500
1501 if !replaceAll {
1502 if count := countLineMatches(contentLines, searchLines, eq); count > 1 {
1503 return "", true, xerrors.Errorf("search string matches %d occurrences "+
1504 "(expected exactly 1). Include more surrounding "+
1505 "context to make the match unique, or set "+
1506 "replace_all to true", count)
1507 }
1508 var b strings.Builder
1509 for _, l := range contentLines[:start] {
1510 _, _ = b.WriteString(l)
1511 }
1512 _, _ = b.WriteString(buildReplacementLines(contentLines[start:end], searchLines, replace, forcedEnding, atNoNewlineEOF(contentLines, end)))
1513 for _, l := range contentLines[end:] {
1514 _, _ = b.WriteString(l)
1515 }
1516 return b.String(), true, nil
1517 }
1518
1519 // Replace all: collect all match positions, then emit the
1520 // output forward, interleaving unmatched spans with spliced
1521 // replacements. Each match runs through the same per-position
1522 // splice as single-replace, using its own matched content
1523 // slice as the reference.
1524 type lineMatch struct{ start, end int }
1525 var matches []lineMatch
1526 for i := 0; i <= len(contentLines)-len(searchLines); {
1527 found := true
1528 for j, sLine := range searchLines {
1529 if !eq(contentLines[i+j], sLine) {
1530 found = false
1531 break
1532 }
1533 }
1534 if found {
1535 matches = append(matches, lineMatch{i, i + len(searchLines)})
1536 i += len(searchLines) // skip past this match
1537 } else {
1538 i++
1539 }
1540 }
1541
1542 var b strings.Builder
1543 prev := 0
1544 for _, m := range matches {
1545 for _, l := range contentLines[prev:m.start] {
1546 _, _ = b.WriteString(l)

Callers 1

fuzzyReplaceFunction · 0.85

Calls 7

seekLinesFunction · 0.85
countLineMatchesFunction · 0.85
buildReplacementLinesFunction · 0.85
atNoNewlineEOFFunction · 0.85
WriteStringMethod · 0.80
ErrorfMethod · 0.45
StringMethod · 0.45

Tested by

no test coverage detected