1
0
mirror of https://github.com/sharkdp/bat synced 2026-08-02 18:41:42 +00:00

Merge branch 'master' into fix_654_stdin_filename

This commit is contained in:
Kyle Criddle
2020-03-24 19:08:43 -06:00
118 changed files with 1836 additions and 1762 deletions
+38 -38
View File
@@ -17,13 +17,12 @@ use console::Term;
use ansi_term;
use bat::{
assets::BAT_THEME_DEFAULT,
config::{
Config, HighlightedLineRanges, InputFile, LineRange, LineRanges, MappingTarget, OutputWrap,
PagingMode, StyleComponent, StyleComponents, SyntaxMapping,
},
errors::*,
inputfile::InputFile,
line_range::{LineRange, LineRanges},
style::{OutputComponent, OutputComponents, OutputWrap},
syntax_mapping::SyntaxMapping,
Config, PagingMode,
HighlightingAssets,
};
fn is_truecolor_terminal() -> bool {
@@ -79,7 +78,7 @@ impl App {
pub fn config(&self) -> Result<Config> {
let files = self.files();
let output_components = self.output_components()?;
let style_components = self.style_components()?;
let paging_mode = match self.matches.value_of("paging") {
Some("always") => PagingMode::Always,
@@ -105,17 +104,17 @@ impl App {
}
};
let mut syntax_mapping = SyntaxMapping::new();
let mut syntax_mapping = SyntaxMapping::builtin();
if let Some(values) = self.matches.values_of("map-syntax") {
for from_to in values {
let parts: Vec<_> = from_to.split(':').collect();
if parts.len() != 2 {
return Err("Invalid syntax mapping. The format of the -m/--map-syntax option is 'from:to'.".into());
return Err("Invalid syntax mapping. The format of the -m/--map-syntax option is '<glob-pattern>:<syntax-name>'. For example: '*.cpp:C++'.".into());
}
syntax_mapping.insert(parts[0], parts[1]);
syntax_mapping.insert(parts[0], MappingTarget::MapTo(parts[1]))?;
}
}
@@ -158,7 +157,7 @@ impl App {
Some("character") => OutputWrap::Character,
Some("never") => OutputWrap::None,
Some("auto") | _ => {
if output_components.plain() {
if style_components.plain() {
OutputWrap::None
} else {
OutputWrap::Character
@@ -188,7 +187,7 @@ impl App {
.or_else(|| env::var("BAT_TABS").ok())
.and_then(|t| t.parse().ok())
.unwrap_or(
if output_components.plain() && paging_mode == PagingMode::Never {
if style_components.plain() && paging_mode == PagingMode::Never {
0
} else {
4
@@ -201,33 +200,34 @@ impl App {
.or_else(|| env::var("BAT_THEME").ok())
.map(|s| {
if s == "default" {
String::from(BAT_THEME_DEFAULT)
String::from(HighlightingAssets::default_theme())
} else {
s
}
})
.unwrap_or_else(|| String::from(BAT_THEME_DEFAULT)),
line_ranges: LineRanges::from(
self.matches
.values_of("line-range")
.map(|vs| vs.map(LineRange::from).collect())
.transpose()?
.unwrap_or_else(|| vec![]),
),
output_components,
.unwrap_or_else(|| String::from(HighlightingAssets::default_theme())),
line_ranges: self
.matches
.values_of("line-range")
.map(|vs| vs.map(LineRange::from).collect())
.transpose()?
.map(LineRanges::from)
.unwrap_or_default(),
style_components,
syntax_mapping,
pager: self.matches.value_of("pager"),
use_italic_text: match self.matches.value_of("italic-text") {
Some("always") => true,
_ => false,
},
highlight_lines: LineRanges::from(
self.matches
.values_of("highlight-line")
.map(|ws| ws.map(LineRange::from).collect())
.transpose()?
.unwrap_or_else(|| vec![LineRange { lower: 0, upper: 0 }]),
),
highlighted_lines: self
.matches
.values_of("highlight-line")
.map(|ws| ws.map(LineRange::from).collect())
.transpose()?
.map(LineRanges::from)
.map(|lr| HighlightedLineRanges(lr))
.unwrap_or_default(),
filenames: self
.matches
.values_of("file-name")
@@ -252,23 +252,23 @@ impl App {
.unwrap_or_else(|| vec![InputFile::StdIn])
}
fn output_components(&self) -> Result<OutputComponents> {
fn style_components(&self) -> Result<StyleComponents> {
let matches = &self.matches;
Ok(OutputComponents(
Ok(StyleComponents(
if matches.value_of("decorations") == Some("never") {
HashSet::new()
} else if matches.is_present("number") {
[OutputComponent::Numbers].iter().cloned().collect()
[StyleComponent::Numbers].iter().cloned().collect()
} else if matches.is_present("plain") {
[OutputComponent::Plain].iter().cloned().collect()
[StyleComponent::Plain].iter().cloned().collect()
} else {
let env_style_components: Option<Vec<OutputComponent>> = env::var("BAT_STYLE")
let env_style_components: Option<Vec<StyleComponent>> = env::var("BAT_STYLE")
.ok()
.map(|style_str| {
style_str
.split(',')
.map(|x| OutputComponent::from_str(&x))
.collect::<Result<Vec<OutputComponent>>>()
.map(|x| StyleComponent::from_str(&x))
.collect::<Result<Vec<StyleComponent>>>()
})
.transpose()?;
@@ -277,12 +277,12 @@ impl App {
.map(|styles| {
styles
.split(',')
.map(|style| style.parse::<OutputComponent>())
.map(|style| style.parse::<StyleComponent>())
.filter_map(|style| style.ok())
.collect::<Vec<_>>()
})
.or(env_style_components)
.unwrap_or_else(|| vec![OutputComponent::Full])
.unwrap_or_else(|| vec![StyleComponent::Full])
.into_iter()
.map(|style| style.components(self.interactive_output))
.fold(HashSet::new(), |mut acc, components| {
+38
View File
@@ -0,0 +1,38 @@
use std::borrow::Cow;
use std::fs;
use std::path::PathBuf;
use crate::directories::PROJECT_DIRS;
use bat::HighlightingAssets;
fn theme_set_path() -> PathBuf {
PROJECT_DIRS.cache_dir().join("themes.bin")
}
fn syntax_set_path() -> PathBuf {
PROJECT_DIRS.cache_dir().join("syntaxes.bin")
}
pub fn config_dir() -> Cow<'static, str> {
PROJECT_DIRS.config_dir().to_string_lossy()
}
pub fn cache_dir() -> Cow<'static, str> {
PROJECT_DIRS.cache_dir().to_string_lossy()
}
pub fn clear_assets() {
print!("Clearing theme set cache ... ");
fs::remove_file(theme_set_path()).ok();
println!("okay");
print!("Clearing syntax set cache ... ");
fs::remove_file(syntax_set_path()).ok();
println!("okay");
}
pub fn assets_from_cache_or_binary() -> HighlightingAssets {
HighlightingAssets::from_cache(&theme_set_path(), &syntax_set_path())
.unwrap_or(HighlightingAssets::from_binary())
}
+7 -7
View File
@@ -260,13 +260,13 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
.multiple(true)
.takes_value(true)
.number_of_values(1)
.value_name("from:to")
.help("Map a file extension or name to an existing syntax.")
.value_name("glob:syntax")
.help("Use the specified syntax for files matching the glob pattern ('*.cpp:C++').")
.long_help(
"Map a file extension or file name to an existing syntax (specified by a file \
extension or file name). For example, to highlight *.build files with the \
Python syntax, use '-m build:py'. To highlight files named '.myignore' with \
the Git Ignore syntax, use '-m .myignore:gitignore'.",
"Map a glob pattern to an existing syntax name. The glob pattern is matched \
on the full path and the filename. For example, to highlight *.build files \
with the Python syntax, use -m '*.build:Python'. To highlight files named \
'.myignore' with the Git Ignore syntax, use -m '.myignore:Git Ignore'.",
)
.takes_value(true),
)
@@ -293,7 +293,7 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
.arg(
Arg::with_name("style")
.long("style")
.value_name("style-components")
.value_name("components")
// Need to turn this off for overrides_with to work as we want. See the bottom most
// example at https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.overrides_with
.use_delimiter(false)
+1 -1
View File
@@ -5,7 +5,7 @@ use std::path::PathBuf;
use shell_words;
use bat::dirs::PROJECT_DIRS;
use crate::directories::PROJECT_DIRS;
pub fn config_file() -> PathBuf {
env::var("BAT_CONFIG_PATH")
+67
View File
@@ -0,0 +1,67 @@
use std::env;
use std::path::{Path, PathBuf};
use dirs;
use lazy_static::lazy_static;
/// Wrapper for 'dirs' that treats MacOS more like Linux, by following the XDG specification.
/// This means that the `XDG_CACHE_HOME` and `XDG_CONFIG_HOME` environment variables are
/// checked first. The fallback directories are `~/.cache/bat` and `~/.config/bat`, respectively.
pub struct BatProjectDirs {
cache_dir: PathBuf,
config_dir: PathBuf,
}
impl BatProjectDirs {
fn new() -> Option<BatProjectDirs> {
let cache_dir = BatProjectDirs::get_cache_dir()?;
#[cfg(target_os = "macos")]
let config_dir_op = env::var_os("XDG_CONFIG_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs::home_dir().map(|d| d.join(".config")));
#[cfg(not(target_os = "macos"))]
let config_dir_op = dirs::config_dir();
let config_dir = config_dir_op.map(|d| d.join("bat"))?;
Some(BatProjectDirs {
cache_dir,
config_dir,
})
}
pub fn get_cache_dir() -> Option<PathBuf> {
// on all OS prefer BAT_CACHE_PATH if set
let cache_dir_op = env::var_os("BAT_CACHE_PATH").map(PathBuf::from);
if cache_dir_op.is_some() {
return cache_dir_op;
}
#[cfg(target_os = "macos")]
let cache_dir_op = env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs::home_dir().map(|d| d.join(".cache")));
#[cfg(not(target_os = "macos"))]
let cache_dir_op = dirs::cache_dir();
cache_dir_op.map(|d| d.join("bat"))
}
pub fn cache_dir(&self) -> &Path {
&self.cache_dir
}
pub fn config_dir(&self) -> &Path {
&self.config_dir
}
}
lazy_static! {
pub static ref PROJECT_DIRS: BatProjectDirs =
BatProjectDirs::new().expect("Could not get home directory");
}
+27 -19
View File
@@ -4,9 +4,13 @@
#[macro_use]
extern crate clap;
extern crate dirs as dirs_rs;
mod app;
mod assets;
mod clap_app;
mod config;
mod directories;
use std::collections::HashSet;
use std::ffi::OsStr;
@@ -19,25 +23,31 @@ use ansi_term::Colour::Green;
use ansi_term::Style;
use crate::{app::App, config::config_file};
use bat::controller::Controller;
use assets::{assets_from_cache_or_binary, cache_dir, clear_assets, config_dir};
use bat::Controller;
use directories::PROJECT_DIRS;
use bat::{
assets::{cache_dir, clear_assets, config_dir, HighlightingAssets},
config::{Config, InputFile, StyleComponent, StyleComponents},
errors::*,
inputfile::InputFile,
style::{OutputComponent, OutputComponents},
Config,
HighlightingAssets,
};
fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
if matches.is_present("build") {
let source_dir = matches.value_of("source").map(Path::new);
let target_dir = matches.value_of("target").map(Path::new);
let source_dir = matches
.value_of("source")
.map(Path::new)
.unwrap_or_else(|| PROJECT_DIRS.config_dir());
let target_dir = matches
.value_of("target")
.map(Path::new)
.unwrap_or_else(|| PROJECT_DIRS.cache_dir());
let blank = matches.is_present("blank");
let assets = HighlightingAssets::from_files(source_dir, blank)?;
assets.save(target_dir)?;
let assets = HighlightingAssets::from_files(source_dir, !blank)?;
assets.save_to_cache(target_dir)?;
} else if matches.is_present("clear") {
clear_assets();
}
@@ -46,9 +56,8 @@ fn run_cache_subcommand(matches: &clap::ArgMatches) -> Result<()> {
}
pub fn list_languages(config: &Config) -> Result<()> {
let assets = HighlightingAssets::new();
let assets = assets_from_cache_or_binary();
let mut languages = assets
.syntax_set
.syntaxes()
.iter()
.filter(|syntax| !syntax.hidden && !syntax.file_extensions.is_empty())
@@ -109,19 +118,18 @@ pub fn list_languages(config: &Config) -> Result<()> {
}
pub fn list_themes(cfg: &Config) -> Result<()> {
let assets = HighlightingAssets::new();
let themes = &assets.theme_set.themes;
let assets = assets_from_cache_or_binary();
let mut config = cfg.clone();
let mut style = HashSet::new();
style.insert(OutputComponent::Plain);
style.insert(StyleComponent::Plain);
config.files = vec![InputFile::ThemePreviewFile];
config.output_components = OutputComponents(style);
config.style_components = StyleComponents(style);
let stdout = io::stdout();
let mut stdout = stdout.lock();
if config.colored_output {
for (theme, _) in themes.iter() {
for theme in assets.themes() {
writeln!(
stdout,
"Theme: {}\n",
@@ -132,7 +140,7 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
writeln!(stdout)?;
}
} else {
for (theme, _) in themes.iter() {
for theme in assets.themes() {
writeln!(stdout, "{}", theme)?;
}
}
@@ -141,7 +149,7 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
}
fn run_controller(config: &Config) -> Result<bool> {
let assets = HighlightingAssets::new();
let assets = assets_from_cache_or_binary();
let controller = Controller::new(&config, &assets);
controller.run()
}
@@ -199,7 +207,7 @@ fn main() {
match result {
Err(error) => {
handle_error(&error);
default_error_handler(&error);
process::exit(1);
}
Ok(false) => {