Skip to content

Commit

Permalink
Merge pull request #49 from dandavison/2-honor-theme-env-vars
Browse files Browse the repository at this point in the history
Honor BAT_THEME env var, refactor theme selection
  • Loading branch information
dandavison committed Nov 2, 2019
2 parents 4b7bbdd + ce5c4d8 commit 0052bd7
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 72 deletions.
43 changes: 28 additions & 15 deletions README.md
Expand Up @@ -111,20 +111,25 @@ USAGE:
delta [FLAGS] [OPTIONS]
FLAGS:
--compare-themes Compare available syntax highlighting themes. To use this option, supply git diff output
to delta on standard input. For example: `git show --color=always | delta --compare-
themes`.
--dark Use colors appropriate for a dark terminal background. For more control, see --theme,
--plus-color, and --minus-color.
-h, --help Prints help information
--highlight-removed Apply syntax highlighting to removed lines. The default is to apply syntax highlighting
to unchanged and new lines only.
--light Use colors appropriate for a light terminal background. For more control, see --theme,
--plus-color, and --minus-color.
--list-languages List supported languages and associated file extensions.
--list-themes List available syntax highlighting themes.
--show-colors Show the command-line arguments for the current colors.
-V, --version Prints version information
--compare-themes Compare available syntax highlighting themes. To use this option, supply git diff
output to delta on standard input. For example: `git show --color=always | delta
--compare-themes`.
--dark Use colors appropriate for a dark terminal background. For more control, see
--theme, --plus-color, and --minus-color.
-h, --help Prints help information
--highlight-removed Apply syntax highlighting to removed lines. The default is to apply syntax
highlighting to unchanged and new lines only.
--light Use colors appropriate for a light terminal background. For more control, see
--theme, --plus-color, and --minus-color.
--list-languages List supported languages and associated file extensions.
--list-themes List available syntax highlighting themes.
--show-background-colors Show the command-line arguments (RGB hex codes) for the background colors that are
in effect. The hex codes are displayed with their associated background color. This
option can be combined with --light and --dark to view the background colors for
those modes. It can also be used to experiment with different RGB hex codes by
combining this option with --minus-color, --minus-emph-color, --plus-color, --plus-
emph-color.
-V, --version Prints version information
OPTIONS:
--commit-style <commit_style>
Expand All @@ -148,7 +153,15 @@ OPTIONS:
--plus-emph-color <plus_emph_color>
The background color (RGB hex) to use for emphasized sections of added lines.
--theme <theme> The syntax highlighting theme to use.
--tabs <tab_width>
The number of spaces to replace tab characters with. Use --tabs=0 to pass tab characters through directly,
but note that in that case delta will calculate line widths assuming tabs occupy one character's width on
the screen: if your terminal renders tabs as more than than one character wide then delta's output will look
incorrect. [default: 4]
--theme <theme>
The syntax highlighting theme to use. Use --theme=none to disable syntax highlighting. If the theme is not
set using this option, it will be taken from the BAT_THEME environment variable, if that contains a valid
theme name. Use --list-themes and --compare-themes to view available themes. [env: BAT_THEME=]
-w, --width <width>
The width (in characters) of the background color highlighting. By default, the width is the current
terminal width. Use --width=variable to apply background colors to the end of each line, without right
Expand Down
14 changes: 3 additions & 11 deletions src/bat/output.rs
@@ -1,14 +1,15 @@
// https://github.com/sharkdp/bat a1b9334a44a2c652f52dddaa83dbacba57372468
// src/output.rs
// See src/bat/LICENSE
use std::env;
use std::ffi::OsString;
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};

use shell_words;

use crate::env;

