diff --git a/crates/term/src/backends/channel.rs b/crates/term/src/backends/channel.rs index daf0c12a..a0102919 100644 --- a/crates/term/src/backends/channel.rs +++ b/crates/term/src/backends/channel.rs @@ -64,11 +64,17 @@ impl Channel { } impl super::Backend for Channel { - fn with_term(&mut self, f: &mut dyn FnMut(&mut Term)) { + fn with_term(&mut self, f: F) -> T + where + F: FnOnce(&mut Term) -> T, + { f(&mut self.term) } - fn with_event_recv(&mut self, f: &mut dyn FnMut(&mut Receiver)) { + fn with_event_recv(&mut self, f: F) -> T + where + F: FnOnce(&mut Receiver) -> T, + { f(&mut self.event_reciever) } diff --git a/crates/term/src/backends/mod.rs b/crates/term/src/backends/mod.rs index 9deb4f27..2d6d53d7 100644 --- a/crates/term/src/backends/mod.rs +++ b/crates/term/src/backends/mod.rs @@ -32,7 +32,7 @@ pub use channel::Channel; pub use process::Process; #[derive(Clone)] -pub(crate) struct EventListener(Sender); +pub struct EventListener(Sender); impl alacritty_terminal::event::EventListener for EventListener { fn send_event(&self, event: Event) { @@ -41,10 +41,14 @@ impl alacritty_terminal::event::EventListener for EventListener { } } -pub(crate) trait Backend { - fn with_term(&mut self, f: &mut dyn FnMut(&mut alacritty_terminal::Term)); +pub trait Backend { + fn with_term(&mut self, f: F) -> T + where + F: FnOnce(&mut alacritty_terminal::Term) -> T; - fn with_event_recv(&mut self, f: &mut dyn FnMut(&mut Receiver)); + fn with_event_recv(&mut self, f: F) -> T + where + F: FnOnce(&mut Receiver) -> T; fn size(&self) -> (usize, usize); @@ -52,5 +56,7 @@ pub(crate) trait Backend { fn update(&mut self) {} + fn send(&mut self, _msg: alacritty_terminal::event_loop::Msg) {} + fn kill(&mut self) {} } diff --git a/crates/term/src/backends/process.rs b/crates/term/src/backends/process.rs index 9e6824b0..8ccb092c 100644 --- a/crates/term/src/backends/process.rs +++ b/crates/term/src/backends/process.rs @@ -83,12 +83,17 @@ impl Process { } impl super::Backend for Process { - fn with_term(&mut self, f: &mut dyn FnMut(&mut Term)) { - let mut lock = self.term.lock(); - f(&mut lock) + fn with_term(&mut self, f: F) -> T + where + F: FnOnce(&mut Term) -> T, + { + f(&mut self.term.lock()) } - fn with_event_recv(&mut self, f: &mut dyn FnMut(&mut Receiver)) { + fn with_event_recv(&mut self, f: F) -> T + where + F: FnOnce(&mut Receiver) -> T, + { f(&mut self.event_reciever) } @@ -107,6 +112,10 @@ impl super::Backend for Process { self.term.lock().resize(TermSize::new(cols, rows)) } + fn send(&mut self, msg: alacritty_terminal::event_loop::Msg) { + let _ = self.event_loop_sender.send(msg); + } + fn kill(&mut self) { let _ = self.event_loop_sender.send(Msg::Shutdown); } diff --git a/crates/term/src/widget/mod.rs b/crates/term/src/widget/mod.rs index 1a447952..ecd0f2d9 100644 --- a/crates/term/src/widget/mod.rs +++ b/crates/term/src/widget/mod.rs @@ -29,33 +29,42 @@ use crate::backends::Backend; mod theme; pub use theme::Theme; -pub struct Terminal { - // REVIEW should we use generics or trait objects? - backend: Box, +pub struct Terminal { + backend: T, theme: Theme, // TODO convert into shared config (possibly do this in luminol-preferences) title: String, } -impl Terminal { - fn new(backend: impl Backend + 'static) -> Self { +pub type ProcessTerminal = Terminal; +pub type ChannelTerminal = Terminal; + +impl Terminal { + fn new(backend: T) -> Self { Self { - backend: Box::new(backend), + backend, theme: Theme::default(), title: "Luminol Terminal".to_string(), } } +} +impl ProcessTerminal { pub fn process(options: &alacritty_terminal::tty::Options) -> std::io::Result { crate::backends::Process::new(options).map(Self::new) } +} +impl ChannelTerminal { pub fn channel(recv: std::sync::mpsc::Receiver) -> Self { let backend = crate::backends::Channel::new(recv); Self::new(backend) } } -impl Terminal { +impl Terminal +where + T: Backend, +{ pub fn title(&self) -> String { self.title.to_string() } @@ -89,13 +98,13 @@ impl Terminal { } pub fn erase_scrollback(&mut self) { - self.backend.with_term(&mut |term| { + self.backend.with_term(|term| { term.grid_mut().clear_history(); }); } pub fn erase_scrollback_and_viewport(&mut self) { - self.backend.with_term(&mut |term| { + self.backend.with_term(|term| { term.grid_mut().clear_viewport(); }); } @@ -107,7 +116,8 @@ impl Terminal { pub fn ui(&mut self, ui: &mut egui::Ui) -> color_eyre::Result<()> { self.backend.update(); - self.backend.with_term(&mut |term| { + // TODO cache render jobs + let job = self.backend.with_term(|term| { let content = term.renderable_content(); let mut job = egui::text::LayoutJob::default(); @@ -128,23 +138,26 @@ impl Terminal { job.append("\n", 0.0, Default::default()); } } - let galley = ui.fonts(|f| f.layout_job(job)); - let (response, painter) = - ui.allocate_painter(galley.rect.size(), egui::Sense::click_and_drag()); - painter.rect_filled( - galley.rect.translate(response.rect.min.to_vec2()), - 0.0, - egui::Color32::from_rgb(40, 39, 39), - ); + job + }); - painter.galley(response.rect.min, galley, egui::Color32::WHITE); + let galley = ui.fonts(|f| f.layout_job(job)); + let (response, painter) = + ui.allocate_painter(galley.rect.size(), egui::Sense::click_and_drag()); - if response.hovered() { - ui.output_mut(|o| o.mutable_text_under_cursor = true); - ui.ctx().set_cursor_icon(egui::CursorIcon::Text); - } - }); + painter.rect_filled( + galley.rect.translate(response.rect.min.to_vec2()), + 0.0, + egui::Color32::from_rgb(40, 39, 39), + ); + + painter.galley(response.rect.min, galley, egui::Color32::WHITE); + + if response.hovered() { + ui.output_mut(|o| o.mutable_text_under_cursor = true); + ui.ctx().set_cursor_icon(egui::CursorIcon::Text); + } Ok(()) } diff --git a/crates/ui/src/windows/console.rs b/crates/ui/src/windows/console.rs index a82f69db..6c44bebe 100644 --- a/crates/ui/src/windows/console.rs +++ b/crates/ui/src/windows/console.rs @@ -23,7 +23,7 @@ // Program grant you additional permission to convey the resulting work. pub struct Window { - term: luminol_term::widget::Terminal, + term: luminol_term::widget::ProcessTerminal, } impl Window { diff --git a/src/app/log_window.rs b/src/app/log_window.rs index 158954cb..8029d035 100644 --- a/src/app/log_window.rs +++ b/src/app/log_window.rs @@ -24,7 +24,7 @@ pub struct LogWindow { pub(super) term_shown: bool, - term: luminol_term::widget::Terminal, + term: luminol_term::widget::ChannelTerminal, save_promise: Option>>, }