pub struct Config {
    pub recent: Option<u32>,
    pub main_tag_selector: TagSelector,
    pub editor: Vec<String>,
    pub tag_selectors: Vec<NamedTagSelector>,
    pub alias: HashMap<String, Alias>,
    pub types: HashMap<ScriptType, ScriptTypeConfig>,
    pub env: HashMap<String, String>,
    /* private fields */
}

Fields§

§recent: Option<u32>§main_tag_selector: TagSelector§editor: Vec<String>§tag_selectors: Vec<NamedTagSelector>§alias: HashMap<String, Alias>§types: HashMap<ScriptType, ScriptTypeConfig>§env: HashMap<String, String>

Implementations§

Examples found in repository?
src/config.rs (line 222)
221
222
223
224
    pub fn init() -> Result {
        CONFIG.set(Config::load(path::get_home())?);
        Ok(())
    }
More examples
Hide additional examples
src/util/completion_util.rs (line 114)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
pub async fn handle_completion(comp: Completion, repo: &mut Option<ScriptRepo>) -> Result {
    match comp {
        Completion::LS { name, args } => {
            let mut new_root = match Root::try_parse_from(args) {
                Ok(Root {
                    subcmd: Some(Subs::Tags(_) | Subs::Types(_)),
                    ..
                }) => {
                    // 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_from_alias(false)?;
            new_root.sanitize_flags();
            *repo = Some(init_repo(new_root.root_args, false).await?);

            let iter = repo.as_mut().unwrap().iter_mut(Visibility::Normal);
            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()), " ");
        }
        Completion::NoSubcommand { args } => {
            if let Ok(root) = parse_alias_root(&args) {
                if root.subcmd.is_some() {
                    log::debug!("子命令 = {:?}", root.subcmd);
                    return Err(Error::Completion);
                }
            } // else: 解析錯誤當然不可能有子命令啦
        }
        Completion::Alias { args } => {
            let root = parse_alias_root(&args)?;

            if root.root_args.no_alias {
                log::info!("無別名模式");
                return Err(Error::Completion);
            }

            let home = path::compute_home_path_optional(root.root_args.hs_home.as_ref(), false)?;
            let conf = Config::load(&home)?;
            if let Some(new_args) = root.expand_alias(&args, &conf) {
                print_iter(new_args, " ");
            } else {
                log::info!("並非別名");
                return Err(Error::Completion);
            };
        }
        Completion::Home { args } => {
            let root = parse_alias_root(&args)?;
            let home = root.root_args.hs_home.ok_or_else(|| Error::Completion)?;
            print!("{}", home);
        }
        Completion::ParseRun { args } => {
            let mut root = Root::try_parse_from(args).map_err(|e| {
                log::warn!("補全時出錯 {}", e);
                Error::Completion
            })?;
            root.sanitize()?;
            match root.subcmd {
                Some(Subs::Run {
                    script_query, args, ..
                }) => {
                    let iter = std::iter::once(script_query.to_string())
                        .chain(args.into_iter().map(|s| to_display_args(s)));
                    print_iter(iter, " ");
                }
                res @ _ => {
                    log::warn!("非執行指令 {:?}", res);
                    return Err(Error::Completion);
                }
            }
        }
    }
    Ok(())
}
Examples found in repository?
src/args/mod.rs (line 365)
363
364
365
366
fn set_home(p: &Option<String>, create_on_missing: bool) -> Result {
    path::set_home(p.as_ref(), create_on_missing)?;
    Config::init()
}
Examples found in repository?
src/query/util.rs (line 106)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
pub async fn do_script_query<'b>(
    script_query: &ScriptQuery,
    script_repo: &'b mut ScriptRepo,
    finding_filtered: bool,
    forbid_prompt: bool,
) -> Result<Option<RepoEntry<'b>>> {
    log::debug!("開始尋找 `{:?}`", script_query);
    let mut visibility = compute_vis(script_query.bang);
    if finding_filtered {
        visibility = visibility.invert();
    }
    match &script_query.inner {
        ScriptQueryInner::Prev(prev) => {
            assert!(!finding_filtered); // XXX 很難看的作法,應設法靜態檢查
            let latest = script_repo.latest_mut(prev.get(), visibility);
            log::trace!("找最新腳本");
            return if latest.is_some() {
                Ok(latest)
            } else {
                Err(Error::Empty)
            };
        }
        ScriptQueryInner::Exact(name) => Ok(script_repo.get_mut(name, visibility)),
        ScriptQueryInner::Fuzz(name) => {
            let level = if forbid_prompt {
                PromptLevel::Never
            } else {
                Config::get_prompt_level()
            };

            let iter = script_repo.iter_mut(visibility);
            let fuzz_res = fuzzy::fuzz(name, iter, SEP).await?;
            let mut is_low = false;
            let mut is_multi_fuzz = false;
            let entry = match fuzz_res {
                Some(fuzzy::High(entry)) => entry,
                Some(fuzzy::Low(entry)) => {
                    is_low = true;
                    entry
                }
                #[cfg(feature = "benching")]
                Some(fuzzy::Multi { ans, .. }) => {
                    is_multi_fuzz = true;
                    ans
                }
                #[cfg(not(feature = "benching"))]
                Some(fuzzy::Multi { ans, others, .. }) => {
                    is_multi_fuzz = true;
                    the_multifuzz_algo(ans, others)
                }
                None => return Ok(None),
            };
            let need_prompt = {
                match level {
                    PromptLevel::Always => true,
                    PromptLevel::Never => false,
                    PromptLevel::Smart => is_low || is_multi_fuzz,
                    PromptLevel::OnMultiFuzz => is_multi_fuzz,
                }
            };
            if need_prompt {
                prompt_fuzz_acceptable(&*entry)?;
            }
            Ok(Some(entry))
        }
    }
}
Examples found in repository?
src/config.rs (line 227)
226
227
228
229
230
    pub fn set_prompt_level(l: Option<PromptLevel>) {
        let c = Config::get();
        let l = l.unwrap_or(c.prompt_level); // TODO: 測試由設定檔設定 prompt-level 的情境?
        PROMPT_LEVEL.set(l);
    }
