use chrono::{Local, TimeZone, Utc};
use clap_builder::{ColorChoice, CommandFactory};
use clap_complete::Shell;
use ex_cli::cli::cli::Cli;
use ex_cli::config::Config;
use ex_cli::error::MyResult;
use ex_cli::finder::Finder;
use ex_cli::fs::system::FileSystem;
use ex_cli::printer::{IndentChars, Printer};
use ex_cli::sorter::Sorter;
use ex_cli::util::color::ColorMap;
use std::{env, process};
#[cfg(windows)]
use sysinfo::{Pid, Process, ProcessesToUpdate, System};
use termcolor::StandardStream;
fn main() {
let result = run_main();
if let Err(error) = result {
error.print_error();
}
}
fn run_main() -> MyResult<()> {
let args = env::args().collect();
let piped = atty::isnt(atty::Stream::Stdout);
let config = Config::new(args, piped, Utc::now)?;
if let Some(shell) = config.completion() {
create_completion(shell);
} else if config.show_utc() {
run_config(config, &Utc)?;
} else {
run_config(config, &Local)?;
}
Ok(())
}
fn create_completion(shell: Shell) {
let name = env!("CARGO_BIN_NAME");
let mut command = Cli::command();
let mut stdout = std::io::stdout();
clap_complete::generate(shell, &mut command, name, &mut stdout);
process::exit(1);
}
fn run_config<Tz: TimeZone>(config: Config, zone: &Tz) -> MyResult<()> {
let current = env::current_dir()?;
let colors = env::var("LS_COLORS").ok();
let git_bash = test_bash()?;
let system = FileSystem::new(&config);
let finder = Finder::new(&config, &system, zone, current, git_bash);
let sorter = Sorter::new(&config);
let writer = create_stream(&config);
let colors = ColorMap::new(colors);
let chars = IndentChars {
branching: '\u{251c}',
terminating: '\u{2514}',
horizontal: '\u{2500}',
vertical: '\u{2502}',
};
let mut printer = Printer::new(&config, zone, writer, colors, chars, git_bash);
let mut files = finder.find_files()?;
let total = finder.create_total(&files);
sorter.sort_files(&mut files);
printer.print_files(&files, &total, zone)?;
Ok(())
}
fn create_stream(config: &Config) -> StandardStream {
let color = match config.color().unwrap_or(ColorChoice::Auto) {
ColorChoice::Auto => if atty::is(atty::Stream::Stdout) {
termcolor::ColorChoice::Auto
} else {
termcolor::ColorChoice::Never
}
ColorChoice::Always => termcolor::ColorChoice::Always,
ColorChoice::Never => termcolor::ColorChoice::Never,
};
StandardStream::stdout(color)
}
#[cfg(windows)]
fn test_bash() -> MyResult<bool> {
let mut system = System::new();
let mut pid = sysinfo::get_current_pid()?;
while let Some(process) = get_process(&mut system, pid) {
let name = process.name();
if name == "bash.exe" {
return Ok(true);
} else if let Some(ppid) = process.parent() {
pid = ppid;
} else {
break;
}
}
Ok(false)
}
#[cfg(windows)]
fn get_process(system: &mut System, pid: Pid) -> Option<&Process> {
system.refresh_processes(ProcessesToUpdate::Some(&[pid]), false);
system.process(pid)
}
#[cfg(not(windows))]
fn test_bash() -> MyResult<bool> {
Ok(false)
}