use anyhow::Result;
use crossterm::{
event::{
DisableBracketedPaste, EnableBracketedPaste, KeyboardEnhancementFlags,
PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
},
execute,
terminal::{
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
supports_keyboard_enhancement,
},
};
struct EnableScrollMouseCapture;
impl crossterm::Command for EnableScrollMouseCapture {
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
f.write_str("\x1b[?1000h\x1b[?1006h")
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
use crossterm::event::EnableMouseCapture;
EnableMouseCapture.execute_winapi()
}
}
struct DisableScrollMouseCapture;
impl crossterm::Command for DisableScrollMouseCapture {
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
f.write_str("\x1b[?1006l\x1b[?1000l")
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
use crossterm::event::DisableMouseCapture;
DisableMouseCapture.execute_winapi()
}
}
use ratatui::prelude::*;
use std::io::{self, Stdout};
#[cfg(unix)]
pub fn redirect_stderr(log_dir: &std::path::Path) {
use std::os::unix::io::IntoRawFd;
let path = crate::config::dated_log_path(log_dir, "stderr", 7);
if let Ok(f) = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&path)
{
unsafe {
libc::dup2(f.into_raw_fd(), 2);
}
}
}
#[cfg(not(unix))]
pub fn redirect_stderr(_log_dir: &std::path::Path) {}
pub type Tui = Terminal<CrosstermBackend<Stdout>>;
pub fn init() -> Result<Tui> {
let original_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
use std::sync::atomic::{AtomicBool, Ordering};
static IN_PANIC: AtomicBool = AtomicBool::new(false);
if !IN_PANIC.swap(true, Ordering::SeqCst) {
let _ = restore();
}
original_hook(panic_info);
}));
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(
stdout,
EnterAlternateScreen,
EnableScrollMouseCapture,
EnableBracketedPaste
)?;
if supports_keyboard_enhancement().unwrap_or(false) {
let _ = execute!(
stdout,
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
);
}
let backend = CrosstermBackend::new(stdout);
let terminal = Terminal::new(backend)?;
Ok(terminal)
}
pub fn restore() -> Result<()> {
if supports_keyboard_enhancement().unwrap_or(false) {
let _ = execute!(io::stdout(), PopKeyboardEnhancementFlags);
}
disable_raw_mode()?;
execute!(
io::stdout(),
LeaveAlternateScreen,
DisableScrollMouseCapture,
DisableBracketedPaste
)?;
Ok(())
}