Determine whether an Insert hunk is a Prepend, Append, or Middle insert. For multi-vertex files (files that have been recorded at least once with per-line vertex granularity), a middle insert is resolved to the vertex boundary at `old_start`. For single-vertex files there are no internal boundaries, so we return an error and let the caller fall back to Replace.
(
vertices: &[GraphNode<NodeId>],
inode_pos: Position<NodeId>,
old_start: usize,
old_line_count: Option<usize>,
)
| 629 | /// boundary at `old_start`. For single-vertex files there are no internal |
| 630 | /// boundaries, so we return an error and let the caller fall back to Replace. |
| 631 | fn classify_insert( |
| 632 | vertices: &[GraphNode<NodeId>], |
| 633 | inode_pos: Position<NodeId>, |
| 634 | old_start: usize, |
| 635 | old_line_count: Option<usize>, |
| 636 | ) -> GlobalizeResult<InsertPosition> { |
| 637 | log::debug!( |
| 638 | "classify_insert: old_start={} old_line_count={:?} vertices={}", |
| 639 | old_start, |
| 640 | old_line_count, |
| 641 | vertices.len(), |
| 642 | ); |
| 643 | |
| 644 | // Empty file → append (predecessor is the inode itself). |
| 645 | if vertices.is_empty() { |
| 646 | return Ok(InsertPosition::Append { |
| 647 | last_content_end: inode_pos, |
| 648 | }); |
| 649 | } |
| 650 | |
| 651 | // Prepend: insert before the very first line. |
| 652 | if old_start == 0 { |
| 653 | let first_start = Position::new(vertices[0].change, vertices[0].start); |
| 654 | return Ok(InsertPosition::Prepend { |
| 655 | first_content: first_start, |
| 656 | }); |
| 657 | } |
| 658 | |
| 659 | // Append: insert after the very last line. |
| 660 | let total_old_lines = old_line_count.unwrap_or(vertices.len()); |
| 661 | if old_start >= total_old_lines { |
| 662 | let last = vertices.last().unwrap(); |
| 663 | let last_end = Position::new(last.change, last.end); |
| 664 | return Ok(InsertPosition::Append { |
| 665 | last_content_end: last_end, |
| 666 | }); |
| 667 | } |
| 668 | |
| 669 | // ── Middle insertion ── |
| 670 | // |
| 671 | // For single-vertex files we cannot split at a line boundary, so we |
| 672 | // return an error. The caller (`globalize_insert`) catches this and |
| 673 | // falls back to a whole-file Replace. |
| 674 | if vertices.len() == 1 { |
| 675 | return Err(GlobalizeError::MissingContext { |
| 676 | path: "(middle insertion into single-vertex file — needs consolidation)".to_string(), |
| 677 | line: old_start as u64, |
| 678 | }); |
| 679 | } |
| 680 | |
| 681 | // Multi-vertex file: walk vertices to find the boundary. |
| 682 | // After per-line vertex creation, each vertex corresponds roughly |
| 683 | // to one line, so vertex[old_start-1] / vertex[old_start] gives |
| 684 | // the correct boundary. |
| 685 | if old_start < vertices.len() { |
| 686 | let pred = &vertices[old_start - 1]; |
| 687 | let succ = &vertices[old_start]; |
| 688 | return Ok(InsertPosition::Middle { |
no test coverage detected