More examples
Hide additional examples
src/util/mod.rs (line 74)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
pub fn open_editor(path: &Path) -> Result {
    let conf = Config::get();
    let cmd = create_concat_cmd(&conf.editor, &[&path]);
    let stat = run_cmd(cmd)?;
    if !stat.success() {
        let code = stat.code().unwrap_or_default();
        return Err(Error::EditorError(code, conf.editor.clone()));
    }
    Ok(())
}

pub fn create_concat_cmd<'a, 'b, I1, S1, I2, S2>(arg1: I1, arg2: I2) -> Command
where
    I1: IntoIterator<Item = &'a S1>,
    I2: IntoIterator<Item = &'b S2>,
    S1: AsRef<OsStr> + 'a,
    S2: AsRef<OsStr> + 'b,
{
    let mut arg1 = arg1.into_iter();
    let cmd = arg1.next().unwrap();
    let remaining = arg1
        .map(|s| s.as_ref())
        .chain(arg2.into_iter().map(|s| s.as_ref()));
    create_cmd(cmd, remaining)
}

pub fn file_modify_time(path: &Path) -> Result<DateTime<Utc>> {
    let meta = handle_fs_res(&[path], std::fs::metadata(path))?;
    let modified = handle_fs_res(&[path], meta.modified())?;
    Ok(modified.into())
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = handle_fs_res(&[path], File::open(path)).context("唯讀開啟檔案失敗")?;
    let mut content = String::new();
    handle_fs_res(&[path], file.read_to_string(&mut content)).context("讀取檔案失敗")?;
    Ok(content)
}

pub fn write_file(path: &Path, content: &str) -> Result<()> {
    let mut file = handle_fs_res(&[path], File::create(path))?;
    handle_fs_res(&[path], file.write_all(content.as_bytes()))
}
pub fn remove(script_path: &Path) -> Result<()> {
    handle_fs_res(&[&script_path], remove_file(&script_path))
}
pub fn mv(origin: &Path, new: &Path) -> Result<()> {
    log::info!("修改 {:?} 為 {:?}", origin, new);
    // NOTE: 創建資料夾和檔案
    if let Some(parent) = new.parent() {
        handle_fs_res(&[&new], create_dir_all(parent))?;
    }
    handle_fs_res(&[&new, &origin], rename(&origin, &new))
}
pub fn cp(origin: &Path, new: &Path) -> Result<()> {
    // NOTE: 創建資料夾和檔案
    if let Some(parent) = new.parent() {
        handle_fs_res(&[parent], create_dir_all(parent))?;
    }
    let _copied = handle_fs_res(&[&origin, &new], std::fs::copy(&origin, &new))?;
    Ok(())
}

