diff options
author | Dan Davison <dandavison7@gmail.com> | 2019-07-04 18:43:10 -0400 |
---|---|---|
committer | Dan Davison <dandavison7@gmail.com> | 2019-07-08 23:51:09 -0400 |
commit | cc8e8adf297a2042fe6409d77ff97a41e8747b34 (patch) | |
tree | eb99ba632588f8560892972e76237bd8f8398e16 /src/bat | |
parent | bfe5b728b51e36e4e37c7cb5c09b1fcf92b24448 (diff) |
Create bat directory for bat-derived code
Diffstat (limited to 'src/bat')
-rw-r--r-- | src/bat/assets.rs | 116 | ||||
-rw-r--r-- | src/bat/mod.rs | 2 | ||||
-rw-r--r-- | src/bat/output.rs | 143 |
3 files changed, 261 insertions, 0 deletions
diff --git a/src/bat/assets.rs b/src/bat/assets.rs new file mode 100644 index 00000000..981ec13b --- /dev/null +++ b/src/bat/assets.rs @@ -0,0 +1,116 @@ +// Based on code from https://github.com/sharkdp/bat a1b9334a44a2c652f52dddaa83dbacba57372468 +// +// Copyright (c) 2018 bat-developers (https://github.com/sharkdp/bat). + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +use std::io::{self, Write}; + +use ansi_term::Colour::Green; +use ansi_term::Style; +use syntect::dumps::from_binary; +use syntect::highlighting::ThemeSet; +use syntect::parsing::SyntaxSet; + +pub struct HighlightingAssets { + pub syntax_set: SyntaxSet, + pub theme_set: ThemeSet, +} + +impl HighlightingAssets { + pub fn new() -> Self { + Self::from_binary() + } + + fn get_integrated_syntaxset() -> SyntaxSet { + from_binary(include_bytes!("../../assets/syntaxes.bin")) + } + + fn get_integrated_themeset() -> ThemeSet { + from_binary(include_bytes!("../../assets/themes.bin")) + } + + fn from_binary() -> Self { + let syntax_set = Self::get_integrated_syntaxset(); + let theme_set = Self::get_integrated_themeset(); + + HighlightingAssets { + syntax_set, + theme_set, + } + } +} + +pub fn list_languages() -> std::io::Result<()> { + let assets = HighlightingAssets::new(); + let mut languages = assets + .syntax_set + .syntaxes() + .iter() + .filter(|syntax| !syntax.hidden && !syntax.file_extensions.is_empty()) + .collect::<Vec<_>>(); + languages.sort_by_key(|lang| lang.name.to_uppercase()); + + let loop_through = false; + let colored_output = true; + + let stdout = io::stdout(); + let mut stdout = stdout.lock(); + + if loop_through { + for lang in languages { + write!(stdout, "{}:{}\n", lang.name, lang.file_extensions.join(","))?; + } + } else { + let longest = languages + .iter() + .map(|syntax| syntax.name.len()) + .max() + .unwrap_or(32); // Fallback width if they have no language definitions. + + let comma_separator = ", "; + let separator = " "; + // Line-wrapping for the possible file extension overflow. + let desired_width = 100; + + let style = if colored_output { + Green.normal() + } else { + Style::default() + }; + + for lang in languages { + write!(stdout, "{:width$}{}", lang.name, separator, width = longest)?; + + // Number of characters on this line so far, wrap before `desired_width` + let mut num_chars = 0; + + let mut extension = lang.file_extensions.iter().peekable(); + while let Some(word) = extension.next() { + // If we can't fit this word in, then create a line break and align it in. + let new_chars = word.len() + comma_separator.len(); + if num_chars + new_chars >= desired_width { + num_chars = 0; + write!(stdout, "\n{:width$}{}", "", separator, width = longest)?; + } + + num_chars += new_chars; + write!(stdout, "{}", style.paint(&word[..]))?; + if extension.peek().is_some() { + write!(stdout, "{}", comma_separator)?; + } + } + writeln!(stdout)?; + } + } + + Ok(()) +} diff --git a/src/bat/mod.rs b/src/bat/mod.rs new file mode 100644 index 00000000..e26ac304 --- /dev/null +++ b/src/bat/mod.rs @@ -0,0 +1,2 @@ +pub mod assets; +pub mod output; diff --git a/src/bat/output.rs b/src/bat/output.rs new file mode 100644 index 00000000..24c5def5 --- /dev/null +++ b/src/bat/output.rs @@ -0,0 +1,143 @@ +// https://github.com/sharkdp/bat a1b9334a44a2c652f52dddaa83dbacba57372468 +// src/output.rs +// with minor modifications (see git history). +// +// Copyright (c) 2018 bat-developers (https://github.com/sharkdp/bat). + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +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; + +#[derive(Debug, Clone, Copy, PartialEq)] +#[allow(dead_code)] +pub enum PagingMode { + Always, + QuitIfOneScreen, + Never, +} +use crate::errors::*; + +pub enum OutputType { + Pager(Child), + Stdout(io::Stdout), +} + +impl OutputType { + pub fn from_mode(mode: PagingMode, pager: Option<&str>) -> Result<Self> { + use self::PagingMode::*; + Ok(match mode { + Always => OutputType::try_pager(false, pager)?, + QuitIfOneScreen => OutputType::try_pager(true, pager)?, + _ => OutputType::stdout(), + }) + } + + /// Try to launch the pager. Fall back to stdout in case of errors. + 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 (env::var("BAT_PAGER"), env::var("PAGER")) { + (Ok(bat_pager), _) => Some(bat_pager), + (_, Ok(pager)) => { + // less needs to be called with the '-R' option in order to properly interpret the + // ANSI color sequences printed by bat. If someone has set PAGER="less -F", we + // therefore need to overwrite the arguments and add '-R'. + // + // We only do this for PAGER (as it is not specific to 'bat'), not for BAT_PAGER + // or bats '--pager' command line option. + replace_arguments_to_less = true; + Some(pager) + } + _ => None, + }; + + let pager_from_config = pager_from_config.map(|p| p.to_string()); + + if pager_from_config.is_some() { + replace_arguments_to_less = false; + } + + let pager = pager_from_config.or(pager_from_env).unwrap_or_else( + || String::from("less"), + ); + + let pagerflags = shell_words::split(&pager).chain_err( + || "Could not parse pager command.", + )?; + + match pagerflags.split_first() { + Some((pager_name, args)) => { + let mut pager_path = PathBuf::from(pager_name); + + if pager_path.file_stem() == Some(&OsString::from("bat")) { + pager_path = PathBuf::from("less"); + } + + let is_less = pager_path.file_stem() == Some(&OsString::from("less")); + + let mut process = if is_less { + let mut p = Command::new(&pager_path); + if args.is_empty() || replace_arguments_to_less { + p.args(vec!["--RAW-CONTROL-CHARS", "--no-init"]); + if quit_if_one_screen { + p.arg("--quit-if-one-screen"); + } + } else { + p.args(args); + } + p.env("LESSCHARSET", "UTF-8"); + p + } else { + let mut p = Command::new(&pager_path); + p.args(args); + p + }; + + Ok( + process + .stdin(Stdio::piped()) + .spawn() + .map(OutputType::Pager) + .unwrap_or_else(|_| OutputType::stdout()), + ) + } + None => Ok(OutputType::stdout()), + } + } + + fn stdout() -> Self { + OutputType::Stdout(io::stdout()) + } + + pub fn handle(&mut self) -> Result<&mut Write> { + Ok(match *self { + OutputType::Pager(ref mut command) => { + command.stdin.as_mut().chain_err( + || "Could not open stdin for pager", + )? + } + OutputType::Stdout(ref mut handle) => handle, + }) + } +} + +impl Drop for OutputType { + fn drop(&mut self) { + if let OutputType::Pager(ref mut command) = *self { + let _ = command.wait(); + } + } +} |