diff --git a/crates/git_ui/src/conflict_view.rs b/crates/git_ui/src/conflict_view.rs index 91cc3ce76b3f10aa310185b566b6c6086580b69c..2f954bfe1045d9819c1f7c276346a6f811c09108 100644 --- a/crates/git_ui/src/conflict_view.rs +++ b/crates/git_ui/src/conflict_view.rs @@ -372,7 +372,7 @@ fn render_conflict_buttons( .gap_1() .bg(cx.theme().colors().editor_background) .child( - Button::new("head", "Use HEAD") + Button::new("head", format!("Use {}", conflict.ours_branch_name)) .label_size(LabelSize::Small) .on_click({ let editor = editor.clone(); @@ -392,7 +392,7 @@ fn render_conflict_buttons( }), ) .child( - Button::new("origin", "Use Origin") + Button::new("origin", format!("Use {}", conflict.theirs_branch_name)) .label_size(LabelSize::Small) .on_click({ let editor = editor.clone(); diff --git a/crates/project/src/git_store/conflict_set.rs b/crates/project/src/git_store/conflict_set.rs index bd80214c2c0b6d5b1a5da3ba497c5670cb26cb93..064b6998cdb72423d1123166a2ce6a75765db029 100644 --- a/crates/project/src/git_store/conflict_set.rs +++ b/crates/project/src/git_store/conflict_set.rs @@ -1,4 +1,4 @@ -use gpui::{App, Context, Entity, EventEmitter}; +use gpui::{App, Context, Entity, EventEmitter, SharedString}; use std::{cmp::Ordering, ops::Range, sync::Arc}; use text::{Anchor, BufferId, OffsetRangeExt as _}; @@ -92,6 +92,8 @@ impl ConflictSetSnapshot { #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConflictRegion { + pub ours_branch_name: SharedString, + pub theirs_branch_name: SharedString, pub range: Range, pub ours: Range, pub theirs: Range, @@ -179,18 +181,25 @@ impl ConflictSet { let mut conflict_start: Option = None; let mut ours_start: Option = None; let mut ours_end: Option = None; + let mut ours_branch_name: Option = None; let mut base_start: Option = None; let mut base_end: Option = None; let mut theirs_start: Option = None; + let mut theirs_branch_name: Option = None; while let Some(line) = lines.next() { let line_end = line_pos + line.len(); - if line.starts_with("<<<<<<< ") { + if let Some(branch_name) = line.strip_prefix("<<<<<<< ") { // If we see a new conflict marker while already parsing one, // abandon the previous one and start a new one conflict_start = Some(line_pos); ours_start = Some(line_end + 1); + + let branch_name = branch_name.trim(); + if !branch_name.is_empty() { + ours_branch_name = Some(SharedString::new(branch_name)); + } } else if line.starts_with("||||||| ") && conflict_start.is_some() && ours_start.is_some() @@ -208,12 +217,17 @@ impl ConflictSet { base_end = Some(line_pos); } theirs_start = Some(line_end + 1); - } else if line.starts_with(">>>>>>> ") + } else if let Some(branch_name) = line.strip_prefix(">>>>>>> ") && conflict_start.is_some() && ours_start.is_some() && ours_end.is_some() && theirs_start.is_some() { + let branch_name = branch_name.trim(); + if !branch_name.is_empty() { + theirs_branch_name = Some(SharedString::new(branch_name)); + } + let theirs_end = line_pos; let conflict_end = (line_end + 1).min(buffer_len); @@ -229,6 +243,12 @@ impl ConflictSet { .map(|(start, end)| buffer.anchor_after(start)..buffer.anchor_before(end)); conflicts.push(ConflictRegion { + ours_branch_name: ours_branch_name + .take() + .unwrap_or_else(|| SharedString::new_static("HEAD")), + theirs_branch_name: theirs_branch_name + .take() + .unwrap_or_else(|| SharedString::new_static("Origin")), range, ours, theirs, @@ -304,6 +324,8 @@ mod tests { let first = &conflict_snapshot.conflicts[0]; assert!(first.base.is_none()); + assert_eq!(first.ours_branch_name.as_ref(), "HEAD"); + assert_eq!(first.theirs_branch_name.as_ref(), "branch-name"); let our_text = snapshot .text_for_range(first.ours.clone()) .collect::(); @@ -315,6 +337,8 @@ mod tests { let second = &conflict_snapshot.conflicts[1]; assert!(second.base.is_some()); + assert_eq!(second.ours_branch_name.as_ref(), "HEAD"); + assert_eq!(second.theirs_branch_name.as_ref(), "branch-name"); let our_text = snapshot .text_for_range(second.ours.clone()) .collect::(); @@ -381,6 +405,8 @@ mod tests { // The conflict should have our version, their version, but no base let conflict = &conflict_snapshot.conflicts[0]; assert!(conflict.base.is_none()); + assert_eq!(conflict.ours_branch_name.as_ref(), "HEAD"); + assert_eq!(conflict.theirs_branch_name.as_ref(), "branch-nested"); // Check that the nested conflict was detected correctly let our_text = snapshot @@ -407,6 +433,14 @@ mod tests { let conflict_snapshot = ConflictSet::parse(&snapshot); assert_eq!(conflict_snapshot.conflicts.len(), 1); + assert_eq!( + conflict_snapshot.conflicts[0].ours_branch_name.as_ref(), + "ours" + ); + assert_eq!( + conflict_snapshot.conflicts[0].theirs_branch_name.as_ref(), + "Origin" // default branch name if there is none + ); } #[test] @@ -449,6 +483,38 @@ mod tests { let conflict_snapshot = ConflictSet::parse(&snapshot); assert_eq!(conflict_snapshot.conflicts.len(), 4); + assert_eq!( + conflict_snapshot.conflicts[0].ours_branch_name.as_ref(), + "HEAD1" + ); + assert_eq!( + conflict_snapshot.conflicts[0].theirs_branch_name.as_ref(), + "branch1" + ); + assert_eq!( + conflict_snapshot.conflicts[1].ours_branch_name.as_ref(), + "HEAD2" + ); + assert_eq!( + conflict_snapshot.conflicts[1].theirs_branch_name.as_ref(), + "branch2" + ); + assert_eq!( + conflict_snapshot.conflicts[2].ours_branch_name.as_ref(), + "HEAD3" + ); + assert_eq!( + conflict_snapshot.conflicts[2].theirs_branch_name.as_ref(), + "branch3" + ); + assert_eq!( + conflict_snapshot.conflicts[3].ours_branch_name.as_ref(), + "HEAD4" + ); + assert_eq!( + conflict_snapshot.conflicts[3].theirs_branch_name.as_ref(), + "branch4" + ); let range = test_content.find("seven").unwrap()..test_content.find("eleven").unwrap(); let range = buffer.anchor_before(range.start)..buffer.anchor_after(range.end);