pub fn handle_fs_err<P: AsRef<Path>>(path: &[P], err: std::io::Error) -> Error {
    use std::sync::Arc;
    let mut p = path.iter().map(|p| p.as_ref().to_owned()).collect();
    log::warn!("檔案系統錯誤:{:?}, {:?}", p, err);
    match err.kind() {
        std::io::ErrorKind::PermissionDenied => Error::PermissionDenied(p),
        std::io::ErrorKind::NotFound => Error::PathNotFound(p),
        std::io::ErrorKind::AlreadyExists => Error::PathExist(p.remove(0)),
        _ => Error::GeneralFS(p, Arc::new(err)),
    }
}
pub fn handle_fs_res<T, P: AsRef<Path>>(path: &[P], res: std::io::Result<T>) -> Result<T> {
    match res {
        Ok(t) => Ok(t),
        Err(e) => Err(handle_fs_err(path, e)),
    }
}

/// check_subtype 是為避免太容易生出子模版
pub fn get_or_create_template_path<T: AsScriptFullTypeRef>(
    ty: &T,
    force: bool,
    check_subtype: bool,
) -> Result<(PathBuf, Option<&'static str>)> {
    if !force {
        Config::get().get_script_conf(ty.get_ty())?; // 確認類型存在與否
    }
    let tmpl_path = path::get_template_path(ty)?;
    if !tmpl_path.exists() {
        if check_subtype && ty.get_sub().is_some() {
            return Err(Error::UnknownType(ty.display().to_string()));
        }
        let default_tmpl = get_default_template(ty);
        return write_file(&tmpl_path, default_tmpl).map(|_| (tmpl_path, Some(default_tmpl)));
    }
    Ok((tmpl_path, None))
}
pub fn get_or_create_template<T: AsScriptFullTypeRef>(
    ty: &T,
    force: bool,
    check_subtype: bool,
) -> Result<String> {
    let (tmpl_path, default_tmpl) = get_or_create_template_path(ty, force, check_subtype)?;
    if let Some(default_tmpl) = default_tmpl {
        return Ok(default_tmpl.to_owned());
    }
    read_file(&tmpl_path)
}

/// copied from `shell_escape` crate
pub fn to_display_args(arg: String) -> String {
    fn non_whitelisted(ch: char) -> bool {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '=' | '/' | ',' | '.' | '+' => false,
            _ => true,
        }
    }
    if !arg.is_empty() && !arg.contains(non_whitelisted) {
        return arg;
    }

    let mut es = String::with_capacity(arg.len() + 2);
    es.push('\'');
    for ch in arg.chars() {
        match ch {
            '\'' | '!' => {
                es.push_str("'\\");
                es.push(ch);
                es.push('\'');
            }
            _ => es.push(ch),
        }
    }
    es.push('\'');
    es
}

fn relative_to_home(p: &Path) -> Option<&Path> {
    const CUR_DIR: &str = ".";
    let home = dirs::home_dir()?;
    if p == home {
        return Some(CUR_DIR.as_ref());
    }
    p.strip_prefix(&home).ok()
}

fn get_birthplace() -> Result<PathBuf> {
    // NOTE: 用 $PWD 可以取到 symlink 還沒解開前的路徑
    // 若用 std::env::current_dir,該路徑已為真實路徑
    let here = std::env::var("PWD")?;
    Ok(here.into())
}

