diff --git a/Cargo.lock b/Cargo.lock index ff41799ce0..4b061a0c16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" +[[package]] +name = "cansi" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185b9281d84fc234662dc95ef999e5ac4e9b7591a6e5aa54edabda3179b80b4f" + [[package]] name = "cc" version = "1.0.73" @@ -189,6 +195,7 @@ version = "0.29.0" dependencies = [ "atty", "bumpalo", + "cansi", "cc", "clap", "const_format", @@ -212,6 +219,7 @@ dependencies = [ "typed-arena", "walkdir", "wu-diff", + "yansi", ] [[package]] @@ -678,3 +686,9 @@ name = "wu-diff" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e3e6735fcde06432870db8dc9d7e3ab1b93727c14eaef329969426299f28893" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index b86d227584..43bf9bd707 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,11 @@ license = "MIT" version = "0.29.0" authors = ["Wilfred Hughes "] keywords = ["diff", "syntax"] -categories = ["development-tools", "command-line-utilities", "parser-implementations"] +categories = [ + "development-tools", + "command-line-utilities", + "parser-implementations", +] edition = "2018" rust-version = "1.56.0" include = [ @@ -42,6 +46,8 @@ owo-colors = "3.3.0" rpds = "0.10.0" wu-diff = "0.1.2" rayon = "1.5.2" +yansi = "0.5.1" +cansi = "2.1.1" tree_magic_mini = "3.0.3" bumpalo = "3.9.1" diff --git a/src/display/side_by_side.rs b/src/display/side_by_side.rs index 4df078ad57..6f31b0d13f 100644 --- a/src/display/side_by_side.rs +++ b/src/display/side_by_side.rs @@ -1,8 +1,10 @@ //! Side-by-side (two column) display of diffs. +use cansi::{self, categorise_text}; use owo_colors::{OwoColorize, Style}; use rustc_hash::FxHashMap; use std::{cmp::max, collections::HashSet}; +use yansi::{Color, Paint}; use crate::{ constants::Side, @@ -438,14 +440,39 @@ pub fn print( match rhs_line_num { Some(rhs_line_num) => { let rhs_line = &rhs_colored_lines[rhs_line_num.0]; - if same_lines { - println!("{}{}", display_rhs_line_num, rhs_line); + let line_to_print = if same_lines { + format!("{}{}", display_rhs_line_num, rhs_line) } else { - println!( + format!( "{}{}{}", display_lhs_line_num, display_rhs_line_num, rhs_line - ); - } + ) + }; + let (line_bg, padding_len) = if rhs_lines_with_novel.contains(&rhs_line_num) + { + ( + Color::Fixed(194), + display_options.display_width + // we are using cansi::categorize_text to remove ANSI escapes + // if we don't do this, we can't properly pad the line length + // tried several other ANSI stripping libs, this one actually works + - categorise_text(&line_to_print) + .iter() + .map(|s| (s.end - s.start) as usize) + .sum::(), + ) + } else { + (Color::Default, 0) + }; + println!( + "{}", + Paint::wrapping(format!( + "{}{}", + line_to_print, + " ".repeat(padding_len) + )) + .bg(line_bg) + ); } None => { // We didn't have any changed RHS lines in the @@ -458,17 +485,42 @@ pub fn print( match lhs_line_num { Some(lhs_line_num) => { let lhs_line = &lhs_colored_lines[lhs_line_num.0]; - if same_lines { - println!("{}{}", display_lhs_line_num, lhs_line); + let line_to_print = if same_lines { + format!("{}{}", display_lhs_line_num, lhs_line) } else { - println!( + format!( "{}{}{}", - display_lhs_line_num, display_rhs_line_num, lhs_line - ); - } + display_lhs_line_num, display_lhs_line_num, lhs_line + ) + }; + let (line_bg, padding_len) = if lhs_lines_with_novel.contains(&lhs_line_num) + { + ( + Color::Fixed(224), + display_options.display_width + // we are using cansi::categorize_text to remove ANSI escapes + // if we don't do this, we can't properly pad the line length + // tried several other ANSI stripping libs, this one actually works + - categorise_text(&line_to_print) + .iter() + .map(|s| (s.end - s.start) as usize) + .sum::(), + ) + } else { + (Color::Default, 0) + }; + println!( + "{}", + Paint::wrapping(format!( + "{}{}", + line_to_print, + " ".repeat(padding_len) + )) + .bg(line_bg) + ); } None => { - println!("{}{}", display_lhs_line_num, display_rhs_line_num); + println!("{}{}", display_lhs_line_num, display_lhs_line_num); } } } else { @@ -543,7 +595,28 @@ pub fn print( s }; - println!("{}{}{}{}{}", lhs_num, lhs_line, SPACER, rhs_num, rhs_line); + println!( + "{}{}{}", + Paint::wrapping(format!("{}{}", lhs_num, lhs_line)).bg( + if lhs_line_num.is_some() + && lhs_lines_with_novel.contains(&lhs_line_num.unwrap()) + { + Color::Fixed(224) + } else { + Color::Default + } + ), + SPACER, + Paint::wrapping(format!("{}{}", rhs_num, rhs_line)).bg( + if rhs_line_num.is_some() + && rhs_lines_with_novel.contains(&rhs_line_num.unwrap()) + { + Color::Fixed(194) + } else { + Color::Default + } + ), + ); } } diff --git a/src/display/style.rs b/src/display/style.rs index c9fe47fa70..18cdbf8920 100644 --- a/src/display/style.rs +++ b/src/display/style.rs @@ -90,7 +90,7 @@ pub fn split_and_apply( ) -> Vec { if styles.is_empty() && !line.trim().is_empty() { // Missing styles is a bug, so highlight in purple to make this obvious. - return split_string_by_codepoint(line, max_len, matches!(side, Side::Left)) + return split_string_by_codepoint(line, max_len, true) .into_iter() .map(|part| { if use_color { @@ -105,7 +105,7 @@ pub fn split_and_apply( let mut styled_parts = vec![]; let mut part_start = 0; - for part in split_string_by_codepoint(line, max_len, matches!(side, Side::Left)) { + for part in split_string_by_codepoint(line, max_len, true) { let mut res = String::with_capacity(part.len()); let mut prev_style_end = 0; for (span, style) in styles { @@ -225,14 +225,14 @@ fn apply(s: &str, styles: &[(SingleLineSpan, Style)]) -> String { pub fn novel_style(style: Style, is_lhs: bool, background: BackgroundColor) -> Style { if background.is_dark() { if is_lhs { - style.bright_red() + style.on_red() } else { - style.bright_green() + style.on_green() } } else if is_lhs { - style.red() + style.on_bright_red() } else { - style.green() + style.on_bright_green() } }