1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use super::{init_repo, print_iter};
use crate::args::{AliasRoot, Completion, Root, Subs};
use crate::config::Config;
use crate::error::{Error, Result};
use crate::fuzzy::{fuzz, FuzzResult};
use crate::path;
use crate::script_repo::{RepoEntry, ScriptRepo};
use std::cmp::Reverse;
use structopt::StructOpt;

async fn fuzz_arr<'a>(name: &str, repo: &'a mut ScriptRepo) -> Result<Vec<RepoEntry<'a>>> {
    let res = fuzz(name, repo.iter_mut(false), "/").await?;
    Ok(match res {
        None => vec![],
        Some(FuzzResult::High(t) | FuzzResult::Low(t)) => vec![t],
        Some(FuzzResult::Multi { ans, mut others }) => {
            others.push(ans);
            others
        }
    })
}

pub async fn handle_completion(comp: Completion) -> Result {
    match comp {
        Completion::LS { name, args } => {
            let mut new_root = match Root::from_iter_safe(args) {
                Ok(Root {
                    subcmd: Some(Subs::Tags(_)),
                    ..
                }) => {
                    // TODO: 在補全腳本中處理,而不要在這邊
                    return Err(Error::Completion);
                }
                Ok(t) => t,
                Err(e) => {
                    log::warn!("補全時出錯 {}", e);
                    // NOTE: -V 或 --help 也會走到這裡
                    return Err(Error::Completion);
                }
            };
            log::info!("補完模式,參數為 {:?}", new_root);
            new_root.set_home_unless_set()?;
            new_root.sanitize_flags();
            let mut repo = init_repo(new_root.root_args, false).await?;

            let mut scripts = if let Some(name) = name {
                fuzz_arr(&name, &mut repo).await?
            } else {
                repo.iter_mut(false).collect()
            };

            scripts.sort_by_key(|s| Reverse(s.last_time()));
            print_iter(scripts.iter().map(|s| s.name.key()), " ");

            Ok(())
        }
        Completion::Alias { args } => {
            match AliasRoot::from_iter_safe(&args) {
                Ok(alias_root) => {
                    fn print_iter<T: std::fmt::Display>(iter: impl Iterator<Item = T>) {
                        for arg in iter {
                            print!("{} ", arg);
                        }
                    }

                    let p =
                        path::compute_home_path_optional(alias_root.root_args.hs_home.as_ref())?;
                    let conf = Config::load(&p)?;
                    if let Some(new_args) = alias_root.expand_alias(&args, &conf) {
                        print_iter(new_args);
                    } else {
                        print_iter(args.iter());
                    };
                    Ok(())
                }
                Err(e) => {
                    log::warn!("展開別名時出錯 {}", e);
                    // NOTE: -V 或 --help 也會走到這裡
                    Err(Error::Completion)
                }
            }
        }
    }
}