soroban-cli 26.0.0

Soroban CLI
Documentation
use serde::{Deserialize, Serialize};
use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

use crate::{commands::global, print::Print, utils::http};

use super::super::config::locator;

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error(transparent)]
    Config(#[from] locator::Error),

    #[error("unable to retrieve the list of plugins from GitHub")]
    Http(#[from] reqwest::Error),

    #[error(transparent)]
    Io(#[from] std::io::Error),
}

#[derive(Debug, clap::Parser, Clone)]
#[group(skip)]
pub struct Cmd;

impl Cmd {
    pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
        let print = Print::new(global_args.quiet);
        let url =
            "https://api.github.com/search/repositories?q=topic%3Astellar-cli-plugin+fork%3Afalse+archived%3Afalse&per_page=100&sort=stars&order=desc";

        let resp = http::client().get(url).send().await?;
        let search: SearchResponse = resp.json().await?;

        if search.total_count == 0 {
            print.searchln("No plugins found.".to_string());
            return Ok(());
        }

        let wording = if search.total_count == 1 {
            "plugin"
        } else {
            "plugins"
        };

        print.searchln(format!(
            "Found {total} {wording}:",
            total = search.total_count
        ));

        let mut stdout = StandardStream::stdout(ColorChoice::Auto);

        for item in search.items {
            println!();
            stdout.set_color(ColorSpec::new().set_fg(Some(Color::Blue)))?;
            writeln!(&mut stdout, "  {}", item.full_name)?;
            stdout.reset()?;

            if let Some(description) = item.description {
                writeln!(&mut stdout, "  {description}")?;
            }

            print.blankln(item.html_url.clone());
        }
        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize)]
struct SearchResponse {
    total_count: u32,
    incomplete_results: bool,
    items: Vec<Repository>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Repository {
    id: u64,
    name: String,
    full_name: String,
    html_url: String,
    description: Option<String>,
}