parent
f840865597
commit
ec3f78b8cd
10 changed files with 187 additions and 11 deletions
@ -0,0 +1,82 @@ |
||||
mod state; |
||||
mod ui; |
||||
|
||||
use anyhow::Result; |
||||
use crossterm::event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}; |
||||
use crossterm::execute; |
||||
use crossterm::terminal::{ |
||||
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, |
||||
}; |
||||
use state::State; |
||||
use std::panic::set_hook; |
||||
use std::process::exit; |
||||
use std::{ |
||||
io::{stdout, Stdout}, |
||||
sync::mpsc, |
||||
thread, |
||||
time::Duration, |
||||
}; |
||||
use tui::{backend::CrosstermBackend, Terminal}; |
||||
|
||||
type Frame<'f> = tui::Frame<'f, CrosstermBackend<Stdout>>; |
||||
|
||||
pub fn init_tui(token: String) -> Result<()> { |
||||
//TODO: fix this
|
||||
set_hook(Box::new(|p| { |
||||
teardown().unwrap(); |
||||
eprintln!("{}", p); |
||||
exit(254); |
||||
})); |
||||
let mut state = State::new(token); |
||||
if let Err(e) = init(&mut state) { |
||||
teardown()?; |
||||
return Err(e); |
||||
} |
||||
Ok(()) |
||||
} |
||||
|
||||
fn init(state: &mut State) -> Result<()> { |
||||
let mut stdout = stdout(); |
||||
enable_raw_mode()?; |
||||
execute!(&mut stdout, EnterAlternateScreen, EnableMouseCapture)?; |
||||
|
||||
let backend = CrosstermBackend::new(stdout); |
||||
let mut terminal = Terminal::new(backend)?; |
||||
let (tx, rx) = mpsc::channel(); |
||||
|
||||
thread::spawn(move || loop { |
||||
if event::poll(Duration::from_millis(10)).unwrap() { |
||||
match event::read().unwrap() { |
||||
key @ Event::Key(_) => tx.send(key).unwrap(), |
||||
_ => (), |
||||
} |
||||
} |
||||
}); |
||||
|
||||
terminal.clear()?; |
||||
|
||||
loop { |
||||
terminal.draw(|f| ui::draw(f, state))?; |
||||
match rx.recv()? { |
||||
Event::Key(key) => match key.code { |
||||
KeyCode::Esc => { |
||||
teardown()?; |
||||
terminal.show_cursor()?; |
||||
break; |
||||
} |
||||
KeyCode::Left => state.prev_tab(), |
||||
KeyCode::Right => state.next_tab(), |
||||
_ => (), |
||||
}, |
||||
_ => unreachable!(), |
||||
} |
||||
} |
||||
Ok(()) |
||||
} |
||||
|
||||
fn teardown() -> Result<()> { |
||||
disable_raw_mode()?; |
||||
execute!(stdout(), LeaveAlternateScreen, DisableMouseCapture)?; |
||||
eprintln!("teardown"); |
||||
Ok(()) |
||||
} |
@ -0,0 +1,53 @@ |
||||
use std::str::FromStr; |
||||
use strum::VariantNames; |
||||
|
||||
#[derive(strum::Display, strum::EnumVariantNames, strum::EnumString)] |
||||
pub enum UiTabs { |
||||
Agents, |
||||
Jobs, |
||||
Map, |
||||
} |
||||
|
||||
impl UiTabs { |
||||
pub fn variants() -> &'static [&'static str] { |
||||
Self::VARIANTS |
||||
} |
||||
|
||||
pub fn index(&self) -> usize { |
||||
let ss = self.to_string(); |
||||
Self::VARIANTS.iter().position(|el| **el == ss).unwrap() |
||||
} |
||||
|
||||
pub fn next(&self) -> Self { |
||||
let next_idx = (self.index() + 1) % Self::VARIANTS.len(); |
||||
Self::from_str(Self::VARIANTS[next_idx]).unwrap() |
||||
} |
||||
|
||||
pub fn prev(&self) -> Self { |
||||
let vlen = Self::VARIANTS.len(); |
||||
let next_idx = (self.index() + vlen - 1) % vlen; |
||||
Self::from_str(Self::VARIANTS[next_idx]).unwrap() |
||||
} |
||||
} |
||||
|
||||
pub struct State { |
||||
pub token: String, |
||||
pub active_tab: UiTabs, |
||||
} |
||||
|
||||
impl State { |
||||
pub fn new(token: String) -> Self { |
||||
State { |
||||
token, |
||||
active_tab: UiTabs::Agents, |
||||
} |
||||
} |
||||
|
||||
pub fn next_tab(&mut self) { |
||||
self.active_tab = self.active_tab.next() |
||||
} |
||||
|
||||
pub fn prev_tab(&mut self) { |
||||
self.active_tab = self.active_tab.prev() |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
use super::{ |
||||
state::{State, UiTabs}, |
||||
Frame, |
||||
}; |
||||
use tui::style::{Color, Style}; |
||||
use tui::text::Spans; |
||||
use tui::widgets::{Block, Borders, Tabs}; |
||||
|
||||
pub fn draw(f: &mut Frame, s: &mut State) { |
||||
let titles = UiTabs::variants() |
||||
.iter() |
||||
.cloned() |
||||
.map(Spans::from) |
||||
.collect(); |
||||
let tabs = Tabs::new(titles) |
||||
.block( |
||||
Block::default() |
||||
.title("The whole that you need to know") |
||||
.borders(Borders::ALL), |
||||
) |
||||
.style(Style::default().fg(Color::White)) |
||||
.highlight_style(Style::default().fg(Color::Yellow)) |
||||
.divider("-") |
||||
.select(s.active_tab.index()); |
||||
f.render_widget(tabs, f.size()) |
||||
} |
Loading…
Reference in new issue