1pub fn contains_line_start_conflict_markers(content: &[u8]) -> bool {
14 content.split(|byte| *byte == b'\n').any(|line| {
15 line.starts_with(b"<<<<<<<") || line.starts_with(b"=======") || line.starts_with(b">>>>>>>")
16 })
17}
18
19pub fn unresolved_conflict_paths(conflicts: &[String], resolved: &[String]) -> Vec<String> {
21 conflicts
22 .iter()
23 .filter(|path| !resolved.iter().any(|r| r == *path))
24 .cloned()
25 .collect()
26}
27
28pub fn path_is_active_conflict(conflicts: &[String], path: &str) -> bool {
30 conflicts.iter().any(|c| c == path)
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ResolveSideSelection {
36 Worktree,
38 Ours,
40 Theirs,
42}
43
44pub fn plan_resolve_side(ours: bool, theirs: bool) -> Option<ResolveSideSelection> {
49 match (ours, theirs) {
50 (true, true) => None,
51 (true, false) => Some(ResolveSideSelection::Ours),
52 (false, true) => Some(ResolveSideSelection::Theirs),
53 (false, false) => Some(ResolveSideSelection::Worktree),
54 }
55}
56
57pub fn resolve_requires_marker_check(side: ResolveSideSelection, force: bool) -> bool {
59 matches!(side, ResolveSideSelection::Worktree) && !force
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn line_start_markers_detect_git_style_lines() {
68 assert!(contains_line_start_conflict_markers(
69 b"keep\n<<<<<<< HEAD\nours\n=======\ntheirs\n>>>>>>> branch\n"
70 ));
71 assert!(contains_line_start_conflict_markers(b"=======\n"));
72 assert!(!contains_line_start_conflict_markers(b"no markers here\n"));
73 assert!(!contains_line_start_conflict_markers(b"x<<<<<<<\n"));
75 }
76
77 #[test]
78 fn unresolved_paths_filter_resolved() {
79 let conflicts = vec!["a.rs".into(), "b.rs".into(), "c.rs".into()];
80 let resolved = vec!["b.rs".into()];
81 assert_eq!(
82 unresolved_conflict_paths(&conflicts, &resolved),
83 vec!["a.rs".to_string(), "c.rs".to_string()]
84 );
85 assert!(path_is_active_conflict(&conflicts, "a.rs"));
86 assert!(!path_is_active_conflict(&conflicts, "z.rs"));
87 }
88
89 #[test]
90 fn plan_resolve_side_and_marker_gate() {
91 assert_eq!(
92 plan_resolve_side(false, false),
93 Some(ResolveSideSelection::Worktree)
94 );
95 assert_eq!(
96 plan_resolve_side(true, false),
97 Some(ResolveSideSelection::Ours)
98 );
99 assert_eq!(
100 plan_resolve_side(false, true),
101 Some(ResolveSideSelection::Theirs)
102 );
103 assert_eq!(plan_resolve_side(true, true), None);
104 assert!(resolve_requires_marker_check(
105 ResolveSideSelection::Worktree,
106 false
107 ));
108 assert!(!resolve_requires_marker_check(
109 ResolveSideSelection::Worktree,
110 true
111 ));
112 assert!(!resolve_requires_marker_check(
113 ResolveSideSelection::Ours,
114 false
115 ));
116 }
117}