repo_description: Count your code, quickly.
repo_topics: badge cli cloc code command-line-tool linux macos rust sloc statistics tokei windows
code: #[macro_use]
  extern crate log;
  
  mod cli;
  mod cli_utils;
  mod consts;
  mod input;
  
  use std::{error::Error, io, process};
  
  use tokei::{Config, Languages, Sort};
  
  use crate::{
      cli::Cli,
      cli_utils::Printer,
      consts::{
          BLANKS_COLUMN_WIDTH, CODE_COLUMN_WIDTH, COMMENTS_COLUMN_WIDTH, FALLBACK_ROW_LEN,
          LANGUAGE_COLUMN_WIDTH, LINES_COLUMN_WIDTH, PATH_COLUMN_WIDTH,
      },
      input::add_input,
  };
  
  fn main() -> Result<(), Box<dyn Error>> {
      let mut cli = Cli::from_args();
  
      if cli.print_languages {
          Cli::print_supported_languages()?;
          process::exit(0);
      }
      let config = cli.override_config(Config::from_config_files());
      let mut languages = Languages::new();
  
      if let Some(input) = cli.file_input() {
          if !add_input(input, &mut languages) {
              Cli::print_input_parse_failure(input);
              process::exit(1);
          }
      }
  
      let input = cli.input();
  
      for path in &input {
          if ::std::fs::metadata(path).is_err() {
              eprintln!("Error: '{}' not found.", path);
              process::exit(1);
          }
      }
  
      let columns = cli
          .columns
          .or(config.columns)
          .or_else(|| {
              if cli.files {
                  term_size::dimensions().map(|(w, _)| w)
              } else {
                  None
              }
          })
          .unwrap_or(FALLBACK_ROW_LEN)
          .max(FALLBACK_ROW_LEN);
  
      if cli.streaming == Some(crate::cli::Streaming::Simple) {
          println!(
              "#{:^LANGUAGE_COLUMN_WIDTH$} {:^PATH_COLUMN_WIDTH$} {:^LINES_COLUMN_WIDTH$} {:^CODE_COLUMN_WIDTH$} {:^COMMENTS_COLUMN_WIDTH$} {:^BLANKS_COLUMN_WIDTH$}",
              "language", "path", "lines", "code", "comments", "blanks"
          );
          println!(
              "{:>LANGUAGE_COLUMN_WIDTH$} {:<PATH_COLUMN_WIDTH$} {:>LINES_COLUMN_WIDTH$} {:>CODE_COLUMN_WIDTH$} {:>COMMENTS_COLUMN_WIDTH$} {:>BLANKS_COLUMN_WIDTH$}",
              (0..10).map(|_| "#").collect::<String>(),
              (0..80).map(|_| "#").collect::<String>(),
              (0..12).map(|_| "#").collect::<String>(),
              (0..12).map(|_| "#").collect::<String>(),
              (0..12).map(|_| "#").collect::<String>(),
              (0..12).map(|_| "#").collect::<String>()
          );
      }
  
      languages.get_statistics(&input, &cli.ignored_directories(), &config);
      if config.for_each_fn.is_some() {
          process::exit(0);
      }
  
      if let Some(format) = cli.output {
          print!("{}", format.print(&languages).unwrap());
          process::exit(0);
      }
  
      let mut printer = Printer::new(
          columns,
          cli.files,
          io::BufWriter::new(io::stdout()),
          cli.number_format,
      );
  
      if languages.iter().any(|(_, lang)| lang.inaccurate) {
          printer.print_inaccuracy_warning()?;
      }
  
      printer.print_header()?;
  
      let mut is_sorted = false;
      if let Some(sort_category) = cli.sort.or(config.sort) {
          for (_, ref mut language) in &mut languages {
              language.sort_by(sort_category);
          }
  
          let mut languages: Vec<_> = languages.iter().collect();
          match sort_category {
              Sort::Blanks => languages.sort_by(|a, b| b.1.blanks.cmp(&a.1.blanks)),
              Sort::Comments => languages.sort_by(|a, b| b.1.comments.cmp(&a.1.comments)),
              Sort::Code => languages.sort_by(|a, b| b.1.code.cmp(&a.1.code)),
              Sort::Files => languages.sort_by(|a, b| b.1.reports.len().cmp(&a.1.reports.len())),
              Sort::Lines => languages.sort_by(|a, b| b.1.lines().cmp(&a.1.lines())),
          }
          is_sorted = true;
          if cli.sort_reverse {
              printer.print_results(languages.into_iter().rev(), cli.compact, is_sorted)?;
          } else {
              printer.print_results(languages.into_iter(), cli.compact, is_sorted)?;
          }
      } else {
          printer.print_results(languages.iter(), cli.compact, is_sorted)?;
      }
  
      printer.print_total(&languages)?;
  
      Ok(())
  }
  