memorph 0.1.7

Convert, import, and export AI coding sessions between Claude Code, Codex, and OpenCode
use anyhow::Result;
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyModifiers};
use ratatui::{backend::Backend, Terminal};
use std::time::Duration;

use super::app::{App, AppResult};

/// TUI 事件循环
pub fn run<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> Result<()> {
    let mut last_tick = std::time::Instant::now();
    let tick_rate = Duration::from_millis(250);

    loop {
        terminal.draw(|f| super::ui::draw(f, app))?;

        let timeout = tick_rate
            .checked_sub(last_tick.elapsed())
            .unwrap_or_else(|| Duration::from_secs(0));

        if crossterm::event::poll(timeout)? {
            if let Event::Key(key) = event::read()? {
                match handle_key_event(key, app) {
                    AppResult::Continue => {}
                    AppResult::Quit => {
                        return Ok(());
                    }
                    AppResult::Error(e) => {
                        return Err(e);
                    }
                }
            }
        }

        if last_tick.elapsed() >= tick_rate {
            app.on_tick();
            last_tick = std::time::Instant::now();
        }
    }
}

fn handle_key_event(key: KeyEvent, app: &mut App) -> AppResult {
    if key.kind != event::KeyEventKind::Press {
        return AppResult::Continue;
    }

    if key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) {
        return AppResult::Quit;
    }

    if key.code == KeyCode::Char('?') || key.code == KeyCode::Char('h') {
        if key.modifiers.is_empty() {
            app.toggle_help();
            return AppResult::Continue;
        }
    }

    if app.show_help {
        match key.code {
            KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('?') | KeyCode::Char('h') => {
                app.show_help = false;
            }
            _ => {}
        }
        return AppResult::Continue;
    }

    app.handle_key(key)
}