tr_lang/
interactive.rs

1use crate::errwarn::ErrorGenerator;
2use crate::lexer::Lexer;
3use crate::parser::Parser;
4use crate::runtime::Run;
5use crate::store::VERSION;
6use crate::util::{get_lang, SupportedLanguage};
7use lazy_static::lazy_static;
8use regex::Regex;
9use rustyline::completion::Completer;
10use rustyline::completion::Pair;
11use rustyline::error::ReadlineError;
12use rustyline::Editor;
13
14// TODO: Finish completer
15/// Completer in progress
16struct InteractiveCompleter;
17impl Completer for InteractiveCompleter {
18    type Candidate = Pair;
19    fn complete(
20        &self,
21        line: &str,
22        pos: usize,
23        _ctx: &rustyline::Context<'_>,
24    ) -> rustyline::Result<(usize, Vec<Pair>)> {
25        lazy_static! {
26            static ref RE: Regex =
27                Regex::new(r#"[^()\d,'"+\-*/><!=%?.@\s][^\s"':?=<>!/%*@,()]*"#).unwrap();
28            static ref KNOWN_KEYWORDS: Vec<&'static str> = vec![
29                "at", "ver", "de", "ise", "son", "iken", "yoksa", "doğru", "yanlış", "kpy", "tks",
30                "üst", "veya", "ve", "dön", "girdi", "işlev", "yükle",
31            ];
32        }
33        let matches = RE.find_iter(line);
34        for m in matches.into_iter() {
35            if m.end() == pos {
36                return Ok((
37                    m.start(),
38                    KNOWN_KEYWORDS
39                        .iter()
40                        .filter(|a| a.starts_with(m.as_str()))
41                        .map(|a| Pair {
42                            display: a.to_string(),
43                            replacement: a.to_string(),
44                        })
45                        .collect(),
46                ));
47            }
48        }
49        Ok((0, Vec::with_capacity(0)))
50    }
51}
52
53#[derive(Debug, PartialEq, Eq)]
54pub enum QuietLevel {
55    None,
56    Quiet,
57    Quieter,
58    Quietest,
59}
60impl QuietLevel {
61    pub fn inc(&mut self) {
62        match self {
63            Self::None => *self = Self::Quiet,
64            Self::Quiet => *self = Self::Quieter,
65            Self::Quieter => *self = Self::Quietest,
66            Self::Quietest => (),
67        }
68    }
69    pub fn inc_by(&mut self, i: usize) {
70        for _ in 0..i {
71            self.inc()
72        }
73    }
74}
75
76pub struct Interactive {
77    line: usize,
78    quiet: QuietLevel,
79}
80impl Default for Interactive {
81    fn default() -> Self {
82        Self {
83            line: 1,
84            quiet: QuietLevel::None,
85        }
86    }
87}
88impl Interactive {
89    pub fn new(quiet: QuietLevel) -> Self {
90        Self {
91            quiet,
92            ..Default::default()
93        }
94    }
95    pub fn start(&mut self) {
96        if self.quiet == QuietLevel::None {
97            match get_lang() {
98                SupportedLanguage::Turkish => {
99                    println!("tr-lang ({VERSION}) interaktif konsol");
100                    println!("çıkmak için `#çık` yazın");
101                    println!("yürütmek için `#yürüt` yazın");
102                }
103                SupportedLanguage::English => {
104                    println!("tr-lang ({VERSION}) interactive console");
105                    println!("type `#çık` to exit");
106                    println!("type `#yürüt` to run");
107                }
108            }
109        }
110        let mut fbuf = String::new();
111        let mut editor = Editor::<()>::new();
112        if editor.load_history(".trlhistory").is_err() {
113            match get_lang() {
114                SupportedLanguage::Turkish => println!("Tarih bulunamadı."),
115                SupportedLanguage::English => println!("No previous history."),
116            }
117        }
118        loop {
119            let pr = match self.quiet {
120                QuietLevel::None => format!("trli:{:03}#> ", self.line),
121                QuietLevel::Quiet => format!("{:03}#> ", self.line),
122                QuietLevel::Quieter => "#> ".to_string(),
123                QuietLevel::Quietest => "".to_string(),
124            };
125            let rl = editor.readline(&pr);
126            match rl {
127                Ok(buf) => match buf.as_str() {
128                    "#çık" => break,
129                    "#yürüt" => {
130                        let (mut memcs, _) = Run::new(
131                            match match Parser::from_lexer(&mut Lexer::new(fbuf.clone()), ".".to_string()) {
132                                Ok(parser) => parser,
133                                Err(e) => {
134                                    e.eprint();
135                                    continue;
136                                }
137                            }.parse() {
138                                Ok(ptk) => ptk,
139                                Err(e) => { e.eprint(); continue; }
140                            },
141                        )
142                        .run("<trli>".to_string(), None, true)
143                        .unwrap_or_else(|(s, h, e)| {
144                            e.eprint();
145                            (s, h)
146                        });
147                        println!();
148                        if memcs.len() > 0 {
149                            println!("=> {:?}", memcs.iter_vec());
150                        }
151                        fbuf = String::new();
152                        self.line = 1;
153                    }
154                    _ => {
155                        editor.add_history_entry(&buf);
156                        fbuf.push_str(&buf);
157                        fbuf.push('\n');
158                        self.line += 1;
159                    }
160                },
161                Err(ReadlineError::Interrupted) => {
162                    eprintln!("Ctrl+C");
163                }
164                Err(ReadlineError::Eof) => break,
165                Err(e) => match get_lang() {
166                    SupportedLanguage::Turkish => ErrorGenerator::error(
167                        "EditörHatası",
168                        &format!("{}", e),
169                        self.line,
170                        0,
171                        "<trli>".to_string(),
172                        None,
173                    ),
174                    SupportedLanguage::English => ErrorGenerator::error(
175                        "EditorError",
176                        &format!("{}", e),
177                        self.line,
178                        0,
179                        "<trli>".to_string(),
180                        None,
181                    ),
182                }
183                .eprint(),
184            }
185        }
186        editor.save_history(".trlhistory").unwrap();
187    }
188}