substringMatchLines returns the 1-based line numbers where needle occurs in content as a byte-for-byte substring, including overlapping starts. Repeat occurrences on the same line collapse to a single line number.
(content, needle string)
| 1251 | // overlapping starts. Repeat occurrences on the same line collapse |
| 1252 | // to a single line number. |
| 1253 | func substringMatchLines(content, needle string) []int { |
| 1254 | if needle == "" { |
| 1255 | return nil |
| 1256 | } |
| 1257 | var lines []int |
| 1258 | seen := make(map[int]struct{}) |
| 1259 | for offset := 0; ; { |
| 1260 | rel := strings.Index(content[offset:], needle) |
| 1261 | if rel < 0 { |
| 1262 | break |
| 1263 | } |
| 1264 | idx := offset + rel |
| 1265 | line := 1 + strings.Count(content[:idx], "\n") |
| 1266 | if _, dup := seen[line]; !dup { |
| 1267 | seen[line] = struct{}{} |
| 1268 | lines = append(lines, line) |
| 1269 | } |
| 1270 | // Advance by one byte so self-overlapping needles (e.g. |
| 1271 | // "A\nB\nA\n" inside "A\nB\nA\nB\nA\n") still report |
| 1272 | // every distinct starting line. |
| 1273 | offset = idx + 1 |
| 1274 | if offset > len(content) { |
| 1275 | break |
| 1276 | } |
| 1277 | } |
| 1278 | return lines |
| 1279 | } |
| 1280 | |
| 1281 | // lineEquivalentMatchLines returns the 1-based start line of every |
| 1282 | // contiguous block of contentLines that matches needleLines under eq. |