repo_description: A cat(1) clone with wings.
repo_topics: cli command-line git hacktoberfest rust syntax-highlighting terminal tool
code: use shell_words::ParseError;
  use std::env;
  
  /// If we use a pager, this enum tells us from where we were told to use it.
  #[derive(Debug, PartialEq)]
  pub(crate) enum PagerSource {
      /// From --config
      Config,
  
      /// From the env var BAT_PAGER
      EnvVarBatPager,
  
      /// From the env var PAGER
      EnvVarPager,
  
      /// No pager was specified, default is used
      Default,
  }
  
  /// We know about some pagers, for example 'less'. This is a list of all pagers we know about
  #[derive(Debug, PartialEq)]
  pub(crate) enum PagerKind {
      /// bat
      Bat,
  
      /// less
      Less,
  
      /// more
      More,
  
      /// most
      Most,
  
      /// builtin
      Builtin,
  
      /// A pager we don't know about
      Unknown,
  }
  
  impl PagerKind {
      fn from_bin(bin: &str) -> PagerKind {
          use std::path::Path;
  
          if bin == "builtin" {
              return PagerKind::Builtin;
          }
  
          // Set to `less` by default on most Linux distros.
          let pager_bin = Path::new(bin).file_stem();
  
          // The name of the current running binary. Normally `bat` but sometimes
          // `batcat` for compatibility reasons.
          let current_bin = env::args_os().next();
  
          // Check if the current running binary is set to be our pager.
          let is_current_bin_pager = current_bin
              .map(|s| Path::new(&s).file_stem() == pager_bin)
              .unwrap_or(false);
  
          match pager_bin.map(|s| s.to_string_lossy()).as_deref() {
              Some("less") => PagerKind::Less,
              Some("more") => PagerKind::More,
              Some("most") => PagerKind::Most,
              _ if is_current_bin_pager => PagerKind::Bat,
              _ => PagerKind::Unknown,
          }
      }
  }
  
  /// A pager such as 'less', and from where we got it.
  #[derive(Debug)]
  pub(crate) struct Pager {
      /// The pager binary
      pub bin: String,
  
      /// The pager binary arguments (that we might tweak)
      pub args: Vec<String>,
  
      /// What pager this is
      pub kind: PagerKind,
  
      /// From where this pager comes
      pub source: PagerSource,
  }
  
  impl Pager {
      fn new(bin: &str, args: &[String], kind: PagerKind, source: PagerSource) -> Pager {
          Pager {
              bin: String::from(bin),
              args: args.to_vec(),
              kind,
              source,
          }
      }
  }
  
  /// Returns what pager to use, after looking at both config and environment variables.
  pub(crate) fn get_pager(config_pager: Option<&str>) -> Result<Option<Pager>, ParseError> {
      let bat_pager = env::var("BAT_PAGER");
      let pager = env::var("PAGER");
  
      let (cmd, source) = match (config_pager, &bat_pager, &pager) {
          (Some(config_pager), _, _) => (config_pager, PagerSource::Config),
          (_, Ok(bat_pager), _) => (bat_pager.as_str(), PagerSource::EnvVarBatPager),
          (_, _, Ok(pager)) => (pager.as_str(), PagerSource::EnvVarPager),
          _ => ("less", PagerSource::Default),
      };
  
      let parts = shell_words::split(cmd)?;
      match parts.split_first() {
          Some((bin, args)) => {
              let kind = PagerKind::from_bin(bin);
  
              let use_less_instead = if source == PagerSource::EnvVarPager {
                  // 'more' and 'most' do not supports colors; automatically use
                  // 'less' instead if the problematic pager came from the
                  // generic PAGER env var.
                  // If PAGER=bat, silently use 'less' instead to prevent
                  // recursion.
                  // Never silently use 'less' if BAT_PAGER or --pager has been
                  // specified.
                  matches!(kind, PagerKind::More | PagerKind::Most | PagerKind::Bat)
              } else {
                  false
              };
  
              Ok(Some(if use_less_instead {
                  let no_args = vec![];
                  Pager::new("less", &no_args, PagerKind::Less, PagerSource::EnvVarPager)
              } else {
                  Pager::new(bin, args, kind, source)
              }))
          }
          None => Ok(None),
      }
  }
  