MCPcopy Index your code
hub / github.com/coder/coder / buildReplacementLines

Function buildReplacementLines

agent/agentfiles/files.go:965–1077  ·  view source on GitHub ↗

buildReplacementLines emits the splice for a fuzzy match by per-position substitution at leading-ws, body, trailing-ws, and ending. Search and replace agreement at a position -> file's bytes win; disagreement -> replacement's bytes are spliced. Extra replace lines past the matched region reference t

(matched, searchLines []string, replace, forcedEnding string, atNoNewlineEOF bool)

Source from the content-addressed store, hash-verified

963//
964//nolint:revive // atNoNewlineEOF is a computed match property, not caller control coupling.
965func buildReplacementLines(matched, searchLines []string, replace, forcedEnding string, atNoNewlineEOF bool) string {
966 repLines := strings.SplitAfter(replace, "\n")
967 // SplitAfter on a string ending in "\n" yields a trailing empty
968 // element. Drop it so it doesn't pair with a phantom line.
969 if len(repLines) > 0 && repLines[len(repLines)-1] == "" {
970 repLines = repLines[:len(repLines)-1]
971 }
972 prefix, suffix := alignSearchReplace(searchLines, repLines)
973
974 // Combine search and replace so a zero-width search still
975 // informs the unit from the replacement's inserted depths.
976 // Fallback for detection failure lives in the inserted branch.
977 searchUnit, searchUnitOK := detectIndentUnit(append(append([]string(nil), searchLines...), repLines...))
978 fileUnit, fileUnitOK := detectIndentUnit(matched)
979 var b strings.Builder
980 for i, rLine := range repLines {
981 var refIdx int
982 inserted := false
983 searchMiddleLen := len(searchLines) - prefix - suffix
984 switch {
985 case i < prefix:
986 refIdx = i
987 case i >= len(repLines)-suffix:
988 refIdx = i - (len(repLines) - len(searchLines))
989 case i-prefix < searchMiddleLen:
990 refIdx = prefix + (i - prefix)
991 default:
992 // Pure insertion: pick the reference content line by
993 // the caller's indent signal. An inserted line whose
994 // lead matches the suffix's first rep line belongs to
995 // the suffix scope; one matching the prefix's last rep
996 // line belongs to the prefix scope. Fall back to
997 // suffix, then prefix, then i-clamped.
998 inserted = true
999 rLeadForI := leadOnly(rLine)
1000 switch {
1001 case prefix > 0 && suffix > 0:
1002 prefixRLead := leadOnly(repLines[prefix-1])
1003 suffixRLead := leadOnly(repLines[len(repLines)-suffix])
1004 switch {
1005 case rLeadForI == suffixRLead:
1006 refIdx = len(searchLines) - suffix
1007 case rLeadForI == prefixRLead:
1008 refIdx = prefix - 1
1009 default:
1010 refIdx = len(searchLines) - suffix
1011 }
1012 case suffix > 0:
1013 refIdx = len(searchLines) - suffix
1014 case prefix > 0:
1015 refIdx = prefix - 1
1016 default:
1017 refIdx = min(i, len(searchLines)-1)
1018 }
1019 }
1020 refContent := matched[refIdx]
1021 sLead, _, sTrail, sEnd := splitLineParts(searchLines[refIdx])
1022 rLead, rMid, rTrail, rEnd := splitLineParts(rLine)

Callers 1

fuzzyReplaceLinesFunction · 0.85

Calls 8

alignSearchReplaceFunction · 0.85
detectIndentUnitFunction · 0.85
leadOnlyFunction · 0.85
splitLinePartsFunction · 0.85
translateIndentLevelFunction · 0.85
endingShapeEqualFunction · 0.85
WriteStringMethod · 0.80
StringMethod · 0.45

Tested by

no test coverage detected