#[derive(Debug)]
pub struct PrepareRespond {
    pub is_new: bool,
    pub time: DateTime<Utc>,
}
pub fn prepare_script<T: AsRef<str>>(
    path: &Path,
    script: &ScriptInfo,
    sub_type: Option<&ScriptType>,
    no_template: bool,
    content: &[T],
) -> Result<PrepareRespond> {
    log::info!("開始準備 {} 腳本內容……", script.name);
    let has_content = !content.is_empty();
    let is_new = !path.exists();
    if is_new {
        let birthplace = get_birthplace()?;
        let birthplace_rel = relative_to_home(&birthplace);

        let mut file = handle_fs_res(&[path], File::create(&path))?;

        let content = content.iter().map(|s| s.as_ref().split('\n')).flatten();
        if !no_template {
            let content: Vec<_> = content.collect();
            let info = json!({
                "birthplace_in_home": birthplace_rel.is_some(),
                "birthplace_rel": birthplace_rel,
                "birthplace": birthplace,
                "name": script.name.key().to_owned(),
                "content": content,
            });
            log::debug!("編輯模版資訊:{:?}", info);
            // NOTE: 計算 `path` 時早已檢查過腳本類型,這裡直接不檢查了
            let template = get_or_create_template(&(&script.ty, sub_type), true, true)?;
            handle_fs_res(&[path], write_prepare_script(file, &template, &info))?;
        } else {
            let mut first = true;
            for line in content {
                if !first {
                    writeln!(file, "")?;
                }
                first = false;
                write!(file, "{}", line)?;
            }
        }
    } else {
        if has_content {
            log::debug!("腳本已存在,往後接上給定的訊息");
            let mut file = handle_fs_res(
                &[path],
                std::fs::OpenOptions::new()
                    .append(true)
                    .write(true)
                    .open(path),
            )?;
            for content in content.iter() {
                handle_fs_res(&[path], writeln!(&mut file, "{}", content.as_ref()))?;
            }
        }
    }

    Ok(PrepareRespond {
        is_new,
        time: file_modify_time(path)?,
    })
}
fn write_prepare_script<W: Write>(
    w: W,
    template: &str,
    info: &serde_json::Value,
) -> std::io::Result<()> {
    use handlebars::{Handlebars, TemplateRenderError};
    let reg = Handlebars::new();
    reg.render_template_to_write(&template, &info, w)
        .map_err(|err| match err {
            TemplateRenderError::IOError(err, ..) => err,
            e => panic!("解析模版錯誤:{}", e),
        })
}

/// 可用來表示「未知類別」的概念 TODO: 測試之
pub struct DisplayType<'a> {
    ty: &'a ScriptType,
    color: Option<Color>,
}
impl<'a> DisplayType<'a> {
    pub fn is_unknown(&self) -> bool {
        self.color.is_none()
    }
    pub fn color(&self) -> Color {
        self.color.unwrap_or(Color::BrightBlack)
    }
    pub fn display(&self) -> Cow<'a, str> {
        if self.is_unknown() {
            Cow::Owned(format!("{}, unknown", self.ty))
        } else {
            Cow::Borrowed(self.ty.as_ref())
        }
    }
}
pub fn get_display_type(ty: &ScriptType) -> DisplayType {
    let conf = Config::get();
    match conf.get_color(ty) {
        Err(e) => {
            log::warn!("取腳本顏色時出錯:{},視為未知類別", e);
            DisplayType { ty, color: None }
        }
        Ok(c) => DisplayType { ty, color: Some(c) },
    }
}
src/script.rs (line 158)
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
        fn add_ext(
            name: &mut String,
            ty: &ScriptType,
            fallback: bool,
            err: &mut Option<Error>,
        ) -> Result {
            let ext = match Config::get().get_script_conf(ty) {
                Err(e) => {
                    if !fallback {
                        return Err(e);
                    }
                    log::warn!(
                        "取腳本路徑時找不到類別設定:{},直接把類別名當擴展名試試",
                        e,
                    );
                    *err = Some(e);
                    Some(ty.as_ref())
                }
                Ok(c) => c.ext.as_ref().map(|s| s.as_ref()),
            };
            if let Some(ext) = ext {
                write!(name, ".{}", ext).unwrap();
            }
            Ok(())
        }
