mirror of
https://codeberg.org/Cyborus/forgejo-cli.git
synced 2024-11-10 12:09:33 +01:00
Merge pull request 'add optional fancy output' (#53) from optional-pretty into main
Reviewed-on: https://codeberg.org/Cyborus/forgejo-cli/pulls/53
This commit is contained in:
commit
0a30d14035
3 changed files with 140 additions and 10 deletions
112
src/main.rs
112
src/main.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use std::io::IsTerminal;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use eyre::{eyre, Context, OptionExt};
|
use eyre::{eyre, Context, OptionExt};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
@ -14,6 +16,8 @@ mod repo;
|
||||||
pub struct App {
|
pub struct App {
|
||||||
#[clap(long, short = 'H')]
|
#[clap(long, short = 'H')]
|
||||||
host: Option<String>,
|
host: Option<String>,
|
||||||
|
#[clap(long)]
|
||||||
|
style: Option<Style>,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Command,
|
command: Command,
|
||||||
}
|
}
|
||||||
|
@ -36,6 +40,9 @@ pub enum Command {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> eyre::Result<()> {
|
async fn main() -> eyre::Result<()> {
|
||||||
let args = App::parse();
|
let args = App::parse();
|
||||||
|
|
||||||
|
let _ = SPECIAL_RENDER.set(SpecialRender::new(args.style.unwrap_or_default()));
|
||||||
|
|
||||||
let mut keys = KeyInfo::load().await?;
|
let mut keys = KeyInfo::load().await?;
|
||||||
|
|
||||||
let host_name = args.host.as_deref();
|
let host_name = args.host.as_deref();
|
||||||
|
@ -137,3 +144,108 @@ async fn tempfile(ext: Option<&str>) -> tokio::io::Result<(tokio::fs::File, std:
|
||||||
.await?;
|
.await?;
|
||||||
Ok((file, path))
|
Ok((file, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
static SPECIAL_RENDER: OnceLock<SpecialRender> = OnceLock::new();
|
||||||
|
|
||||||
|
fn special_render() -> &'static SpecialRender {
|
||||||
|
SPECIAL_RENDER
|
||||||
|
.get()
|
||||||
|
.expect("attempted to get special characters before that was initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::ValueEnum, Clone, Copy, Debug, Default)]
|
||||||
|
enum Style {
|
||||||
|
/// Use special characters, and colors.
|
||||||
|
#[default]
|
||||||
|
Fancy,
|
||||||
|
/// No special characters and no colors. Always used in non-terminal contexts (i.e. pipes)
|
||||||
|
Minimal,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SpecialRender {
|
||||||
|
dash: char,
|
||||||
|
bullet: char,
|
||||||
|
body_prefix: char,
|
||||||
|
|
||||||
|
red: &'static str,
|
||||||
|
bright_red: &'static str,
|
||||||
|
green: &'static str,
|
||||||
|
bright_green: &'static str,
|
||||||
|
blue: &'static str,
|
||||||
|
bright_blue: &'static str,
|
||||||
|
cyan: &'static str,
|
||||||
|
bright_cyan: &'static str,
|
||||||
|
yellow: &'static str,
|
||||||
|
bright_yellow: &'static str,
|
||||||
|
magenta: &'static str,
|
||||||
|
bright_magenta: &'static str,
|
||||||
|
black: &'static str,
|
||||||
|
dark_grey: &'static str,
|
||||||
|
light_grey: &'static str,
|
||||||
|
white: &'static str,
|
||||||
|
reset: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecialRender {
|
||||||
|
fn new(display: Style) -> Self {
|
||||||
|
let is_tty = std::io::stdout().is_terminal();
|
||||||
|
match display {
|
||||||
|
_ if !is_tty => Self::minimal(),
|
||||||
|
Style::Fancy => Self::fancy(),
|
||||||
|
Style::Minimal => Self::minimal(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fancy() -> Self {
|
||||||
|
Self {
|
||||||
|
dash: '—',
|
||||||
|
bullet: '•',
|
||||||
|
body_prefix: '▌',
|
||||||
|
|
||||||
|
red: "\x1b[31m",
|
||||||
|
bright_red: "\x1b[91m",
|
||||||
|
green: "\x1b[32m",
|
||||||
|
bright_green: "\x1b[92m",
|
||||||
|
blue: "\x1b[34m",
|
||||||
|
bright_blue: "\x1b[94m",
|
||||||
|
cyan: "\x1b[36m",
|
||||||
|
bright_cyan: "\x1b[96m",
|
||||||
|
yellow: "\x1b[33m",
|
||||||
|
bright_yellow: "\x1b[93m",
|
||||||
|
magenta: "\x1b[35m",
|
||||||
|
bright_magenta: "\x1b[95m",
|
||||||
|
black: "\x1b[30m",
|
||||||
|
dark_grey: "\x1b[90m",
|
||||||
|
light_grey: "\x1b[37m",
|
||||||
|
white: "\x1b[97m",
|
||||||
|
reset: "\x1b[0m",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minimal() -> Self {
|
||||||
|
Self {
|
||||||
|
dash: '-',
|
||||||
|
bullet: '-',
|
||||||
|
body_prefix: '>',
|
||||||
|
|
||||||
|
red: "",
|
||||||
|
bright_red: "",
|
||||||
|
green: "",
|
||||||
|
bright_green: "",
|
||||||
|
blue: "",
|
||||||
|
bright_blue: "",
|
||||||
|
cyan: "",
|
||||||
|
bright_cyan: "",
|
||||||
|
yellow: "",
|
||||||
|
bright_yellow: "",
|
||||||
|
magenta: "",
|
||||||
|
bright_magenta: "",
|
||||||
|
black: "",
|
||||||
|
dark_grey: "",
|
||||||
|
light_grey: "",
|
||||||
|
white: "",
|
||||||
|
reset: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use tokio::io::AsyncWriteExt;
|
||||||
use crate::{
|
use crate::{
|
||||||
keys::KeyInfo,
|
keys::KeyInfo,
|
||||||
repo::{RepoInfo, RepoName},
|
repo::{RepoInfo, RepoName},
|
||||||
|
SpecialRender,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Args, Clone, Debug)]
|
#[derive(Args, Clone, Debug)]
|
||||||
|
@ -374,6 +375,13 @@ async fn view_release(
|
||||||
&time::format_description::well_known::Rfc2822,
|
&time::format_description::well_known::Rfc2822,
|
||||||
)?;
|
)?;
|
||||||
println!();
|
println!();
|
||||||
|
let SpecialRender {
|
||||||
|
bullet,
|
||||||
|
body_prefix,
|
||||||
|
dark_grey,
|
||||||
|
reset,
|
||||||
|
..
|
||||||
|
} = crate::special_render();
|
||||||
let body = release
|
let body = release
|
||||||
.body
|
.body
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -381,7 +389,7 @@ async fn view_release(
|
||||||
if !body.is_empty() {
|
if !body.is_empty() {
|
||||||
println!();
|
println!();
|
||||||
for line in body.lines() {
|
for line in body.lines() {
|
||||||
println!("> {line}");
|
println!("{dark_grey}{body_prefix}{reset} {line}");
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
@ -396,10 +404,10 @@ async fn view_release(
|
||||||
.name
|
.name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| eyre::eyre!("asset does not have name"))?;
|
.ok_or_else(|| eyre::eyre!("asset does not have name"))?;
|
||||||
println!("- {}", name);
|
println!("{bullet} {}", name);
|
||||||
}
|
}
|
||||||
println!("- source.zip");
|
println!("{bullet} source.zip");
|
||||||
println!("- source.tar.gz");
|
println!("{bullet} source.tar.gz");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
22
src/repo.rs
22
src/repo.rs
|
@ -3,6 +3,8 @@ use eyre::{eyre, OptionExt};
|
||||||
use forgejo_api::structs::CreateRepoOption;
|
use forgejo_api::structs::CreateRepoOption;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::SpecialRender;
|
||||||
|
|
||||||
pub struct RepoInfo {
|
pub struct RepoInfo {
|
||||||
url: Url,
|
url: Url,
|
||||||
name: Option<RepoName>,
|
name: Option<RepoName>,
|
||||||
|
@ -351,6 +353,14 @@ impl RepoCommand {
|
||||||
.ok_or_eyre("couldn't get repo name, please specify")?;
|
.ok_or_eyre("couldn't get repo name, please specify")?;
|
||||||
let repo = api.repo_get(repo.owner(), repo.name()).await?;
|
let repo = api.repo_get(repo.owner(), repo.name()).await?;
|
||||||
|
|
||||||
|
let SpecialRender {
|
||||||
|
dash,
|
||||||
|
body_prefix,
|
||||||
|
dark_grey,
|
||||||
|
reset,
|
||||||
|
..
|
||||||
|
} = crate::special_render();
|
||||||
|
|
||||||
println!("{}", repo.full_name.ok_or_eyre("no full name")?);
|
println!("{}", repo.full_name.ok_or_eyre("no full name")?);
|
||||||
|
|
||||||
if let Some(parent) = &repo.parent {
|
if let Some(parent) = &repo.parent {
|
||||||
|
@ -370,7 +380,7 @@ impl RepoCommand {
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
for line in desc.lines() {
|
for line in desc.lines() {
|
||||||
println!("> {line}");
|
println!("{dark_grey}{body_prefix}{reset} {line}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
@ -382,13 +392,13 @@ impl RepoCommand {
|
||||||
|
|
||||||
let stars = repo.stars_count.unwrap_or_default();
|
let stars = repo.stars_count.unwrap_or_default();
|
||||||
if stars == 1 {
|
if stars == 1 {
|
||||||
print!("{stars} star - ");
|
print!("{stars} star {dash} ");
|
||||||
} else {
|
} else {
|
||||||
print!("{stars} stars - ");
|
print!("{stars} stars {dash} ");
|
||||||
}
|
}
|
||||||
|
|
||||||
let watchers = repo.watchers_count.unwrap_or_default();
|
let watchers = repo.watchers_count.unwrap_or_default();
|
||||||
print!("{watchers} watching - ");
|
print!("{watchers} watching {dash} ");
|
||||||
|
|
||||||
let forks = repo.forks_count.unwrap_or_default();
|
let forks = repo.forks_count.unwrap_or_default();
|
||||||
if forks == 1 {
|
if forks == 1 {
|
||||||
|
@ -410,7 +420,7 @@ impl RepoCommand {
|
||||||
}
|
}
|
||||||
if repo.has_pull_requests.unwrap_or_default() {
|
if repo.has_pull_requests.unwrap_or_default() {
|
||||||
if !first {
|
if !first {
|
||||||
print!(" - ");
|
print!(" {dash} ");
|
||||||
}
|
}
|
||||||
let pulls = repo.open_pr_counter.unwrap_or_default();
|
let pulls = repo.open_pr_counter.unwrap_or_default();
|
||||||
if pulls == 1 {
|
if pulls == 1 {
|
||||||
|
@ -422,7 +432,7 @@ impl RepoCommand {
|
||||||
}
|
}
|
||||||
if repo.has_releases.unwrap_or_default() {
|
if repo.has_releases.unwrap_or_default() {
|
||||||
if !first {
|
if !first {
|
||||||
print!(" - ");
|
print!(" {dash} ");
|
||||||
}
|
}
|
||||||
let releases = repo.release_counter.unwrap_or_default();
|
let releases = repo.release_counter.unwrap_or_default();
|
||||||
if releases == 1 {
|
if releases == 1 {
|
||||||
|
|
Loading…
Reference in a new issue