diff options
author | Dan Davison <dandavison7@gmail.com> | 2021-04-21 09:07:36 -0400 |
---|---|---|
committer | Thomas Otto <th1000s@posteo.net> | 2021-10-16 14:07:30 +0200 |
commit | 32aef48ccf6d03a1c316228b9d0398c38e22f8fc (patch) | |
tree | fff66585b1ec9f7207362ff0aedb5f9eb3229b6d | |
parent | 7c93d279e60253fc380d73f2f84fe5e2a4a274e6 (diff) |
Add inline-hint-style option and use for side-by-side wrap symbols
-rw-r--r-- | src/cli.rs | 6 | ||||
-rw-r--r-- | src/config.rs | 17 | ||||
-rw-r--r-- | src/options/set.rs | 1 | ||||
-rw-r--r-- | src/syntect_utils.rs | 73 | ||||
-rw-r--r-- | src/wrapping.rs | 39 |
5 files changed, 123 insertions, 13 deletions
@@ -447,6 +447,12 @@ pub struct Opt { #[structopt(long = "default-language")] pub default_language: Option<String>, + #[structopt(long = "inline-hint-style", default_value = "blue")] + /// Style (foreground, background, attributes) for content added by delta to + /// the original diff such as special characters to highlight tabs, and the + /// symbols used to indicate wrapped lines. See STYLES section. + pub inline_hint_style: String, + /// The regular expression used to decide what a word is for the within-line highlight /// algorithm. For less fine-grained matching than the default try --word-diff-regex="\S+" /// --max-line-distance=1.0 (this is more similar to `git --word-diff`). diff --git a/src/config.rs b/src/config.rs index 15b3b75d..d89af7d5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -21,7 +21,7 @@ use crate::features::side_by_side; use crate::git_config::{GitConfig, GitConfigEntry}; use crate::paint::BgFillMethod; use crate::style::{self, Style}; -use crate::syntect_utils; +use crate::syntect_utils::FromDeltaStyle; use crate::wrapping::WrapConfig; pub const INLINE_SYMBOL_WIDTH_1: usize = 1; @@ -84,7 +84,7 @@ pub struct Config { pub hyperlinks: bool, pub hyperlinks_commit_link_format: Option<String>, pub hyperlinks_file_link_format: String, - pub inline_hint_color: Option<SyntectStyle>, + pub inline_hint_style: Style, pub inspect_raw_lines: cli::InspectRawLines, pub keep_plus_minus_markers: bool, pub line_fill_method: BgFillMethod, @@ -209,6 +209,13 @@ impl From<cli::Opt> for Config { &opt.computed.available_terminal_width, ); + let inline_hint_style = Style::from_str( + &opt.inline_hint_style, + None, + None, + opt.computed.true_color, + false, + ); let git_minus_style = match opt.git_config_entries.get("color.diff.old") { Some(GitConfigEntry::Style(s)) => Style::from_git_str(s), _ => *style::GIT_DEFAULT_MINUS_STYLE, @@ -291,10 +298,7 @@ impl From<cli::Opt> for Config { hyperlinks_commit_link_format: opt.hyperlinks_commit_link_format, hyperlinks_file_link_format: opt.hyperlinks_file_link_format, inspect_raw_lines: opt.computed.inspect_raw_lines, - inline_hint_color: Some(SyntectStyle { - foreground: syntect_utils::syntect_color_from_ansi_name("blue").unwrap(), - ..SyntectStyle::default() - }), + inline_hint_style, keep_plus_minus_markers: opt.keep_plus_minus_markers, line_fill_method: if opt.side_by_side { // Panels in side-by-side always sum up to an even number, if the terminal has @@ -386,6 +390,7 @@ impl From<cli::Opt> for Config { } }, max_lines: wrap_max_lines_plus1, + inline_hint_syntect_style: SyntectStyle::from_delta_style(inline_hint_style), }, whitespace_error_style, zero_style, diff --git a/src/options/set.rs b/src/options/set.rs index 1d6f13ed..8f53d5b7 100644 --- a/src/options/set.rs +++ b/src/options/set.rs @@ -145,6 +145,7 @@ pub fn set_options( hyperlinks, hyperlinks_commit_link_format, hyperlinks_file_link_format, + inline_hint_style, inspect_raw_lines, keep_plus_minus_markers, line_buffer_size, diff --git a/src/syntect_utils.rs b/src/syntect_utils.rs index 3569b318..6f7e4af5 100644 --- a/src/syntect_utils.rs +++ b/src/syntect_utils.rs @@ -1,8 +1,9 @@ use std::str::FromStr; -use syntect::highlighting::Color; +use syntect::highlighting::{Color, FontStyle, Style}; use crate::color; +use crate::style as delta_style; pub fn syntect_color_from_ansi_name(name: &str) -> Option<Color> { color::ansi_16_color_name_to_number(name).and_then(syntect_color_from_ansi_number) @@ -13,3 +14,73 @@ pub fn syntect_color_from_ansi_name(name: &str) -> Option<Color> { pub fn syntect_color_from_ansi_number(n: u8) -> Option<Color> { Color::from_str(&format!("#{:02x}000000", n)).ok() } + +pub trait FromAnsiTermStyle { + fn from_ansi_term_style(ansi_term_style: ansi_term::Style) -> Self; +} + +impl FromAnsiTermStyle for Style { + fn from_ansi_term_style(ansi_term_style: ansi_term::Style) -> Self { + let default = Self::default(); + Self { + foreground: if let Some(color) = ansi_term_style.foreground { + Color::from_ansi_term_color(color) + } else { + default.foreground + }, + background: if let Some(color) = ansi_term_style.background { + Color::from_ansi_term_color(color) + } else { + default.background + }, + font_style: FontStyle::from_ansi_term_style(ansi_term_style), + } + } +} + +impl FromAnsiTermStyle for FontStyle { + fn from_ansi_term_style(ansi_term_style: ansi_term::Style) -> Self { + let mut font_style = FontStyle::empty(); + if ansi_term_style.is_bold { + font_style |= FontStyle::BOLD + } + if ansi_term_style.is_italic { + font_style |= FontStyle::ITALIC + } + if ansi_term_style.is_underline { + font_style |= FontStyle::UNDERLINE + } + font_style + } +} + +pub trait FromAnsiTermColor { + fn from_ansi_term_color(ansi_term_color: ansi_term::Color) -> Self; +} + +impl FromAnsiTermColor for Color { + fn from_ansi_term_color(ansi_term_color: ansi_term::Color) -> Self { + match ansi_term_color { + ansi_term::Color::Black => syntect_color_from_ansi_number(0).unwrap(), + ansi_term::Color::Red => syntect_color_from_ansi_number(1).unwrap(), + ansi_term::Color::Green => syntect_color_from_ansi_number(2).unwrap(), + ansi_term::Color::Yellow => syntect_color_from_ansi_number(3).unwrap(), + ansi_term::Color::Blue => syntect_color_from_ansi_number(4).unwrap(), + ansi_term::Color::Purple => syntect_color_from_ansi_number(5).unwrap(), + ansi_term::Color::Cyan => syntect_color_from_ansi_number(6).unwrap(), + ansi_term::Color::White => syntect_color_from_ansi_number(7).unwrap(), + ansi_term::Color::Fixed(n) => syntect_color_from_ansi_number(n).unwrap(), + ansi_term::Color::RGB(r, g, b) => Self { r, g, b, a: 0xFF }, + } + } +} + +pub trait FromDeltaStyle { + fn from_delta_style(delta_style: delta_style::Style) -> Self; +} + +impl FromDeltaStyle for Style { + fn from_delta_style(delta_style: delta_style::Style) -> Self { + Self::from_ansi_term_style(delta_style.ansi_term_style) + } +} diff --git a/src/wrapping.rs b/src/wrapping.rs index abb19db1..d183afe1 100644 --- a/src/wrapping.rs +++ b/src/wrapping.rs @@ -26,6 +26,7 @@ pub struct WrapConfig { // This value is --wrap-max-lines + 1, and unlimited is 0, see // adapt_wrap_max_lines_argument() pub max_lines: usize, + pub inline_hint_syntect_style: SyntectStyle, } /// Wrap the given `line` if it is longer than `line_width`. Wrap to at most @@ -344,10 +345,23 @@ pub fn wrap_plusminus_block<'c: 'a, 'a>( .unwrap_or_else(|| panic!("bad syntax alignment {}", errhint)), must_wrap, line_width, - &SyntectStyle::default(), - &config.inline_hint_color, + &config.null_syntect_style, + &Some(config.wrap_config.inline_hint_syntect_style), ); + // TODO: Why is the background color set to white when + // ansi_term_style.background is None? + let inline_hint_style = if config + .inline_hint_style + .ansi_term_style + .background + .is_some() + { + Some(config.inline_hint_style) + } else { + None + }; + let (start2, extended_to2) = wrap_if_too_long( config, wrapped_diff, @@ -357,7 +371,7 @@ pub fn wrap_plusminus_block<'c: 'a, 'a>( must_wrap, line_width, fill_style, - &None, + &inline_hint_style, ); // The underlying text is the same for the style and diff, so @@ -510,18 +524,31 @@ pub fn wrap_zero_block<'c: 'a, 'a>( syntax_style_sections.into_iter().flatten(), line_width, &SyntectStyle::default(), - &config.inline_hint_color, + &Some(config.wrap_config.inline_hint_syntect_style), ); + + // TODO: Why is the background color set to white when + // ansi_term_style.background is None? + let inline_hint_style = if config + .inline_hint_style + .ansi_term_style + .background + .is_some() + { + Some(config.inline_hint_style) + } else { + None + }; let diff_style = wrap_line( config, diff_style_sections.into_iter().flatten(), line_width, - // To actually highlight `config.inline_hint_color` characters: + // To actually highlight inline hint characters: &Style { is_syntax_highlighted: true, ..config.null_style }, - &None, + &inline_hint_style, ); states.resize_with(syntax_style.len(), || State::HunkZeroWrapped); |