summaryrefslogtreecommitdiffstats
path: root/src/bat
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2019-07-04 18:43:10 -0400
committerDan Davison <dandavison7@gmail.com>2019-07-08 23:51:09 -0400
commitcc8e8adf297a2042fe6409d77ff97a41e8747b34 (patch)
treeeb99ba632588f8560892972e76237bd8f8398e16 /src/bat
parentbfe5b728b51e36e4e37c7cb5c09b1fcf92b24448 (diff)
Create bat directory for bat-derived code
Diffstat (limited to 'src/bat')
-rw-r--r--src/bat/assets.rs116
-rw-r--r--src/bat/mod.rs2
-rw-r--r--src/bat/output.rs143
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();
+ }
+ }
+}