summaryrefslogtreecommitdiffstats
path: root/src/handlers/merge_conflict.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/handlers/merge_conflict.rs')
-rw-r--r--src/handlers/merge_conflict.rs1352
1 files changed, 0 insertions, 1352 deletions
diff --git a/src/handlers/merge_conflict.rs b/src/handlers/merge_conflict.rs
deleted file mode 100644
index f06364bc..00000000
--- a/src/handlers/merge_conflict.rs
+++ /dev/null
@@ -1,1352 +0,0 @@
-use std::ops::{Index, IndexMut};
-
-use itertools::Itertools;
-use unicode_segmentation::UnicodeSegmentation;
-
-use super::draw;
-use crate::cli;
-use crate::config::{self, delta_unreachable};
-use crate::delta::{DiffType, InMergeConflict, MergeParents, State, StateMachine};
-use crate::minusplus::MinusPlus;
-use crate::paint::{self, prepare};
-use crate::style::Style;
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum MergeConflictCommit {
- Ours,
- Ancestral,
- Theirs,
-}
-
-pub struct MergeConflictCommits<T> {
- ours: T,
- ancestral: T,
- theirs: T,
-}
-
-pub type MergeConflictLines = MergeConflictCommits<Vec<(String, State)>>;
-
-pub type MergeConflictCommitNames = MergeConflictCommits<Option<String>>;
-
-impl<'a> StateMachine<'a> {
- pub fn handle_merge_conflict_line(&mut self) -> std::io::Result<bool> {
- use DiffType::*;
- use MergeConflictCommit::*;
- use State::*;
-
- let mut handled_line = false;
- if self.config.color_only || !self.config.handle_merge_conflicts {
- return Ok(handled_line);
- }
-
- match self.state.clone() {
- HunkHeader(Combined(merge_parents, InMergeConflict::No), _, _, _)
- | HunkMinus(Combined(merge_parents, InMergeConflict::No), _)
- | HunkZero(Combined(merge_parents, InMergeConflict::No), _)
- | HunkPlus(Combined(merge_parents, InMergeConflict::No), _) => {
- handled_line = self.enter_merge_conflict(&merge_parents)
- }
- MergeConflict(merge_parents, Ours) => {
- handled_line = self.enter_ancestral(&merge_parents)
- || self.enter_theirs(&merge_parents)
- || self.exit_merge_conflict(&merge_parents)?
- || self.store_line(
- Ours,
- HunkPlus(Combined(merge_parents, InMergeConflict::Yes), None),
- );
- }
- MergeConflict(merge_parents, Ancestral) => {
- handled_line = self.enter_theirs(&merge_parents)
- || self.exit_merge_conflict(&merge_parents)?
- || self.store_line(
- Ancestral,
- HunkMinus(Combined(merge_parents, InMergeConflict::Yes), None),
- );
- }
- MergeConflict(merge_parents, Theirs) => {
- handled_line = self.exit_merge_conflict(&merge_parents)?
- || self.store_line(
- Theirs,
- HunkPlus(Combined(merge_parents, InMergeConflict::Yes), None),
- );
- }
- _ => {}
- }
-
- Ok(handled_line)
- }
-
- fn enter_merge_conflict(&mut self, merge_parents: &MergeParents) -> bool {
- use State::*;
- if let Some(commit) = parse_merge_marker(&self.line, "++<<<<<<<") {
- self.state = MergeConflict(merge_parents.clone(), Ours);
- self.painter.merge_conflict_commit_names[Ours] = Some(commit.to_string());
- true
- } else {
- false
- }
- }
-
- fn enter_ancestral(&mut self, merge_parents: &MergeParents) -> bool {
- use State::*;
- if let Some(commit) = parse_merge_marker(&self.line, "++|||||||") {
- self.state = MergeConflict(merge_parents.clone(), Ancestral);
- self.painter.merge_conflict_commit_names[Ancestral] = Some(commit.to_string());
- true
- } else {
- false
- }
- }
-
- fn enter_theirs(&mut self, merge_parents: &MergeParents) -> bool {
- use State::*;
- if self.line.starts_with("++=======") {
- self.state = MergeConflict(merge_parents.clone(), Theirs);
- true
- } else {
- false
- }
- }
-
- fn exit_merge_conflict(&mut self, merge_parents: &MergeParents) -> std::io::Result<bool> {
- if let Some(commit) = parse_merge_marker(&self.line, "++>>>>>>>") {
- self.painter.merge_conflict_commit_names[Theirs] = Some(commit.to_string());
- self.paint_buffered_merge_conflict_lines(merge_parents)?;
- Ok(true)
- } else {
- Ok(false)
- }
- }
-
- fn store_line(&mut self, commit: MergeConflictCommit, state: State) -> bool {
- use State::*;
- if let HunkMinus(diff_type, _) | HunkZero(diff_type, _) | HunkPlus(diff_type, _) = &state {
- let line = prepare(&self.line, diff_type.n_parents(), self.config);
- self.painter.merge_conflict_lines[commit].push((line, state));
- true
- } else {
- delta_unreachable(&format!("Invalid state: {state:?}"))
- }
- }
-
- fn paint_buffered_merge_conflict_lines(
- &mut self,
- merge_parents: &MergeParents,
- ) -> std::io::Result<()> {
- use DiffType::*;
- use State::*;
- self.painter.emit()?;
-
- write_merge_conflict_bar(
- &self.config.merge_conflict_begin_symbol,
- &mut self.painter,
- self.config,
- )?;
- for (derived_commit_type, header_style) in &[
- (Ours, self.config.merge_conflict_ours_diff_header_style),
- (Theirs, self.config.merge_conflict_theirs_diff_header_style),
- ] {
- write_diff_header(
- derived_commit_type,
- *header_style,
- &mut self.painter,
- self.config,
- )?;
- self.painter.emit()?;
- paint::paint_minus_and_plus_lines(
- MinusPlus::new(
- &self.painter.merge_conflict_lines[Ancestral],
- &self.painter.merge_conflict_lines[derived_commit_type],
- ),
- &mut self.painter.line_numbers_data,
- &mut self.painter.highlighter,
- &mut self.painter.output_buffer,
- self.config,
- );
- self.painter.emit()?;
- }
- // write_merge_conflict_decoration("bold ol", &mut self.painter, self.config)?;
- write_merge_conflict_bar(
- &self.config.merge_conflict_end_symbol,
- &mut self.painter,
- self.config,
- )?;
- self.painter.merge_conflict_lines.clear();
- self.state = HunkZero(Combined(merge_parents.clone(), InMergeConflict::No), None);
- Ok(())
- }
-}
-
-fn write_diff_header(
- derived_commit_type: &MergeConflictCommit,
- style: Style,
- painter: &mut paint::Painter,
- config: &config::Config,
-) -> std::io::Result<()> {
- let (mut draw_fn, pad, decoration_ansi_term_style) =
- draw::get_draw_function(style.decoration_style);
- let derived_commit_name = &painter.merge_conflict_commit_names[derived_commit_type];
- let text = if let Some(_ancestral_commit) = &painter.merge_conflict_commit_names[Ancestral] {
- format!(
- "ancestor {} {}{}",
- config.right_arrow,
- derived_commit_name.as_deref().unwrap_or("?"),
- if pad { " " } else { "" }
- )
- } else {
- derived_commit_name.as_deref().unwrap_or("?").to_string()
- };
- draw_fn(
- painter.writer,
- &text,
- &text,
- "",
- &config.decorations_width,
- style,
- decoration_ansi_term_style,
- )?;
- Ok(())
-}
-
-fn write_merge_conflict_bar(
- s: &str,
- painter: &mut paint::Painter,
- config: &config::Config,
-) -> std::io::Result<()> {
- let width = match config.decorations_width {
- cli::Width::Fixed(width) => width,
- cli::Width::Variable => config.available_terminal_width,
- };
- writeln!(
- painter.writer,
- "{}",
- &s.graphemes(true).cycle().take(width).join("")
- )?;
- Ok(())
-}
-
-fn parse_merge_marker<'a>(line: &'a str, marker: &str) -> Option<&'a str> {
- match line.strip_prefix(marker) {
- Some(suffix) => {
- let suffix = suffix.trim();
- if !suffix.is_empty() {
- Some(suffix)
- } else {
- None
- }
- }
- None => None,
- }
-}
-
-pub use MergeConflictCommit::*;
-
-impl<T> Index<MergeConflictCommit> for MergeConflictCommits<T> {
- type Output = T;
- fn index(&self, commit: MergeConflictCommit) -> &Self::Output {
- match commit {
- Ours => &self.ours,
- Ancestral => &self.ancestral,
- Theirs => &self.theirs,
- }
- }
-}
-
-impl<T> Index<&MergeConflictCommit> for MergeConflictCommits<T> {
- type Output = T;
- fn index(&self, commit: &MergeConflictCommit) -> &Self::Output {
- match commit {
- Ours => &self.ours,
- Ancestral => &self.ancestral,
- Theirs => &self.theirs,
- }
- }
-}
-
-impl<T> IndexMut<MergeConflictCommit> for MergeConflictCommits<T> {
- fn index_mut(&mut self, commit: MergeConflictCommit) -> &mut Self::Output {
- match commit {
- Ours => &mut self.ours,
- Ancestral => &mut self.ancestral,
- Theirs => &mut self.theirs,
- }
- }
-}
-
-impl MergeConflictLines {
- pub fn new() -> Self {
- Self {
- ours: Vec::new(),
- ancestral: Vec::new(),
- theirs: Vec::new(),
- }
- }
-
- fn clear(&mut self) {
- self[Ours].clear();
- self[Ancestral].clear();
- self[Theirs].clear();
- }
-}
-
-impl MergeConflictCommitNames {
- pub fn new() -> Self {
- Self {
- ours: None,
- ancestral: None,
- theirs: None,
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::ansi::strip_ansi_codes;
- use crate::tests::integration_test_utils;
-
- #[test]
- fn test_toy_merge_conflict_no_context() {
- let config = integration_test_utils::make_config_from_args(&[]);
- let output = integration_test_utils::run_delta(GIT_TOY_MERGE_CONFLICT_NO_CONTEXT, &config);
- let output = strip_ansi_codes(&output);
- assert!(output.contains("\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"));
- assert!(output.contains(
- "\
-──────────────────┐
-ancestor ⟶ HEAD │
-──────────────────┘
-"
- ));
- assert!(output.contains("\n▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲"));
- }
-
- #[test]
- fn test_real_merge_conflict() {
- let config = integration_test_utils::make_config_from_args(&[]);
- let output = integration_test_utils::run_delta(GIT_MERGE_CONFLICT, &config);
- let output = strip_ansi_codes(&output);
- assert!(output.contains("\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"));
- assert!(output.contains(
- "\
-──────────────────┐
-ancestor ⟶ HEAD │
-──────────────────┘
-"
- ));
- assert!(output.contains("\n▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲"));
- }
-
- #[test]
- #[allow(non_snake_case)]
- fn test_real_merge_conflict_U0() {
- let config = integration_test_utils::make_config_from_args(&[]);
- let output = integration_test_utils::run_delta(GIT_MERGE_CONFLICT_U0, &config);
- let output = strip_ansi_codes(&output);
- assert!(output.contains("\n▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼"));
- assert!(output.contains(
- "\
-──────────────────┐
-ancestor ⟶ HEAD │
-──────────────────┘
-"
- ));
- assert!(output.contains("\n▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲"));
- }
-
- const GIT_TOY_MERGE_CONFLICT_NO_CONTEXT: &str = "\
-diff --cc file
-index 6178079,7898192..0000000
---- a/file
-+++ b/file
-@@@ -1,1 -1,1 +1,6 @@@
-++<<<<<<< HEAD
- +a
-++||||||| parent of 0c20c9d... wip
-++=======
-+ b
-++>>>>>>> 0c20c9d... wip
-";
-
- const GIT_MERGE_CONFLICT: &str = r#"\
-diff --cc src/handlers/merge_conflict.rs
-index 27d47c0,3a7e7b9..0000000
---- a/src/handlers/merge_conflict.rs
-+++ b/src/handlers/merge_conflict.rs
-@@@ -1,14 -1,13 +1,24 @@@
- -use std::cmp::min;
- use std::ops::{Index, IndexMut};
-
-++<<<<<<< HEAD
- +use itertools::Itertools;
- +use unicode_segmentation::UnicodeSegmentation;
- +
- +use super::draw;
- +use crate::cli;
- +use crate::config::{self, delta_unreachable};
- +use crate::delta::{DiffType, InMergeConflict, MergeParents, State, StateMachine};
-++||||||| parent of b2b28c8... Display merge conflict branches
-++use crate::delta::{DiffType, MergeParents, State, StateMachine};
-++=======
-+ use super::draw;
-+ use crate::cli;
-+ use crate::config::{self, delta_unreachable};
-+ use crate::delta::{DiffType, MergeParents, State, StateMachine};
-++>>>>>>> b2b28c8... Display merge conflict branches
- use crate::minusplus::MinusPlus;
- use crate::paint;
-+ use crate::style::DecorationStyle;
-
- #[derive(Clone, Debug, PartialEq)]
- pub enum MergeConflictCommit {
-@@@ -30,7 -29,8 +40,15 @@@ pub type MergeConflictCommitNames = Mer
- impl<'a> StateMachine<'a> {
- pub fn handle_merge_conflict_line(&mut self) -> std::io::Result<bool> {
- use DiffType::*;
-++<<<<<<< HEAD
- use MergeConflictCommit::*;
-++||||||| parent of b2b28c8... Display merge conflict branches
-+ use MergeParents::*;
-++ use Source::*;
-++=======
-++ use MergeConflictCommit::*;
-++ use MergeParents::*;
-++>>>>>>> b2b28c8... Display merge conflict branches
- use State::*;
-
- let mut handled_line = false;
-@@@ -38,36 -38,28 +56,113 @@@
- return Ok(handled_line);
- }
-
-++<<<<<<< HEAD
- + match self.state.clone() {
- + HunkHeader(Combined(merge_parents, InMergeConflict::No), _, _)
- + | HunkMinus(Combined(merge_parents, InMergeConflict::No), _)
- + | HunkZero(Combined(merge_parents, InMergeConflict::No))
- + | HunkPlus(Combined(merge_parents, InMergeConflict::No), _) => {
- + handled_line = self.enter_merge_conflict(&merge_parents)
- + }
- + MergeConflict(merge_parents, Ours) => {
- + handled_line = self.enter_ancestral(&merge_parents)
- + || self.enter_theirs(&merge_parents)
- + || self.exit_merge_conflict(&merge_parents)?
- + || self.store_line(
- + Ours,
- + HunkPlus(Combined(merge_parents, InMergeConflict::Yes), None),
- + );
-++||||||| parent of b2b28c8... Display merge conflict branches
-++ // TODO: don't allocate on heap at this point
-++ let prefix = self.line[..min(self.line.len(), 2)].to_string();
-++ let diff_type = Combined(Prefix(prefix));
-++
-++ match self.state {
-++ // The only transition into a merge conflict is HunkZero => MergeConflict(Ours)
-++ // TODO: shouldn't this be HunkZero(Some(_))?
-++ HunkZero(_) => {
-++ if self.line.starts_with("++<<<<<<<") {
-++ self.state = MergeConflict(Ours);
-++ handled_line = true
-++ }
- + }
-++ MergeConflict(Ours) => {
-++ if self.line.starts_with("++|||||||") {
-++ self.state = MergeConflict(Ancestral);
-++ } else if self.line.starts_with("++=======") {
-++ self.state = MergeConflict(Theirs);
-++ } else if self.line.starts_with("++>>>>>>>") {
-++ self.paint_buffered_merge_conflict_lines(diff_type)?;
-++ } else {
-++ let line = self.painter.prepare(&self.line, diff_type.n_parents());
-++ self.painter.merge_conflict_lines[Ours].push((line, HunkPlus(diff_type, None)));
-++ }
-++ handled_line = true
-++=======
-+ // TODO: don't allocate on heap at this point
-+ let prefix = self.line[..min(self.line.len(), 2)].to_string();
-+ let diff_type = Combined(Prefix(prefix));
-+
-+ match self.state {
-+ // The only transition into a merge conflict is HunkZero => MergeConflict(Ours)
-+ // TODO: shouldn't this be HunkZero(Some(_))?
-+ HunkZero(_) => handled_line = self.enter_merge_conflict(),
-+ MergeConflict(Ours) => {
-+ handled_line = self.enter_ancestral()
-+ || self.enter_theirs()
-+ || self.exit_merge_conflict(diff_type.clone())?
-+ || self.store_line(Ours, HunkPlus(diff_type, None));
-++>>>>>>> b2b28c8... Display merge conflict branches
-+ }
-++<<<<<<< HEAD
- + MergeConflict(merge_parents, Ancestral) => {
- + handled_line = self.enter_theirs(&merge_parents)
- + || self.exit_merge_conflict(&merge_parents)?
- + || self.store_line(
- + Ancestral,
- + HunkMinus(Combined(merge_parents, InMergeConflict::Yes), None),
- + );
-++||||||| parent of b2b28c8... Display merge conflict branches
-++ MergeConflict(Ancestral) => {
-++ if self.line.starts_with("++=======") {
-++ self.state = MergeConflict(Theirs);
-++ } else if self.line.starts_with("++>>>>>>>") {
-++ self.paint_buffered_merge_conflict_lines(diff_type)?;
-++ } else {
-++ let line = self.painter.prepare(&self.line, diff_type.n_parents());
-++ self.painter.merge_conflict_lines[Ancestral]
-++ .push((line, HunkMinus(diff_type, None)));
-++ }
-++ handled_line = true
-++=======
-+ MergeConflict(Ancestral) => {
-+ handled_line = self.enter_theirs()
-+ || self.exit_merge_conflict(diff_type.clone())?
-+ || self.store_line(Ancestral, HunkMinus(diff_type, None));
-++>>>>>>> b2b28c8... Display merge conflict branches
- }
-++<<<<<<< HEAD
- + MergeConflict(merge_parents, Theirs) => {
- + handled_line = self.exit_merge_conflict(&merge_parents)?
- + || self.store_line(
- + Theirs,
- + HunkPlus(Combined(merge_parents, InMergeConflict::Yes), None),
- + );
-++||||||| parent of b2b28c8... Display merge conflict branches
-++ MergeConflict(Theirs) => {
-++ if self.line.starts_with("++>>>>>>>") {
-++ self.paint_buffered_merge_conflict_lines(diff_type)?;
-++ } else {
-++ let line = self.painter.prepare(&self.line, diff_type.n_parents());
-++ self.painter.merge_conflict_lines[Theirs]
-++ .push((line, HunkPlus(diff_type, None)));
-++ }
-++ handled_line = true
-++=======
-+ MergeConflict(Theirs) => {
-+ handled_line = self.exit_merge_conflict(diff_type.clone())?
-+ || self.store_line(Theirs, HunkPlus(diff_type, None));
-++>>>>>>> b2b28c8... Display merge conflict branches
- }
- _ => {}
- }
-@@@ -75,75 -67,71 +170,150 @@@
- Ok(handled_line)
- }
-
-++<<<<<<< HEAD
- + fn enter_merge_conflict(&mut self, merge_parents: &MergeParents) -> bool {
- + use State::*;
- + if let Some(commit) = parse_merge_marker(&self.line, "++<<<<<<<") {
- + self.state = MergeConflict(merge_parents.clone(), Ours);
- + self.painter.merge_conflict_commit_names[Ours] = Some(commit.to_string());
- + true
- + } else {
- + false
- + }
- + }
- +
- + fn enter_ancestral(&mut self, merge_parents: &MergeParents) -> bool {
- + use State::*;
- + if let Some(commit) = parse_merge_marker(&self.line, "++|||||||") {
- + self.state = MergeConflict(merge_parents.clone(), Ancestral);
- + self.painter.merge_conflict_commit_names[Ancestral] = Some(commit.to_string());
- + true
- + } else {
- + false
- + }
- + }
- +
- + fn enter_theirs(&mut self, merge_parents: &MergeParents) -> bool {
- + use State::*;
- + if self.line.starts_with("++=======") {
- + self.state = MergeConflict(merge_parents.clone(), Theirs);
- + true
- + } else {
- + false
- + }
- + }
- +
- + fn exit_merge_conflict(&mut self, merge_parents: &MergeParents) -> std::io::Result<bool> {
- + if let Some(commit) = parse_merge_marker(&self.line, "++>>>>>>>") {
- + self.painter.merge_conflict_commit_names[Theirs] = Some(commit.to_string());
- + self.paint_buffered_merge_conflict_lines(merge_parents)?;
- + Ok(true)
- + } else {
- + Ok(false)
- + }
- + }
- +
- + fn store_line(&mut self, commit: MergeConflictCommit, state: State) -> bool {
- + use State::*;
- + if let HunkMinus(diff_type, _) | HunkZero(diff_type) | HunkPlus(diff_type, _) = &state {
- + let line = self.painter.prepare(&self.line, diff_type.n_parents());
- + self.painter.merge_conflict_lines[commit].push((line, state));
- + true
- + } else {
- + delta_unreachable(&format!("Invalid state: {:?}", state))
- + }
- + }
- +
- + fn paint_buffered_merge_conflict_lines(
- + &mut self,
- + merge_parents: &MergeParents,
- + ) -> std::io::Result<()> {
- + use DiffType::*;
- + use State::*;
-++||||||| parent of b2b28c8... Display merge conflict branches
-++ fn paint_buffered_merge_conflict_lines(&mut self, diff_type: DiffType) -> std::io::Result<()> {
-++=======
-+ fn enter_merge_conflict(&mut self) -> bool {
-+ use State::*;
-+ if let Some(commit) = parse_merge_marker(&self.line, "++<<<<<<<") {
-+ self.state = MergeConflict(Ours);
-+ self.painter.merge_conflict_commit_names[Ours] = Some(commit.to_string());
-+ true
-+ } else {
-+ false
-+ }
-+ }
-+
-+ fn enter_ancestral(&mut self) -> bool {
-+ use State::*;
-+ if let Some(commit) = parse_merge_marker(&self.line, "++|||||||") {
-+ self.state = MergeConflict(Ancestral);
-+ self.painter.merge_conflict_commit_names[Ancestral] = Some(commit.to_string());
-+ true
-+ } else {
-+ false
-+ }
-+ }
-+
-+ fn enter_theirs(&mut self) -> bool {
-+ use State::*;
-+ if self.line.starts_with("++=======") {
-+ self.state = MergeConflict(Theirs);
-+ true
-+ } else {
-+ false
-+ }
-+ }
-+
-+ fn exit_merge_conflict(&mut self, diff_type: DiffType) -> std::io::Result<bool> {
-+ if let Some(commit) = parse_merge_marker(&self.line, "++>>>>>>>") {
-+ self.painter.merge_conflict_commit_names[Theirs] = Some(commit.to_string());
-+ self.paint_buffered_merge_conflict_lines(diff_type)?;
-+ Ok(true)
-+ } else {
-+ Ok(false)
-+ }
-+ }
-+
-+ fn store_line(&mut self, commit: MergeConflictCommit, state: State) -> bool {
-+ use State::*;
-+ if let HunkMinus(diff_type, _) | HunkZero(diff_type) | HunkPlus(diff_type, _) = &state {
-+ let line = self.painter.prepare(&self.line, diff_type.n_parents());
-+ self.painter.merge_conflict_lines[commit].push((line, state));
-+ true
-+ } else {
-+ delta_unreachable(&format!("Invalid state: {:?}", state))
-+ }
-+ }
-+
-+ fn paint_buffered_merge_conflict_lines(&mut self, diff_type: DiffType) -> std::io::Result<()> {
-++>>>>>>> b2b28c8... Display merge conflict branches
- self.painter.emit()?;
-++<<<<<<< HEAD
- +
- + write_merge_conflict_bar(
- + &self.config.merge_conflict_begin_symbol,
- + &mut self.painter,
- + self.config,
- + )?;
- + for derived_commit_type in &[Ours, Theirs] {
- + write_diff_header(derived_commit_type, &mut self.painter, self.config)?;
- + self.painter.emit()?;
-++||||||| parent of b2b28c8... Display merge conflict branches
-++ let lines = &self.painter.merge_conflict_lines;
-++ for derived_lines in &[&lines[Ours], &lines[Theirs]] {
-++=======
-+
-+ write_merge_conflict_bar("▼", &mut self.painter, self.config)?;
-+ for (derived_commit_type, decoration_style) in &[(Ours, "box"), (Theirs, "box")] {
-+ write_subhunk_header(
-+ derived_commit_type,
-+ decoration_style,
-+ &mut self.painter,
-+ self.config,
-+ )?;
-+ self.painter.emit()?;
-++>>>>>>> b2b28c8... Display merge conflict branches
- paint::paint_minus_and_plus_lines(
- MinusPlus::new(
- &self.painter.merge_conflict_lines[Ancestral],
-@@@ -156,78 -144,94 +326,190 @@@
- );
- self.painter.emit()?;
- }
-++<<<<<<< HEAD
- + // write_merge_conflict_decoration("bold ol", &mut self.painter, self.config)?;
- + write_merge_conflict_bar(
- + &self.config.merge_conflict_end_symbol,
- + &mut self.painter,
- + self.config,
- + )?;
-++||||||| parent of b2b28c8... Display merge conflict branches
-++=======
-+ // write_merge_conflict_decoration("bold ol", &mut self.painter, self.config)?;
-+ write_merge_conflict_bar("▲", &mut self.painter, self.config)?;
-++>>>>>>> b2b28c8... Display merge conflict branches
- self.painter.merge_conflict_lines.clear();
- - self.state = State::HunkZero(diff_type);
- + self.state = HunkZero(Combined(merge_parents.clone(), InMergeConflict::No));
- Ok(())
- }
- }
-
-++<<<<<<< HEAD
- +fn write_diff_header(
- + derived_commit_type: &MergeConflictCommit,
- + painter: &mut paint::Painter,
- + config: &config::Config,
- +) -> std::io::Result<()> {
- + let (mut draw_fn, pad, decoration_ansi_term_style) =
- + draw::get_draw_function(config.merge_conflict_diff_header_style.decoration_style);
- + let derived_commit_name = &painter.merge_conflict_commit_names[derived_commit_type];
- + let text = if let Some(_ancestral_commit) = &painter.merge_conflict_commit_names[Ancestral] {
- + format!(
- + "ancestor {} {}{}",
- + config.right_arrow,
- + derived_commit_name.as_deref().unwrap_or("?"),
- + if pad { " " } else { "" }
- + )
- + } else {
- + derived_commit_name.as_deref().unwrap_or("?").to_string()
- + };
- + draw_fn(
- + painter.writer,
- + &text,
- + &text,
- + &config.decorations_width,
- + config.merge_conflict_diff_header_style,
- + decoration_ansi_term_style,
- + )?;
- + Ok(())
- +}
- +
- +fn write_merge_conflict_bar(
- + s: &str,
- + painter: &mut paint::Painter,
- + config: &config::Config,
- +) -> std::io::Result<()> {
- + if let cli::Width::Fixed(width) = config.decorations_width {
- + writeln!(
- + painter.writer,
- + "{}",
- + &s.graphemes(true).cycle().take(width).join("")
- + )?;
- + }
- + Ok(())
- +}
- +
- +fn parse_merge_marker<'a>(line: &'a str, marker: &str) -> Option<&'a str> {
- + match line.strip_prefix(marker) {
- + Some(suffix) => {
- + let suffix = suffix.trim();
- + if !suffix.is_empty() {
- + Some(suffix)
- + } else {
- + None
- + }
- + }
- + None => None,
- + }
- +}
- +
- +pub use MergeConflictCommit::*;
- +
-++impl<T> Index<MergeConflictCommit> for MergeConflictCommits<T> {
-++ type Output = T;
-++ fn index(&self, commit: MergeConflictCommit) -> &Self::Output {
-++ match commit {
-++ Ours => &self.ours,
-++ Ancestral => &self.ancestral,
-++ Theirs => &self.theirs,
-++ }
-++ }
-++}
-++||||||| parent of b2b28c8... Display merge conflict branches
-++pub use Source::*;
-++=======
-+ fn write_subhunk_header(
-+ derived_commit_type: &MergeConflictCommit,
-+ decoration_style: &str,
-+ painter: &mut paint::Painter,
-+ config: &config::Config,
-+ ) -> std::io::Result<()> {
-+ let (mut draw_fn, pad, decoration_ansi_term_style) =
-+ draw::get_draw_function(DecorationStyle::from_str(
-+ decoration_style,
-+ config.true_color,
-+ config.git_config.as_ref(),
-+ ));
-+ let derived_commit_name = &painter.merge_conflict_commit_names[derived_commit_type];
-+ let text = if let Some(_ancestral_commit) = &painter.merge_conflict_commit_names[Ancestral] {
-+ format!(
-+ "ancestor {} {}{}",
-+ config.right_arrow,
-+ derived_commit_name.as_deref().unwrap_or("?"),
-+ if pad { " " } else { "" }
-+ )
-+ } else {
-+ derived_commit_name.as_deref().unwrap_or("?").to_string()
-+ };
-+ draw_fn(
-+ painter.writer,
-+ &text,
-+ &text,
-+ &config.decorations_width,
-+ config.hunk_header_style,
-+ decoration_ansi_term_style,
-+ )?;
-+ Ok(())
-+ }
-++>>>>>>> b2b28c8... Display merge conflict branches
-+
-++<<<<<<< HEAD
-++impl<T> Index<&MergeConflictCommit> for MergeConflictCommits<T> {
-++ type Output = T;
-++ fn index(&self, commit: &MergeConflictCommit) -> &Self::Output {
-++ match commit {
-++||||||| parent of b2b28c8... Display merge conflict branches
-++impl Index<Source> for MergeConflictLines {
-++ type Output = Vec<(String, State)>;
-++ fn index(&self, source: Source) -> &Self::Output {
-++ match source {
-++=======
-+ #[allow(unused)]
-+ fn write_merge_conflict_line(
-+ painter: &mut paint::Painter,
-+ config: &config::Config,
-+ ) -> std::io::Result<()> {
-+ let (mut draw_fn, _pad, decoration_ansi_term_style) = draw::get_draw_function(
-+ DecorationStyle::from_str("bold ol", config.true_color, config.git_config.as_ref()),
-+ );
-+ draw_fn(
-+ painter.writer,
-+ "",
-+ "",
-+ &config.decorations_width,
-+ config.hunk_header_style,
-+ decoration_ansi_term_style,
-+ )?;
-+ Ok(())
-+ }
-+
-+ fn write_merge_conflict_bar(
-+ s: &str,
-+ painter: &mut paint::Painter,
-+ config: &config::Config,
-+ ) -> std::io::Result<()> {
-+ if let cli::Width::Fixed(width) = config.decorations_width {
-+ writeln!(painter.writer, "{}", s.repeat(width))?;
-+ }
-+ Ok(())
-+ }
-+
-+ fn parse_merge_marker&