use std::sync::atomic::AtomicBool;
use super::{
ConflictStyle, ContentHunk, ContentMerge, ContentOptions, Favor, MarkerOptions, content_with,
};
use crate::Config;
use crate::attributes::State;
use crate::content_diff::BinaryMode;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Driver<'a> {
Automatic,
Text,
Binary,
Union,
Custom(&'a [u8]),
}
impl<'a> Driver<'a> {
pub fn from_attribute(state: State<'a>) -> Self {
match state {
State::Unspecified => Self::Automatic,
State::Set => Self::Text,
State::Unset => Self::Binary,
State::Value(value) => Self::named(value),
}
}
pub fn configured(state: State<'a>, config: &'a Config) -> Self {
match state {
State::Unspecified => config
.string("merge", None, "default")
.map_or(Self::Automatic, Self::named),
_ => Self::from_attribute(state),
}
}
fn named(name: &'a [u8]) -> Self {
match name {
b"text" => Self::Text,
b"binary" => Self::Binary,
b"union" => Self::Union,
_ => Self::Custom(name),
}
}
pub fn merge(
self,
base: &[u8],
ours: &[u8],
theirs: &[u8],
mut options: ContentOptions,
cancel: &AtomicBool,
) -> Result<ContentMerge, DriverError> {
match self {
Self::Automatic => options.binary = BinaryMode::Auto,
Self::Text => options.binary = BinaryMode::Auto,
Self::Binary => options.binary = BinaryMode::Binary,
Self::Union => {
options.binary = BinaryMode::Auto;
options.favor = Favor::Union;
}
Self::Custom(name) => return Err(DriverError::CustomRequired(name.to_vec())),
}
Ok(content_with(base, ours, theirs, options, cancel)?)
}
}
impl ContentMerge {
pub fn resolved(bytes: Vec<u8>) -> Self {
Self {
hunks: vec![ContentHunk::Resolved(bytes)],
binary: false,
}
}
pub fn conflicted(base: Vec<u8>, ours: Vec<u8>, theirs: Vec<u8>, binary: bool) -> Self {
Self {
hunks: vec![ContentHunk::Conflict { base, ours, theirs }],
binary,
}
}
}
impl MarkerOptions {
pub fn from_config(config: &Config) -> Result<Self, DriverError> {
let style = match config.value("merge", None, "conflictstyle") {
None => ConflictStyle::Merge,
Some(Some(b"merge")) => ConflictStyle::Merge,
Some(Some(b"diff3")) => ConflictStyle::Diff3,
Some(Some(b"zdiff3")) => ConflictStyle::Zdiff3,
Some(value) => return Err(DriverError::ConflictStyle(value.map(<[u8]>::to_vec))),
};
Ok(Self {
style,
..Self::default()
})
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum DriverError {
#[error("custom merge driver requires caller execution")]
CustomRequired(Vec<u8>),
#[error("invalid merge.conflictStyle")]
ConflictStyle(Option<Vec<u8>>),
#[error("running built-in merge driver")]
Content(#[from] super::Error),
}