Compute cursor visual position: (visual_row, visual_col) considering wrap.
(&self, inner_width: u16, prefix_w: usize)
| 244 | |
| 245 | /// Compute cursor visual position: (visual_row, visual_col) considering wrap. |
| 246 | fn cursor_visual_position(&self, inner_width: u16, prefix_w: usize) -> (usize, usize) { |
| 247 | // Use cursor_line_col() to get accurate logical line position |
| 248 | let (cursor_logical_line, _, line_start) = self.cursor_line_col(); |
| 249 | |
| 250 | // Calculate display width of text before cursor on the current line only |
| 251 | let byte_pos = self.char_pos_to_byte_pos(self.cursor); |
| 252 | let line_start_byte = self.char_pos_to_byte_pos(line_start); |
| 253 | let text_before_cursor = &self.input[line_start_byte..byte_pos]; |
| 254 | let cursor_col_w = text_before_cursor.width(); |
| 255 | |
| 256 | let avail = Self::avail_width(inner_width, prefix_w); |
| 257 | |
| 258 | let mut visual_row = 0usize; |
| 259 | for (i, logical_line) in self.input.split('\n').enumerate() { |
| 260 | if i >= cursor_logical_line { |
| 261 | break; |
| 262 | } |
| 263 | let text_w = logical_line.width(); |
| 264 | if text_w == 0 { |
| 265 | visual_row += 1; |
| 266 | } else { |
| 267 | visual_row += (text_w + avail - 1) / avail; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | let extra_rows = if cursor_col_w > 0 { |
| 272 | (cursor_col_w - 1) / avail |
| 273 | } else { |
| 274 | 0 |
| 275 | }; |
| 276 | visual_row += extra_rows; |
| 277 | let visual_col = prefix_w + cursor_col_w - extra_rows * avail; |
| 278 | (visual_row, visual_col) |
| 279 | } |
| 280 | |
| 281 | /// Update scroll_offset so the cursor stays visible within `visible_lines`. |
| 282 | fn ensure_cursor_visible(&mut self, inner_width: u16, prefix_w: usize, visible_lines: usize) { |
no test coverage detected