hyper_scripter/util/
completion_util.rs1use super::{init_repo, print_iter};
2use crate::args::{AliasRoot, Completion, Root, Subs};
3use crate::config::Config;
4use crate::error::{Error, Result};
5use crate::fuzzy::{fuzz_with_multifuzz_ratio, is_prefix, FuzzResult};
6use crate::path;
7use crate::script_repo::{RepoEntry, ScriptRepo, Visibility};
8use crate::SEP;
9use crate::{to_display_args, Either};
10use clap::Parser;
11use std::cmp::Reverse;
12
13fn sort(v: &mut Vec<RepoEntry<'_>>) {
14 v.sort_by_key(|s| Reverse(s.last_time()));
15}
16
17fn parse_alias_root(args: &[String]) -> Result<AliasRoot> {
18 match AliasRoot::try_parse_from(args) {
19 Ok(root) => Ok(root),
20 Err(e) => {
21 log::warn!("展開別名時出錯 {}", e);
22 Err(Error::Completion)
24 }
25 }
26}
27
28async fn fuzz_arr<'a>(
29 name: &str,
30 iter: impl Iterator<Item = RepoEntry<'a>>,
31) -> Result<Vec<RepoEntry<'a>>> {
32 let res = fuzz_with_multifuzz_ratio(name, iter, SEP, Some(60)).await?;
34 Ok(match res {
35 None => vec![],
36 Some(FuzzResult::High(t) | FuzzResult::Low(t)) => vec![t],
37 Some(FuzzResult::Multi {
38 ans,
39 others,
40 mut still_others,
41 }) => {
42 let prefix = ans.name.key();
43 let mut first_others = vec![];
44 let mut prefixed_others = vec![];
45 for candidate in others.into_iter() {
46 if is_prefix(&*prefix, &*candidate.name.key(), SEP) {
47 prefixed_others.push(candidate);
48 } else {
49 first_others.push(candidate);
50 }
51 }
52 first_others.push(ans);
53
54 sort(&mut first_others);
55 sort(&mut prefixed_others);
56 sort(&mut still_others);
57 first_others.append(&mut prefixed_others);
58 first_others.append(&mut still_others);
59 first_others
60 }
61 })
62}
63
64pub async fn handle_completion(comp: Completion, repo: &mut Option<ScriptRepo>) -> Result {
65 match comp {
66 Completion::LS {
67 name,
68 args,
69 limit,
70 bang,
71 } => {
72 let mut new_root = match Root::try_parse_from(args) {
73 Ok(Root {
74 subcmd: Some(Subs::Tags(_) | Subs::Types(_) | Subs::Alias { before: None, .. }),
75 ..
76 }) => {
77 return Err(Error::Completion);
79 }
80 Ok(t) => t,
81 Err(e) => {
82 log::warn!("補全時出錯 {}", e);
83 return Err(Error::Completion);
85 }
86 };
87 log::info!("補完模式,參數為 {:?}", new_root);
88 new_root.set_home_unless_from_alias(false)?;
89 new_root.sanitize_flags(bang);
90 *repo = Some(init_repo(new_root.root_args, false).await?);
91
92 let iter = repo.as_mut().unwrap().iter_mut(Visibility::Normal);
93 let scripts = if let Some(name) = name {
94 fuzz_arr(&name, iter).await?
95 } else {
96 let mut t: Vec<_> = iter.collect();
97 sort(&mut t);
98 t
99 };
100
101 let iter = scripts.iter().map(|s| s.name.key());
102 if let Some(limit) = limit {
103 print_iter(iter.take(limit.get()), " ");
104 } else {
105 print_iter(iter, " ");
106 }
107 }
108 Completion::NoSubcommand { args } => {
109 if let Ok(root) = parse_alias_root(&args) {
110 if root.subcmd.is_some() {
111 log::debug!("子命令 = {:?}", root.subcmd);
112 return Err(Error::Completion);
113 }
114 } }
116 Completion::Alias { args } => {
117 let root = parse_alias_root(&args)?;
118
119 if root.root_args.no_alias {
120 log::info!("無別名模式");
121 return Err(Error::Completion);
122 }
123
124 let home = path::compute_home_path_optional(root.root_args.hs_home.as_ref(), false)?;
125 let conf = Config::load(&home)?;
126 if let Some(Either::One(new_args)) = root.expand_alias(&args, &conf) {
127 print_iter(new_args, " ");
128 } else {
129 log::info!("並非別名");
130 return Err(Error::Completion);
131 };
132 }
133 Completion::Home { args } => {
134 let root = parse_alias_root(&args)?;
135 let home = root.root_args.hs_home.ok_or_else(|| Error::Completion)?;
136 print!("{}", home);
137 }
138 Completion::ParseRun { args } => {
139 let mut root = Root::try_parse_from(args).map_err(|e| {
140 log::warn!("補全時出錯 {}", e);
141 Error::Completion
142 })?;
143 root.sanitize()?;
144 match root.subcmd {
145 Some(Subs::Run {
146 script_query, args, ..
147 }) => {
148 print!("{}", script_query);
149 for arg in args {
150 print!(" {}", to_display_args(&arg));
151 }
152 }
153 res @ _ => {
154 log::warn!("非執行指令 {:?}", res);
155 return Err(Error::Completion);
156 }
157 }
158 }
159 }
160 Ok(())
161}