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:
+38
-38
@@ -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| {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user