Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide an option to cycle through delta themes using --show-themes #550

Merged
merged 19 commits into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
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()) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's display them in alphabetical order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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