src/args/mod.rs (line 398)
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
fn handle_alias_args(args: Vec<String>) -> Result<Root> {
    if args.iter().any(|s| s == "--no-alias") {
        log::debug!("不使用別名!"); // NOTE: --no-alias 的判斷存在於 clap 之外!
        let root = Root::parse_from(args);
        return Ok(root);
    }
    match AliasRoot::try_parse_from(&args) {
        Ok(alias_root) => {
            log::info!("別名命令行物件 {:?}", alias_root);
            set_home(&alias_root.root_args.hs_home, true)?;
            let mut root = match alias_root.expand_alias(&args, Config::get()) {
                Some(new_args) => Root::parse_from(new_args),
                None => Root::parse_from(&args),
            };
            root.is_from_alias = true;
            Ok(root)
        }
        Err(e) => {
            log::warn!("解析別名參數出錯:{}", e); // NOTE: 不要讓這個錯誤傳上去,而是讓它掉入 Root::parse_from 中再來報錯
            Root::parse_from(args);
            unreachable!()
        }
    }
}
src/util/init_repo.rs (line 35)
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
pub async fn init_repo(args: RootArgs, need_journal: bool) -> Result<ScriptRepo> {
    let RootArgs {
        no_trace,
        humble,
        archaeology,
        select,
        toggle,
        recent,
        timeless,
        ..
    } = args;

    let conf = Config::get();

    let recent = if timeless {
        None
    } else {
        recent.or(conf.recent).map(|recent| RecentFilter {
            recent,
            archaeology,
        })
    };

    // TODO: 測試 toggle 功能,以及名字不存在的錯誤
    let tag_group = {
        let mut toggle: HashSet<_> = toggle.into_iter().collect();
        let mut tag_group = conf.get_tag_selector_group(&mut toggle);
        if let Some(name) = toggle.into_iter().next() {
            return Err(Error::TagSelectorNotFound(name));
        }
        for select in select.into_iter() {
            tag_group.push(select);
        }
        tag_group
    };

    let (env, init) = init_env(need_journal).await?;
    let mut repo = ScriptRepo::new(recent, env, &tag_group)
        .await
        .context("載入腳本倉庫失敗")?;
    if no_trace {
        repo.no_trace();
    } else if humble {
        repo.humble();
    }

    if init {
        log::info!("初次使用,載入好用工具和預執行腳本");
        main_util::load_utils(&mut repo).await?;
        main_util::prepare_pre_run(None)?;
        main_util::load_templates()?;
    }

    Ok(repo)
}
src/util/main_util.rs (line 150)
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
fn run(
    script_path: &Path,
    info: &ScriptInfo,
    remaining: &[String],
    hs_tmpl_val: &serde_json::Value,
    remaining_envs: &[EnvPair],
) -> Result<()> {
    let conf = Config::get();
    let ty = &info.ty;

    let script_conf = conf.get_script_conf(ty)?;
    let cmd_str = if let Some(cmd) = &script_conf.cmd {
        cmd
    } else {
        return Err(Error::PermissionDenied(vec![script_path.to_path_buf()]));
    };

    let env = conf.gen_env(&hs_tmpl_val)?;
    let ty_env = script_conf.gen_env(&hs_tmpl_val)?;

    let pre_run_script = prepare_pre_run(None)?;
    let (cmd, shebang) = super::shebang_handle::handle(&pre_run_script)?;
    let args = shebang
        .iter()
        .map(|s| s.as_ref())
        .chain(std::iter::once(pre_run_script.as_os_str()))
        .chain(remaining.iter().map(|s| s.as_ref()));

    let set_cmd_envs = |cmd: &mut Command| {
        cmd.envs(ty_env.iter().map(|(a, b)| (a, b)));
        cmd.envs(env.iter().map(|(a, b)| (a, b)));
        cmd.envs(remaining_envs.iter().map(|p| (&p.key, &p.val)));
    };

    let mut cmd = super::create_cmd(cmd, args);
    set_cmd_envs(&mut cmd);

    let stat = super::run_cmd(cmd)?;
    log::info!("預腳本執行結果:{:?}", stat);
    if !stat.success() {
        // TODO: 根據返回值做不同表現
        let code = stat.code().unwrap_or_default();
        return Err(Error::PreRunError(code));
    }

    let args = script_conf.args(&hs_tmpl_val)?;
    let full_args = args
        .iter()
        .map(|s| s.as_str())
        .chain(remaining.iter().map(|s| s.as_str()));

    let mut cmd = super::create_cmd(&cmd_str, full_args);
    set_cmd_envs(&mut cmd);

    let stat = super::run_cmd(cmd)?;
    log::info!("程式執行結果:{:?}", stat);
    if !stat.success() {
        let code = stat.code().unwrap_or_default();
        Err(Error::ScriptError(code))
    } else {
        Ok(())
    }
}
Examples found in repository?
src/util/main_util.rs (line 160)
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
fn run(
    script_path: &Path,
    info: &ScriptInfo,
    remaining: &[String],
    hs_tmpl_val: &serde_json::Value,
    remaining_envs: &[EnvPair],
) -> Result<()> {
    let conf = Config::get();
    let ty = &info.ty;

    let script_conf = conf.get_script_conf(ty)?;
    let cmd_str = if let Some(cmd) = &script_conf.cmd {
        cmd
    } else {
        return Err(Error::PermissionDenied(vec![script_path.to_path_buf()]));
    };

    let env = conf.gen_env(&hs_tmpl_val)?;
    let ty_env = script_conf.gen_env(&hs_tmpl_val)?;

    let pre_run_script = prepare_pre_run(None)?;
    let (cmd, shebang) = super::shebang_handle::handle(&pre_run_script)?;
    let args = shebang
        .iter()
        .map(|s| s.as_ref())
        .chain(std::iter::once(pre_run_script.as_os_str()))
        .chain(remaining.iter().map(|s| s.as_ref()));

    let set_cmd_envs = |cmd: &mut Command| {
        cmd.envs(ty_env.iter().map(|(a, b)| (a, b)));
        cmd.envs(env.iter().map(|(a, b)| (a, b)));
        cmd.envs(remaining_envs.iter().map(|p| (&p.key, &p.val)));
    };

    let mut cmd = super::create_cmd(cmd, args);
    set_cmd_envs(&mut cmd);

    let stat = super::run_cmd(cmd)?;
    log::info!("預腳本執行結果:{:?}", stat);
    if !stat.success() {
        // TODO: 根據返回值做不同表現
        let code = stat.code().unwrap_or_default();
        return Err(Error::PreRunError(code));
    }

    let args = script_conf.args(&hs_tmpl_val)?;
    let full_args = args
        .iter()
        .map(|s| s.as_str())
        .chain(remaining.iter().map(|s| s.as_str()));

    let mut cmd = super::create_cmd(&cmd_str, full_args);
    set_cmd_envs(&mut cmd);

    let stat = super::run_cmd(cmd)?;
    log::info!("程式執行結果:{:?}", stat);
    if !stat.success() {
        let code = stat.code().unwrap_or_default();
        Err(Error::ScriptError(code))
    } else {
        Ok(())
    }
}
Examples found in repository?
src/util/mod.rs (line 331)
329
330
331
332
333
334
335
336
337
338
pub fn get_display_type(ty: &ScriptType) -> DisplayType {
    let conf = Config::get();
    match conf.get_color(ty) {
        Err(e) => {
            log::warn!("取腳本顏色時出錯:{},視為未知類別", e);
            DisplayType { ty, color: None }
        }
        Ok(c) => DisplayType { ty, color: Some(c) },
    }
}
Examples found in repository?
src/config.rs (line 256)
255
256
257
258
    pub fn get_color(&self, ty: &ScriptType) -> Result<Color> {
        let c = self.get_script_conf(ty)?.color.as_str();
        Ok(Color::from(c))
    }
