use std::cmp::max;
use lazy_static::lazy_static;
use regex::Regex;
use unicode_segmentation::UnicodeSegmentation;
use crate::config;
use crate::delta::State;
use crate::features::hyperlinks;
use crate::features::side_by_side;
use crate::features::side_by_side::LeftRight;
use crate::features::OptionValueFunction;
use crate::style::Style;
use crate::features::side_by_side::PanelSide::{Left, Right};
pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
builtin_feature!([
(
"line-numbers",
bool,
None,
_opt => true
),
(
"line-numbers-left-style",
String,
None,
_opt => "blue"
),
(
"line-numbers-right-style",
String,
None,
_opt => "blue"
),
(
"line-numbers-minus-style",
String,
None,
opt => if opt.computed.is_light_mode {
"red".to_string()
} else {
"88".to_string()
}
),
(
"line-numbers-zero-style",
String,
None,
opt => if opt.computed.is_light_mode {"#dddddd"} else {"#444444"}
),
(
"line-numbers-plus-style",
String,
None,
opt => if opt.computed.is_light_mode {
"green".to_string()
} else {
"28".to_string()
}
)
])
}
/// Return a vec of `ansi_term::ANSIGenericString`s representing the left and right fields of the
/// two-column line number display.
pub fn format_and_paint_line_numbers<'a>(
line_numbers_data: &'a mut LineNumbersData,
state: &State,
side_by_side_panel: Option<side_by_side::PanelSide>,
config: &'a config::Config,
) -> Vec<ansi_term::ANSIGenericString<'a, str>> {
let nr_left = line_numbers_data.line_number[Left];
let nr_right = line_numbers_data.line_number[Right];
let (minus_style, zero_style, plus_style) = (
config.line_numbers_minus_style,
config.line_numbers_zero_style,
config.line_numbers_plus_style,
);
let ((minus_number, plus_number), (minus_style, plus_style)) = match state {
State::HunkMinus(_) => {
line_numbers_data.line_number[Left] += 1;
((Some(nr_left), None), (minus_style, plus_style))
}
State::HunkZero => {
line_numbers_data.line_number[Left] += 1;
line_numbers_data.line_number[Right] += 1;
((Some(nr_left), Some(nr_right)), (zero_style, zero_style))
}
State::HunkPlus(_) => {
line_numbers_data.line_number[Right] += 1;
((None, Some(nr_right)), (minus_style, plus_style))
}
_ => return Vec::new(),
};
let mut formatted_numbers = Vec::new();
let (emit_left, emit_right) = match (config.side_by_side, side_by_side_panel) {
(false, _) => (true, true),
(true, Some(side_by_side::PanelSide::Left)) => (true, false),
(true, Some(side_by_side::PanelSide::Right)) => (false, true),
(true, None) => unreachable!(),
};
if emit_left {
formatted_numbers.extend(format_and_paint_line_number_field(
&line_numbers_data.format_data[Left],
&config.line_numbers_left_style,
minus_number,
plus_number,
line_numbers_data.hunk_max_line_number_width,
&minus_style,
&plus_style,
&line_numbers_data.plus_file,
config,
));
}
if emit_right {
formatted_numbers.extend(format_and_paint_line_number_field(
&line_numbers_data.format_data[Right],
&config.line_numbers_right_style,
minus_number,
plus_number,
line_numbers_data.hunk_max_line_number_width,
&minus_style,
&plus_style,
&line_numbers_data.plus_file,
config,
));
}
formatted_numbers
}
lazy_static! {
static ref LINE_NUMBERS_PLACEHOLDER_REGEX: Regex = Regex::new(
r"(?x)
\{
(nm|np) # 1: Literal nm or np
(?: # Start optional format spec (non-capturing)
: # Literal colon
(?: