diff options
Diffstat (limited to 'src/bat_utils/config.rs')
-rw-r--r-- | src/bat_utils/config.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/bat_utils/config.rs b/src/bat_utils/config.rs new file mode 100644 index 00000000..fa19b8d3 --- /dev/null +++ b/src/bat_utils/config.rs @@ -0,0 +1,188 @@ +// Based on code from https://github.com/sharkdp/bat v0.17.1 (6d981498d80aa0127df9547ec0ac69d8314b29e5) +// See src/bat_utils/LICENSE + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io::{self, Write}; +use std::path::PathBuf; + +use crate::directories::PROJECT_DIRS; + +pub fn make_syntax_mapping() { + // From bat/src/bin/bat/app.rs + 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 '<glob-pattern>:<syntax-name>'. For example: '*.cpp:C++'.".into()); + } + + syntax_mapping.insert(parts[0], MappingTarget::MapTo(parts[1]))?; + } + } +} + +pub fn config_file() -> PathBuf { + env::var("BAT_CONFIG_PATH") + .ok() + .map(PathBuf::from) + .filter(|config_path| config_path.is_file()) + .unwrap_or_else(|| PROJECT_DIRS.config_dir().join("config")) +} + +pub fn generate_config_file() -> bat::error::Result<()> { + let config_file = config_file(); + if config_file.exists() { + println!( + "A config file already exists at: {}", + config_file.to_string_lossy() + ); + + print!("Overwrite? (y/N): "); + io::stdout().flush()?; + let mut decision = String::new(); + io::stdin().read_line(&mut decision)?; + + if !decision.trim().eq_ignore_ascii_case("Y") { + return Ok(()); + } + } else { + let config_dir = config_file.parent(); + match config_dir { + Some(path) => fs::create_dir_all(path)?, + None => { + return Err(format!( + "Unable to write config file to: {}", + config_file.to_string_lossy() + ) + .into()); + } + } + } + + let default_config = r#"# This is `bat`s configuration file. Each line either contains a comment or +# a command-line option that you want to pass to `bat` by default. You can +# run `bat --help` to get a list of all possible configuration options. + +# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes` +# for a list of all available themes +#--theme="TwoDark" + +# Enable this to use italic text on the terminal. This is not supported on all +# terminal emulators (like tmux, by default): +#--italic-text=always + +# Uncomment the following line to disable automatic paging: +#--paging=never + +# Uncomment the following line if you are using less version >= 551 and want to +# enable mouse scrolling support in `bat` when running inside tmux. This might +# disable text selection, unless you press shift. +#--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse" + +# Syntax mappings: map a certain filename pattern to a language. +# Example 1: use the C++ syntax for .ino files +# Example 2: Use ".gitignore"-style highlighting for ".ignore" files +#--map-syntax "*.ino:C++" +#--map-syntax ".ignore:Git Ignore" +"#; + + fs::write(&config_file, default_config)?; + println!( + "Success! Config file written to {}", + config_file.to_string_lossy() + ); + + Ok(()) +} + +pub fn get_args_from_config_file() -> Result<Vec<OsString>, shell_words::ParseError> { + Ok(fs::read_to_string(config_file()) + .ok() + .map(|content| get_args_from_str(&content)) + .transpose()? + .unwrap_or_else(Vec::new)) +} + +pub fn get_args_from_env_var() -> Option<Result<Vec<OsString>, shell_words::ParseError>> { + env::var("BAT_OPTS").ok().map(|s| get_args_from_str(&s)) +} + +fn get_args_from_str(content: &str) -> Result<Vec<OsString>, shell_words::ParseError> { + let args_per_line = content + .split('\n') + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + .filter(|line| !line.starts_with('#')) + .map(|line| shell_words::split(line)) + .collect::<Result<Vec<_>, _>>()?; + + Ok(args_per_line + .iter() + .flatten() + .map(|line| line.into()) + .collect()) +} + +#[test] +fn empty() { + let args = get_args_from_str("").unwrap(); + assert!(args.is_empty()); +} + +#[test] +fn single() { + assert_eq!(vec!["--plain"], get_args_from_str("--plain").unwrap()); +} + +#[test] +fn multiple() { + assert_eq!( + vec!["--plain", "--language=cpp"], + get_args_from_str("--plain --language=cpp").unwrap() + ); +} + +#[test] +fn quotes() { + assert_eq!( + vec!["--theme", "Sublime Snazzy"], + get_args_from_str("--theme \"Sublime Snazzy\"").unwrap() + ); +} + +#[test] +fn multi_line() { + let config = " + -p + --style numbers,changes + + --color=always + "; + assert_eq!( + vec!["-p", "--style", "numbers,changes", "--color=always"], + get_args_from_str(config).unwrap() + ); +} + +#[test] +fn comments() { + let config = " + # plain style + -p + + # show line numbers and Git modifications + --style numbers,changes + + # Always show ANSI colors + --color=always + "; + assert_eq!( + vec!["-p", "--style", "numbers,changes", "--color=always"], + get_args_from_str(config).unwrap() + ); +} |