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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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_with_multifuzz_ratio, is_prefix, FuzzResult};
use crate::path;
use crate::script_repo::RepoEntry;
use crate::SEP;
use std::cmp::Reverse;
use structopt::StructOpt;
fn sort(v: &mut Vec<RepoEntry<'_>>) {
v.sort_by_key(|s| Reverse(s.last_time()));
}
fn parse_alias_root(args: &[String]) -> Result<AliasRoot> {
match AliasRoot::from_iter_safe(args) {
Ok(root) => Ok(root),
Err(e) => {
log::warn!("展開別名時出錯 {}", e);
Err(Error::Completion)
}
}
}
async fn fuzz_arr<'a>(
name: &str,
iter: impl Iterator<Item = RepoEntry<'a>>,
) -> Result<Vec<RepoEntry<'a>>> {
let res = fuzz_with_multifuzz_ratio(name, iter, SEP, 0.6).await?;
Ok(match res {
None => vec![],
Some(FuzzResult::High(t) | FuzzResult::Low(t)) => vec![t],
Some(FuzzResult::Multi {
ans,
others,
mut still_others,
}) => {
let prefix = ans.name.key();
let mut first_others = vec![];
let mut prefixed_others = vec![];
for candidate in others.into_iter() {
if is_prefix(&*prefix, &*candidate.name.key(), SEP) {
prefixed_others.push(candidate);
} else {
first_others.push(candidate);
}
}
first_others.push(ans);
sort(&mut first_others);
sort(&mut prefixed_others);
sort(&mut still_others);
first_others.append(&mut prefixed_others);
first_others.append(&mut still_others);
first_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(_)),
..
}) => {
return Err(Error::Completion);
}
Ok(t) => t,
Err(e) => {
log::warn!("補全時出錯 {}", e);
return Err(Error::Completion);
}
};
log::info!("補完模式,參數為 {:?}", new_root);
new_root.set_home_unless_from_alias()?;
new_root.sanitize_flags();
let mut repo = init_repo(new_root.root_args, false).await?;
let iter = repo.iter_mut(false);
let scripts = if let Some(name) = name {
fuzz_arr(&name, iter).await?
} else {
let mut t: Vec<_> = iter.collect();
sort(&mut t);
t
};
print_iter(scripts.iter().map(|s| s.name.key()), " ");
Ok(())
}
Completion::Alias { args } => {
let root = parse_alias_root(&args)?;
let home = path::compute_home_path_optional(root.root_args.hs_home.as_ref())?;
let conf = Config::load(&home)?;
if let Some(new_args) = root.expand_alias(&args, &conf) {
print_iter(new_args, " ");
} else {
print_iter(args.iter(), " ");
}
Ok(())
}
Completion::Home { args } => {
let root = parse_alias_root(&args)?;
let home = root.root_args.hs_home.ok_or_else(|| Error::Completion)?;
print!("{}", home);
Ok(())
}
}
}