crashdump_parser/tui.rs
1// Copyright (c) Meta Platforms, Inc. and affiliates.
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::app::{App, AppResult};
16use crate::event::EventHandler;
17use crate::ui;
18use crossterm::event::DisableMouseCapture;
19use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
20use ratatui::backend::Backend;
21use ratatui::Terminal;
22use std::io;
23use std::panic;
24
25/// Representation of a terminal user interface.
26///
27/// It is responsible for setting up the terminal,
28/// initializing the interface and handling the draw events.
29#[derive(Debug)]
30pub struct Tui<B: Backend> {
31 /// Interface to the Terminal.
32 terminal: Terminal<B>,
33 /// Terminal event handler.
34 pub events: EventHandler,
35}
36
37impl<B: Backend> Tui<B> {
38 /// Constructs a new instance of [`Tui`].
39 pub fn new(terminal: Terminal<B>, events: EventHandler) -> Self {
40 Self { terminal, events }
41 }
42
43 /// Initializes the terminal interface.
44 ///
45 /// It enables the raw mode and sets terminal properties.
46 pub fn init(&mut self) -> AppResult<()> {
47 terminal::enable_raw_mode()?;
48 crossterm::execute!(io::stdout(), EnterAlternateScreen, DisableMouseCapture)?;
49
50 // Define a custom panic hook to reset the terminal properties.
51 // This way, you won't have your terminal messed up if an unexpected error happens.
52 let panic_hook = panic::take_hook();
53 panic::set_hook(Box::new(move |panic| {
54 Self::reset().expect("failed to reset the terminal");
55 panic_hook(panic);
56 }));
57
58 self.terminal.hide_cursor()?;
59 self.terminal.clear()?;
60 Ok(())
61 }
62
63 /// [`Draw`] the terminal interface by [`rendering`] the widgets.
64 ///
65 /// [`Draw`]: ratatui::Terminal::draw
66 /// [`rendering`]: crate::ui::render
67 pub fn draw(&mut self, app: &mut App) -> AppResult<()> {
68 self.terminal.draw(|frame| ui::render(app, frame))?;
69 Ok(())
70 }
71
72 /// Resets the terminal interface.
73 ///
74 /// This function is also used for the panic hook to revert
75 /// the terminal properties if unexpected errors occur.
76 fn reset() -> AppResult<()> {
77 terminal::disable_raw_mode()?;
78 crossterm::execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
79 Ok(())
80 }
81
82 /// Exits the terminal interface.
83 ///
84 /// It disables the raw mode and reverts back the terminal properties.
85 pub fn exit(&mut self) -> AppResult<()> {
86 Self::reset()?;
87 self.terminal.show_cursor()?;
88 Ok(())
89 }
90}