mod actions;
mod ahead_behind;
mod app;
mod client;
mod clipboard;
mod hub;
mod keys;
mod layout;
mod local_state;
mod mouse;
mod panes;
mod popup;
mod render;
mod row_colors;
mod supervisor;
mod terminal;
mod tree;
mod view_model;
mod wire;
use std::io::Stdout;
use std::path::PathBuf;
use anyhow::Result;
use clap::Parser;
use crossterm::event::{
DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture,
};
use crossterm::execute;
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use ratatui::backend::CrosstermBackend;
use ratatui::Terminal;
use tokio_util::sync::CancellationToken;
use crate::daemon::server;
use actions::Dispatcher;
use client::WorktreesClient;
#[derive(Parser)]
pub struct UiCommand {
#[arg(long, value_name = "PATH")]
pub socket: Option<PathBuf>,
}
impl UiCommand {
pub async fn execute(self) -> Result<()> {
let socket = server::resolve_socket(self.socket)?;
let cancel = CancellationToken::new();
let handle = hub::spawn(socket.clone(), cancel.clone());
let commands = handle.commands.clone();
let dispatcher = Dispatcher::new(WorktreesClient::new(socket), commands.clone());
let mut guard = TerminalGuard::enter()?;
let result = app::run(&mut guard.terminal, handle, dispatcher, commands).await;
drop(guard); cancel.cancel();
result
}
}
struct TerminalGuard {
terminal: Terminal<CrosstermBackend<Stdout>>,
}
impl TerminalGuard {
fn enter() -> Result<Self> {
enable_raw_mode()?;
let mut stdout = std::io::stdout();
if let Err(e) = execute!(
stdout,
EnterAlternateScreen,
EnableMouseCapture,
EnableBracketedPaste
) {
let _ = execute!(
std::io::stdout(),
DisableBracketedPaste,
LeaveAlternateScreen,
DisableMouseCapture
);
let _ = disable_raw_mode();
return Err(e.into());
}
let terminal = match Terminal::new(CrosstermBackend::new(stdout)) {
Ok(terminal) => terminal,
Err(e) => {
let _ = execute!(
std::io::stdout(),
DisableBracketedPaste,
LeaveAlternateScreen,
DisableMouseCapture
);
let _ = disable_raw_mode();
return Err(e.into());
}
};
Ok(Self { terminal })
}
}
impl Drop for TerminalGuard {
fn drop(&mut self) {
let _ = disable_raw_mode();
let _ = execute!(
self.terminal.backend_mut(),
DisableBracketedPaste,
LeaveAlternateScreen,
DisableMouseCapture
);
let _ = self.terminal.show_cursor();
}
}