diff options
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 96 |
1 files changed, 93 insertions, 3 deletions
diff --git a/src/config.rs b/src/config.rs index 5a013a1b..4a93cfe2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,9 @@ use structopt::clap; use syntect::highlighting::Style as SyntectStyle; use syntect::highlighting::Theme as SyntaxTheme; use syntect::parsing::SyntaxSet; +use unicode_segmentation::UnicodeSegmentation; +use crate::ansi; use crate::bat_utils::output::PagingMode; use crate::cli; use crate::color; @@ -19,6 +21,37 @@ use crate::features::side_by_side; use crate::git_config::{GitConfig, GitConfigEntry}; use crate::paint::BgFillMethod; use crate::style::{self, Style}; +use crate::syntect_color; +use crate::wrapping::WrapConfig; + +pub const INLINE_SYMBOL_WIDTH_1: usize = 1; + +fn remove_percent_suffix(arg: &str) -> &str { + match &arg.strip_suffix('%') { + Some(s) => s, + None => arg, + } +} + +fn ensure_display_width_1(what: &str, arg: String) -> String { + match arg.grapheme_indices(true).count() { + INLINE_SYMBOL_WIDTH_1 => arg, + width => fatal(format!( + "Invalid value for {}, display width of \"{}\" must be {} but is {}", + what, arg, INLINE_SYMBOL_WIDTH_1, width + )), + } +} + +fn adapt_wrap_max_lines_argument(arg: String) -> usize { + if arg == "∞" || arg == "unlimited" || arg.starts_with("inf") { + 0 + } else { + arg.parse::<usize>() + .unwrap_or_else(|err| fatal(format!("Invalid wrap-max-lines argument: {}", err))) + + 1 + } +} pub struct Config { pub available_terminal_width: usize, @@ -51,6 +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 inspect_raw_lines: cli::InspectRawLines, pub keep_plus_minus_markers: bool, pub line_fill_method: BgFillMethod, @@ -96,6 +130,7 @@ pub struct Config { pub true_color: bool, pub truncation_symbol: String, pub whitespace_error_style: Style, + pub wrap_config: WrapConfig, pub zero_style: Style, } @@ -210,6 +245,8 @@ impl From<cli::Opt> for Config { None }; + let wrap_max_lines_plus1 = adapt_wrap_max_lines_argument(opt.wrap_max_lines); + Self { available_terminal_width: opt.computed.available_terminal_width, background_color_extends_to_terminal_width: opt @@ -254,8 +291,20 @@ 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_color::syntect_color_from_ansi_name("blue").unwrap(), + ..SyntectStyle::default() + }), keep_plus_minus_markers: opt.keep_plus_minus_markers, - line_fill_method, + line_fill_method: if opt.side_by_side { + // Panels in side-by-side always sum up to an even number, if the terminal has + // an odd width then extending the background color with an ANSI sequence + // would indicate the wrong width and extend beyond truncated or wrapped content, + // thus spaces are used here by default. + BgFillMethod::Spaces + } else { + line_fill_method + }, line_numbers: opt.line_numbers, line_numbers_left_format: opt.line_numbers_left_format, line_numbers_left_style, @@ -267,7 +316,23 @@ impl From<cli::Opt> for Config { line_buffer_size: opt.line_buffer_size, max_line_distance: opt.max_line_distance, max_line_distance_for_naively_paired_lines, - max_line_length: opt.max_line_length, + max_line_length: match (opt.side_by_side, wrap_max_lines_plus1) { + (false, _) | (true, 1) => opt.max_line_length, + // Ensure there is enough text to wrap, either don't truncate the input at all (0) + // or ensure there is enough for the requested number of lines. + // The input can contain ANSI sequences, so round up a bit. This is enough for + // normal `git diff`, but might not be with ANSI heavy input. + (true, 0) => 0, + (true, wrap_max_lines) => { + let single_pane_width = opt.computed.available_terminal_width / 2; + let add_25_percent_or_term_width = + |x| x + std::cmp::max((x * 250) / 1000, single_pane_width) as usize; + std::cmp::max( + opt.max_line_length, + add_25_percent_or_term_width(single_pane_width * wrap_max_lines), + ) + } + }, minus_emph_style, minus_empty_line_marker_style, minus_file: opt.minus_file, @@ -296,7 +361,32 @@ impl From<cli::Opt> for Config { tab_width: opt.tab_width, tokenization_regex, true_color: opt.computed.true_color, - truncation_symbol: "→".to_string(), + truncation_symbol: format!("{}→{}", ansi::ANSI_SGR_REVERSE, ansi::ANSI_SGR_RESET), + wrap_config: WrapConfig { + left_symbol: ensure_display_width_1("wrap-left-symbol", opt.wrap_left_symbol), + right_symbol: ensure_display_width_1("wrap-right-symbol", opt.wrap_right_symbol), + right_prefix_symbol: ensure_display_width_1( + "wrap-right-prefix-symbol", + opt.wrap_right_prefix_symbol, + ), + use_wrap_right_permille: { + let arg = &opt.wrap_right_percent; + let percent = remove_percent_suffix(arg) + .parse::<f64>() + .unwrap_or_else(|err| { + fatal(format!( + "Could not parse wrap-right-percent argument {}: {}.", + &arg, err + )) + }); + if percent.is_finite() && percent > 0.0 && percent < 100.0 { + (percent * 10.0).round() as usize + } else { + fatal("Invalid value for wrap-right-percent, not between 0 and 100.") + } + }, + max_lines: wrap_max_lines_plus1, + }, whitespace_error_style, zero_style, } |