pyc_shell/shell/prompt/
mod.rs

1//! # Prompt
2//!
3//! `prompt` is the module which takes care of processing the shell prompt
4
5/*
6*
7*   Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
8*
9* 	This file is part of "Pyc"
10*
11*   Pyc is free software: you can redistribute it and/or modify
12*   it under the terms of the GNU General Public License as published by
13*   the Free Software Foundation, either version 3 of the License, or
14*   (at your option) any later version.
15*
16*   Pyc is distributed in the hope that it will be useful,
17*   but WITHOUT ANY WARRANTY; without even the implied warranty of
18*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19*   GNU General Public License for more details.
20*
21*   You should have received a copy of the GNU General Public License
22*   along with Pyc.  If not, see <http://www.gnu.org/licenses/>.
23*
24*/
25
26extern crate regex;
27
28mod cache;
29mod modules;
30
31use super::ShellProps;
32use crate::config::PromptConfig;
33use crate::translator::ioprocessor::IOProcessor;
34use cache::PromptCache;
35use modules::*;
36
37use regex::Regex;
38use std::time::Duration;
39
40const PROMPT_KEY_REGEX: &str = r"\$\{(.*?)\}";
41//Prompt standard keys
42const PROMPT_USER: &str = "${USER}";
43const PROMPT_HOSTNAME: &str = "${HOSTNAME}";
44const PROMPT_WRKDIR: &str = "${WRKDIR}";
45const PROMPT_CMDTIME: &str = "${CMD_TIME}";
46const PROMPT_RC: &str = "${RC}";
47
48/// ## ShellPrompt
49///
50/// ShellPrompt is the struct which contains the current shell prompt configuration
51pub struct ShellPrompt {
52    prompt_line: String,
53    translate: bool,
54    break_opt: Option<BreakOptions>,
55    duration_opt: Option<DurationOptions>,
56    rc_opt: Option<RcOptions>,
57    git_opt: Option<GitOptions>,
58    cache: PromptCache,
59}
60
61/// ## ShellPrompt
62///
63/// ShellPrompt is the struct which contains the current shell prompt configuration
64struct BreakOptions {
65    pub break_with: String,
66}
67
68/// ## DurationOptions
69///
70/// DurationOptions is the struct which contains the current duration configuration
71struct DurationOptions {
72    pub minimum: Duration,
73}
74
75/// ## RcOptions
76///
77/// RcOptions is the struct which contains the return code configuration
78struct RcOptions {
79    pub ok: String,
80    pub err: String,
81}
82
83/// ## GitOptions
84///
85/// GitOptions is the struct which contains the current git module configuration
86struct GitOptions {
87    pub branch: String,
88    pub commit_ref_len: usize,
89    pub commit_ref_prepend: Option<String>,
90    pub commit_ref_append: Option<String>
91}
92
93impl ShellPrompt {
94    /// ### new
95    ///
96    /// Instantiate a new ShellPrompt with the provided parameters
97    pub(super) fn new(prompt_opt: &PromptConfig) -> ShellPrompt {
98        let break_opt: Option<BreakOptions> = match prompt_opt.break_enabled {
99            true => Some(BreakOptions::new(&prompt_opt.break_str)),
100            false => None,
101        };
102        let duration_opt: Option<DurationOptions> =
103            match DurationOptions::should_enable(&prompt_opt.prompt_line) {
104                true => Some(DurationOptions::new(prompt_opt.min_duration)),
105                false => None,
106            };
107        let rc_opt: Option<RcOptions> = match RcOptions::should_enable(&prompt_opt.prompt_line) {
108            true => Some(RcOptions::new(&prompt_opt.rc_ok, &prompt_opt.rc_err)),
109            false => None,
110        };
111        let git_opt: Option<GitOptions> = match GitOptions::should_enable(&prompt_opt.prompt_line) {
112            true => Some(GitOptions::new(
113                &prompt_opt.git_branch,
114                prompt_opt.git_commit_ref,
115                &prompt_opt.git_commit_prepend,
116                &prompt_opt.git_commit_append
117            )),
118            false => None,
119        };
120        ShellPrompt {
121            prompt_line: prompt_opt.prompt_line.clone(),
122            translate: prompt_opt.translate,
123            break_opt: break_opt,
124            duration_opt: duration_opt,
125            rc_opt: rc_opt,
126            git_opt: git_opt,
127            cache: PromptCache::new(),
128        }
129    }
130
131    /// ### get_line
132    ///
133    /// get prompt line with resolved values
134    pub(super) fn get_line(&mut self, shell_props: &ShellProps, processor: &IOProcessor) -> String {
135        let mut prompt_line: String = self.process_prompt(shell_props, processor);
136        //Translate prompt if necessary
137        if self.translate {
138            prompt_line = processor.text_to_cyrillic(&prompt_line);
139        }
140        //Write prompt
141        prompt_line
142    }
143
144    /// ### process_prompt
145    ///
146    /// Process prompt keys and resolve prompt line
147    /// Returns the processed prompt line
148    /// This function is optimized to try to cache the previous values
149    fn process_prompt(&mut self, shell_props: &ShellProps, processor: &IOProcessor) -> String {
150        let mut prompt_line: String = self.prompt_line.clone();
151        //Iterate over keys through regex ```\${(.*?)}```
152        lazy_static! {
153            static ref RE: Regex = Regex::new(PROMPT_KEY_REGEX).unwrap();
154        }
155        for regex_match in RE.captures_iter(prompt_line.clone().as_str()) {
156            let mtch: String = String::from(&regex_match[0]);
157            let replace_with: String = self.resolve_key(shell_props, processor, &mtch);
158            prompt_line = prompt_line.replace(mtch.as_str(), replace_with.as_str());
159        }
160        //Trim prompt line
161        prompt_line = String::from(prompt_line.trim());
162        //If break, break line
163        if let Some(brkopt) = &self.break_opt {
164            prompt_line += "\n";
165            prompt_line += brkopt.break_with.trim();
166        }
167        //Invalidate cache
168        self.cache.invalidate();
169        //Return prompt line
170        prompt_line
171    }
172
173    /// ### resolve_key
174    ///
175    /// Replace the provided key with the resolved value
176    fn resolve_key(
177        &mut self,
178        shell_props: &ShellProps,
179        processor: &IOProcessor,
180        key: &String,
181    ) -> String {
182        match key.as_str() {
183            PROMPT_CMDTIME => {
184                match &self.duration_opt {
185                    Some(opt) => {
186                        if shell_props.elapsed_time.as_millis() >= opt.minimum.as_millis() {
187                            let millis: u128 = shell_props.elapsed_time.as_millis();
188                            let secs: f64 = (millis as f64 / 1000 as f64) as f64;
189                            String::from(format!("took {:.1}s", secs))
190                        } else {
191                            String::from("")
192                        }
193                    }
194                    None => String::from(""),
195                }
196            }
197            modules::git::PROMPT_GIT_BRANCH => {
198                if self.git_opt.is_none() {
199                    return String::from("");
200                }
201                //If repository is not cached, find repository
202                if self.cache.get_cached_git().is_none() {
203                    let repo_opt = git::find_repository(&shell_props.wrkdir);
204                    match repo_opt {
205                        Some(repo) => self.cache.cache_git(repo),
206                        None => return String::from(""),
207                    };
208                }
209                //Get branch (unwrap without fear; can't be None here)
210                let branch: String = match git::get_branch(self.cache.get_cached_git().unwrap()) {
211                    Some(branch) => branch,
212                    None => return String::from(""),
213                };
214                //Format branch
215                String::from(format!(
216                    "{}{}",
217                    self.git_opt.as_ref().unwrap().branch.clone(),
218                    branch
219                ))
220            }
221            modules::git::PROMPT_GIT_COMMIT => {
222                if self.git_opt.is_none() {
223                    return String::from("");
224                }
225                //If repository is not cached, find repository
226                if self.cache.get_cached_git().is_none() {
227                    let repo_opt = git::find_repository(&shell_props.wrkdir);
228                    match repo_opt {
229                        Some(repo) => self.cache.cache_git(repo),
230                        None => return String::from(""),
231                    };
232                }
233                //Get commit (unwrap without fear; can't be None here)
234                match git::get_commit(
235                    self.cache.get_cached_git().unwrap(),
236                    self.git_opt.as_ref().unwrap().commit_ref_len,
237                ) {
238                    Some(commit) => {
239                        // Format commit
240                        let commit_prepend: String = match &self.git_opt.as_ref().unwrap().commit_ref_prepend {
241                            Some(s) => s.clone(),
242                            None => String::from("")
243                        };
244                        let commit_append: String = match &self.git_opt.as_ref().unwrap().commit_ref_append {
245                            Some(s) => s.clone(),
246                            None => String::from("")
247                        };
248                        format!("{}{}{}", commit_prepend, commit, commit_append)
249                    },
250                    None => String::from(""),
251                }
252            }
253            PROMPT_HOSTNAME => shell_props.hostname.clone(),
254            modules::colors::PROMPT_KBLINK | modules::colors::PROMPT_KBLK | modules::colors::PROMPT_KBLU | modules::colors::PROMPT_KBOLD | modules::colors::PROMPT_KCYN | modules::colors::PROMPT_KGRN | modules::colors::PROMPT_KGRY | modules::colors::PROMPT_KMAG | modules::colors::PROMPT_KRED | modules::colors::PROMPT_KRST | modules::colors::PROMPT_KSELECT | modules::colors::PROMPT_KWHT | modules::colors::PROMPT_KYEL => colors::PromptColor::from_key(key.as_str()).to_string(),
255            modules::language::PROMPT_LANG => language::language_to_str(processor.language),
256            PROMPT_RC => match &self.rc_opt {
257                Some(opt) => match shell_props.exit_status {
258                    0 => opt.ok.clone(),
259                    _ => opt.err.clone(),
260                },
261                None => String::from(""),
262            },
263            PROMPT_USER => shell_props.username.clone(),
264            PROMPT_WRKDIR => shell_props.wrkdir.as_path().display().to_string(),
265            _ => key.clone(), //Keep unresolved keys
266        }
267    }
268}
269
270impl BreakOptions {
271    /// ### new
272    ///
273    /// Instantiate a new BreakOptions with the provided parameters
274    pub fn new(break_with: &String) -> BreakOptions {
275        BreakOptions {
276            break_with: break_with.clone(),
277        }
278    }
279}
280
281impl DurationOptions {
282    /// ### should_enable
283    ///
284    /// helper which says if duration module should be enabled
285    pub fn should_enable(prompt_line: &String) -> bool {
286        prompt_line.contains(PROMPT_CMDTIME)
287    }
288
289    /// ### new
290    ///
291    /// Instantiate a new DurationOptions with the provided parameters
292    pub fn new(min_duration: usize) -> DurationOptions {
293        DurationOptions {
294            minimum: Duration::from_millis(min_duration as u64),
295        }
296    }
297}
298
299impl RcOptions {
300    /// ### should_enable
301    ///
302    /// helper which says if rc module should be enabled
303    pub fn should_enable(prompt_line: &String) -> bool {
304        prompt_line.contains(PROMPT_RC)
305    }
306
307    /// ### new
308    ///
309    /// Instantiate a new RcOptions with the provided parameters
310    pub fn new(ok_str: &String, err_str: &String) -> RcOptions {
311        RcOptions {
312            ok: ok_str.clone(),
313            err: err_str.clone(),
314        }
315    }
316}
317
318impl GitOptions {
319    /// ### should_enable
320    ///
321    /// helper which says if git module should be enabled
322    pub fn should_enable(prompt_line: &String) -> bool {
323        prompt_line.contains(modules::git::PROMPT_GIT_BRANCH) || prompt_line.contains(modules::git::PROMPT_GIT_COMMIT)
324    }
325
326    /// ### new
327    ///
328    /// Instantiate a new GitOptions with the provided parameters
329    pub fn new(branch: &String, commit: usize, commit_prepend: &Option<String>, commit_append: &Option<String>) -> GitOptions {
330        GitOptions {
331            branch: branch.clone(),
332            commit_ref_len: commit,
333            commit_ref_prepend: commit_prepend.clone(),
334            commit_ref_append: commit_append.clone()
335        }
336    }
337}
338
339#[cfg(test)]
340mod tests {
341
342    use super::*;
343    use crate::config::PromptConfig;
344    use crate::translator::ioprocessor::IOProcessor;
345    use crate::translator::new_translator;
346    use crate::translator::lang::Language;
347    use colors::PromptColor;
348
349    use git2::Repository;
350    use std::path::PathBuf;
351    use std::time::Duration;
352
353    #[test]
354    fn test_prompt_simple() {
355        let prompt_config_default = PromptConfig::default();
356        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
357        let iop: IOProcessor = get_ioprocessor();
358        let shellenv: ShellProps = get_shellenv();
359        //Print first in latin
360        let _ = prompt.get_line(&shellenv, &iop);
361        prompt.translate = true;
362        //Then in cyrillic
363        let _ = prompt.get_line(&shellenv, &iop);
364        //Get prompt line
365        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
366        let expected_prompt_line = String::from(format!(
367            "{}@{}:{}$",
368            shellenv.username.clone(),
369            shellenv.hostname.clone(),
370            shellenv.wrkdir.display()
371        ));
372        assert_eq!(prompt_line, expected_prompt_line);
373        //Terminate shell at the end of a test
374        //terminate_shell(&mut shellenv);
375        println!("\n");
376    }
377
378    #[test]
379    fn test_prompt_colors() {
380        let mut prompt_config_default = PromptConfig::default();
381        //Update prompt line
382        prompt_config_default.prompt_line = String::from("${KRED}RED${KYEL}YEL${KBLU}BLU${KGRN}GRN${KWHT}WHT${KGRY}GRY${KBLK}BLK${KMAG}MAG${KCYN}CYN${KBOLD}BOLD${KBLINK}BLINK${KSELECT}SELECTED${KRST}");
383        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
384        let iop: IOProcessor = get_ioprocessor();
385        let shellenv: ShellProps = get_shellenv();
386        //Print first in latin
387        let _ = prompt.get_line(&shellenv, &iop);
388        prompt.translate = true;
389        //Then in cyrillic
390        let _ = prompt.get_line(&shellenv, &iop);
391        //Get prompt line
392        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
393        let expected_prompt_line = String::from(format!(
394            "{}RED{}YEL{}BLU{}GRN{}WHT{}GRY{}BLK{}MAG{}CYN{}BOLD{}BLINK{}SELECTED{}",
395            PromptColor::Red.to_string(),
396            PromptColor::Yellow.to_string(),
397            PromptColor::Blue.to_string(),
398            PromptColor::Green.to_string(),
399            PromptColor::White.to_string(),
400            PromptColor::Gray.to_string(),
401            PromptColor::Black.to_string(),
402            PromptColor::Magenta.to_string(),
403            PromptColor::Cyan.to_string(),
404            PromptColor::Bold.to_string(),
405            PromptColor::Blink.to_string(),
406            PromptColor::Select.to_string(),
407            PromptColor::Reset.to_string()
408        ));
409        assert_eq!(prompt_line, expected_prompt_line);
410        //Terminate shell at the end of a test
411        //terminate_shell(&mut shellenv);
412        println!("\n");
413    }
414
415    #[test]
416    fn test_prompt_lang_time_with_break() {
417        let mut prompt_config_default = PromptConfig::default();
418        //Update prompt line
419        prompt_config_default.prompt_line = String::from("${LANG} ~ ${KYEL}${USER}${KRST} on ${KGRN}${HOSTNAME}${KRST} in ${KCYN}${WRKDIR}${KRST} ${KYEL}${CMD_TIME}${KRST}");
420        prompt_config_default.break_enabled = true;
421        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
422        let iop: IOProcessor = get_ioprocessor();
423        let mut shellenv: ShellProps = get_shellenv();
424        shellenv.elapsed_time = Duration::from_millis(5100);
425        shellenv.wrkdir = PathBuf::from("/tmp/");
426        //Print first in latin
427        let _ = prompt.get_line(&shellenv, &iop);
428        prompt.translate = true;
429        //Then in cyrillic
430        let _ = prompt.get_line(&shellenv, &iop);
431        //Get prompt line
432        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
433        let expected_prompt_line = String::from(format!(
434            "{} ~ {}{}{} on {}{}{} in {}{}{} {}took 5.1s{}\n❯",
435            language::language_to_str(Language::Russian),
436            PromptColor::Yellow.to_string(),
437            shellenv.username.clone(),
438            PromptColor::Reset.to_string(),
439            PromptColor::Green.to_string(),
440            shellenv.hostname.clone(),
441            PromptColor::Reset.to_string(),
442            PromptColor::Cyan.to_string(),
443            shellenv.wrkdir.display(),
444            PromptColor::Reset.to_string(),
445            PromptColor::Yellow.to_string(),
446            PromptColor::Reset.to_string()
447        ));
448        assert_eq!(prompt_line, expected_prompt_line);
449        //Terminate shell at the end of a test
450        //terminate_shell(&mut shellenv);
451        println!("\n");
452    }
453
454    #[test]
455    fn test_prompt_git() {
456        //Get current git info
457        //Initialize module
458        let repo: Repository = git::find_repository(&PathBuf::from("./")).unwrap();
459        //Branch should be none
460        let branch: String = git::get_branch(&repo).unwrap();
461        let commit: String = git::get_commit(&repo, 8).unwrap();
462        let mut prompt_config = PromptConfig::default();
463        //Update prompt line
464        prompt_config.prompt_line =
465            String::from("${USER}@${HOSTNAME}:${WRKDIR} ${GIT_BRANCH} ${GIT_COMMIT}");
466        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config);
467        let iop: IOProcessor = get_ioprocessor();
468        let mut shellenv: ShellProps = get_shellenv();
469        shellenv.elapsed_time = Duration::from_millis(5100);
470        shellenv.wrkdir = PathBuf::from("./");
471        //Print first in latin
472        let _ = prompt.get_line(&shellenv, &iop);
473        prompt.translate = true;
474        //Then in cyrillic
475        let _ = prompt.get_line(&shellenv, &iop);
476        //Get prompt line
477        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
478        let expected_prompt_line = String::from(format!(
479            "{}@{}:{} on {} {}",
480            shellenv.username.clone(),
481            shellenv.hostname.clone(),
482            shellenv.wrkdir.display(),
483            branch,
484            commit
485        ));
486        assert_eq!(prompt_line, expected_prompt_line);
487        //Terminate shell at the end of a test
488        //terminate_shell(&mut shellenv);
489        println!("\n");
490        // @! Set prepend / append
491        prompt_config.git_commit_append = Some(String::from(")"));
492        prompt_config.git_commit_prepend = Some(String::from("("));
493        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config);
494        let iop: IOProcessor = get_ioprocessor();
495        let mut shellenv: ShellProps = get_shellenv();
496        shellenv.elapsed_time = Duration::from_millis(5100);
497        shellenv.wrkdir = PathBuf::from("./");
498        //Print first in latin
499        let _ = prompt.get_line(&shellenv, &iop);
500        prompt.translate = true;
501        //Then in cyrillic
502        let _ = prompt.get_line(&shellenv, &iop);
503        //Get prompt line
504        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
505        let expected_prompt_line = String::from(format!(
506            "{}@{}:{} on {} ({})",
507            shellenv.username.clone(),
508            shellenv.hostname.clone(),
509            shellenv.wrkdir.display(),
510            branch,
511            commit
512        ));
513        assert_eq!(prompt_line, expected_prompt_line);
514        //Terminate shell at the end of a test
515        //terminate_shell(&mut shellenv);
516        println!("\n");
517    }
518
519    #[test]
520    fn test_prompt_git_not_in_repo() {
521        let mut prompt_config_default = PromptConfig::default();
522        //Update prompt line
523        prompt_config_default.prompt_line =
524            String::from("${USER}@${HOSTNAME}:${WRKDIR} ${GIT_BRANCH} ${GIT_COMMIT}");
525        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
526        let iop: IOProcessor = get_ioprocessor();
527        let mut shellenv: ShellProps = get_shellenv();
528        shellenv.elapsed_time = Duration::from_millis(5100);
529        shellenv.wrkdir = PathBuf::from("/");
530        //Print first in latin
531        let _ = prompt.get_line(&shellenv, &iop);
532        prompt.translate = true;
533        //Then in cyrillic
534        let _ = prompt.get_line(&shellenv, &iop);
535        //Get prompt line
536        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
537        let expected_prompt_line = String::from(format!(
538            "{}@{}:{}",
539            shellenv.username.clone(),
540            shellenv.hostname.clone(),
541            shellenv.wrkdir.display()
542        ));
543        assert_eq!(prompt_line, expected_prompt_line);
544        //Terminate shell at the end of a test
545        //terminate_shell(&mut shellenv);
546        println!("\n");
547    }
548
549    #[test]
550    fn test_prompt_rc_ok() {
551        let mut prompt_config_default = PromptConfig::default();
552        //Update prompt line
553        prompt_config_default.prompt_line = String::from("${RC} ${USER}@${HOSTNAME}:${WRKDIR}");
554        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
555        let iop: IOProcessor = get_ioprocessor();
556        let mut shellenv: ShellProps = get_shellenv();
557        shellenv.elapsed_time = Duration::from_millis(5100);
558        shellenv.wrkdir = PathBuf::from("/");
559        //Print first in latin
560        let _ = prompt.get_line(&shellenv, &iop);
561        prompt.translate = true;
562        //Then in cyrillic
563        let _ = prompt.get_line(&shellenv, &iop);
564        //Get prompt line
565        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
566        let expected_prompt_line = String::from(format!(
567            "✔ {}@{}:{}",
568            shellenv.username.clone(),
569            shellenv.hostname.clone(),
570            shellenv.wrkdir.display()
571        ));
572        assert_eq!(prompt_line, expected_prompt_line);
573        //Terminate shell at the end of a test
574        //terminate_shell(&mut shellenv);
575        println!("\n");
576    }
577
578    #[test]
579    fn test_prompt_rc_error() {
580        let mut prompt_config_default = PromptConfig::default();
581        //Update prompt line
582        prompt_config_default.prompt_line = String::from("${RC} ${USER}@${HOSTNAME}:${WRKDIR}");
583        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
584        let iop: IOProcessor = get_ioprocessor();
585        let mut shellenv: ShellProps = get_shellenv();
586        shellenv.elapsed_time = Duration::from_millis(5100);
587        shellenv.wrkdir = PathBuf::from("/");
588        shellenv.exit_status = 255;
589        //Print first in latin
590        let _ = prompt.get_line(&shellenv, &iop);
591        prompt.translate = true;
592        //Then in cyrillic
593        let _ = prompt.get_line(&shellenv, &iop);
594        //Get prompt line
595        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
596        let expected_prompt_line = String::from(format!(
597            "✖ {}@{}:{}",
598            shellenv.username.clone(),
599            shellenv.hostname.clone(),
600            shellenv.wrkdir.display()
601        ));
602        assert_eq!(prompt_line, expected_prompt_line);
603        //Terminate shell at the end of a test
604        //terminate_shell(&mut shellenv);
605        println!("\n");
606    }
607
608    #[test]
609    fn test_prompt_unresolved() {
610        let mut prompt_config_default = PromptConfig::default();
611        //Update prompt line
612        prompt_config_default.prompt_line = String::from("${USER}@${HOSTNAME}:${WRKDIR} ${FOOBAR}");
613        let mut prompt: ShellPrompt = ShellPrompt::new(&prompt_config_default);
614        let iop: IOProcessor = get_ioprocessor();
615        let mut shellenv: ShellProps = get_shellenv();
616        shellenv.elapsed_time = Duration::from_millis(5100);
617        shellenv.wrkdir = PathBuf::from("/");
618        shellenv.exit_status = 255;
619        //Print first in latin
620        let _ = prompt.get_line(&shellenv, &iop);
621        prompt.translate = true;
622        //Then in cyrillic
623        let _ = prompt.get_line(&shellenv, &iop);
624        //Get prompt line
625        let prompt_line: String = prompt.process_prompt(&shellenv, &iop);
626        let expected_prompt_line = String::from(format!(
627            "{}@{}:{} {}",
628            shellenv.username.clone(),
629            shellenv.hostname.clone(),
630            shellenv.wrkdir.display(),
631            "${FOOBAR}"
632        ));
633        assert_eq!(prompt_line, expected_prompt_line);
634        //Terminate shell at the end of a test
635        //terminate_shell(&mut shellenv);
636        println!("\n");
637    }
638
639    fn get_ioprocessor() -> IOProcessor {
640        IOProcessor::new(Language::Russian, new_translator(Language::Russian))
641    }
642
643    fn get_shellenv() -> ShellProps {
644        ShellProps {
645            hostname: String::from("default"),
646            username: String::from("user"),
647            elapsed_time: Duration::from_secs(0),
648            exit_status: 0,
649            wrkdir: PathBuf::from("/home/user/")
650        }
651    }
652}