Skip to main content

oak_repl/
lib.rs

1//! Oak REPL (Custom Implementation)
2//!
3//! 深度集成 Oak 语言特性的 REPL 框架。
4//! 支持多行输入、语法完整性检查、以及自定义高亮。
5
6use crossterm::{
7    cursor::MoveToColumn,
8    event::{self, Event, KeyCode, KeyModifiers},
9    execute,
10    terminal::{self, Clear, ClearType},
11};
12use oak_highlight::{AnsiExporter, Exporter, HighlightResult, OakHighlighter};
13use std::io::{self, Write};
14
15use std::{
16    error::Error,
17    fmt::{Display, Formatter},
18};
19
20#[derive(Debug)]
21pub enum ReplError {
22    Io(std::io::Error),
23    Other(String),
24}
25
26impl Display for ReplError {
27    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
28        match self {
29            ReplError::Io(e) => write!(f, "IO error: {}", e),
30            ReplError::Other(s) => write!(f, "{}", s),
31        }
32    }
33}
34
35impl Error for ReplError {}
36
37impl From<std::io::Error> for ReplError {
38    fn from(e: std::io::Error) -> Self {
39        ReplError::Io(e)
40    }
41}
42
43impl From<String> for ReplError {
44    fn from(s: String) -> Self {
45        ReplError::Other(s)
46    }
47}
48
49impl From<&str> for ReplError {
50    fn from(s: &str) -> Self {
51        ReplError::Other(s.to_string())
52    }
53}
54
55/// REPL 处理结果
56pub enum HandleResult {
57    /// 继续 REPL
58    Continue,
59    /// 退出 REPL
60    Exit,
61}
62
63/// 语言集成接口
64pub trait ReplHandler {
65    /// 获取语法高亮结果
66    fn highlight<'a>(&self, _code: &'a str) -> Option<HighlightResult<'a>> {
67        None
68    }
69
70    /// 提示符
71    fn prompt(&self, is_continuation: bool) -> &str;
72
73    /// 检查输入是否已完整(例如括号是否闭合)
74    /// 如果返回 false,REPL 将进入多行输入模式
75    fn is_complete(&self, code: &str) -> bool;
76
77    /// 执行代码行
78    fn handle_line(&mut self, line: &str) -> Result<HandleResult, ReplError>;
79
80    /// 获取当前缩进级别
81    fn get_indent(&self, _code: &str) -> usize {
82        // 默认不缩进
83        0
84    }
85}
86
87pub struct LineBuffer {
88    lines: Vec<String>,
89    current_line: usize,
90    cursor_pos: usize,
91}
92
93impl LineBuffer {
94    pub fn new() -> Self {
95        Self { lines: vec![String::new()], current_line: 0, cursor_pos: 0 }
96    }
97
98    pub fn insert(&mut self, ch: char) {
99        self.lines[self.current_line].insert(self.cursor_pos, ch);
100        self.cursor_pos += 1;
101    }
102
103    pub fn backspace(&mut self) -> bool {
104        if self.cursor_pos > 0 {
105            self.cursor_pos -= 1;
106            self.lines[self.current_line].remove(self.cursor_pos);
107            true
108        }
109        else if self.current_line > 0 {
110            // 合并到上一行
111            let current = self.lines.remove(self.current_line);
112            self.current_line -= 1;
113            self.cursor_pos = self.lines[self.current_line].chars().count();
114            self.lines[self.current_line].push_str(&current);
115            true
116        }
117        else {
118            false
119        }
120    }
121
122    pub fn full_text(&self) -> String {
123        self.lines.join("\n")
124    }
125
126    pub fn clear(&mut self) {
127        self.lines = vec![String::new()];
128        self.current_line = 0;
129        self.cursor_pos = 0;
130    }
131
132    pub fn is_empty(&self) -> bool {
133        self.lines.len() == 1 && self.lines[0].is_empty()
134    }
135}
136
137pub struct OakRepl<H: ReplHandler> {
138    handler: H,
139}
140
141impl<H: ReplHandler> OakRepl<H> {
142    pub fn new(handler: H) -> Self {
143        Self { handler }
144    }
145
146    pub fn run(&mut self) -> Result<(), ReplError> {
147        let mut stdout = io::stdout();
148        let mut line_buf = LineBuffer::new();
149        let mut is_continuation = false;
150        let _highlighter = OakHighlighter::new();
151        let exporter = AnsiExporter;
152
153        terminal::enable_raw_mode()?;
154
155        loop {
156            // 绘制当前行
157            execute!(stdout, MoveToColumn(0), Clear(ClearType::CurrentLine))?;
158            let prompt = self.handler.prompt(is_continuation);
159
160            let current_line_text = &line_buf.lines[line_buf.current_line];
161
162            // 语法高亮
163            let displayed_text = if let Some(highlighted) = self.handler.highlight(current_line_text) { exporter.export(&highlighted) } else { current_line_text.clone() };
164
165            write!(stdout, "{}{}", prompt, displayed_text)?;
166
167            let cursor_col = (prompt.chars().count() + line_buf.cursor_pos) as u16;
168            execute!(stdout, MoveToColumn(cursor_col))?;
169            stdout.flush()?;
170
171            if let Event::Key(key_event) = event::read()? {
172                match key_event.code {
173                    KeyCode::Char('c') if key_event.modifiers.contains(KeyModifiers::CONTROL) => {
174                        println!("\nInterrupted");
175                        line_buf.clear();
176                        is_continuation = false;
177                        continue;
178                    }
179                    KeyCode::Char('d') if key_event.modifiers.contains(KeyModifiers::CONTROL) => {
180                        if line_buf.is_empty() {
181                            println!("\nEOF");
182                            break;
183                        }
184                    }
185                    KeyCode::Char(ch) => {
186                        line_buf.insert(ch);
187                    }
188                    KeyCode::Enter => {
189                        let full_code = line_buf.full_text();
190
191                        if self.handler.is_complete(&full_code) {
192                            terminal::disable_raw_mode()?;
193                            println!();
194
195                            match self.handler.handle_line(&full_code) {
196                                Ok(HandleResult::Exit) => break,
197                                Ok(HandleResult::Continue) => {}
198                                Err(e) => eprintln!("Error: {}", e),
199                            }
200
201                            line_buf.clear();
202                            is_continuation = false;
203                            terminal::enable_raw_mode()?;
204                        }
205                        else {
206                            // 继续多行输入
207                            println!();
208                            line_buf.lines.push(String::new());
209                            line_buf.current_line += 1;
210                            line_buf.cursor_pos = 0;
211                            is_continuation = true;
212
213                            // 自动缩进
214                            let indent_size = self.handler.get_indent(&full_code);
215                            for _ in 0..indent_size {
216                                line_buf.insert(' ');
217                            }
218                        }
219                    }
220                    KeyCode::Backspace => {
221                        line_buf.backspace();
222                    }
223                    KeyCode::Left => {
224                        if line_buf.cursor_pos > 0 {
225                            line_buf.cursor_pos -= 1;
226                        }
227                    }
228                    KeyCode::Right => {
229                        if line_buf.cursor_pos < line_buf.lines[line_buf.current_line].chars().count() {
230                            line_buf.cursor_pos += 1;
231                        }
232                    }
233                    _ => {}
234                }
235            }
236        }
237
238        terminal::disable_raw_mode()?;
239        Ok(())
240    }
241}