diff options
author | Dan Davison <dandavison7@gmail.com> | 2021-03-29 06:34:25 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-29 06:34:25 -0500 |
commit | 48fe43fff329e14a74cb1876d040a0de3b29fe8c (patch) | |
tree | fa258d590cf43352a3be0b053f50f5cc0ddceac6 | |
parent | 1f4691f208f4ccbf0c40b6b065b21fb65dbec0ab (diff) | |
parent | 926e3c5e34b926afbea5d30cc6563210edb25486 (diff) |
Merge pull request #550 from clnoll/show-delta-themes
-rw-r--r-- | src/bat_utils/output.rs | 3 | ||||
-rw-r--r-- | src/cli.rs | 17 | ||||
-rw-r--r-- | src/config.rs | 33 | ||||
-rw-r--r-- | src/features/navigate.rs | 26 | ||||
-rw-r--r-- | src/git_config/mod.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 60 | ||||
-rw-r--r-- | src/options/get.rs | 61 | ||||
-rw-r--r-- | src/options/set.rs | 1 | ||||
-rw-r--r-- | src/options/theme.rs | 2 | ||||
-rw-r--r-- | src/sample_diff.rs | 93 | ||||
-rw-r--r-- | src/tests/integration_test_utils.rs | 2 | ||||
-rw-r--r-- | themes.gitconfig | 8 |
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 @@ -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 |