Skip to content

Commit

Permalink
Overhaul the list subcommand (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
filiptibell authored Jun 15, 2024
1 parent 9387868 commit 33d6606
Showing 1 changed file with 73 additions and 40 deletions.
113 changes: 73 additions & 40 deletions src/cli/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,29 @@ use anyhow::Result;
use clap::Parser;
use console::style;

use rokit::{storage::Home, tool::ToolId};
use rokit::{discovery::discover_all_manifests, storage::Home, system::current_dir, tool::ToolId};

/// Lists all existing tools managed by Rokit.
#[derive(Debug, Parser)]
pub struct ListSubcommand {
/// A specific tool identifier to list versions for.
/// A specific tool identifier to list installed versions for.
pub id: Option<ToolId>,
}

impl ListSubcommand {
pub async fn run(self, home: &Home) -> Result<()> {
let no_tools_installed = home.tool_cache().all_installed_ids().is_empty();

let (header, lines) = if no_tools_installed {
list_versions_for_empty(home)
} else if let Some(id) = self.id {
let (header, lines) = if let Some(id) = self.id {
list_versions_for_id(home, &id)
} else {
list_versions_for_all(home)
list_versions(home).await
};

println!(
"{header}{}{}",
if lines.is_empty() { "\n" } else { "\n\n" },
lines.join("\n")
);
println!("{header}\n{}", lines.join("\n"));

Ok(())
}
}

// No tools are installed - just print out a message
fn list_versions_for_empty(_home: &Home) -> (String, Vec<String>) {
let header = String::from("🛠️ No tools are installed.");
(header, Vec::new())
}

// Lists all versions for a specific tool - if it is installed
fn list_versions_for_id(home: &Home, id: &ToolId) -> (String, Vec<String>) {
let cache = home.tool_cache();
Expand All @@ -60,27 +46,74 @@ fn list_versions_for_id(home: &Home, id: &ToolId) -> (String, Vec<String>) {
}
}

// Lists all versions for all installed tools
fn list_versions_for_all(home: &Home) -> (String, Vec<String>) {
let cache = home.tool_cache();
let tools = cache
.all_installed_ids()
.into_iter()
.map(|id| (id.clone(), cache.all_installed_versions_for_id(&id)))
.collect::<Vec<_>>();
// Lists versions for the current manifest, and the global manifest
async fn list_versions(home: &Home) -> (String, Vec<String>) {
let cwd = current_dir().await;
let manifests = discover_all_manifests(true, false).await;

let header = String::from("🛠️ All installed tools:");
let bullet = style("•").dim();
let lines = tools
.into_iter()
.flat_map(|(id, mut versions)| {
versions.reverse(); // List newest versions first
let mut lines = vec![id.to_string()];
for version in versions {
lines.push(format!(" {bullet} {version}"));
}
lines
})
.collect();
(header, lines)
let arrow = style("→").dim();
let at = style("@").dim();

let mut manifest_lines = Vec::new();
for manifest in manifests {
let mut sorted_tools = manifest.tools.into_iter().collect::<Vec<_>>();
sorted_tools.sort_by(|(alias_a, _), (alias_b, _)| alias_a.name().cmp(alias_b.name()));
if sorted_tools.is_empty() {
continue;
}

let longest_alias_len = sorted_tools
.iter()
.map(|(alias, _)| alias.name().len())
.max()
.unwrap_or(0);
let longest_id_len = sorted_tools
.iter()
.map(|(_, spec)| spec.id().to_string().len())
.max()
.unwrap_or(0);

let mut lines = Vec::new();
for (alias, spec) in sorted_tools {
lines.push(format!(
"{bullet} {}{} {arrow} {} {}{at} {}",
style(alias.name()).bold().cyan(),
" ".repeat(longest_alias_len - alias.name().len()),
spec.id(),
" ".repeat(longest_id_len - spec.id().to_string().len()),
spec.version(),
));
}

if lines.is_empty() {
continue;
}

lines.sort();
manifest_lines.push((manifest.path, lines));
}

let mut lines = vec![];
for (index, (path, mlines)) in manifest_lines.iter().enumerate() {
if let Ok(stripped) = path.strip_prefix(home.path()) {
lines.push(format!("~/.rokit/{}", stripped.display()));
} else if let Ok(stripped) = path.strip_prefix(&cwd) {
lines.push(format!("./{}", stripped.display()));
} else {
lines.push(path.display().to_string());
}
lines.extend_from_slice(mlines);
if index < manifest_lines.len() - 1 {
lines.push(String::new()); // Add a newline between manifests
}
}

if lines.is_empty() {
let header = String::from("🛠️ No tools found.");
(header, Vec::new())
} else {
let header = String::from("🛠️ Found tools:\n");
(header, lines)
}
}

0 comments on commit 33d6606

Please sign in to comment.