ratatui_kit/terminal/
cross_terminal.rs

1use super::TerminalImpl;
2use crossterm::event::{self, EventStream};
3use futures::{StreamExt, stream::BoxStream};
4use ratatui::{Frame, TerminalOptions};
5use std::io::{self};
6
7// ================== 终端核心功能实现 ==================
8
9// 跨平台终端结构体
10// input_is_terminal: 标记标准输入是否为终端设备
11// dest: 标准输出流(用于终端操作)
12// raw_mode_enabled: 原始模式启用状态
13// enabled_keyboard_enhancement: 键盘增强功能状态
14// fullscreen: 是否启用全屏模式
15pub struct CrossTerminal {
16    terminal: ratatui::DefaultTerminal,
17}
18
19impl CrossTerminal {
20    // 创建终端实例
21    // fullscreen: 是否启用备用屏幕(全屏模式)
22    pub fn new() -> io::Result<Self> {
23        Ok(Self {
24            terminal: ratatui::init(),
25        })
26    }
27
28    // 启用/禁用原始模式
29    pub fn with_options(options: TerminalOptions) -> io::Result<Self> {
30        Ok(Self {
31            terminal: ratatui::init_with_options(options),
32        })
33    }
34}
35
36// ================== 生命周期管理 ==================
37// 不能在这里调用restore,因为render_loop中途可能会panic,导致提前drop,所以报错信息会被覆盖
38// 需要在render_loop结束后手动调用restore
39// impl Drop for CrossTerminal {
40//     // 析构函数:自动恢复终端原始状态
41//     fn drop(&mut self) {
42//         ratatui::restore();
43//     }
44// }
45
46// ================== 终端接口实现 ==================
47
48impl TerminalImpl for CrossTerminal {
49    type Event = event::Event;
50
51    // 创建事件流
52    fn event_stream(&mut self) -> io::Result<BoxStream<'static, Self::Event>> {
53        // 创建事件流并过滤错误
54        Ok(EventStream::new()
55            .filter_map(|event| async move { event.ok() })
56            .boxed())
57    }
58
59    // 检测Ctrl+C组合键
60    fn received_ctrl_c(event: Self::Event) -> bool {
61        matches!(
62            event,
63            event::Event::Key(event::KeyEvent {
64                code: event::KeyCode::Char('c'),
65                modifiers: event::KeyModifiers::CONTROL,
66                kind: event::KeyEventKind::Press,
67                ..
68            })
69        )
70    }
71
72    fn draw<F>(&mut self, f: F) -> io::Result<()>
73    where
74        F: FnOnce(&mut Frame),
75    {
76        self.terminal.draw(f)?;
77        Ok(())
78    }
79
80    fn insert_before<F>(&mut self, height: u16, draw_fn: F) -> io::Result<()>
81    where
82        F: FnOnce(&mut ratatui::prelude::Buffer),
83    {
84        self.terminal.insert_before(height, draw_fn)?;
85        Ok(())
86    }
87}