More examples
Hide additional examples
src/util/mod.rs (line 161)
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
pub fn get_or_create_template_path<T: AsScriptFullTypeRef>(
    ty: &T,
    force: bool,
    check_subtype: bool,
) -> Result<(PathBuf, Option<&'static str>)> {
    if !force {
        Config::get().get_script_conf(ty.get_ty())?; // 確認類型存在與否
    }
    let tmpl_path = path::get_template_path(ty)?;
    if !tmpl_path.exists() {
        if check_subtype && ty.get_sub().is_some() {
            return Err(Error::UnknownType(ty.display().to_string()));
        }
        let default_tmpl = get_default_template(ty);
        return write_file(&tmpl_path, default_tmpl).map(|_| (tmpl_path, Some(default_tmpl)));
    }
    Ok((tmpl_path, None))
}
src/script.rs (line 158)
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
        fn add_ext(
            name: &mut String,
            ty: &ScriptType,
            fallback: bool,
            err: &mut Option<Error>,
        ) -> Result {
            let ext = match Config::get().get_script_conf(ty) {
                Err(e) => {
                    if !fallback {
                        return Err(e);
                    }
                    log::warn!(
                        "取腳本路徑時找不到類別設定:{},直接把類別名當擴展名試試",
                        e,
                    );
                    *err = Some(e);
                    Some(ty.as_ref())
                }
                Ok(c) => c.ext.as_ref().map(|s| s.as_ref()),
            };
            if let Some(ext) = ext {
                write!(name, ".{}", ext).unwrap();
            }
            Ok(())
        }
