wsx 0.15.6

TUI workspace manager — git worktrees + tmux sessions in one tree
use crate::action::Action;
use anyhow::Result;
use crossterm::event::{
    self, Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
};
use std::time::Duration;

pub fn poll_event(timeout: Duration, in_input: bool) -> Result<Option<Action>> {
    if event::poll(timeout)? {
        let action = match event::read()? {
            Event::Key(key) => {
                if in_input {
                    translate_input_key(key)
                } else {
                    translate_key(key)
                }
            }
            Event::Mouse(mouse) => translate_mouse(mouse),
            Event::Resize(_, _) => Action::Resize,
            _ => Action::None,
        };
        Ok(Some(action))
    } else {
        Ok(None)
    }
}

/// Input mode: only special keys are translated; all chars go to the buffer.
fn translate_input_key(key: KeyEvent) -> Action {
    match key.code {
        KeyCode::Enter => Action::Select,
        KeyCode::Esc => Action::InputEscape,
        KeyCode::Backspace => Action::InputBackspace,
        KeyCode::Tab => Action::InputTab,
        KeyCode::BackTab => Action::InputBackTab,
        KeyCode::Down => Action::NavigateDown,
        KeyCode::Up => Action::NavigateUp,
        KeyCode::Left => Action::NavigateLeft,
        KeyCode::Right => Action::NavigateRight,
        KeyCode::Char(c) => Action::InputChar(c),
        _ => Action::None,
    }
}

fn translate_mouse(mouse: MouseEvent) -> Action {
    match mouse.kind {
        MouseEventKind::Down(MouseButton::Left) => Action::MouseClick {
            col: mouse.column,
            row: mouse.row,
        },
        _ => Action::None,
    }
}

fn translate_key(key: KeyEvent) -> Action {
    match (key.modifiers, key.code) {
        (KeyModifiers::NONE, KeyCode::Char('q')) => Action::Quit,
        (KeyModifiers::NONE, KeyCode::Char('j')) | (KeyModifiers::NONE, KeyCode::Down) => {
            Action::NavigateDown
        }
        (KeyModifiers::NONE, KeyCode::Char('k')) | (KeyModifiers::NONE, KeyCode::Up) => {
            Action::NavigateUp
        }
        (KeyModifiers::NONE, KeyCode::Char('h')) | (KeyModifiers::NONE, KeyCode::Left) => {
            Action::NavigateLeft
        }
        (KeyModifiers::NONE, KeyCode::Char('l')) | (KeyModifiers::NONE, KeyCode::Right) => {
            Action::NavigateRight
        }
        (KeyModifiers::NONE, KeyCode::Enter) => Action::Select,
        (KeyModifiers::NONE, KeyCode::Char('p')) => Action::AddProject,
        (KeyModifiers::NONE, KeyCode::Char('w')) => Action::AddWorktree,
        (KeyModifiers::NONE, KeyCode::Char('s')) => Action::AddSession,
        (KeyModifiers::NONE, KeyCode::Char('d')) => Action::Delete,
        (KeyModifiers::NONE, KeyCode::Char('c')) => Action::Clean,
        (KeyModifiers::NONE, KeyCode::Char('e')) => Action::Edit,
        (KeyModifiers::NONE, KeyCode::Char('r')) => Action::SetAlias,
        (KeyModifiers::SHIFT, KeyCode::Char('R')) | (KeyModifiers::NONE, KeyCode::Char('R')) => {
            Action::Refresh
        }
        (KeyModifiers::NONE, KeyCode::Char('?')) => Action::Help,
        (KeyModifiers::NONE, KeyCode::Char('y')) => Action::ConfirmYes,
        (KeyModifiers::NONE, KeyCode::Char('n')) => Action::NextAttention,
        (KeyModifiers::SHIFT, KeyCode::Char('N')) | (KeyModifiers::NONE, KeyCode::Char('N')) => {
            Action::PrevAttention
        }
        (KeyModifiers::NONE, KeyCode::Char('x')) => Action::DismissAttention,
        (KeyModifiers::NONE, KeyCode::Char('m')) => Action::EnterMove,
        (KeyModifiers::NONE, KeyCode::Char(']')) => Action::JumpProjectDown,
        (KeyModifiers::NONE, KeyCode::Char('[')) => Action::JumpProjectUp,
        (KeyModifiers::NONE, KeyCode::Char('a')) => Action::NextActive,
        (KeyModifiers::SHIFT, KeyCode::Char('A')) | (KeyModifiers::NONE, KeyCode::Char('A')) => Action::PrevActive,
        (KeyModifiers::NONE, KeyCode::Char('i')) => Action::NextIdle,
        (KeyModifiers::SHIFT, KeyCode::Char('I')) | (KeyModifiers::NONE, KeyCode::Char('I')) => Action::PrevIdle,
        (KeyModifiers::SHIFT, KeyCode::Char('S')) | (KeyModifiers::NONE, KeyCode::Char('S')) => {
            Action::SendCommand
        }
        (KeyModifiers::SHIFT, KeyCode::Char('C')) | (KeyModifiers::NONE, KeyCode::Char('C')) => {
            Action::SendCtrlC
        }
        (KeyModifiers::NONE, KeyCode::Char('/')) => Action::SearchStart,
        (KeyModifiers::NONE, KeyCode::Char('g')) => Action::GitPopup,
        (KeyModifiers::SHIFT, KeyCode::Char('{')) | (KeyModifiers::NONE, KeyCode::Char('{')) => Action::TabPrev,
        (KeyModifiers::SHIFT, KeyCode::Char('}')) | (KeyModifiers::NONE, KeyCode::Char('}')) => Action::TabNext,
        (KeyModifiers::SHIFT, KeyCode::Char('T')) | (KeyModifiers::NONE, KeyCode::Char('T')) => Action::TabManager,
        (KeyModifiers::NONE, KeyCode::Esc) => Action::InputEscape,
        (KeyModifiers::NONE, KeyCode::Backspace) => Action::InputBackspace,
        _ => Action::None,
    }
}