proto_cli 0.59.0

A multi-language version manager, a unified toolchain.
use crate::session::{ProtoSession, SessionResult};
use clap::Args;
use iocraft::prelude::{FlexDirection, Size, Text, View, element};
use proto_core::PluginLocator;
use proto_core::registry::PluginFormat;
use proto_core::reporter::NoticeOutput;
use starbase_console::ui::*;
use tracing::instrument;

#[derive(Args, Clone, Debug)]
pub struct PluginSearchArgs {
    #[arg(required = true, help = "Query to search available plugins")]
    query: String,
}

#[instrument(skip(session))]
pub async fn search(session: ProtoSession, args: PluginSearchArgs) -> SessionResult {
    let mut registry = session.create_registry();
    let plugins = registry.load_external_plugins().await?;

    let query = &args.query;
    let queried_plugins = plugins
        .into_iter()
        .filter(|data| {
            data.id.as_str().contains(query)
                || data.name.contains(query)
                || data.description.contains(query)
        })
        .collect::<Vec<_>>();

    if session.is_json_format() {
        session.console.write_json_for_format(queried_plugins)?;

        return Ok(None);
    }

    if queried_plugins.is_empty() {
        session.console.notice_with(NoticeOutput {
            variant: Variant::Caution,
            title: Some("No results".into()),
            messages: vec![
                format!(
                    "Please try again, there are no plugins found in the registry for the query <shell>{query}</shell>"
                ),
            ],
            ..Default::default()
        })?;

        return Ok(Some(1));
    }

    let (name_width, author_width) = queried_plugins.iter().fold((0, 0), |acc, plugin| {
        (
            acc.0.max(plugin.name.len()),
            acc.1.max(plugin.author.get_name().len()),
        )
    });

    session.console.render(element! {
        Container {
            View(padding_top: 1, padding_left: 1, flex_direction: FlexDirection::Column) {
                StyledText(
                    content: format!("Search results for: <label>{query}</label>"),
                )
                StyledText(
                    content: "Learn more about plugins: <url>https://moonrepo.dev/docs/proto/plugins</url>"
                )
            }
            Table(
                headers: vec![
                    TableHeader::new("Plugin", Size::Length(name_width.max(6) as u32)),
                    TableHeader::new("Author", Size::Length(author_width.max(6) as u32)),
                    TableHeader::new("Format", Size::Length(6)),
                    TableHeader::new("Description", Size::Percent(30.0)),
                    TableHeader::new("Locator", Size::Auto),
                ]
            ) {
                #(queried_plugins.into_iter().enumerate().map(|(i, plugin)| {
                    element! {
                        TableRow(row: i as i32) {
                            TableCol(col: 0) {
                                StyledText(
                                    content: &plugin.name,
                                    style: Style::Id
                                )
                            }
                            TableCol(col: 1) {
                                Text(
                                    content: plugin.author.get_name()
                                )
                            }
                            TableCol(col: 2) {
                                Text(
                                    content: match plugin.format {
                                        PluginFormat::Json => "JSON",
                                        PluginFormat::Toml => "TOML",
                                        PluginFormat::Wasm => "WASM",
                                        PluginFormat::Yaml => "YAML",
                                    }
                                )
                            }
                            TableCol(col: 3) {
                                Text(content: &plugin.description)
                            }
                            TableCol(col: 4) {
                                StyledText(
                                    content: plugin.locator.to_string(),
                                    style: match plugin.locator {
                                        PluginLocator::File(_) => Style::Path,
                                        PluginLocator::Url(_) => Style::Url,
                                        _ => Style::File,
                                    }
                                )
                            }
                        }
                    }
                }))
            }
            View(padding_bottom: 1, padding_left: 1, flex_direction: FlexDirection::Row) {
                StyledText(
                    content: "Find a plugin above that you want to use? Enable it with: ",
                )
                StyledText(
                    content: "proto plugin add [id] [locator]",
                    style: Style::Shell
                )
            }
        }
    })?;

    Ok(None)
}