src/util/main_util.rs (line 153)
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
fn run(
    script_path: &Path,
    info: &ScriptInfo,
    remaining: &[String],
    hs_tmpl_val: &serde_json::Value,
    remaining_envs: &[EnvPair],
) -> Result<()> {
    let conf = Config::get();
    let ty = &info.ty;

    let script_conf = conf.get_script_conf(ty)?;
    let cmd_str = if let Some(cmd) = &script_conf.cmd {
        cmd
    } else {
        return Err(Error::PermissionDenied(vec![script_path.to_path_buf()]));
    };

    let env = conf.gen_env(&hs_tmpl_val)?;
    let ty_env = script_conf.gen_env(&hs_tmpl_val)?;

    let pre_run_script = prepare_pre_run(None)?;
    let (cmd, shebang) = super::shebang_handle::handle(&pre_run_script)?;
    let args = shebang
        .iter()
        .map(|s| s.as_ref())
        .chain(std::iter::once(pre_run_script.as_os_str()))
        .chain(remaining.iter().map(|s| s.as_ref()));

    let set_cmd_envs = |cmd: &mut Command| {
        cmd.envs(ty_env.iter().map(|(a, b)| (a, b)));
        cmd.envs(env.iter().map(|(a, b)| (a, b)));
        cmd.envs(remaining_envs.iter().map(|p| (&p.key, &p.val)));
    };

    let mut cmd = super::create_cmd(cmd, args);
    set_cmd_envs(&mut cmd);

    let stat = super::run_cmd(cmd)?;
    log::info!("預腳本執行結果:{:?}", stat);
    if !stat.success() {
        // TODO: 根據返回值做不同表現
        let code = stat.code().unwrap_or_default();
        return Err(Error::PreRunError(code));
    }

    let args = script_conf.args(&hs_tmpl_val)?;
    let full_args = args
        .iter()
        .map(|s| s.as_str())
        .chain(remaining.iter().map(|s| s.as_str()));

    let mut cmd = super::create_cmd(&cmd_str, full_args);
    set_cmd_envs(&mut cmd);

    let stat = super::run_cmd(cmd)?;
    log::info!("程式執行結果:{:?}", stat);
    if !stat.success() {
        let code = stat.code().unwrap_or_default();
        Err(Error::ScriptError(code))
    } else {
        Ok(())
    }
}
Examples found in repository?
src/util/init_repo.rs (line 49)
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
pub async fn init_repo(args: RootArgs, need_journal: bool) -> Result<ScriptRepo> {
    let RootArgs {
        no_trace,
        humble,
        archaeology,
        select,
        toggle,
        recent,
        timeless,
        ..
    } = args;

    let conf = Config::get();

    let recent = if timeless {
        None
    } else {
        recent.or(conf.recent).map(|recent| RecentFilter {
            recent,
            archaeology,
        })
    };

    // TODO: 測試 toggle 功能,以及名字不存在的錯誤
    let tag_group = {
        let mut toggle: HashSet<_> = toggle.into_iter().collect();
        let mut tag_group = conf.get_tag_selector_group(&mut toggle);
        if let Some(name) = toggle.into_iter().next() {
            return Err(Error::TagSelectorNotFound(name));
        }
        for select in select.into_iter() {
            tag_group.push(select);
        }
        tag_group
    };

    let (env, init) = init_env(need_journal).await?;
    let mut repo = ScriptRepo::new(recent, env, &tag_group)
        .await
        .context("載入腳本倉庫失敗")?;
    if no_trace {
        repo.no_trace();
    } else if humble {
        repo.humble();
    }

    if init {
        log::info!("初次使用,載入好用工具和預執行腳本");
        main_util::load_utils(&mut repo).await?;
        main_util::prepare_pre_run(None)?;
        main_util::load_templates()?;
    }

    Ok(repo)
}

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Compare self to key and return true if they are equal.

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Should always be Self
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.