Given visual lines and a global cursor position, return (visual_line_index, column_in_visual_line).
(visual_lines: &[VisualLine], cursor_pos: usize)
| 1647 | |
| 1648 | /// Given visual lines and a global cursor position, return (visual_line_index, column_in_visual_line). |
| 1649 | pub fn cursor_to_visual_pos(visual_lines: &[VisualLine], cursor_pos: usize) -> (usize, usize) { |
| 1650 | for (i, vl) in visual_lines.iter().enumerate() { |
| 1651 | let line_end = vl.global_char_start + vl.char_count; |
| 1652 | if cursor_pos < line_end || i == visual_lines.len() - 1 { |
| 1653 | return (i, cursor_pos.saturating_sub(vl.global_char_start)); |
| 1654 | } |
| 1655 | // If cursor_pos == line_end and this isn't the last line, it could be at the |
| 1656 | // start of the next line OR the end of this one. For wrapped lines (no \n), |
| 1657 | // prefer placing it at the start of the next line. |
| 1658 | if cursor_pos == line_end { |
| 1659 | // Check if next line continues from this one (wrapped) or is a new paragraph |
| 1660 | if i + 1 < visual_lines.len() { |
| 1661 | let next = &visual_lines[i + 1]; |
| 1662 | if next.global_char_start == line_end { |
| 1663 | // Wrapped continuation — cursor goes to start of next visual line |
| 1664 | return (i + 1, 0); |
| 1665 | } |
| 1666 | // Hard break (\n between them) — cursor at end of this line |
| 1667 | return (i, cursor_pos - vl.global_char_start); |
| 1668 | } |
| 1669 | return (i, cursor_pos - vl.global_char_start); |
| 1670 | } |
| 1671 | } |
| 1672 | (0, 0) |
| 1673 | } |
| 1674 | |
| 1675 | /// Navigate cursor one visual line up. Returns the new global cursor position. |
| 1676 | /// `col` is the desired column (preserved across up/down moves). |
no outgoing calls
no test coverage detected