pub mod completion;
pub mod critique;
pub mod db;
pub mod events;
pub mod fetch;
pub mod init;
pub mod insights;
pub mod milestone;
pub mod next;
pub mod overlaps;
pub mod problem;
pub mod push;
pub mod rank;
pub mod search;
pub mod solution;
pub mod status;
pub mod sync;
pub mod tags;
pub mod timeline;
pub mod ui;
use crate::cli::{Cli, Commands};
use crate::context::CommandContext;
use crate::db::{search as db_search, Database};
use crate::display::short_id;
use crate::error::Result;
pub fn execute(cli: Cli) -> Result<()> {
match cli.command {
Commands::Init => init::execute(),
Commands::Ui => ui::execute(),
Commands::Completion { shell } => completion::execute(shell),
_ => {
let ctx = CommandContext::new()?;
execute_with_context(&ctx, cli.command)
}
}
}
fn execute_with_context(ctx: &CommandContext, command: Commands) -> Result<()> {
match command {
Commands::Problem { action } => problem::execute(ctx, action),
Commands::Solution { action } => solution::execute(ctx, action),
Commands::Critique { action } => critique::execute(ctx, action),
Commands::Milestone { action } => milestone::execute(ctx, action),
Commands::Status {
all,
mine,
limit,
json,
} => status::execute(ctx, all, mine, limit, json),
Commands::Next {
top,
mine,
json,
claim,
} => next::execute(ctx, top, mine, json, claim),
Commands::Overlaps { json } => overlaps::execute(ctx, json),
Commands::Insights { json } => insights::execute(ctx, json),
Commands::Fetch { remote } => fetch::execute(ctx, &remote),
Commands::Push {
bookmarks,
remote,
no_prompt,
dry_run,
} => push::execute(ctx, bookmarks, &remote, no_prompt, dry_run),
Commands::Sync {
remote,
no_prompt,
dry_run,
} => {
fetch::execute(ctx, &remote)?;
push::execute(ctx, vec![], &remote, no_prompt, dry_run)
}
Commands::Github { action, dry_run } => sync::execute(ctx, action, dry_run),
Commands::Init | Commands::Ui | Commands::Completion { .. } => {
unreachable!("These commands should be handled in execute()")
}
Commands::Events {
action,
from,
to,
problem,
solution,
event_type,
search,
since,
json,
limit,
} => events::execute(
ctx, action, from, to, problem, solution, event_type, search, since, json, limit,
),
Commands::Timeline { problem_id, json } => timeline::execute(ctx, problem_id, json),
Commands::Tags { json } => tags::execute(ctx, json),
Commands::Rank { action } => rank::execute(ctx, action),
Commands::Search {
query,
r#type,
text_only,
json,
} => search::execute(ctx, &query, r#type.as_deref(), text_only, json),
Commands::Db { action } => db::execute(ctx, action),
}
}
pub(crate) fn show_related_items(
ctx: &CommandContext,
entity_type: &str,
entity_id: &str,
) -> Result<()> {
let jj_client = ctx.jj();
let repo_root = jj_client.repo_root();
let db_path = repo_root.join(".jj").join("jjj.db");
if !db_path.exists() {
return Ok(());
}
let db = Database::open(&db_path)?;
let conn = db.conn();
let has_embedding =
crate::db::embeddings::load_embedding(conn, entity_type, entity_id)?.is_some();
if !has_embedding {
return Ok(());
}
let results = db_search::find_similar(conn, entity_type, entity_id, None, 5)?;
if results.is_empty() {
return Ok(());
}
let results: Vec<_> = results.into_iter().filter(|r| r.similarity > 0.5).collect();
if results.is_empty() {
return Ok(());
}
println!("\n{}", "─".repeat(50));
println!("\nRelated:");
for result in results {
let type_prefix = result.entity_type.chars().next().unwrap_or('?');
println!(
" {}/{} [{:.2}] \"{}\"",
type_prefix,
short_id(&result.entity_id),
result.similarity,
truncate_title(&result.title, 50)
);
}
Ok(())
}
pub(crate) fn truncate_title(s: &str, max_len: usize) -> String {
crate::utils::truncate(s, max_len)
}