Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,14 @@ pub struct Opt {
/// Display diffs in side-by-side layout.
pub side_by_side: bool,

#[arg(long = "side-by-side-fill-empty", value_name = "CHAR_AND_STYLE")]
/// Fill empty side. Can be "true", or a fill character, or a character plus a style.
///
/// On "true" the unmatched side will be filled with "/" in the style of
/// --line-numbers-zero-style, if a single character is given this is used instead.
/// If the character is followed by a style, that style is used.
pub side_by_side_fill_empty: Option<String>,

#[arg(long = "syntax-theme", value_name = "SYNTAX_THEME")]
/// The syntax-highlighting theme to use.
///
Expand Down
19 changes: 19 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use regex::Regex;
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::cli;
Expand Down Expand Up @@ -127,6 +128,7 @@ pub struct Config {
pub relative_paths: bool,
pub show_themes: bool,
pub side_by_side_data: side_by_side::SideBySideData,
pub side_by_side_fill_empty: Option<side_by_side::SideBySideFillEmpty>,
pub side_by_side: bool,
pub syntax_set: SyntaxSet,
pub syntax_theme: Option<SyntaxTheme>,
Expand Down Expand Up @@ -247,6 +249,13 @@ impl From<cli::Opt> for Config {
side_by_side_data,
);

let side_by_side_fill_empty = side_by_side::SideBySideFillEmpty::from_str(
opt.side_by_side_fill_empty,
&opt.line_numbers_zero_style,
opt.computed.true_color,
opt.git_config.as_ref(),
);

let navigate_regex = if (opt.navigate || opt.show_themes)
&& (opt.navigate_regex.is_none() || opt.navigate_regex == Some("".to_string()))
{
Expand Down Expand Up @@ -426,6 +435,7 @@ impl From<cli::Opt> for Config {
show_themes: opt.show_themes,
side_by_side: opt.side_by_side && !handlers::hunk::is_word_diff(),
side_by_side_data,
side_by_side_fill_empty,
styles_map,
syntax_set: opt.computed.syntax_set,
syntax_theme: opt.computed.syntax_theme,
Expand Down Expand Up @@ -462,6 +472,15 @@ pub fn user_supplied_option(option: &str, arg_matches: &clap::ArgMatches) -> boo
arg_matches.value_source(option) == Some(ValueSource::CommandLine)
}

pub 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 {what}, display width of \"{arg}\" must be {INLINE_SYMBOL_WIDTH_1} but is {width}",
)),
}
}

pub fn delta_unreachable(message: &str) -> ! {
fatal(format!(
"{message} This should not be possible. \
Expand Down
75 changes: 69 additions & 6 deletions src/features/side_by_side.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use unicode_width::UnicodeWidthStr;

use crate::ansi;
use crate::cli;
use crate::config::ensure_display_width_1;
use crate::config::{self, delta_unreachable, Config};
use crate::delta::DiffType;
use crate::delta::State;
Expand Down Expand Up @@ -56,6 +57,59 @@ impl SideBySideData {
}
}

#[derive(Clone, Debug)]
pub struct SideBySideFillEmpty {
pub filler: smol_str::SmolStr,
pub style: Style,
}

impl SideBySideFillEmpty {
fn new(filler: smol_str::SmolStr, style: Style) -> Self {
ensure_display_width_1(
"first argument of side-by-side-fill-empty",
filler.to_string(),
);
Self { filler, style }
}

fn default_filler(style: Style) -> Self {
Self {
filler: "/".into(),
style,
}
}

pub fn from_str(
s: Option<String>,
default_style: &str,
true_color: bool,
git_config: Option<&crate::git_config::GitConfig>,
) -> Option<Self> {
match s?.split(char::is_whitespace).collect::<Vec<_>>().as_slice() {
[] | [""] => None,
[single_arg] => match single_arg.to_lowercase().as_str() {
"false" => None,
"true" => Some(SideBySideFillEmpty::default_filler(Style::from_str(
default_style,
None,
None,
true_color,
git_config,
))),
_ => Some(SideBySideFillEmpty::new(
single_arg.into(),
Style::from_str(default_style, None, None, true_color, git_config),
)),
},
args => {
let style =
Style::from_str(&args[1..].join(" "), None, None, true_color, git_config);
Some(SideBySideFillEmpty::new(args[0].into(), style))
}
}
}
}

pub fn available_line_width(
config: &Config,
data: &line_numbers::LineNumbersData,
Expand Down Expand Up @@ -518,18 +572,27 @@ fn pad_panel_line_to_width(
config,
);

match bg_fill_mode {
Some(BgFillMethod::TryAnsiSequence) => {
match (
bg_fill_mode,
config.side_by_side_fill_empty.as_ref(),
panel_line_is_empty,
) {
(_, Some(fill), true) => panel_line.push_str(
&fill
.style
.paint(fill.filler.repeat(panel_width - text_width))
.to_string(),
),
(Some(BgFillMethod::TryAnsiSequence), _, _) => {
Painter::right_fill_background_color(panel_line, fill_style)
}
Some(BgFillMethod::Spaces) if text_width >= panel_width => (),
Some(BgFillMethod::Spaces) => panel_line.push_str(
#[allow(clippy::unnecessary_to_owned)]
(Some(BgFillMethod::Spaces), _, _) if text_width >= panel_width => (),
(Some(BgFillMethod::Spaces), _, _) => panel_line.push_str(
&fill_style
.paint(" ".repeat(panel_width - text_width))
.to_string(),
),
None => (),
(None, _, _) => (),
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/options/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ pub fn set_options(
.unwrap_or_else(|| "magenta reverse".to_string())
}

// Sets opt.computed.color_mode to the computed or provided value (by --light or --dark),
// then used e.g. by the line numbers feature.
theme::set__color_mode__syntax_theme__syntax_set(opt, assets);

set_options!(
[
blame_code_style,
Expand Down Expand Up @@ -214,6 +218,7 @@ pub fn set_options(
show_colors,
show_themes,
side_by_side,
side_by_side_fill_empty,
wrap_max_lines,
wrap_right_prefix_symbol,
wrap_right_percent,
Expand All @@ -237,7 +242,6 @@ pub fn set_options(
// Setting ComputedValues
set_widths_and_isatty(opt);
set_true_color(opt);
theme::set__color_mode__syntax_theme__syntax_set(opt, assets);
opt.computed.inspect_raw_lines =
cli::InspectRawLines::from_str(&opt.inspect_raw_lines).unwrap();
opt.computed.paging_mode = parse_paging_mode(&opt.paging_mode);
Expand Down
12 changes: 1 addition & 11 deletions src/wrapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;

use crate::cli;
use crate::config::INLINE_SYMBOL_WIDTH_1;
use crate::config::{ensure_display_width_1, Config, INLINE_SYMBOL_WIDTH_1};
use crate::fatal;

use crate::config::Config;
use crate::delta::DiffType;
use crate::delta::State;
use crate::features::line_numbers::{self, SideBySideLineWidth};
Expand Down Expand Up @@ -97,15 +96,6 @@ fn remove_percent_suffix(arg: &str) -> &str {
}
}

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 {what}, display width of \"{arg}\" must be {INLINE_SYMBOL_WIDTH_1} but is {width}",
)),
}
}

fn adapt_wrap_max_lines_argument(arg: String) -> usize {
if arg == "∞" || arg == "unlimited" || arg.starts_with("inf") {
0
Expand Down
Loading