caretToByteOffset converts a (1-based line, 0-based column) caret position into a byte offset into statement. The column is interpreted as a UTF-16 code-unit offset (the monaco/LSP convention the caller uses), matching how the completion test derives the caret from a "|" marker.
(statement string, caretLine, caretColumn int)
| 202 | // code-unit offset (the monaco/LSP convention the caller uses), matching how |
| 203 | // the completion test derives the caret from a "|" marker. |
| 204 | func caretToByteOffset(statement string, caretLine, caretColumn int) int { |
| 205 | line := 1 |
| 206 | col := 0 // UTF-16 code units consumed on the current line |
| 207 | for i := 0; i < len(statement); { |
| 208 | if line == caretLine && col >= caretColumn { |
| 209 | return i |
| 210 | } |
| 211 | r, size := utf8.DecodeRuneInString(statement[i:]) |
| 212 | if r == '\n' { |
| 213 | if line == caretLine { |
| 214 | // Caret column is past the end of this line; clamp to line end. |
| 215 | return i |
| 216 | } |
| 217 | line++ |
| 218 | col = 0 |
| 219 | } else if r <= 0xFFFF { |
| 220 | col++ |
| 221 | } else { |
| 222 | col += 2 // surrogate pair |
| 223 | } |
| 224 | i += size |
| 225 | } |
| 226 | return len(statement) |
| 227 | } |