pub mod clap_args;
mod app_launch_args;
mod install_launch_args;
pub use {
app_launch_args::*,
install_launch_args::*,
};
use {
crate::{
app::{App, AppContext},
conf::Conf,
display,
errors::{ProgramError, TreeBuildError},
launchable::Launchable,
shell_install::ShellInstall,
tree::TreeOptions,
verb::VerbStore,
},
clap::{self, ArgMatches},
crossterm::{
self,
cursor,
event::{DisableMouseCapture, EnableMouseCapture},
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
QueueableCommand,
},
std::{
env,
io::{self, Write},
path::{Path, PathBuf},
},
};
#[cfg(not(windows))]
fn canonicalize_root(root: &Path) -> io::Result<PathBuf> {
root.canonicalize()
}
#[cfg(windows)]
fn canonicalize_root(root: &Path) -> io::Result<PathBuf> {
Ok(if root.is_relative() {
env::current_dir()?.join(root)
} else {
root.to_path_buf()
})
}
fn get_root_path(cli_args: &ArgMatches<'_>) -> Result<PathBuf, ProgramError> {
let mut root = cli_args
.value_of("ROOT")
.map_or(env::current_dir()?, PathBuf::from);
if !root.exists() {
return Err(TreeBuildError::FileNotFound {
path: format!("{:?}", &root),
}.into());
}
if !root.is_dir() {
if let Some(parent) = root.parent() {
info!("Passed path isn't a directory => opening parent instead");
root = parent.to_path_buf();
} else {
return Err(TreeBuildError::NotADirectory {
path: format!("{:?}", &root),
}.into());
}
}
Ok(canonicalize_root(&root)?)
}
pub fn run() -> Result<Option<Launchable>, ProgramError> {
let clap_app = clap_args::clap_app();
let cli_matches = clap_app.get_matches();
let install_args = InstallLaunchArgs::from(&cli_matches)?;
let mut must_quit = false;
if let Some(state) = install_args.set_install_state {
state.write_file()?;
must_quit = true;
}
if let Some(shell) = &install_args.print_shell_function {
ShellInstall::print(shell)?;
must_quit = true;
}
if must_quit {
return Ok(None);
}
let specific_conf: Option<Vec<PathBuf>> = cli_matches
.value_of("conf")
.map(|s| s.split(';').map(PathBuf::from).collect());
if specific_conf.is_none() && install_args.install != Some(false) {
let mut shell_install = ShellInstall::new(install_args.install == Some(true));
shell_install.check()?;
if shell_install.should_quit {
return Ok(None);
}
}
let mut config = match &specific_conf {
Some(conf_paths) => {
let mut conf = Conf::default();
for path in conf_paths {
conf.read_file(path.to_path_buf())?;
}
conf
}
_ => time!(Conf::from_default_location())?,
};
debug!("config: {:#?}", &config);
let mut tree_options = TreeOptions::default();
tree_options.apply_config(&config)?;
tree_options.apply_launch_args(&cli_matches);
let mut verb_store = VerbStore::default();
verb_store.init(&mut config)?;
let file_export_path = cli_matches.value_of("file-export-path").map(str::to_string);
let cmd_export_path = cli_matches.value_of("cmd-export-path").map(str::to_string);
let commands = cli_matches.value_of("commands").map(str::to_string);
let height = cli_matches.value_of("height").and_then(|s| s.parse().ok());
let color = match cli_matches.value_of("color") {
Some("yes") => Some(true),
Some("no") => Some(false),
_ => None,
};
let root = get_root_path(&cli_matches)?;
#[cfg(unix)]
if let Some(server_name) = cli_matches.value_of("send") {
use crate::{
command::Sequence,
net::{Client, Message},
};
let client = Client::new(server_name);
if let Some(seq) = &commands {
let message = Message::Sequence(Sequence::new_local(seq.to_string()));
client.send(&message)?;
} else if !cli_matches.is_present("get-root") {
let message = Message::Command(format!(":focus {}", root.to_string_lossy()));
client.send(&message)?;
};
if cli_matches.is_present("get-root") {
client.send(&Message::GetRoot)?;
}
return Ok(None);
}
let mut launch_args = AppLaunchArgs {
root,
file_export_path,
cmd_export_path,
tree_options,
commands,
height,
color,
listen: cli_matches.value_of("listen").map(str::to_string),
};
if color == Some(false) {
launch_args.tree_options.show_selection_mark = true;
}
let context = AppContext::from(launch_args, verb_store, &config)?;
let mut w = display::writer();
let app = App::new(&context)?;
w.queue(EnterAlternateScreen)?;
w.queue(cursor::Hide)?;
let capture_mouse = config.disable_mouse_capture != Some(true);
if capture_mouse {
w.queue(EnableMouseCapture)?;
}
let r = app.run(&mut w, &context, &config);
if capture_mouse {
w.queue(DisableMouseCapture)?;
}
w.queue(cursor::Show)?;
w.queue(LeaveAlternateScreen)?;
w.flush()?;
r
}
pub fn ask_authorization() -> Result<bool, ProgramError> {
let mut answer = String::new();
io::stdin().read_line(&mut answer)?;
let answer = answer.trim();
Ok(!matches!(answer, "n" | "N"))
}