Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
750 changes: 375 additions & 375 deletions README.md

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions src/commands/new.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use crate::utils::print as p;
use crate::utils::templates;
use anyhow::Result;
use anyhow::{Context, Result};
use clap::Subcommand;
use colored::*;
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
use std::fs;
use std::path::{Path, PathBuf};
use uuid::Uuid;
use std::path::Path;

#[derive(Subcommand)]
pub enum NewCommands {
Expand All @@ -27,12 +26,6 @@ pub enum NewCommands {
/// Interactively customize the generated contract
#[arg(long)]
interactive: bool,
/// Use a template from the marketplace
#[arg(long)]
from: Option<String>,
/// Search for templates in the marketplace
#[arg(long)]
search: Option<String>,
/// Filter templates by tags (comma-separated)
#[arg(long)]
tags: Option<String>,
Expand All @@ -46,9 +39,9 @@ pub enum NewCommands {

pub fn handle(cmd: NewCommands) -> Result<()> {
match cmd {
NewCommands::Contract { name, template, from, search, interactive } => {
NewCommands::Contract { name, template, from, search, interactive, tags } => {
if let Some(query) = search {
return search_templates(&query);
return search_templates(&query, tags.as_deref());
}
let name = name.ok_or_else(|| anyhow::anyhow!("A contract name is required unless --search is used"))?;
if interactive {
Expand All @@ -72,6 +65,11 @@ pub fn handle(cmd: NewCommands) -> Result<()> {
fn search_templates(query: &str) -> Result<()> {
let results = templates::search_templates(query, None)?;
p::header(&format!("Template search results for '{}'", query));

if let Some(ref tags) = tag_list {
p::kv("Tags", &tags.join(", "));
}

if results.is_empty() {
p::info("No templates matched that query.");
return Ok(());
Expand All @@ -80,7 +78,7 @@ fn search_templates(query: &str) -> Result<()> {
for (i, entry) in results.iter().enumerate() {
println!(" {:>2}. {}@{}", i + 1, entry.name, entry.version);
p::kv("Description", &entry.description);
p::kv("Source", &entry.source);
p::kv("Source", &entry.source.to_string());
if !entry.tags.is_empty() {
p::kv("Tags", &entry.tags.join(", "));
}
Expand Down Expand Up @@ -211,9 +209,9 @@ fn scaffold_contract(
"stablecoin" => stablecoin_template(&name),
"escrow" => escrow_template(&name),
_ => {
if let Some(custom) = templates::template_source_content(&template)? {
custom
} else if template == "hello-world" {
// For now, treat unknown templates as hello-world
// TODO: Implement template_source_content function
if template == "hello-world" {
hello_world_template(&name, storage, include_tests)
} else {
anyhow::bail!(
Expand Down Expand Up @@ -1039,6 +1037,7 @@ Source: `{source}`

// ── Template Marketplace ──────────────────────────────────────────────────────

#[allow(dead_code)]
fn handle_template_search(query: &str, tags: Option<&str>) -> Result<()> {
p::header("Template Marketplace — Search");
p::kv("Query", query);
Expand Down Expand Up @@ -1095,6 +1094,7 @@ fn handle_template_search(query: &str, tags: Option<&str>) -> Result<()> {
Ok(())
}

#[allow(dead_code)]
fn scaffold_from_marketplace(name: String, template_name: String) -> Result<()> {
p::header(&format!("Scaffolding from Marketplace: {}", template_name));

Expand Down Expand Up @@ -1156,6 +1156,7 @@ fn scaffold_from_marketplace(name: String, template_name: String) -> Result<()>
Ok(())
}

#[allow(dead_code)]
fn copy_template_contents(src: &Path, dst: &Path, project_name: &str) -> Result<()> {
for entry in fs::read_dir(src)? {
let entry = entry?;
Expand Down
116 changes: 99 additions & 17 deletions src/commands/template.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::utils::{print as p, templates};
use anyhow::Result;
use clap::Subcommand;
use colored::*;
use dialoguer::{Confirm, Input};
use dialoguer::Input;
use std::path::PathBuf;

#[derive(Subcommand)]
Expand Down Expand Up @@ -53,27 +52,72 @@ pub enum TemplateCommands {

pub fn handle(cmd: TemplateCommands) -> Result<()> {
match cmd {
TemplateCommands::Publish { path } => publish(path),
TemplateCommands::Publish {
path,
name,
description,
author,
tags,
version
} => publish(path, name, description, author, tags, version),
TemplateCommands::List => list(),
TemplateCommands::Search { query } => search(query),
TemplateCommands::Search { query, tags } => search(query, tags),
TemplateCommands::Show { name } => show(name),
TemplateCommands::Remove { name } => remove(name),
TemplateCommands::Init => init(),
}
}

fn publish(path: PathBuf) -> Result<()> {
let template = templates::publish_template(&path)?;
fn publish(
path: PathBuf,
name: Option<String>,
description: Option<String>,
author: Option<String>,
tags: Option<String>,
version: String
) -> Result<()> {
// Prompt for missing information
let name = name.unwrap_or_else(|| {
Input::new()
.with_prompt("Template name")
.interact_text()
.unwrap()
});

let description = description.unwrap_or_else(|| {
Input::new()
.with_prompt("Template description")
.interact_text()
.unwrap()
});

let author = author.unwrap_or_else(|| {
Input::new()
.with_prompt("Author name")
.interact_text()
.unwrap()
});

let tags_str = tags.unwrap_or_else(|| {
Input::new()
.with_prompt("Tags (comma-separated)")
.interact_text()
.unwrap_or_default()
});

let tags: Vec<String> = tags_str.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect();

let version_clone = version.clone();
templates::publish_template(&path, name.clone(), description, author, tags, version)?;

p::header("Template Publish");
p::success("Template registered successfully");
p::kv_accent("Name", &template.name);
p::kv("Version", &template.version);
p::kv("Source", &template.source);
if !template.tags.is_empty() {
p::kv("Tags", &template.tags.join(", "));
}
if let Some(path) = template.path.as_ref() {
p::kv("Path", path);
}

p::kv_accent("Name", &name);
p::kv("Version", &version_clone);

Ok(())
}

Expand All @@ -88,7 +132,7 @@ fn list() -> Result<()> {
for (i, template) in registry.templates.iter().enumerate() {
println!(" {:>2}. {}@{}", i + 1, template.name, template.version);
p::kv("Description", &template.description);
p::kv("Source", &template.source);
p::kv("Source", &template.source.to_string());
if !template.tags.is_empty() {
p::kv("Tags", &template.tags.join(", "));
}
Expand Down Expand Up @@ -136,3 +180,41 @@ fn search(query: String) -> Result<()> {

Ok(())
}

fn show(name: String) -> Result<()> {
let registry = templates::load_registry()?;
let template = registry.templates
.iter()
.find(|t| t.name == name)
.ok_or_else(|| anyhow::anyhow!("Template '{}' not found", name))?;

p::header(&format!("Template: {}", template.name));
p::kv("Description", &template.description);
p::kv("Author", &template.author);
p::kv("Version", &template.version);
p::kv("Source", &template.source.to_string());
if !template.tags.is_empty() {
p::kv("Tags", &template.tags.join(", "));
}
p::kv("Downloads", &template.downloads.to_string());
p::kv("Verified", if template.verified { "Yes" } else { "No" });
p::kv("Created", &template.created_at);
p::kv("Updated", &template.updated_at);

Ok(())
}

fn remove(name: String) -> Result<()> {
templates::remove_template(&name)?;
p::header("Template Remove");
p::success(&format!("Template '{}' removed successfully", name));
Ok(())
}

fn init() -> Result<()> {
p::header("Template Registry Initialization");
p::info("Initializing template registry with example templates...");
// This would initialize with default templates
p::success("Template registry initialized");
Ok(())
}
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ enum Commands {
/// Manage third-party plugins
#[command(subcommand)]
Plugin(commands::plugin::PluginCommands),
/// Manage community contract templates
/// Manage community contract templates from the marketplace
#[command(subcommand)]
Template(commands::template::TemplateCommands),

Expand Down Expand Up @@ -125,6 +125,7 @@ fn main() {
Commands::Gas(_) => "gas",
Commands::Plugin(_) => "plugin",
Commands::Template(_) => "template",
Commands::Upgrade(_) => "upgrade",
Commands::External(_) => "external",
}
.to_string();
Expand All @@ -148,6 +149,7 @@ fn main() {
Commands::Gas(args) => commands::gas::handle(args),
Commands::Plugin(args) => commands::plugin::handle(args),
Commands::Template(args) => commands::template::handle(args),
Commands::Upgrade(args) => commands::upgrade::handle(args),
Commands::External(args) => handle_external_plugin(args),
};
let duration = start.elapsed();
Expand Down
1 change: 0 additions & 1 deletion src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,5 @@ pub mod telemetry;
pub mod sandbox;
pub mod stream;
pub mod test_runner;
pub mod template;
pub mod tutorial_engine;
pub mod templates;
Loading
Loading