SpliceOverlay splices `overlay` onto `bg` at visual cell position (x, y). Both strings are newline-separated; ANSI CSI escapes are preserved. Style state active at the cut point is re-emitted before the suffix so chars just past the overlay keep their original styling (otherwise they'd render in ter
(bg, overlay string, x, y int)
| 364 | // the suffix so chars just past the overlay keep their original styling |
| 365 | // (otherwise they'd render in terminal default, often appearing white). |
| 366 | func SpliceOverlay(bg, overlay string, x, y int) string { |
| 367 | bgLines := splitLines(bg) |
| 368 | ovLines := splitLines(overlay) |
| 369 | const reset = "\x1b[0m" |
| 370 | for i, ov := range ovLines { |
| 371 | row := y + i |
| 372 | if row < 0 || row >= len(bgLines) { |
| 373 | continue |
| 374 | } |
| 375 | ovW := visibleWidth(ov) |
| 376 | prefix, rest := splitAtVisual(bgLines[row], x) |
| 377 | _, suffix := splitAtVisual(rest, ovW) |
| 378 | // Find style that was active at the position AFTER the overlay. |
| 379 | styleAfter := effectiveStyleAt(bgLines[row], x+ovW) |
| 380 | if styleAfter == reset { |
| 381 | styleAfter = "" |
| 382 | } |
| 383 | bgLines[row] = prefix + reset + ov + reset + styleAfter + suffix |
| 384 | } |
| 385 | return joinLines(bgLines) |
| 386 | } |
| 387 | |
| 388 | func splitLines(s string) []string { |
| 389 | out := []string{} |
no test coverage detected