add tldr and base

This commit is contained in:
2022-12-17 21:51:41 +01:00
commit 6dc747f8b0
13 changed files with 764 additions and 0 deletions

2
crates/tldr/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target
/Cargo.lock

14
crates/tldr/Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
name = "tldr"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
util = { path = "../util" }
eyre.workspace = true
clap.workspace = true
dirs.workspace = true
walkdir.workspace = true

86
crates/tldr/src/lib.rs Normal file
View File

@@ -0,0 +1,86 @@
pub(crate) mod update;
pub struct Tldr;
impl Tldr {
fn run() -> eyre::Result<()> {
let cache_dir =
dirs::cache_dir().ok_or(eyre::anyhow!("could not find a valid cache dir"))?;
let mut tldr_cache_dir = cache_dir.clone();
tldr_cache_dir.push("kah-toolkit/tldr/store/");
if !tldr_cache_dir.exists() {
return Err(eyre::anyhow!("you need to run <toolkit tldr update> first"));
}
let mut tldr_pages_path = tldr_cache_dir.clone();
tldr_pages_path.push("pages");
if !tldr_pages_path.exists() {
return Err(eyre::anyhow!("you need to run <toolkit tldr update> first"));
}
let mut entries: Vec<String> = Vec::new();
for entry in walkdir::WalkDir::new(&tldr_pages_path) {
let entry = entry?;
let path = entry.path().to_path_buf();
match path.extension() {
None => continue,
Some(ext) => {
if ext != "md" {
continue;
}
}
}
let parent_str = path
.parent()
.ok_or(eyre::anyhow!("could not find parent for file"))?
.to_string_lossy();
let parent = parent_str.split("/").last();
let file_name = entry.file_name();
entries.push(format!(
"{}/{}",
parent.ok_or(eyre::anyhow!("path contains non ascii characters"))?,
file_name
.to_str()
.ok_or(eyre::anyhow!("path contains non ascii characters"))?,
))
}
let paths = entries.join("\n");
let output = util::shell::run_with_input_and_output(&["fzf"], paths)?;
let choice = std::str::from_utf8(output.stdout.as_slice())?.trim();
let mut tldr_choice_path = tldr_pages_path;
tldr_choice_path.push(choice);
let contents = std::fs::read_to_string(tldr_choice_path)?;
util::shell::run_with_input(&["glow", "-"], contents)?;
Ok(())
}
}
impl util::Cmd for Tldr {
fn cmd() -> eyre::Result<clap::Command> {
let cmd = clap::Command::new("tldr").subcommands([update::Update::cmd()?]);
Ok(cmd)
}
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
match args.subcommand() {
Some(("update", subcmd)) => update::Update::exec(subcmd),
_ => Tldr::run(),
}
}
}

32
crates/tldr/src/update.rs Normal file
View File

@@ -0,0 +1,32 @@
pub struct Update;
impl util::Cmd for Update {
fn cmd() -> eyre::Result<clap::Command> {
Ok(clap::Command::new("update"))
}
fn exec(_: &clap::ArgMatches) -> eyre::Result<()> {
let cache_dir =
dirs::cache_dir().ok_or(eyre::anyhow!("could not find a valid cache dir"))?;
let mut tldr_cache_dir = cache_dir.clone();
tldr_cache_dir.push("kah-toolkit/tldr/store/");
std::fs::remove_dir_all(&tldr_cache_dir)?;
std::fs::create_dir_all(&tldr_cache_dir)?;
util::shell::run(
format!(
"gh repo clone tldr-pages/tldr {}",
&tldr_cache_dir
.to_str()
.ok_or(eyre::anyhow!("pathstring contains non ascii-characters"))?
)
.split(" ")
.collect::<Vec<&str>>()
.as_slice(),
)?;
Ok(())
}
}

10
crates/util/Cargo.toml Normal file
View File

@@ -0,0 +1,10 @@
[package]
name = "util"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
eyre.workspace = true
clap.workspace = true

7
crates/util/src/lib.rs Normal file
View File

@@ -0,0 +1,7 @@
pub mod shell;
pub trait Cmd {
fn cmd() -> eyre::Result<clap::Command>;
fn exec(args: &clap::ArgMatches) -> eyre::Result<()>;
}

123
crates/util/src/shell.rs Normal file
View File

@@ -0,0 +1,123 @@
use std::io::Write;
pub fn run(args: &[&str]) -> eyre::Result<()> {
let output = std::process::Command::new(
args.first()
.ok_or(eyre::anyhow!("could not find first arg"))?,
)
.args(
args.to_vec()
.into_iter()
.skip(1)
.collect::<Vec<&str>>()
.as_slice(),
)
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit())
.stdin(std::process::Stdio::inherit())
.output();
match output {
Ok(o) => {
if o.status.success() {
Ok(())
} else {
Err(eyre::anyhow!(
"command failed with statuscode: {}",
o.status
.code()
.ok_or(eyre::anyhow!("could not get a status code from process"))?
))
}
}
Err(e) => Err(eyre::anyhow!(e)),
}
}
pub fn run_with_input(args: &[&str], input: String) -> eyre::Result<()> {
let output = std::process::Command::new(
args.first()
.ok_or(eyre::anyhow!("could not find first arg"))?,
)
.args(
args.to_vec()
.into_iter()
.skip(1)
.collect::<Vec<&str>>()
.as_slice(),
)
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit())
.stdin(std::process::Stdio::piped())
.spawn();
match output {
Ok(mut o) => {
let stdin = o
.stdin
.as_mut()
.ok_or(eyre::anyhow!("could not acquire stdin"))?;
stdin.write_all(input.as_bytes())?;
drop(stdin);
let o = o.wait_with_output()?;
if o.status.success() {
Ok(())
} else {
Err(eyre::anyhow!(
"command failed with statuscode: {}",
o.status
.code()
.ok_or(eyre::anyhow!("could not get a status code from process"))?
))
}
}
Err(e) => Err(eyre::anyhow!(e)),
}
}
pub fn run_with_input_and_output(
args: &[&str],
input: String,
) -> eyre::Result<std::process::Output> {
let output = std::process::Command::new(
args.first()
.ok_or(eyre::anyhow!("could not find first arg"))?,
)
.args(
args.to_vec()
.into_iter()
.skip(1)
.collect::<Vec<&str>>()
.as_slice(),
)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::inherit())
.stdin(std::process::Stdio::piped())
.spawn();
match output {
Ok(mut o) => {
let stdin = o
.stdin
.as_mut()
.ok_or(eyre::anyhow!("could not acquire stdin"))?;
stdin.write_all(input.as_bytes())?;
drop(stdin);
let o = o.wait_with_output()?;
if o.status.success() {
Ok(o)
} else {
Err(eyre::anyhow!(
"command failed with statuscode: {}",
o.status
.code()
.ok_or(eyre::anyhow!("could not get a status code from process"))?
))
}
}
Err(e) => Err(eyre::anyhow!(e)),
}
}