#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(dead_code)]
pub enum PagingMode {
Expand All @@ -23,15 +24,6 @@ pub enum OutputType {
Stdout(io::Stdout),
}

/// If key is set and, after trimming whitespace, is not empty string, then return that trimmed
/// string. Else None.
pub fn get_env_var(key: &str) -> Option<String> {
match env::var(key).unwrap_or("".to_string()).trim() {
"" => None,
non_empty_string => Some(non_empty_string.to_string()),
}
}

impl OutputType {
pub fn from_mode(mode: PagingMode, pager: Option<&str>) -> Result<Self> {
use self::PagingMode::*;
Expand All @@ -46,7 +38,7 @@ impl OutputType {
fn try_pager(quit_if_one_screen: bool, pager_from_config: Option<&str>) -> Result<Self> {
let mut replace_arguments_to_less = false;

let pager_from_env = match (get_env_var("BAT_PAGER"), get_env_var("PAGER")) {
let pager_from_env = match (env::get_env_var("BAT_PAGER"), env::get_env_var("PAGER")) {
(Some(bat_pager), _) => Some(bat_pager),
(_, Some(pager)) => {
// less needs to be called with the '-R' option in order to properly interpret the
Expand Down
12 changes: 7 additions & 5 deletions src/cli.rs
Expand Up @@ -9,7 +9,7 @@ use crate::bat::assets::HighlightingAssets;
use crate::config;
use crate::style;

#[derive(StructOpt, Debug)]
#[derive(StructOpt, Clone, Debug)]
#[structopt(name = "delta", about = "A syntax-highlighting pager for git")]
pub struct Opt {
/// Use colors appropriate for a light terminal background. For
Expand Down Expand Up @@ -38,8 +38,10 @@ pub struct Opt {
/// The background color (RGB hex) to use for emphasized sections of added lines.
pub plus_emph_color: Option<String>,

#[structopt(long = "theme")]
#[structopt(long = "theme", env = "BAT_THEME")]
/// The syntax highlighting theme to use. Use --theme=none to disable syntax highlighting.
/// If the theme is not set using this option, it will be taken from the BAT_THEME environment variable,
/// if that contains a valid theme name. Use --list-themes and --compare-themes to view available themes.
pub theme: Option<String>,

#[structopt(long = "highlight-removed")]
Expand Down Expand Up @@ -105,7 +107,7 @@ pub struct Opt {
pub max_line_distance: f64,
}

#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum SectionStyle {
Box,
Plain,
Expand Down Expand Up @@ -146,12 +148,12 @@ pub fn process_command_line_arguments<'a>(
process::exit(1);
}
match &opt.theme {
Some(theme) if theme.to_lowercase() != "none" => {
Some(theme) if !style::is_no_syntax_highlighting_theme_name(&theme) => {
if !assets.theme_set.themes.contains_key(theme.as_str()) {
eprintln!("Invalid theme: '{}'", theme);
process::exit(1);
}
let is_light_theme = style::LIGHT_THEMES.contains(&theme.as_str());
let is_light_theme = style::is_light_theme(&theme);
if is_light_theme && opt.dark {
eprintln!(
"{} is a light theme, but you supplied --dark. \
Expand Down
110 changes: 79 additions & 31 deletions src/config.rs
Expand Up @@ -4,11 +4,12 @@ use syntect::highlighting::{Color, Style, StyleModifier, Theme, ThemeSet};
use syntect::parsing::SyntaxSet;

use crate::cli;
use crate::env;
use crate::style;

pub struct Config<'a> {
pub theme: Option<&'a Theme>,
pub theme_name: &'a str,
pub theme_name: String,
pub minus_style_modifier: StyleModifier,
pub minus_emph_style_modifier: StyleModifier,
pub plus_style_modifier: StyleModifier,
Expand All @@ -29,31 +30,24 @@ pub fn get_config<'a>(
terminal_width: usize,
width: Option<usize>,
) -> Config<'a> {
let theme_name = match opt.theme {
Some(ref theme) => theme,
None => {
if opt.light {
style::DEFAULT_LIGHT_THEME
} else {
style::DEFAULT_DARK_THEME
}
}
};
let theme = if theme_name.to_lowercase() == "none" {
let theme_name_from_bat_pager = env::get_env_var("BAT_THEME");
let (is_light_mode, theme_name) = get_is_light_mode_and_theme_name(
opt.theme.as_ref(),
theme_name_from_bat_pager.as_ref(),
opt.light,
theme_set,
);

let theme = if style::is_no_syntax_highlighting_theme_name(&theme_name) {
None
} else {
Some(&theme_set.themes[theme_name])
};
let is_light_theme = if theme.is_none() {
!opt.dark
} else {
style::LIGHT_THEMES.contains(&theme_name)
Some(&theme_set.themes[&theme_name])
};

let minus_style_modifier = StyleModifier {
background: Some(color_from_arg(
&opt.minus_color,
is_light_theme,
opt.minus_color.as_ref(),
is_light_mode,
style::LIGHT_THEME_MINUS_COLOR,
style::DARK_THEME_MINUS_COLOR,
)),
Expand All @@ -67,8 +61,8 @@ pub fn get_config<'a>(

let minus_emph_style_modifier = StyleModifier {
background: Some(color_from_arg(
&opt.minus_emph_color,
is_light_theme,
opt.minus_emph_color.as_ref(),
is_light_mode,
style::LIGHT_THEME_MINUS_EMPH_COLOR,
style::DARK_THEME_MINUS_EMPH_COLOR,
)),
Expand All @@ -82,8 +76,8 @@ pub fn get_config<'a>(

let plus_style_modifier = StyleModifier {
background: Some(color_from_arg(
&opt.plus_color,
is_light_theme,
opt.plus_color.as_ref(),
is_light_mode,
style::LIGHT_THEME_PLUS_COLOR,
style::DARK_THEME_PLUS_COLOR,
)),
Expand All @@ -93,8 +87,8 @@ pub fn get_config<'a>(

let plus_emph_style_modifier = StyleModifier {
background: Some(color_from_arg(
&opt.plus_emph_color,
is_light_theme,
opt.plus_emph_color.as_ref(),
is_light_mode,
style::LIGHT_THEME_PLUS_EMPH_COLOR,
style::DARK_THEME_PLUS_EMPH_COLOR,
)),
Expand All @@ -119,16 +113,70 @@ pub fn get_config<'a>(
}
}

/// Return a (theme_name, is_light_mode) tuple.
/// theme_name == None in return value means syntax highlighting is disabled.
///
/// There are two types of color choices that have to be made:
/// 1. The choice of "theme". This is the language syntax highlighting theme; you have to make this choice when using `bat` also.
/// 2. The choice of "light vs dark mode". This determines whether the background colors should be 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 by the `BAT_PAGER` 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.
///
/// In the absence of other factors, the default assumes a dark terminal background.
///
/// Specifically, the rules are as follows:
///
/// | --theme | $BAT_THEME | --light/--dark | Behavior |
/// |------------|------------|----------------|----------------------------------------------------------------------------|
/// | - | - | - | default dark theme, dark mode |
/// | some_theme | (IGNORED) | - | some_theme with light/dark mode inferred accordingly |
/// | - | BAT_THEME | - | BAT_THEME, with light/dark mode inferred accordingly |
/// | - | - | yes | default light/dark theme, light/dark mode |
/// | some_theme | (IGNORED) | yes | some_theme, light/dark mode (even if some_theme conflicts with light/dark) |
/// | - | BAT_THEME | yes | BAT_THEME, light/dark mode (even if BAT_THEME conflicts with light/dark) |
fn get_is_light_mode_and_theme_name(
theme_arg: Option<&String>,
bat_theme_env_var: Option<&String>,
light_mode_arg: bool,
theme_set: &ThemeSet,
) -> (bool, String) {
let theme_arg = valid_theme_name_or_none(theme_arg, theme_set);
let bat_theme_env_var = valid_theme_name_or_none(bat_theme_env_var, theme_set);
match (theme_arg, bat_theme_env_var, light_mode_arg) {
(None, None, false) => (false, style::DEFAULT_DARK_THEME.to_string()),
(Some(theme_name), _, false) => (style::is_light_theme(&theme_name), theme_name),
(None, Some(theme_name), false) => (style::is_light_theme(&theme_name), theme_name),
(None, None, true) => (true, style::DEFAULT_LIGHT_THEME.to_string()),
(Some(theme_name), _, is_light_mode) => (is_light_mode, theme_name),
(None, Some(theme_name), is_light_mode) => (is_light_mode, theme_name),
}
}

// At this stage the theme name is considered valid if it is either a real theme name or the special
// no-syntax-highlighting name.
fn valid_theme_name_or_none(theme_name: Option<&String>, theme_set: &ThemeSet) -> Option<String> {
match theme_name {
Some(name)
if style::is_no_syntax_highlighting_theme_name(name)
|| theme_set.themes.contains_key(name) =>
{
Some(name.to_string())
}
_ => None,
}
}

fn color_from_arg(
arg: &Option<String>,
is_light_theme: bool,
arg: Option<&String>,
is_light_mode: bool,
light_theme_default: Color,
dark_theme_default: Color,
) -> Color {
arg.as_ref()
.and_then(|s| Color::from_str(s).ok())
arg.and_then(|s| Color::from_str(s).ok())
.unwrap_or_else(|| {
if is_light_theme {
if is_light_mode {
light_theme_default
} else {
dark_theme_default
Expand Down

0 comments on commit 0052bd7

Please sign in to comment.