Skip to content

Commit

Permalink
Do not panic on superimposition mismatch in release builds
Browse files Browse the repository at this point in the history
Lines which would trigger a panic and early exit with the message
"String mismatch encountered while superimposing style sections"
now try to print the line as well as possible plus a brief error message.

In debug builds and when running from the target/ dir (such as when
core.pager = "target/release/delta" is set) or when the env var
DELTA_NO_WORKAROUNDS is set this mismatch panics as before.
  • Loading branch information
th1000s authored and dandavison committed Jul 17, 2024
1 parent c1e8e7b commit dc55684
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 8 deletions.
90 changes: 83 additions & 7 deletions src/paint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -918,19 +918,86 @@ mod superimpose_style_sections {
exploded
}

// Do not panic in release builds, instead try to produce some output.
// Always panic in debug builds, if an env var is set, or the delta binary is
// running from target/*/delta.
#[inline(never)]
#[allow(clippy::type_complexity)]
fn on_superimpose_error(
char_1: char,
char_2: char,
style_section_pairs: Vec<(&(SyntectStyle, char), (Style, char))>,
) -> Vec<((SyntectStyle, Style), char)> {
let mut errormsg: Vec<((SyntectStyle, Style), char)> = Vec::new();
let errorstyle = Style {
ansi_term_style: ansi_term::Style::new().fg(ansi_term::Color::Red).bold(),
..Default::default()
};

for prefix in " !!<delta bug 1450> ".chars() {
errormsg.push(((SyntectStyle::default(), errorstyle), prefix));
}
let to_text = |
syntax_or_diff: fn(&(&(SyntectStyle, char), (Style, char))) -> char,
| -> (String, String) {
let text_raw: String = style_section_pairs.iter().map(syntax_or_diff).collect();
let text = crate::ansi::strip_ansi_codes(&text_raw);
let text = text.trim().to_string();
(text_raw, text)
};

let (syn_raw, syn) = to_text(|((_syn, c1), (_style, _c2))| *c1);
let (style_raw, style) = to_text(|((_syn, _c1), (_style, c2))| *c2);

let longer = if syn.len() > style.len() {
&syn
} else {
&style
};
for c in longer.chars() {
errormsg.push(((SyntectStyle::default(), Style::default()), c));
}
for suffix in " !please report! ".chars() {
errormsg.push(((SyntectStyle::default(), errorstyle), suffix));
}

let in_worktree = || {
let arg0 = std::env::args_os().next().unwrap_or("".into());
let arg0 = arg0.to_str().unwrap_or("");
let arg0 = arg0.strip_suffix(".exe").unwrap_or(arg0);
let arg0 = std::path::Path::new(&arg0);
arg0.ends_with("target/debug/delta") || arg0.ends_with("target/release/delta")
};

#[cfg(debug_assertions)]
let release = false;
#[cfg(not(debug_assertions))]
let release = true;

if std::env::var(crate::utils::workarounds::NO_WORKAROUNDS).is_err()
&& release
&& !in_worktree()
{
return errormsg;
}

panic!(
"String mismatch encountered while superimposing style sections: '{}' vs '{}'. Syntect {:?} vs Style {:?}",
char_1, char_2, syn_raw, style_raw,
);
}

#[allow(clippy::type_complexity)]
fn superimpose(
style_section_pairs: Vec<(&(SyntectStyle, char), (Style, char))>,
) -> Vec<((SyntectStyle, Style), char)> {
let mut superimposed: Vec<((SyntectStyle, Style), char)> = Vec::new();
for ((syntax_style, char_1), (style, char_2)) in style_section_pairs {
if *char_1 != char_2 {
panic!(
"String mismatch encountered while superimposing style sections: '{}' vs '{}'",
*char_1, char_2
)
for ((syntax_style, char_1), (style, char_2)) in style_section_pairs.iter() {
if *char_1 == *char_2 {
superimposed.push(((*syntax_style, *style), *char_1));
} else {
return on_superimpose_error(*char_1, *char_2, style_section_pairs);
}
superimposed.push(((*syntax_style, style), *char_1));
}
superimposed
}
Expand Down Expand Up @@ -1099,5 +1166,14 @@ mod superimpose_style_sections {
vec![((*SYNTAX_STYLE, *SYNTAX_HIGHLIGHTED_STYLE), 'a')]
);
}

#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn test_superimpose_panic() {
let x = (*SYNTAX_STYLE, 'a');
let pairs = vec![(&x, (*SYNTAX_HIGHLIGHTED_STYLE, 'b'))];
superimpose(pairs);
}
}
}
2 changes: 1 addition & 1 deletion src/utils/workarounds.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// env var which should disable workarounds
const NO_WORKAROUNDS: &str = "DELTA_NO_WORKAROUNDS";
pub const NO_WORKAROUNDS: &str = "DELTA_NO_WORKAROUNDS";

// Work around a bug in the 'console' crate (inherited from 'terminal-size', #25): On Windows
// it can not determine the width of an MSYS2 / MINGW64 terminal (e.g. from Git-Bash) correctly.
Expand Down

0 comments on commit dc55684

Please sign in to comment.