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