|
1 | | -use crate::stage::{ |
2 | | - Stage, |
3 | | - structs::{Entity, Text}, |
4 | | -}; |
| 1 | +use egui::Margin; |
| 2 | + |
| 3 | +use crate::stage::{Stage, structs::Entity}; |
5 | 4 |
|
6 | 5 | pub struct Terminal { |
7 | 6 | input: String, |
| 7 | + history: Vec<HistoryItem>, |
8 | 8 | } |
9 | 9 |
|
10 | 10 | impl Terminal { |
11 | 11 | pub fn new() -> Self { |
12 | 12 | Terminal { |
13 | 13 | input: String::new(), |
| 14 | + history: Vec::new(), |
14 | 15 | } |
15 | 16 | } |
16 | 17 |
|
17 | 18 | pub fn ui(&mut self, ui: &mut egui::Ui, stage: &mut Stage) { |
18 | | - ui.heading("Terminal"); |
19 | | - ui.separator(); |
20 | | - ui.text_edit_multiline(&mut self.input); |
21 | | - if ui.button("execute").clicked() { |
22 | | - match knus::parse::<Vec<Entity>>("terminal_input.kdl", &self.input) { |
23 | | - Ok(doc) => { |
24 | | - for entity in doc { |
25 | | - stage.context.add(entity.into()); |
| 19 | + egui::ScrollArea::vertical() |
| 20 | + .stick_to_bottom(true) |
| 21 | + .show(ui, |ui| { |
| 22 | + // 历史记录 |
| 23 | + for item in &self.history { |
| 24 | + match item { |
| 25 | + HistoryItem::In(cmd) => { |
| 26 | + for (i, line) in cmd.lines().enumerate() { |
| 27 | + let prefix = if i == 0 { "> " } else { " " }; |
| 28 | + ui.label( |
| 29 | + egui::RichText::new(format!("{}{}", prefix, line)) |
| 30 | + .color(egui::Color32::LIGHT_BLUE) |
| 31 | + .font(egui::FontId::monospace(14.0)), |
| 32 | + ); |
| 33 | + } |
| 34 | + } |
| 35 | + HistoryItem::Out(output) => { |
| 36 | + ui.label( |
| 37 | + egui::RichText::new(output) |
| 38 | + .color(egui::Color32::WHITE) |
| 39 | + .font(egui::FontId::monospace(14.0)), |
| 40 | + ); |
| 41 | + } |
| 42 | + HistoryItem::Err(err) => { |
| 43 | + ui.label( |
| 44 | + egui::RichText::new(err) |
| 45 | + .color(egui::Color32::LIGHT_RED) |
| 46 | + .font(egui::FontId::monospace(14.0)), |
| 47 | + ); |
| 48 | + } |
26 | 49 | } |
27 | 50 | } |
28 | | - Err(e) => { |
29 | | - log::error!("{:?}", miette::Report::new(e)); |
30 | | - } |
31 | | - } |
32 | | - self.input.clear(); |
33 | | - } |
| 51 | + |
| 52 | + // 输入框 |
| 53 | + ui.horizontal(|ui| { |
| 54 | + ui.label( |
| 55 | + egui::RichText::new(">") |
| 56 | + .color(egui::Color32::LIGHT_BLUE) |
| 57 | + .font(egui::FontId::monospace(14.0)), |
| 58 | + ); |
| 59 | + |
| 60 | + let response = ui.add( |
| 61 | + egui::TextEdit::multiline(&mut self.input) |
| 62 | + .id(ui.make_persistent_id("terminal_input")) |
| 63 | + .desired_width(f32::INFINITY) |
| 64 | + .desired_rows(1) |
| 65 | + .lock_focus(true) |
| 66 | + .text_color(egui::Color32::LIGHT_BLUE) |
| 67 | + .font(egui::FontId::monospace(14.0)) |
| 68 | + .margin(Margin::ZERO) |
| 69 | + .frame(false), |
| 70 | + ); |
| 71 | + if response.has_focus() |
| 72 | + && ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::Enter)) |
| 73 | + { |
| 74 | + let modifiers = ui.input(|i| i.modifiers); |
| 75 | + if !modifiers.shift && !modifiers.ctrl && !modifiers.alt { |
| 76 | + self.history |
| 77 | + .push(HistoryItem::In(self.input.clone().trim().to_string())); |
| 78 | + match knus::parse::<Vec<Entity>>("terminal_input.kdl", &self.input) { |
| 79 | + Ok(doc) => { |
| 80 | + for entity in doc { |
| 81 | + stage.context.add(entity.into()); |
| 82 | + } |
| 83 | + } |
| 84 | + Err(e) => { |
| 85 | + // log::error!("{:?}", miette::Report::new(e.into())); |
| 86 | + self.history.push(HistoryItem::Err(get_plain_report_string( |
| 87 | + miette::Report::new(e), |
| 88 | + ))); |
| 89 | + } |
| 90 | + } |
| 91 | + self.input.clear(); |
| 92 | + response.request_focus(); |
| 93 | + } |
| 94 | + } |
| 95 | + }); |
| 96 | + |
| 97 | + ui.allocate_space(ui.available_size()); |
| 98 | + }); |
34 | 99 | } |
35 | 100 | } |
| 101 | + |
| 102 | +enum HistoryItem { |
| 103 | + In(String), |
| 104 | + Out(String), |
| 105 | + Err(String), |
| 106 | +} |
| 107 | + |
| 108 | +fn get_plain_report_string(report: miette::Report) -> String { |
| 109 | + let mut out = String::new(); |
| 110 | + // 创建一个不带颜色的渲染处理器 |
| 111 | + miette::GraphicalReportHandler::new_themed(miette::GraphicalTheme::unicode_nocolor()) |
| 112 | + .render_report(&mut out, report.as_ref()) |
| 113 | + .unwrap(); |
| 114 | + out |
| 115 | +} |
0 commit comments