pub mod man;
pub mod cheat_sh;
pub mod cheatsheets;
pub mod eg;
use crate::config::Config;
use crate::error::{Error, Result};
use crate::helper::docs::cheat_sh::CheatDotSh;
use crate::helper::docs::cheatsheets::Cheatsheets;
use crate::helper::docs::eg::Eg;
use crate::helper::docs::man::show_man_page;
use console::{style, Style, Term};
use dialoguer::theme::ColorfulTheme;
use dialoguer::Select;
use std::io::Write;
use std::process::{Command, Stdio};
use ureq::Request;
pub trait HelpProvider {
fn url(&self) -> &'static str;
fn build_request(&self, cmd: &str, url: &str) -> Request;
fn handle_error(&self, e: ureq::Error) -> Error {
if e.kind() == ureq::ErrorKind::HTTP {
Error::ProviderError(
"Unknown topic, This topic/command might has no page in this provider yet."
.to_string(),
)
} else {
Error::from(Box::new(e))
}
}
#[inline(always)]
fn _fetch(&self, cmd: &str, custom_url: &Option<String>) -> Result<String> {
let url = {
if let Some(u) = custom_url {
u.as_str()
} else {
self.url()
}
};
let response = self.build_request(cmd, url).call();
let response = response.map_err(|e| self.handle_error(e));
match response {
Ok(response) => Ok(response.into_string()?),
Err(e) => Err(e),
}
}
fn fetch(&self, cmd: &str, custom_url: &Option<String>) -> Result<String> {
self._fetch(cmd, custom_url)
}
}
pub fn get_docs_help<Output: Write>(cmd: &str, config: &Config, output: &mut Output) -> Result<()> {
const MAN_PAGE: usize = 0;
const CHEAT_SHEET: usize = 1;
const EG_PAGE: usize = 2;
const CHEATSHEETS: usize = 3;
let menu_options = [
"Show man page",
"Show cheat.sh page",
"Show the eg page",
"Show the cheatsheet page",
"Exit",
];
let mut selection = Some(MAN_PAGE);
loop {
selection = Select::with_theme(&get_selection_theme())
.with_prompt("Select operation")
.default(selection.unwrap_or_default())
.items(&menu_options)
.interact_on_opt(&Term::stderr())?;
if let Some(MAN_PAGE) = selection {
show_man_page(&config.man_command, cmd)?
} else {
let page = match selection {
Some(CHEAT_SHEET) => CheatDotSh.fetch(cmd, &config.cheat_sh_url)?,
Some(EG_PAGE) => Eg.fetch(cmd, &config.eg_url)?,
Some(CHEATSHEETS) => Cheatsheets.fetch(cmd, &config.cheatsheets_url)?,
_ => return Ok(()),
};
if let Some(pager) = config.pager_command.as_ref() {
let mut process = if cfg!(target_os = "windows") {
Command::new("cmd")
.args(["/C", pager])
.stdin(Stdio::piped())
.spawn()
} else {
Command::new("sh")
.args(["-c", pager])
.stdin(Stdio::piped())
.spawn()
}?;
if let Some(stdin) = process.stdin.as_mut() {
writeln!(stdin, "{}", page)?;
process.wait()?;
}
} else {
writeln!(output, "{}", page)?;
}
}
}
}
fn get_selection_theme() -> ColorfulTheme {
ColorfulTheme {
defaults_style: Style::new().for_stderr().cyan(),
prompt_style: Style::new().for_stderr().bold(),
prompt_prefix: style("(ノ´ヮ`)ノ*: ・゚\n".to_string()).for_stderr().magenta(),
prompt_suffix: style("›".to_string()).for_stderr().magenta().bright(),
success_prefix: style("❤".to_string()).for_stderr().magenta(),
success_suffix: style("·".to_string()).for_stderr().black().bright(),
error_prefix: style("✘".to_string()).for_stderr().red(),
error_style: Style::new().for_stderr().red(),
hint_style: Style::new().for_stderr().black().bright(),
values_style: Style::new().for_stderr().green(),
active_item_style: Style::new().for_stderr().green().bold(),
inactive_item_style: Style::new().for_stderr().italic(),
active_item_prefix: style("✧".to_string()).for_stderr().magenta().bold(),
inactive_item_prefix: style(" ".to_string()).for_stderr(),
checked_item_prefix: style("❤".to_string()).for_stderr().magenta(),
unchecked_item_prefix: style("❤".to_string()).for_stderr().black(),
picked_item_prefix: style("❯".to_string()).for_stderr().green(),
unpicked_item_prefix: style(" ".to_string()).for_stderr(),
}
}