jensmemesclient/cli/src/commands/list.rs

90 lines
2.4 KiB
Rust

use anyhow::{Context, Result};
use std::{
io::Write,
process::{Command, Stdio},
};
use crate::{
table::{self, AsTableRow},
util,
};
use libjens::{util::MemeSorting, JMClient};
pub async fn run(
client: &JMClient,
cat: Option<String>,
user: Option<String>,
sorting: Option<MemeSorting>,
fzf: bool,
) -> Result<()> {
// This needs to be done so both users, memes and categories will be requested
// at once
let (memes, ..) = tokio::try_join!(
async { client.get_memes().await.map_err(|e| e.into()) },
async {
if let Some(c) = cat.as_ref() {
util::assert_category_exists(client, c).await
} else {
Ok(())
}
},
async {
if let Some(u) = user.as_ref() {
util::assert_user_exists(client, u).await
} else {
Ok(())
}
},
)?;
let mut memes = memes
.iter()
.filter(|m| cat.as_ref().map(|c| &m.category == c).unwrap_or(true))
.filter(|m| user.as_ref().map(|u| &m.user == u).unwrap_or(true))
.collect::<Vec<_>>();
if let Some(s) = sorting {
s.sort_with(&mut memes);
}
let mut table = table::list_table();
for m in memes.iter() {
table.add_row(m.as_table_row());
}
let table_str = table.render();
if fzf {
let mut child = Command::new("fzf")
.args(&["--delimiter", "\\t", "--with-nth", "2"])
.stdout(Stdio::piped())
.stdin(Stdio::piped())
.spawn()
.context("Failed to spawn FZF")?;
let stdin = child.stdin.as_mut().context("could not get FZF stdin")?;
for (idx, line) in table_str.lines().enumerate() {
stdin
.write(format!("{}\t{}\n", idx, line).as_bytes())
.context("Failed to write to FZF")?;
}
let out = child.wait_with_output()?;
let out_str = String::from_utf8(out.stdout).context("FZF output is invalid UTF-8")?;
let idx = out_str
.split('\t')
.next()
.and_then(|s| s.parse::<usize>().ok())
.context("Failed to parse FZF output")?;
let meme = memes
.get(idx)
.context("Falied to retrieve meme FZF returned")?;
println!("{}", meme.link);
} else {
println!("{}", table_str);
}
Ok(())
}