Skip to main content

track/cli/handlers/
completion.rs

1use crate::cli::handlers::CommandCtx;
2use crate::cli::CompletionType;
3use crate::models::TodoStatus;
4use crate::services::{LinkService, RepoService, TaskService, TodoService};
5use crate::utils::Result;
6
7pub fn handle_completion(
8    _ctx: &CommandCtx,
9    shell: clap_complete::Shell,
10    dynamic: bool,
11) -> Result<()> {
12    use clap::CommandFactory;
13    use clap_complete::generate;
14    use std::io;
15
16    if dynamic {
17        // Output dynamic completion script
18        let script = match shell {
19            clap_complete::Shell::Bash => {
20                include_str!("../../../completions/track.bash.dynamic")
21            }
22            clap_complete::Shell::Zsh => {
23                include_str!("../../../completions/_track.dynamic")
24            }
25            _ => {
26                eprintln!("Dynamic completions are only available for bash and zsh.");
27                eprintln!("Falling back to static completions for {:?}.", shell);
28                let mut cmd = crate::cli::Cli::command();
29                let bin_name = cmd.get_name().to_string();
30                generate(shell, &mut cmd, bin_name, &mut io::stdout());
31                return Ok(());
32            }
33        };
34        print!("{}", script);
35    } else {
36        // Generate static completion using clap_complete
37        let mut cmd = crate::cli::Cli::command();
38        let bin_name = cmd.get_name().to_string();
39        generate(shell, &mut cmd, bin_name, &mut io::stdout());
40    }
41
42    Ok(())
43}
44
45pub fn handle_complete(ctx: &CommandCtx, completion_type: CompletionType) -> Result<()> {
46    match completion_type {
47        CompletionType::Tasks => {
48            // Output task IDs and names for 'track switch'
49            let task_service = TaskService::new(ctx.db);
50            let tasks = task_service.list_tasks(false)?; // Don't include archived
51
52            for task in tasks {
53                // Format: ID:Name (or ID:Ticket:Name if ticket exists)
54                if let Some(ticket) = &task.ticket_id {
55                    println!("{}:{}:{}", task.id, ticket, task.name);
56                } else {
57                    println!("{}:{}", task.id, task.name);
58                }
59            }
60        }
61        CompletionType::Todos => {
62            // Output TODO IDs and content for current task
63            let current_task_id = ctx.db.get_current_task_id()?;
64            if let Some(task_id) = current_task_id {
65                let todo_service = TodoService::new(ctx.db);
66                let todos = todo_service.list_todos(task_id)?;
67
68                for todo in todos {
69                    // Only show pending todos
70                    if todo.status == TodoStatus::Pending {
71                        // Format: ID:Content
72                        println!("{}:{}", todo.task_index, todo.content);
73                    }
74                }
75            }
76        }
77        CompletionType::Links => {
78            // Output link IDs and URLs for current task
79            let current_task_id = ctx.db.get_current_task_id()?;
80            if let Some(task_id) = current_task_id {
81                let link_service = LinkService::new(ctx.db);
82                let links = link_service.list_links(task_id)?;
83
84                for link in links {
85                    // Format: ID:Title:URL
86                    println!("{}:{}:{}", link.task_index, link.title, link.url);
87                }
88            }
89        }
90        CompletionType::Repos => {
91            // Output repo IDs and paths for current task
92            let current_task_id = ctx.db.get_current_task_id()?;
93            if let Some(task_id) = current_task_id {
94                let repo_service = RepoService::new(ctx.db);
95                let repos = repo_service.list_repos(task_id)?;
96
97                for repo in repos {
98                    // Format: ID:Path
99                    println!("{}:{}", repo.task_index, repo.repo_path);
100                }
101            }
102        }
103    }
104
105    Ok(())
106}