Skip to content

Commit

Permalink
Merge pull request #550 from clnoll/show-delta-themes
Browse files Browse the repository at this point in the history
  • Loading branch information
dandavison authored Mar 29, 2021
2 parents 1f4691f + 926e3c5 commit 48fe43f
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 22 deletions.
3 changes: 3 additions & 0 deletions src/bat_utils/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ delta is not an appropriate value for $PAGER \
navigate::copy_less_hist_file_and_append_navigate_regexp(config)
{
process.env("LESSHISTFILE", hist_file);
if config.show_themes {
process.arg("+n");
}
}
}
Ok(process
Expand Down
17 changes: 14 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::collections::{HashMap, HashSet};
#[cfg(test)]
use std::ffi::OsString;
use std::path::PathBuf;

Expand Down Expand Up @@ -266,10 +265,23 @@ pub struct Opt {

/// Show all available syntax-highlighting themes, each with an example of highlighted diff output.
/// If diff output is supplied on standard input then this will be used for the demo. For
/// example: `git show --color=always | delta --show-syntax-themes`.
/// example: `git show | delta --show-syntax-themes`.
#[structopt(long = "show-syntax-themes")]
pub show_syntax_themes: bool,

/// Show available delta themes, each with an example of highlighted diff
/// output. A delta theme is a delta named feature (see --features) that
/// sets either `light` or `dark`. See
/// https://github.com/dandavison/delta#custom-color-themes. If diff output
/// is supplied on standard input then this will be used for the demo. For
/// example: `git show | delta --show-themes`. By default shows dark or
/// light themes only, according to whether delta is in dark or light mode
/// (as set by the user or inferred from BAT_THEME). To control the themes
/// shown, use --dark or --light, or both, on the command line together with
/// this option.
#[structopt(long = "show-themes")]
pub show_themes: bool,

#[structopt(long = "no-gitconfig")]
/// Do not take any settings from git config. See GIT CONFIG section.
pub no_gitconfig: bool,
Expand Down Expand Up @@ -635,7 +647,6 @@ impl Opt {
Self::from_clap_and_git_config(Self::clap().get_matches(), git_config, assets)
}

#[cfg(test)]
pub fn from_iter_and_git_config<I>(iter: I, git_config: &mut Option<GitConfig>) -> Self
where
I: IntoIterator,
Expand Down
33 changes: 28 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::cli;
use crate::color;
use crate::delta::State;
use crate::env;
use crate::features::navigate;
use crate::features::side_by_side;
use crate::git_config::GitConfigEntry;
use crate::style::{self, Style};
Expand Down Expand Up @@ -58,6 +59,7 @@ pub struct Config {
pub minus_non_emph_style: Style,
pub minus_style: Style,
pub navigate: bool,
pub navigate_regexp: Option<String>,
pub null_style: Style,
pub null_syntect_style: SyntectStyle,
pub paging_mode: PagingMode,
Expand All @@ -68,6 +70,7 @@ pub struct Config {
pub plus_style: Style,
pub git_minus_style: Style,
pub git_plus_style: Style,
pub show_themes: bool,
pub side_by_side: bool,
pub side_by_side_data: side_by_side::SideBySideData,
pub syntax_dummy_theme: SyntaxTheme,
Expand Down Expand Up @@ -154,6 +157,24 @@ impl From<cli::Opt> for Config {
_ => *style::GIT_DEFAULT_PLUS_STYLE,
};

let file_added_label = opt.file_added_label;
let file_copied_label = opt.file_copied_label;
let file_modified_label = opt.file_modified_label;
let file_removed_label = opt.file_removed_label;
let file_renamed_label = opt.file_renamed_label;

let navigate_regexp = if opt.navigate || opt.show_themes {
Some(navigate::make_navigate_regexp(
opt.show_themes,
&file_modified_label,
&file_added_label,
&file_removed_label,
&file_renamed_label,
))
} else {
None
};

Self {
available_terminal_width: opt.computed.available_terminal_width,
background_color_extends_to_terminal_width: opt
Expand All @@ -163,11 +184,11 @@ impl From<cli::Opt> for Config {
color_only: opt.color_only,
decorations_width: opt.computed.decorations_width,
error_exit_code: 2, // Use 2 for error because diff uses 0 and 1 for non-error.
file_added_label: opt.file_added_label,
file_copied_label: opt.file_copied_label,
file_modified_label: opt.file_modified_label,
file_removed_label: opt.file_removed_label,
file_renamed_label: opt.file_renamed_label,
file_added_label,
file_copied_label,
file_modified_label,
file_removed_label,
file_renamed_label,
file_style,
git_config_entries: opt.git_config_entries,
hunk_header_file_style,
Expand Down Expand Up @@ -203,6 +224,7 @@ impl From<cli::Opt> for Config {
minus_non_emph_style,
minus_style,
navigate: opt.navigate,
navigate_regexp,
null_style: Style::new(),
null_syntect_style: SyntectStyle::default(),
paging_mode: opt.computed.paging_mode,
Expand All @@ -213,6 +235,7 @@ impl From<cli::Opt> for Config {
plus_style,
git_minus_style,
git_plus_style,
show_themes: opt.show_themes,
side_by_side: opt.side_by_side,
side_by_side_data,
syntax_dummy_theme: SyntaxTheme::default(),
Expand Down
26 changes: 17 additions & 9 deletions src/features/navigate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
])
}

fn make_navigate_regexp(config: &Config) -> String {
format!(
"^(commit|{}|{}|{}|{})",
config.file_modified_label,
config.file_added_label,
config.file_removed_label,
config.file_renamed_label
)
// Construct the regexp used by less for paging, if --show-themes or --navigate is enabled.
pub fn make_navigate_regexp(
show_themes: bool,
file_modified_label: &str,
file_added_label: &str,
file_removed_label: &str,
file_renamed_label: &str,
) -> String {
if show_themes {
"^Theme:".to_string()
} else {
format!(
"^(commit|{}|{}|{}|{})",
file_modified_label, file_added_label, file_removed_label, file_renamed_label,
)
}
}

// Create a less history file to be used by delta's child less process. This file is initialized
Expand All @@ -57,7 +65,7 @@ pub fn copy_less_hist_file_and_append_navigate_regexp(config: &Config) -> std::i
std::fs::File::create(&delta_less_hist_file)?,
"{}\"{}",
contents,
make_navigate_regexp(config)
config.navigate_regexp.as_ref().unwrap(),
)?;
Ok(delta_less_hist_file)
}
Expand Down
2 changes: 1 addition & 1 deletion src/git_config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::process;
use lazy_static::lazy_static;

pub struct GitConfig {
config: git2::Config,
pub config: git2::Config,
config_from_env_var: HashMap<String, String>,
pub enabled: bool,
pub repo: Option<git2::Repository>,
Expand Down
60 changes: 60 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod options;
mod paint;
mod parse;
mod parse_style;
mod sample_diff;
mod style;
mod syntect_color;
mod tests;
Expand All @@ -38,6 +39,7 @@ use crate::bat_utils::assets::{list_languages, HighlightingAssets};
use crate::bat_utils::output::{OutputType, PagingMode};
use crate::config::delta_unreachable;
use crate::delta::delta;
use crate::options::get::get_themes;
use crate::options::theme::is_light_syntax_theme;

pub mod errors {
Expand Down Expand Up @@ -65,6 +67,9 @@ fn run_app() -> std::io::Result<i32> {
} else if opt.show_syntax_themes {
show_syntax_themes()?;
return Ok(0);
} else if opt.show_themes {
show_themes(opt.dark, opt.light, opt.computed.is_light_mode)?;
return Ok(0);
}

let _show_config = opt.show_config;
Expand Down Expand Up @@ -254,6 +259,7 @@ fn show_config(config: &config::Config, writer: &mut dyn Write) -> std::io::Resu
" max-line-distance = {max_line_distance}
max-line-length = {max_line_length}
navigate = {navigate}
navigate-regexp = {navigate_regexp}
paging = {paging_mode}
side-by-side = {side_by_side}
syntax-theme = {syntax_theme}
Expand All @@ -263,6 +269,10 @@ fn show_config(config: &config::Config, writer: &mut dyn Write) -> std::io::Resu
max_line_distance = config.max_line_distance,
max_line_length = config.max_line_length,
navigate = config.navigate,
navigate_regexp = match &config.navigate_regexp {
None => "".to_string(),
Some(s) => s.to_string(),
},
paging_mode = match config.paging_mode {
PagingMode::Always => "always",
PagingMode::Never => "never",
Expand Down Expand Up @@ -302,6 +312,56 @@ where
}
}

fn show_themes(dark: bool, light: bool, computed_theme_is_light: bool) -> std::io::Result<()> {
use bytelines::ByteLines;
use sample_diff::DIFF;
use std::io::BufReader;
let mut input = DIFF.to_vec();

if !atty::is(atty::Stream::Stdin) {
let mut buf = Vec::new();
io::stdin().lock().read_to_end(&mut buf)?;
if !buf.is_empty() {
input = buf;
}
};

let mut git_config = git_config::GitConfig::try_create();
let opt = cli::Opt::from_iter_and_git_config(
&["", "", "--navigate", "--show-themes"],
&mut git_config,
);
let mut output_type =
OutputType::from_mode(PagingMode::Always, None, &config::Config::from(opt)).unwrap();
let title_style = ansi_term::Style::new().bold();
let writer = output_type.handle().unwrap();

for theme in &get_themes(git_config::GitConfig::try_create()) {
let opt =
cli::Opt::from_iter_and_git_config(&["", "", "--features", &theme], &mut git_config);
let is_dark_theme = opt.dark;
let is_light_theme = opt.light;
let config = config::Config::from(opt);

if (!computed_theme_is_light && is_dark_theme)
|| (computed_theme_is_light && is_light_theme)
|| (dark && light)
{
writeln!(writer, "\n\nTheme: {}\n", title_style.paint(theme))?;

if let Err(error) = delta(ByteLines::new(BufReader::new(&input[0..])), writer, &config)
{
match error.kind() {
ErrorKind::BrokenPipe => process::exit(0),
_ => eprintln!("{}", error),
}
}
}
}

Ok(())
}

#[cfg(not(tarpaulin_include))]
fn show_syntax_themes() -> std::io::Result<()> {
let mut opt = cli::Opt::from_args();
Expand Down
61 changes: 61 additions & 0 deletions src/options/get.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::HashMap;

use crate::cli;
Expand Down Expand Up @@ -38,6 +40,27 @@ where
T::get_option_value(option_name, builtin_features, opt, git_config)
}

lazy_static! {
static ref GIT_CONFIG_THEME_REGEX: Regex = Regex::new(r"^delta\.(.+)\.(light|dark)$").unwrap();
}

pub fn get_themes(git_config: Option<git_config::GitConfig>) -> Vec<String> {
let mut themes: Vec<String> = Vec::new();
for e in &git_config.unwrap().config.entries(None).unwrap() {
let entry = e.unwrap();
let entry_name = entry.name().unwrap();
let caps = GIT_CONFIG_THEME_REGEX.captures(entry_name);
if let Some(caps) = caps {
let name = caps.get(1).map_or("", |m| m.as_str()).to_string();
if !themes.contains(&name) {
themes.push(name)
}
}
}
themes.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase()));
themes
}

pub trait GetOptionValue {
fn get_option_value(
option_name: &str,
Expand Down Expand Up @@ -115,6 +138,7 @@ pub mod tests {
use std::env;
use std::fs::remove_file;

use crate::options::get::get_themes;
use crate::tests::integration_test_utils::integration_test_utils;

// TODO: the followig tests are collapsed into one since they all set the same env var and thus
Expand Down Expand Up @@ -275,4 +299,41 @@ pub mod tests {

remove_file(git_config_path).unwrap();
}

#[test]
fn test_get_themes_from_config() {
let git_config_contents = r#"
[delta "dark-theme"]
max-line-distance = 0.6
dark = true
[delta "light-theme"]
max-line-distance = 0.6
light = true
[delta "light-and-dark-theme"]
max-line-distance = 0.6
light = true
dark = true
[delta "not-a-theme"]
max-line-distance = 0.6
"#;
let git_config_path = "delta__test_get_themes_git_config.gitconfig";

let git_config = Some(integration_test_utils::make_git_config(
git_config_contents.as_bytes(),
git_config_path,
false,
));

let themes = get_themes(git_config);

assert_eq!(
themes,
["dark-theme", "light-and-dark-theme", "light-theme",]
);

remove_file(git_config_path).unwrap();
}
}
1 change: 1 addition & 0 deletions src/options/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ pub fn set_options(
plus_empty_line_marker_style,
plus_non_emph_style,
raw,
show_themes,
side_by_side,
tab_width,
tokenization_regex,
Expand Down
2 changes: 1 addition & 1 deletion src/options/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn is_no_syntax_highlighting_syntax_theme_name(theme_name: &str) -> bool {
/// chosen for a light or dark terminal background. (`bat` has no equivalent.)
///
/// Basically:
/// 1. The theme is specified by the `--theme` option. If this isn't supplied then it is specified
/// 1. The theme is specified by the `--syntax-theme` option. If this isn't supplied then it is specified
/// by the `BAT_THEME` environment variable.
/// 2. Light vs dark mode is specified by the `--light` or `--dark` options. If these aren't
/// supplied then it is inferred from the chosen theme.
Expand Down
Loading

0 comments on commit 48fe43f

Please sign in to comment.