mirror of
https://gitlab.com/fabinfra/fabaccess/sute.git
synced 2025-03-12 14:41:52 +01:00
Reworks state signalling
This commit is contained in:
parent
21550b411d
commit
3e7127f3df
92
src/app.rs
92
src/app.rs
@ -35,33 +35,28 @@ pub struct Sute<'a, S> {
|
||||
// TODO: BE SMART. Inputs change the state, resize signals change the state, futures completing
|
||||
// change the state.
|
||||
|
||||
state: SuteState<'a>,
|
||||
state: Mutable<SuteState>,
|
||||
|
||||
signal: S,
|
||||
inputs: Inputs,
|
||||
api: Option<API>,
|
||||
log: Logger,
|
||||
|
||||
drain: Arc<LogDrain<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, S: Unpin> Sute<'a, S> {
|
||||
pub fn new(s: S, log: Logger, drain: Arc<LogDrain<'a>>, api: API) -> Self {
|
||||
pub fn new(signal: S, log: Logger, drain: Arc<LogDrain<'a>>, api: Option<API>) -> Self {
|
||||
let inputs = Inputs::new();
|
||||
let state = SuteState::new(drain);
|
||||
let state = Mutable::new(SuteState::new());
|
||||
|
||||
Self {
|
||||
state: state,
|
||||
|
||||
signal: s,
|
||||
inputs: inputs,
|
||||
api: Some(api),
|
||||
log: log,
|
||||
}
|
||||
Self { state, signal, inputs, api, log, drain, }
|
||||
}
|
||||
|
||||
fn run_cmd(&mut self, cmdline: String) {
|
||||
let mut words = cmdline.split_ascii_whitespace();
|
||||
match words.next() {
|
||||
Some("quit") => self.state.running = false,
|
||||
Some("quit") => self.state.lock_mut().running = false,
|
||||
Some("connect") => {
|
||||
self.connect(cmdline)
|
||||
},
|
||||
@ -74,98 +69,85 @@ impl<'a, S: Unpin> Sute<'a, S> {
|
||||
}
|
||||
|
||||
fn handle_resize(&mut self, new_size: (u16,u16)) {
|
||||
self.state.size = new_size;
|
||||
self.state.lock_mut().size = new_size;
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> SuteState<'a> {
|
||||
self.state.clone()
|
||||
pub fn get_state(&self) -> SuteState {
|
||||
self.state.get_cloned()
|
||||
}
|
||||
|
||||
// We can make this more efficient by not cloning. But who cares?
|
||||
pub fn signal(&self) -> impl Signal<Item=SuteState> {
|
||||
self.state.signal_cloned()
|
||||
}
|
||||
|
||||
pub fn handle_key(&mut self, key: Key) {
|
||||
let mut state = self.state.lock_mut();
|
||||
match key {
|
||||
Key::Char('\n') => {
|
||||
let cmd = mem::replace(&mut self.state.cmd_line, String::new());
|
||||
let cmd = mem::replace(&mut state.cmd_line, String::new());
|
||||
// drop the mutably borrowed state here so we can mutably re-borrow self afterwards
|
||||
mem::drop(state);
|
||||
self.run_cmd(cmd);
|
||||
},
|
||||
Key::Char(c) => {
|
||||
self.state.cmd_line.push(c);
|
||||
state.cmd_line.push(c);
|
||||
},
|
||||
Key::Backspace => {
|
||||
self.state.cmd_line.pop();
|
||||
state.cmd_line.pop();
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: Signal<Item=(u16,u16)> + Unpin> Signal for Sute<'a, S> {
|
||||
type Item = SuteState<'a>;
|
||||
fn poll_change(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
let mut dirty = false;
|
||||
impl <'a, S: Unpin + Signal<Item=(u16,u16)>> Future for Sute<'a, S> {
|
||||
type Output = ();
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
// Return early if we're not running anymore
|
||||
if ! self.state.lock_ref().running {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
if let Poll::Ready(Some(size)) = Pin::new(&mut self.signal).poll_change(cx) {
|
||||
dirty = true;
|
||||
self.handle_resize(size);
|
||||
}
|
||||
match ready!(Pin::new(&mut self.inputs).poll_next(cx)) {
|
||||
Some(key) => {
|
||||
dirty = true;
|
||||
self.handle_key(key);
|
||||
},
|
||||
// If the input closes stop the program
|
||||
None => {
|
||||
self.state.running = false;
|
||||
return Poll::Ready(None);
|
||||
self.state.lock_mut().running = false;
|
||||
return Poll::Ready(());
|
||||
},
|
||||
}
|
||||
|
||||
if dirty {
|
||||
Poll::Ready(Some(self.get_state()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, S> Future for Sute<'a, S> {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
if self.state.running {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
// TODO: `Signal` struct changes using this struct?
|
||||
// TODO: If so, procmacro here?
|
||||
enum SuteStateChange {
|
||||
active_win(Window),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SuteState<'a> {
|
||||
pub struct SuteState {
|
||||
pub active_win: Window,
|
||||
pub size: (u16,u16),
|
||||
pub running: bool,
|
||||
pub tick: usize,
|
||||
pub server: Option<&'a str>,
|
||||
pub log: Arc<LogDrain<'a>>,
|
||||
pub server: Option<String>,
|
||||
pub cmd_line: String,
|
||||
pub tick_c: char,
|
||||
|
||||
// TODO: Figure out how to put log lines here signaled
|
||||
}
|
||||
|
||||
impl<'a> SuteState<'a> {
|
||||
pub fn new(log: Arc<LogDrain<'a>>) -> Self {
|
||||
impl SuteState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
active_win: Window::Main,
|
||||
size: (80,20),
|
||||
running: true,
|
||||
tick: 0,
|
||||
server: None,
|
||||
log: log,
|
||||
cmd_line: String::new(),
|
||||
tick_c: '|',
|
||||
}
|
||||
|
19
src/main.rs
19
src/main.rs
@ -69,10 +69,11 @@ fn main() -> Result<(), io::Error> {
|
||||
|
||||
let (rpc_future, mut api) = schema::bootstrap(log.clone(), stream);
|
||||
|
||||
let app = app::Sute::new(resize, log.clone(), drain, api);
|
||||
let app = app::Sute::new(resize, log.clone(), drain.clone(), Some(api));
|
||||
|
||||
let mut state = app.get_state();
|
||||
let mut stream = app.to_stream();
|
||||
let mut app_state = app.get_state();
|
||||
let mut ui_state = ui::UIState::new(app_state, drain);
|
||||
let mut stream = app.signal().to_stream();
|
||||
|
||||
let ui_future = async move {
|
||||
let stdout = io::stdout().into_raw_mode()?;
|
||||
@ -87,7 +88,7 @@ fn main() -> Result<(), io::Error> {
|
||||
terminal.resize(tui::layout::Rect::new(0, 0, x,y)).unwrap();
|
||||
}
|
||||
|
||||
terminal.draw(|f| ui::draw_ui(f, &mut state));
|
||||
terminal.draw(|f| ui::draw_ui(f, &mut ui_state));
|
||||
loop {
|
||||
if let Some(mut state) = stream.next().await {
|
||||
if !state.running {
|
||||
@ -102,7 +103,8 @@ fn main() -> Result<(), io::Error> {
|
||||
_ => '|',
|
||||
};
|
||||
state.tick_c = tick_c;
|
||||
terminal.draw(|f| ui::draw_ui(f, &mut state))?;
|
||||
ui_state.app_state = state;
|
||||
terminal.draw(|f| ui::draw_ui(f, &mut ui_state))?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -114,9 +116,10 @@ fn main() -> Result<(), io::Error> {
|
||||
Ok(())
|
||||
};
|
||||
|
||||
//lex.spawn(rpc_future).detach();
|
||||
let r: Result<(), io::Error> = smol::block_on(lex.run(ui_future));
|
||||
//smol::block_on(lex.run(Box::pin(app)));
|
||||
lex.spawn(rpc_future).detach();
|
||||
let t: Task<Result<(), io::Error>> = lex.spawn(ui_future);
|
||||
t.detach();
|
||||
smol::block_on(lex.run(app));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Layout, Direction, Constraint, Rect},
|
||||
@ -5,9 +7,19 @@ use tui::{
|
||||
Frame,
|
||||
};
|
||||
|
||||
use crate::app::SuteState;
|
||||
use crate::app::{SuteState, LogDrain};
|
||||
|
||||
pub fn draw_ui<B: Backend>(f: &mut Frame<B>, app: &mut SuteState) {
|
||||
pub struct UIState<'a> {
|
||||
pub app_state: SuteState,
|
||||
pub loglines: Arc<LogDrain<'a>>,
|
||||
}
|
||||
impl<'a> UIState<'a> {
|
||||
pub fn new(app_state: SuteState, loglines: Arc<LogDrain<'a>>) -> Self {
|
||||
Self { app_state, loglines }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_ui<B: Backend>(f: &mut Frame<B>, state: &mut UIState) {
|
||||
let outer_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
@ -19,32 +31,32 @@ pub fn draw_ui<B: Backend>(f: &mut Frame<B>, app: &mut SuteState) {
|
||||
.split(f.size());
|
||||
|
||||
|
||||
draw_header(f, app, outer_layout[0]);
|
||||
draw_main(f, app, outer_layout[1]);
|
||||
draw_command_line(f, app, outer_layout[2]);
|
||||
draw_header(f, state, outer_layout[0]);
|
||||
draw_main(f, state, outer_layout[1]);
|
||||
draw_command_line(f, state, outer_layout[2]);
|
||||
}
|
||||
|
||||
fn draw_header<B: Backend>(f: &mut Frame<B>, app: &mut SuteState, layout_chunk: Rect) {
|
||||
fn draw_header<B: Backend>(f: &mut Frame<B>, state: &mut UIState, layout_chunk: Rect) {
|
||||
f.render_widget(Block::default()
|
||||
.title("Status")
|
||||
.borders(Borders::ALL), layout_chunk);
|
||||
}
|
||||
|
||||
fn draw_main<B: Backend>(f: &mut Frame<B>, app: &mut SuteState, layout_chunk: Rect) {
|
||||
fn draw_main<B: Backend>(f: &mut Frame<B>, state: &mut UIState, layout_chunk: Rect) {
|
||||
// let chunk = Layout::default()
|
||||
// .direction(Direction::Horizontal)
|
||||
// .constraints([Constraint::Percentage(20), Constraint::Percentage(80)].as_ref())
|
||||
// .split(layout_chunk);
|
||||
|
||||
draw_logs(f, app, layout_chunk)
|
||||
draw_logs(f, state, layout_chunk)
|
||||
}
|
||||
fn draw_logs<B: Backend>(f: &mut Frame<B>, app: &mut SuteState, layout_chunk: Rect) {
|
||||
fn draw_logs<B: Backend>(f: &mut Frame<B>, state: &mut UIState, layout_chunk: Rect) {
|
||||
// TODO: Just use a signal.
|
||||
let v = app.log.get_inner().clone();
|
||||
f.render_widget(Paragraph::new(v.into_iter().collect::<Vec<tui::text::Spans>>()), layout_chunk);
|
||||
let v = state.loglines.get_inner().clone();
|
||||
f.render_widget(Paragraph::new(v), layout_chunk);
|
||||
}
|
||||
|
||||
fn draw_command_line<B: Backend>(f: &mut Frame<B>, app: &mut SuteState, layout_chunk: Rect) {
|
||||
fn draw_command_line<B: Backend>(f: &mut Frame<B>, state: &mut UIState, layout_chunk: Rect) {
|
||||
let block = Block::default()
|
||||
.title("Command line")
|
||||
.borders(Borders::ALL);
|
||||
@ -52,6 +64,6 @@ fn draw_command_line<B: Backend>(f: &mut Frame<B>, app: &mut SuteState, layout_c
|
||||
|
||||
f.render_widget(block, layout_chunk);
|
||||
|
||||
let cmdline = format!("{} > {}", app.tick_c, app.cmd_line);
|
||||
let cmdline = format!("{} > {}", state.app_state.tick_c, state.app_state.cmd_line);
|
||||
f.render_widget(Paragraph::new(&cmdline[..]), inner_rect);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user