git_iblame/extensions/
terminal_raw_mode_scope.rs

1use std::io;
2
3use crossterm::terminal;
4use log::*;
5
6/// Enable or disable the
7/// [terminal raw mode](https://docs.rs/crossterm/latest/crossterm/terminal/index.html#raw-mode)
8/// while its instance is in scope.
9///
10/// While it automatically resets the mode when it's out of scope,
11/// `reset()` should be called at the end
12/// to avoid it being dropped earlier.
13/// # Examples
14/// ```no_run
15/// # fn main() -> std::io::Result<()> {
16/// use git_iblame::TerminalRawModeScope;
17///
18/// let mut terminal_raw_mode = TerminalRawModeScope::new(true)?;
19/// // Do work.
20/// terminal_raw_mode.reset();
21/// # Ok(())
22/// # }
23/// ```
24pub struct TerminalRawModeScope {
25    is_enabled: bool,
26    is_reset: bool,
27}
28
29impl TerminalRawModeScope {
30    pub fn new(enable: bool) -> io::Result<Self> {
31        Self::enable(enable)?;
32        Ok(Self {
33            is_enabled: enable,
34            is_reset: false,
35        })
36    }
37
38    pub fn reset(&mut self) {
39        if !self.is_reset {
40            if let Err(error) = Self::enable(!self.is_enabled) {
41                warn!("Failed to change terminal raw mode, ignored: {error}");
42            }
43            self.is_reset = true;
44        }
45    }
46
47    fn enable(enable: bool) -> io::Result<()> {
48        debug!("TerminalRawModeScope.enable({enable})");
49        if enable {
50            terminal::enable_raw_mode()
51        } else {
52            terminal::disable_raw_mode()
53        }
54    }
55}
56
57impl Drop for TerminalRawModeScope {
58    fn drop(&mut self) {
59        self.reset();
60    }
61}