2024-05-02 23:47:47 +02:00
|
|
|
use std::{io::Stdout, time::Duration};
|
2024-05-01 22:17:39 +02:00
|
|
|
|
|
|
|
use anyhow::{Context, Result};
|
2024-05-02 23:47:47 +02:00
|
|
|
use app::{render_app, App};
|
|
|
|
use components::GraphExplorer;
|
|
|
|
use crossterm::event::{self, Event, KeyCode};
|
|
|
|
use hyperlog_core::state::State;
|
|
|
|
use models::Msg;
|
|
|
|
use ratatui::{backend::CrosstermBackend, Terminal};
|
2024-05-01 22:17:39 +02:00
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
use crate::{state::SharedState, terminal::TerminalInstance};
|
2024-05-01 23:26:25 +02:00
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
pub mod models;
|
2024-05-01 23:26:25 +02:00
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
pub(crate) mod app;
|
|
|
|
pub(crate) mod components;
|
|
|
|
pub(crate) mod state;
|
2024-05-01 23:26:25 +02:00
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
mod logging;
|
|
|
|
mod terminal;
|
2024-05-01 23:26:25 +02:00
|
|
|
|
|
|
|
pub async fn execute(state: State) -> Result<()> {
|
2024-05-01 22:17:39 +02:00
|
|
|
tracing::debug!("starting hyperlog tui");
|
|
|
|
|
|
|
|
logging::initialize_panic_handler()?;
|
|
|
|
logging::initialize_logging()?;
|
|
|
|
|
2024-05-01 23:26:25 +02:00
|
|
|
let state = SharedState::from(state);
|
|
|
|
|
2024-05-01 22:17:39 +02:00
|
|
|
let mut terminal = TerminalInstance::new()?;
|
|
|
|
run(&mut terminal, state).context("app loop failed")?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-05-01 23:26:25 +02:00
|
|
|
fn run(terminal: &mut Terminal<CrosstermBackend<Stdout>>, state: SharedState) -> Result<()> {
|
|
|
|
let mut graph_explorer = GraphExplorer::new(state.clone());
|
|
|
|
graph_explorer.update_graph()?;
|
|
|
|
|
|
|
|
let mut app = App::new(state.clone(), graph_explorer);
|
|
|
|
|
2024-05-01 22:17:39 +02:00
|
|
|
loop {
|
2024-05-02 23:47:47 +02:00
|
|
|
terminal.draw(|f| render_app(f, &mut app))?;
|
|
|
|
|
|
|
|
if update(terminal, &mut app)?.should_quit() {
|
2024-05-01 22:17:39 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
pub struct UpdateConclusion(bool);
|
2024-05-01 23:26:25 +02:00
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
impl UpdateConclusion {
|
|
|
|
pub fn new(should_quit: bool) -> Self {
|
|
|
|
Self(should_quit)
|
2024-05-01 23:26:25 +02:00
|
|
|
}
|
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
pub fn should_quit(self) -> bool {
|
|
|
|
self.0
|
2024-05-01 23:26:25 +02:00
|
|
|
}
|
2024-05-01 22:17:39 +02:00
|
|
|
}
|
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
fn update(
|
|
|
|
_terminal: &mut Terminal<CrosstermBackend<Stdout>>,
|
|
|
|
app: &mut App,
|
|
|
|
) -> Result<UpdateConclusion> {
|
2024-05-01 22:17:39 +02:00
|
|
|
if event::poll(Duration::from_millis(250)).context("event poll failed")? {
|
|
|
|
if let Event::Key(key) = event::read().context("event read failed")? {
|
2024-05-02 23:47:47 +02:00
|
|
|
match key.code {
|
|
|
|
KeyCode::Char('q') => return Ok(UpdateConclusion::new(true)),
|
|
|
|
KeyCode::Char('l') => {
|
|
|
|
app.update(Msg::MoveRight)?;
|
|
|
|
}
|
|
|
|
KeyCode::Char('h') => {
|
|
|
|
app.update(Msg::MoveLeft)?;
|
|
|
|
}
|
|
|
|
KeyCode::Char('j') => {
|
|
|
|
app.update(Msg::MoveDown)?;
|
|
|
|
}
|
|
|
|
KeyCode::Char('k') => {
|
|
|
|
app.update(Msg::MoveUp)?;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2024-05-01 22:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-02 23:47:47 +02:00
|
|
|
Ok(UpdateConclusion::new(false))
|
2024-05-01 22:17:39 +02:00
|
|
|
}
|