cursorRuneOffset returns the cursor as an absolute rune index into Value(). textarea only exposes (row, col) plus LineInfo, so we reconstruct it by walking prior lines' rune counts. SplitSeq avoids materialising a slice on every chip-aware keypress.
()
| 392 | // walking prior lines' rune counts. SplitSeq avoids materialising a slice on |
| 393 | // every chip-aware keypress. |
| 394 | func (p promptInput) cursorRuneOffset() int { |
| 395 | row := p.ta.Line() |
| 396 | info := p.ta.LineInfo() |
| 397 | col := info.StartColumn + info.ColumnOffset |
| 398 | |
| 399 | offset, i := 0, 0 |
| 400 | for line := range strings.SplitSeq(p.ta.Value(), "\n") { |
| 401 | if i == row { |
| 402 | n := utf8.RuneCountInString(line) |
| 403 | if col > n { |
| 404 | col = n |
| 405 | } |
| 406 | return offset + col |
| 407 | } |
| 408 | offset += utf8.RuneCountInString(line) + 1 // +1 for the \n |
| 409 | i++ |
| 410 | } |
| 411 | return offset |
| 412 | } |
| 413 | |
| 414 | // setCursorRuneOffset moves the cursor to an absolute rune position. textarea |
| 415 | // has no (row, col) setter, so we step CursorUp/Down to the target row then |