summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2021-03-29 06:34:25 -0500
committerGitHub <noreply@github.com>2021-03-29 06:34:25 -0500
commit48fe43fff329e14a74cb1876d040a0de3b29fe8c (patch)
treefa258d590cf43352a3be0b053f50f5cc0ddceac6
parent1f4691f208f4ccbf0c40b6b065b21fb65dbec0ab (diff)
parent926e3c5e34b926afbea5d30cc6563210edb25486 (diff)
Merge pull request #550 from clnoll/show-delta-themes
-rw-r--r--src/bat_utils/output.rs3
-rw-r--r--src/cli.rs17
-rw-r--r--src/config.rs33
-rw-r--r--src/features/navigate.rs26
-rw-r--r--src/git_config/mod.rs2
-rw-r--r--src/main.rs60
-rw-r--r--src/options/get.rs61
-rw-r--r--src/options/set.rs1
-rw-r--r--src/options/theme.rs2
-rw-r--r--src/sample_diff.rs93
-rw-r--r--src/tests/integration_test_utils.rs2
-rw-r--r--themes.gitconfig8
12 files changed, 286 insertions, 22 deletions
diff --git a/src/bat_utils/output.rs b/src/bat_utils/output.rs
index 26cd4e21..388bc0c9 100644
--- a/src/bat_utils/output.rs
+++ b/src/bat_utils/output.rs
@@ -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
diff --git a/src/cli.rs b/src/cli.rs
index 41f6eb89..2ee73240 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,5 +1,4 @@
use std::collections::{HashMap, HashSet};
-#[cfg(test)]
use std::ffi::OsString;
use std::path::PathBuf;
@@ -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,
@@ -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,
diff --git a/src/config.rs b/src/config.rs
index 23b7b97d..f822efc2 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -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};
@@ -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,
@@ -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,
@@ -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
@@ -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,
@@ -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,
@@ -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(),
diff --git a/src/features/navigate.rs b/src/features/navigate.rs
index a38815a6..0020d54b 100644
--- a/src/features/navigate.rs
+++ b/src/features/navigate.rs
@@ -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
@@ -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)
}
diff --git a/src/git_config/mod.rs b/src/git_config/mod.rs
index 827446e1..13b494b9 100644
--- a/src/git_config/mod.rs
+++ b/src/git_config/mod.rs
@@ -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>,
diff --git a/src/main.rs b/src/main.rs
index 5757fbab..c99fb464 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,6 +22,7 @@ mod options;
mod paint;
mod parse;
mod parse_style;
+mod sample_diff;
mod style;
mod syntect_color;
mod tests;
@@ -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 {
@@ -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;
@@ -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}
@@ -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",
@@ -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();
diff --git a/src/options/get.rs b/src/options/get.rs
index a36987ca..b907ee88 100644
--- a/src/options/get.rs
+++ b/src/options/get.rs
@@ -1,3 +1,5 @@
+use lazy_static::lazy_static;
+use regex::Regex;
use std::collections::HashMap;
use crate::cli;
@@ -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,
@@ -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
@@ -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();
+ }
}
diff --git a/src/options/set.rs b/src/options/set.rs
index 354eeea6..e5c1edf0 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -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,
diff --git a/src/options/theme.rs b/src/options/theme.rs
index ae831202..420c5be5 100644
--- a/src/options/theme.rs
+++ b/src/options/theme.rs
@@ -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.
diff --git a/src/sample_diff.rs b/src/sample_diff.rs
new file mode 100644
index 00000000..90de4262
--- /dev/null
+++ b/src/sample_diff.rs
@@ -0,0 +1,93 @@
+pub const DIFF: &[u8] = r#"
+commit 7ec4627902020cccd7b3f4fbc63e1b0d6b9798cd
+Author: Evan You <yyx990803@gmail.com>
+Date: Thu Feb 21 08:52:15 2019 -0500
+
+ fix: ensure generated scoped slot code is compatible with 2.5
+
+ fix #9545
+
+diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js
+index a64c3421..d433f756 100644
+--- a/src/compiler/codegen/index.js
++++ b/src/compiler/codegen/index.js
+@@ -409,9 +409,9 @@ function genScopedSlots (
+ .join(',')
+
+ return `scopedSlots:_u([${generatedSlots}]${
+- needsForceUpdate ? `,true` : ``
++ needsForceUpdate ? `,null,true` : ``
+ }${
+- !needsForceUpdate && needsKey ? `,false,${hash(generatedSlots)}` : ``
++ !needsForceUpdate && needsKey ? `,null,false,${hash(generatedSlots)}` : ``
+ })`
+ }
+
+diff --git a/src/core/instance/render-helpers/resolve-scoped-slots.js b/src/core/instance/render-helpers/resolve-scoped-slots.js
+index 6439324b..f11ca000 100644
+--- a/src/core/instance/render-helpers/resolve-scoped-slots.js
++++ b/src/core/instance/render-helpers/resolve-scoped-slots.js
+@@ -2,15 +2,16 @@
+
+ export function resolveScopedSlots (
+ fns: ScopedSlotsData, // see flow/vnode
+- hasDynamicKeys: boolean,
+- contentHashKey: number,
+- res?: Object
++ res?: Object,
++ // the following are added in 2.6
++ hasDynamicKeys?: boolean,
++ contentHashKey?: number
+ ): { [key: string]: Function, $stable: boolean } {
+ res = res || { $stable: !hasDynamicKeys }
+ for (let i = 0; i < fns.length; i++) {
+ const slot = fns[i]
+ if (Array.isArray(slot)) {
+- resolveScopedSlots(slot, hasDynamicKeys, null, res)
++ resolveScopedSlots(slot, res, hasDynamicKeys)
+ } else if (slot) {
+ // marker for reverse proxying v-slot without scope on this.$slots
+ if (slot.proxy) {
+@@ -20,7 +21,7 @@ export function resolveScopedSlots (
+ }
+ }
+ if (contentHashKey) {
+- res.$key = contentHashKey
++ (res: any).$key = contentHashKey
+ }
+ return res
+ }
+diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js
+index 98c202dd..e56b2576 100644
+--- a/test/unit/modules/compiler/codegen.spec.js
++++ b/test/unit/modules/compiler/codegen.spec.js
+@@ -232,25 +232,25 @@ describe('codegen', () => {
+ it('generate dynamic scoped slot', () => {
+ assertCodegen(
+ '<foo><template :slot="foo" slot-scope="bar">{{ bar }}</template></foo>',
+- `with(this){return _c('foo',{scopedSlots:_u([{key:foo,fn:function(bar){return [_v(_s(bar))]}}],true)})}`
++ `with(this){return _c('foo',{scopedSlots:_u([{key:foo,fn:function(bar){return [_v(_s(bar))]}}],null,true)})}`
+ )
+ })
+
+ it('generate scoped slot with multiline v-if', () => {
+ assertCodegen(
+ '<foo><template v-if="\nshow\n" slot-scope="bar">{{ bar }}</template></foo>',
+- `with(this){return _c('foo',{scopedSlots:_u([{key:"default",fn:function(bar){return (\nshow\n)?[_v(_s(bar))]:undefined}}],true)})}`
++ `with(this){return _c('foo',{scopedSlots:_u([{key:"default",fn:function(bar){return (\nshow\n)?[_v(_s(bar))]:undefined}}],null,true)})}`
+ )
+ assertCodegen(
+ '<foo><div v-if="\nshow\n" slot="foo" slot-scope="bar">{{ bar }}</div></foo>',
+- `with(this){return _c(\'foo\',{scopedSlots:_u([{key:"foo",fn:function(bar){return (\nshow\n)?_c(\'div\',{},[_v(_s(bar))]):_e()}}],true)})}`
++ `with(this){return _c(\'foo\',{scopedSlots:_u([{key:"foo",fn:function(bar){return (\nshow\n)?_c(\'div\',{},[_v(_s(bar))]):_e()}}],null,true)})}`
+ )
+ })
+
+ it('generate scoped slot with new slot syntax', () => {
+ assertCodegen(
+ '<foo><template v-if="show" #default="bar">{{ bar }}</template></foo>',
+- `with(this){return _c('foo',{scopedSlots:_u([(show)?{key:"default",fn:function(bar){return [_v(_s(bar))]}}:null],true)})}`
++ `with(this){return _c('foo',{scopedSlots:_u([(show)?{key:"default",fn:function(bar){return [_v(_s(bar))]}}:null],null,true)})}`
+ )
+ })
+ "#.as_bytes();
diff --git a/src/tests/integration_test_utils.rs b/src/tests/integration_test_utils.rs
index 8eb36748..1fdb215a 100644
--- a/src/tests/integration_test_utils.rs
+++ b/src/tests/integration_test_utils.rs
@@ -69,7 +69,7 @@ pub mod integration_test_utils {
config::Config::from(make_options_from_args(args))
}
- fn make_git_config(contents: &[u8], path: &str, honor_env_var: bool) -> GitConfig {
+ pub fn make_git_config(contents: &[u8], path: &str, honor_env_var: bool) -> GitConfig {
let path = Path::new(path);
let mut file = File::create(path).unwrap();
file.write_all(contents).unwrap();
diff --git a/themes.gitconfig b/themes.gitconfig
index 6818a240..db564e57 100644
--- a/themes.gitconfig
+++ b/themes.gitconfig
@@ -14,8 +14,9 @@
# organism: mammal, bird, plant, mollusk -- whatever. It can be in
# any language.
#
-# 2. Please include a comment line describing the terminal
-# theme/colors that you typically use with this theme.
+# 2. Include either `dark = true` or `light = true` according to whether you feel
+# it looks best on a dark or light terminal background. (This marks a feature
+# as a "theme", causing it to be picked up by `delta --show-themes`).
#
# 3. Feel free to include a comment line indicating who is the author
# of the theme. E.g. a link to your github user page.
@@ -52,6 +53,7 @@
[delta "villsau"]
# author: https://github.com/torarnv
+ dark = true
syntax-theme = OneHalfDark
line-numbers = false
hunk-header-style = file line-number syntax
@@ -73,6 +75,7 @@
[delta "collared-trogon"]
# author: https://github.com/clnoll
commit-decoration-style = bold box ul
+ dark = true
file-style = omit
file-decoration-style = none
hunk-header-style = file line-number syntax
@@ -94,6 +97,7 @@
[delta "tangara-chilensis"]
# author: https://github.com/clnoll
commit-decoration-style = bold box ul "#34fd50"
+ dark = true
file-style = omit
file-decoration-style = none
hunk-header-style = file line-number syntax