diff --git a/src/main.rs b/src/main.rs index 48c2b03..e330f53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -241,7 +241,7 @@ struct SpecialRender { // blue: &'static str, bright_blue: &'static str, // cyan: &'static str, - // bright_cyan: &'static str, + bright_cyan: &'static str, yellow: &'static str, // bright_yellow: &'static str, // magenta: &'static str, @@ -292,7 +292,7 @@ impl SpecialRender { // blue: "\x1b[34m", bright_blue: "\x1b[94m", // cyan: "\x1b[36m", - // bright_cyan: "\x1b[96m", + bright_cyan: "\x1b[96m", yellow: "\x1b[33m", // bright_yellow: "\x1b[93m", // magenta: "\x1b[35m", @@ -334,7 +334,7 @@ impl SpecialRender { // blue: "", bright_blue: "", // cyan: "", - // bright_cyan: "", + bright_cyan: "", yellow: "", // bright_yellow: "", // magenta: "", diff --git a/src/user.rs b/src/user.rs index 0adceff..0b7b0ef 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,6 +1,8 @@ use clap::{Args, Subcommand}; +use eyre::OptionExt; +use forgejo_api::Forgejo; -use crate::repo::RepoInfo; +use crate::{repo::RepoInfo, SpecialRender}; #[derive(Args, Clone, Debug)] pub struct UserCommand { @@ -11,13 +13,112 @@ pub struct UserCommand { } #[derive(Subcommand, Clone, Debug)] -pub enum UserSubcommand {} +pub enum UserSubcommand { + View { + /// The name of the user to view + user: Option, + }, + Browse { + /// The name of the user to open in your browser + user: Option, + }, +} impl UserCommand { pub async fn run(self, keys: &mut crate::KeyInfo, host_name: Option<&str>) -> eyre::Result<()> { let repo = RepoInfo::get_current(host_name, None, self.remote.as_deref())?; let api = keys.get_api(repo.host_url()).await?; - match self.command {} + match self.command { + UserSubcommand::View { user } => view_user(&api, user.as_deref()).await?, + UserSubcommand::Browse { user } => { + browse_user(&api, repo.host_url(), user.as_deref()).await? + } + } Ok(()) } } + +async fn view_user(api: &Forgejo, user: Option<&str>) -> eyre::Result<()> { + let SpecialRender { + bold, + dash, + bright_cyan, + light_grey, + reset, + .. + } = *crate::special_render(); + + let user_data = match user { + Some(user) => api.user_get(user).await?, + None => api.user_get_current().await?, + }; + let username = user_data + .login + .as_deref() + .ok_or_eyre("user has no username")?; + print!("{bright_cyan}{bold}{username}{reset}"); + if let Some(pronouns) = user_data.pronouns.as_deref() { + if !pronouns.is_empty() { + print!("{light_grey} {dash} {bold}{pronouns}{reset}"); + } + } + println!(); + let followers = user_data.followers_count.unwrap_or_default(); + let following = user_data.following_count.unwrap_or_default(); + println!("{bold}{followers}{reset} followers {dash} {bold}{following}{reset} following"); + let mut first = true; + if let Some(website) = user_data.website.as_deref() { + if !website.is_empty() { + print!("{bold}{website}{reset}"); + first = false; + } + } + if let Some(email) = user_data.email.as_deref() { + if !email.is_empty() && !email.contains("noreply") { + if !first { + print!(" {dash} "); + } + print!("{bold}{email}{reset}"); + } + } + if !first { + println!(); + } + + if let Some(desc) = user_data.description.as_deref() { + if !desc.is_empty() { + println!(); + println!("{}", crate::markdown(desc)); + println!(); + } + } + + let joined = user_data + .created + .ok_or_eyre("user does not have join date")?; + let date_format = time::macros::format_description!("[month repr:short] [day], [year]"); + println!("Joined on {bold}{}{reset}", joined.format(&date_format)?); + + Ok(()) +} + +async fn browse_user(api: &Forgejo, host_url: &url::Url, user: Option<&str>) -> eyre::Result<()> { + let username = match user { + Some(user) => user.to_owned(), + None => { + let myself = api.user_get_current().await?; + myself + .login + .ok_or_eyre("authenticated user does not have login")? + } + }; + // `User` doesn't have an `html_url` field, so we gotta construct the user + // page url ourselves + let mut url = host_url.clone(); + url.path_segments_mut() + .map_err(|_| eyre::eyre!("invalid host url"))? + .push(&username); + open::that(url.as_str())?; + + Ok(()) +}