mirror of https://github.com/bobwen-dev/hunter
view exec'd processes status/output
This commit is contained in:
parent
fd67621dee
commit
06817602a8
|
@ -32,7 +32,9 @@ pub enum HError {
|
|||
#[fail(display = "No widget found")]
|
||||
NoWidgetError,
|
||||
#[fail(display = "Path: {:?} not in this directory: {:?}", path, dir)]
|
||||
WrongDirectoryError{ path: PathBuf, dir: PathBuf }
|
||||
WrongDirectoryError{ path: PathBuf, dir: PathBuf },
|
||||
#[fail(display = "Widget finnished")]
|
||||
PopupFinnished,
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for HError {
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::tabview::{TabView, Tabbable};
|
|||
use crate::preview::WillBeWidget;
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::window::{Events, send_event};
|
||||
use crate::proclist::ProcView;
|
||||
|
||||
|
||||
|
||||
|
@ -25,12 +26,17 @@ pub struct FileBrowser {
|
|||
pub cwd: File,
|
||||
watcher: INotifyWatcher,
|
||||
watches: Vec<PathBuf>,
|
||||
dir_events: Arc<Mutex<Vec<DebouncedEvent>>>
|
||||
dir_events: Arc<Mutex<Vec<DebouncedEvent>>>,
|
||||
proc_view: Arc<Mutex<ProcView>>,
|
||||
}
|
||||
|
||||
impl Tabbable for TabView<FileBrowser> {
|
||||
fn new_tab(&mut self) {
|
||||
let tab = FileBrowser::new().unwrap();
|
||||
let mut tab = FileBrowser::new().unwrap();
|
||||
|
||||
let proc_view = self.active_tab_().proc_view.clone();
|
||||
tab.proc_view = proc_view;
|
||||
|
||||
self.push_widget(tab);
|
||||
self.active += 1;
|
||||
}
|
||||
|
@ -71,7 +77,7 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
.collect::<Vec<_>>();
|
||||
self.widgets[self.active].exec_cmd(tab_dirs).ok();
|
||||
}
|
||||
_ => self.active_tab_mut().on_key(key)
|
||||
_ => { self.active_tab_mut().on_key(key).ok(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,11 +131,15 @@ impl FileBrowser {
|
|||
let watcher = INotifyWatcher::new(tx_watch, Duration::from_secs(2)).unwrap();
|
||||
watch_dir(rx_watch, dir_events.clone());
|
||||
|
||||
let mut proc_view = ProcView::new();
|
||||
proc_view.set_coordinates(&coords);
|
||||
|
||||
Ok(FileBrowser { columns: miller,
|
||||
cwd: cwd,
|
||||
watcher: watcher,
|
||||
watches: vec![],
|
||||
dir_events: dir_events })
|
||||
dir_events: dir_events,
|
||||
proc_view: Arc::new(Mutex::new(proc_view)) })
|
||||
}
|
||||
|
||||
pub fn enter_dir(&mut self) -> HResult<()> {
|
||||
|
@ -250,7 +260,7 @@ impl FileBrowser {
|
|||
self.watches.push(left_dir.path);
|
||||
}
|
||||
if let Some(preview_dir) = preview_dir {
|
||||
if !watched_dirs.contains(&preview_dir) {
|
||||
if !watched_dirs.contains(&preview_dir) && preview_dir.is_dir() {
|
||||
self.watcher.watch(&preview_dir, RecursiveMode::NonRecursive).unwrap();
|
||||
self.watches.push(preview_dir);
|
||||
}
|
||||
|
@ -380,21 +390,8 @@ impl FileBrowser {
|
|||
cmd = cmd.replace(&tab_identifier, &tab_path);
|
||||
}
|
||||
|
||||
let status = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&cmd)
|
||||
.status();
|
||||
let mut bufout = std::io::BufWriter::new(std::io::stdout());
|
||||
write!(bufout, "{}{}",
|
||||
termion::style::Reset,
|
||||
termion::clear::All).unwrap();
|
||||
self.proc_view.lock()?.run_proc(&cmd)?;
|
||||
|
||||
match status {
|
||||
Ok(status) => self.show_status(&format!("\"{}\" exited with {}",
|
||||
cmd, status)),
|
||||
Err(err) => self.show_status(&format!("Can't run this \"{}\": {}",
|
||||
cmd, err)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +401,8 @@ impl Widget for FileBrowser {
|
|||
&self.columns.coordinates
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.columns.coordinates = coordinates.clone();
|
||||
self.columns.set_coordinates(coordinates);
|
||||
self.proc_view.lock().unwrap().set_coordinates(coordinates);
|
||||
self.refresh();
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
|
@ -467,15 +465,20 @@ impl Widget for FileBrowser {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Char('/') => { self.turbo_cd().ok(); },
|
||||
Key::Char('Q') => { self.quit_with_dir().ok(); },
|
||||
Key::Right | Key::Char('f') => { self.enter_dir().ok(); },
|
||||
Key::Left | Key::Char('b') => { self.go_back().ok(); },
|
||||
_ => self.columns.get_main_widget_mut().unwrap().on_key(key),
|
||||
Key::Char('w') => {
|
||||
self.proc_view.lock()?.popup().ok();
|
||||
}
|
||||
,
|
||||
_ => { self.columns.get_main_widget_mut()?.on_key(key).ok(); },
|
||||
}
|
||||
self.update_preview().ok();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use termion::event::{Event};
|
|||
|
||||
use crate::widget::Widget;
|
||||
use crate::coordinates::{Coordinates, Size, Position};
|
||||
use crate::fail::HResult;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct HBox<T: Widget> {
|
||||
|
@ -106,7 +107,8 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq {
|
|||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
}
|
||||
fn on_event(&mut self, event: Event) {
|
||||
self.widgets.last_mut().unwrap().on_event(event);
|
||||
fn on_event(&mut self, event: Event) -> HResult<()> {
|
||||
self.widgets.last_mut()?.on_event(event).ok();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ where
|
|||
view
|
||||
}
|
||||
|
||||
fn move_up(&mut self) {
|
||||
pub fn move_up(&mut self) {
|
||||
if self.selection == 0 {
|
||||
return;
|
||||
}
|
||||
|
@ -102,11 +102,11 @@ where
|
|||
self.selection -= 1;
|
||||
self.seeking = false;
|
||||
}
|
||||
fn move_down(&mut self) {
|
||||
pub fn move_down(&mut self) {
|
||||
let lines = self.lines;
|
||||
let y_size = self.coordinates.ysize() as usize;
|
||||
|
||||
if self.selection == lines - 1 {
|
||||
if self.lines == 0 || self.selection == lines - 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,7 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
|||
fn refresh(&mut self) {
|
||||
self.on_refresh();
|
||||
self.lines = self.len();
|
||||
if self.selection >= self.lines {
|
||||
if self.selection >= self.lines && self.selection != 0 {
|
||||
self.selection -= 1;
|
||||
}
|
||||
self.buffer = self.render();
|
||||
|
@ -418,7 +418,8 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
|||
format!("{} files", self.len())
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
Listable::on_key(self, key);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ mod tabview;
|
|||
mod async_widget;
|
||||
mod fail;
|
||||
mod minibuffer;
|
||||
mod proclist;
|
||||
|
||||
|
||||
|
||||
|
||||
use window::Window;
|
||||
|
|
|
@ -155,7 +155,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
self.get_main_widget_mut().unwrap().on_key(key);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl Widget for MiniBuffer {
|
|||
self.input)
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Esc | Key::Ctrl('c') => { self.input.clear(); self.done = true; },
|
||||
Key::Char('\n') => {
|
||||
|
@ -205,7 +205,8 @@ impl Widget for MiniBuffer {
|
|||
self.input.insert(self.position, key);
|
||||
self.position += 1;
|
||||
}
|
||||
_ => {}
|
||||
_ => { }
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,12 +185,12 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
|
|||
let widget = widget.as_ref().unwrap();
|
||||
widget.get_drawlist()
|
||||
}
|
||||
fn on_key(&mut self, key: termion::event::Key) {
|
||||
if self.willbe.check().is_err() { return }
|
||||
fn on_key(&mut self, key: termion::event::Key) -> HResult<()> {
|
||||
if self.willbe.check().is_err() { return Ok(()) }
|
||||
let widget = self.widget().unwrap();
|
||||
let mut widget = widget.try_lock().unwrap();
|
||||
let widget = widget.as_mut().unwrap();
|
||||
widget.on_key(key);
|
||||
widget.on_key(key)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::process::Child;
|
||||
use std::process::Stdio;
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
use termion::event::Key;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::coordinates::{Coordinates, Size, Position};
|
||||
use crate::listview::{Listable, ListView};
|
||||
use crate::textview::TextView;
|
||||
use crate::widget::Widget;
|
||||
use crate::window::{send_event, Events};
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::term;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Process {
|
||||
cmd: String,
|
||||
handle: Arc<Mutex<Child>>,
|
||||
output: Arc<Mutex<String>>,
|
||||
status: Arc<Mutex<Option<i32>>>,
|
||||
success: Arc<Mutex<Option<bool>>>
|
||||
}
|
||||
|
||||
impl Process {
|
||||
fn read_proc(&mut self) -> HResult<()> {
|
||||
let handle = self.handle.clone();
|
||||
let output = self.output.clone();
|
||||
let status = self.status.clone();
|
||||
let success = self.success.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let stdout = handle.lock().unwrap().stdout.take().unwrap();
|
||||
let mut stdout = BufReader::new(stdout);
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
match stdout.read_line(&mut line) {
|
||||
Ok(0) => break,
|
||||
Ok(_) => {
|
||||
output.lock().unwrap().push_str(&line);
|
||||
send_event(Events::WidgetReady).unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
dbg!(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Ok(proc_status) = handle.lock().unwrap().wait() {
|
||||
*success.lock().unwrap() = Some(proc_status.success());
|
||||
*status.lock().unwrap() = proc_status.code();
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Listable for ListView<Vec<Process>> {
|
||||
fn len(&self) -> usize { self.content.len() }
|
||||
fn render(&self) -> Vec<String> {
|
||||
self.content.iter().map(|proc| {
|
||||
self.render_proc(proc)
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl ListView<Vec<Process>> {
|
||||
fn run_proc(&mut self, cmd: &str) -> HResult<()> {
|
||||
let handle = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(cmd)
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(unsafe { Stdio::from_raw_fd(2) })
|
||||
.spawn()?;
|
||||
let mut proc = Process {
|
||||
cmd: cmd.to_string(),
|
||||
handle: Arc::new(Mutex::new(handle)),
|
||||
output: Arc::new(Mutex::new(String::new())),
|
||||
status: Arc::new(Mutex::new(None)),
|
||||
success: Arc::new(Mutex::new(None))
|
||||
};
|
||||
proc.read_proc()?;
|
||||
self.content.push(proc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn kill_proc(&mut self) -> HResult<()> {
|
||||
let proc = self.selected_proc()?;
|
||||
proc.handle.lock()?.kill()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_proc(&mut self) -> HResult<()> {
|
||||
self.kill_proc().ok();
|
||||
let selection = self.get_selection();
|
||||
self.content.remove(selection);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn selected_proc(&mut self) -> Option<&mut Process> {
|
||||
let selection = self.get_selection();
|
||||
self.content.get_mut(selection)
|
||||
}
|
||||
|
||||
pub fn render_proc(&self, proc: &Process) -> String {
|
||||
let status = match *proc.status.lock().unwrap() {
|
||||
Some(status) => format!("{}", status),
|
||||
None => "<R>".to_string()
|
||||
};
|
||||
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
let sized_string = term::sized_string(&proc.cmd, xsize);
|
||||
let status_pos = xsize - status.len() as u16;
|
||||
let padding = sized_string.len() - sized_string.width_cjk();
|
||||
let padding = xsize - padding as u16;
|
||||
|
||||
let color_status = match *proc.success.lock().unwrap() {
|
||||
Some(false) => { format!("{}{}", term::color_red(), status) }
|
||||
_ => { status }
|
||||
};
|
||||
|
||||
format!(
|
||||
"{}{}{}{}{}{}",
|
||||
termion::cursor::Save,
|
||||
format!("{}{}{:padding$}{}",
|
||||
term::normal_color(),
|
||||
&sized_string,
|
||||
" ",
|
||||
term::normal_color(),
|
||||
padding = padding as usize),
|
||||
termion::cursor::Restore,
|
||||
termion::cursor::Right(status_pos),
|
||||
term::highlight_color(),
|
||||
color_status
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcView {
|
||||
coordinates: Coordinates,
|
||||
proc_list: ListView<Vec<Process>>,
|
||||
textview: TextView,
|
||||
}
|
||||
|
||||
impl ProcView {
|
||||
pub fn new() -> ProcView {
|
||||
ProcView {
|
||||
coordinates: Coordinates::new(),
|
||||
proc_list: ListView::new(vec![]),
|
||||
textview: TextView::new_blank(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_proc(&mut self, cmd: &str) -> HResult<()> {
|
||||
self.proc_list.run_proc(cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_proc(&mut self) -> HResult<()> {
|
||||
self.proc_list.remove_proc()?;
|
||||
self.textview.set_text("");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_output(&mut self) -> HResult<()> {
|
||||
let output = self.proc_list.selected_proc()?.output.lock()?;
|
||||
self.textview.set_text(&*output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates) {
|
||||
let xsize = self.coordinates.xsize();
|
||||
let ysize = self.coordinates.ysize();
|
||||
let top = self.coordinates.top().y();
|
||||
let ratio = (33, 66);
|
||||
|
||||
let left_xsize = xsize * ratio.0 / 100;
|
||||
let left_size = Size((left_xsize, ysize));
|
||||
let left_pos = self.coordinates.top();
|
||||
|
||||
let main_xsize = xsize * ratio.1 / 100;
|
||||
let main_size = Size((main_xsize, ysize));
|
||||
let main_pos = Position((left_xsize + 2, top));
|
||||
|
||||
|
||||
|
||||
let left_coords = Coordinates {
|
||||
size: left_size,
|
||||
position: left_pos,
|
||||
};
|
||||
|
||||
let main_coords = Coordinates {
|
||||
size: main_size,
|
||||
position: main_pos,
|
||||
};
|
||||
|
||||
(left_coords, main_coords)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Widget for ProcView {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.coordinates = coordinates.clone();
|
||||
|
||||
let (lcoord, rcoord) = self.calculate_coordinates();
|
||||
self.proc_list.set_coordinates(&lcoord);
|
||||
self.textview.set_coordinates(&rcoord);
|
||||
|
||||
self.refresh();
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
self.show_output().ok();
|
||||
self.proc_list.refresh();
|
||||
self.textview.refresh();
|
||||
}
|
||||
fn get_drawlist(&self) -> String {
|
||||
self.proc_list.get_drawlist() + &self.textview.get_drawlist()
|
||||
}
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Char('w') => { return Err(HError::PopupFinnished) }
|
||||
Key::Char('d') => { self.remove_proc()? }
|
||||
Key::Char('k') => { self.proc_list.kill_proc()? }
|
||||
Key::Up | Key::Char('p') => {
|
||||
self.proc_list.move_up();
|
||||
self.proc_list.refresh();
|
||||
}
|
||||
Key::Down | Key::Char('n') => {
|
||||
self.proc_list.move_down();
|
||||
self.proc_list.refresh();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.refresh();
|
||||
self.draw()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ use termion::event::Key;
|
|||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::widget::Widget;
|
||||
use crate::fail::HResult;
|
||||
|
||||
pub trait Tabbable {
|
||||
fn new_tab(&mut self);
|
||||
|
@ -129,7 +130,8 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
self.refresh();
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
Tabbable::on_key(self, key);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,12 @@ impl TextView {
|
|||
coordinates: Coordinates::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, text: &str) {
|
||||
let lines = text.lines().map(|l| l.to_string()).collect();
|
||||
self.lines = lines;
|
||||
self.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for TextView {
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use std::sync::mpsc::channel;
|
||||
|
||||
use termion::event::{Event, Key, MouseEvent};
|
||||
use termion::input::TermRead;
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::fail::HResult;
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::window::{send_event, Events};
|
||||
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::io::{BufWriter, Write, stdin};
|
||||
|
||||
|
||||
pub trait Widget {
|
||||
|
@ -18,7 +22,7 @@ pub trait Widget {
|
|||
fn get_drawlist(&self) -> String;
|
||||
|
||||
|
||||
fn on_event(&mut self, event: Event) {
|
||||
fn on_event(&mut self, event: Event) -> HResult<()> {
|
||||
match event {
|
||||
Event::Key(Key::Char('q')) => panic!("It's your fault!"),
|
||||
Event::Key(key) => self.on_key(key),
|
||||
|
@ -27,22 +31,25 @@ pub trait Widget {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
_ => self.bad(Event::Key(key)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_mouse(&mut self, event: MouseEvent) {
|
||||
fn on_mouse(&mut self, event: MouseEvent) -> HResult<()> {
|
||||
match event {
|
||||
_ => self.bad(Event::Mouse(event)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_wtf(&mut self, event: Vec<u8>) {
|
||||
fn on_wtf(&mut self, event: Vec<u8>) -> HResult<()> {
|
||||
match event {
|
||||
_ => self.bad(Event::Unsupported(event)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_status(&self, status: &str) {
|
||||
|
@ -125,6 +132,49 @@ pub trait Widget {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn popup(&mut self) -> HResult<()> {
|
||||
self.run_widget();
|
||||
send_event(Events::ExclusiveEvent(None));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_widget(&mut self) -> HResult<()> {
|
||||
let (tx_event, rx_event) = channel();
|
||||
send_event(Events::ExclusiveEvent(Some(tx_event)))?;
|
||||
dbg!("sent exclusive request");
|
||||
|
||||
self.clear()?;
|
||||
self.refresh();
|
||||
self.draw()?;
|
||||
|
||||
dbg!("entering loop");
|
||||
|
||||
for event in rx_event.iter() {
|
||||
dbg!(&event);
|
||||
match event {
|
||||
Events::InputEvent(input) => {
|
||||
if let Err(HError::PopupFinnished) = self.on_event(input) {
|
||||
return Err(HError::PopupFinnished)
|
||||
}
|
||||
}
|
||||
Events::WidgetReady => {
|
||||
self.refresh();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.draw()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear(&self) -> HResult<()> {
|
||||
let clearlist = self.get_clearlist();
|
||||
write!(std::io::stdout(), "{}", clearlist)?;
|
||||
std::io::stdout().flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn animate_slide_up(&mut self) {
|
||||
let coords = self.get_coordinates().clone();
|
||||
let xpos = coords.position().x();
|
||||
|
|
|
@ -20,11 +20,12 @@ lazy_static! {
|
|||
= Arc::new(Mutex::new(MiniBuffer::new()));
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Events {
|
||||
InputEvent(Event),
|
||||
WidgetReady,
|
||||
ExclusiveInput(bool),
|
||||
ExclusiveEvent(Option<Sender<Events>>),
|
||||
}
|
||||
|
||||
pub struct Window<T>
|
||||
|
@ -87,32 +88,22 @@ where
|
|||
|
||||
|
||||
pub fn handle_input(&mut self) {
|
||||
let (tx_event_internal, rx_event_internal) = channel();
|
||||
let (tx_event, rx_event) = channel();
|
||||
*TX_EVENT.try_lock().unwrap() = Some(tx_event);
|
||||
let (tx_request_input, rx_request_input) = channel();
|
||||
let (tx_global_event, rx_global_event) = channel();
|
||||
*TX_EVENT.try_lock().unwrap() = Some(tx_global_event);
|
||||
let (tx_internal_event, rx_internal_event) = channel();
|
||||
|
||||
let mut exclusive_mode = false;
|
||||
input_thread(tx_event.clone());
|
||||
global_event_thread(rx_global_event, tx_event.clone());
|
||||
dispatch_events(rx_event, tx_internal_event);
|
||||
|
||||
event_thread(rx_event, tx_event_internal.clone());
|
||||
input_thread(tx_event_internal.clone(), rx_request_input);
|
||||
tx_request_input.send(()).unwrap();
|
||||
|
||||
for event in rx_event_internal.iter() {
|
||||
//Self::clear_status();
|
||||
//let event = event.unwrap();
|
||||
for event in rx_internal_event.iter() {
|
||||
match event {
|
||||
Events::InputEvent(event) => {
|
||||
self.widget.on_event(event);
|
||||
self.screen.cursor_hide();
|
||||
self.draw();
|
||||
if !exclusive_mode {
|
||||
tx_request_input.send(()).unwrap();
|
||||
}
|
||||
},
|
||||
Events::ExclusiveInput(setting) => {
|
||||
exclusive_mode = setting
|
||||
}
|
||||
_ => {
|
||||
self.widget.refresh();
|
||||
self.draw();
|
||||
|
@ -122,23 +113,39 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn event_thread(rx: Receiver<Events>,
|
||||
tx: Sender<Events>) {
|
||||
fn dispatch_events(rx: Receiver<Events>, tx: Sender<Events>) {
|
||||
std::thread::spawn(move || {
|
||||
let mut tx_exclusive_event: Option<Sender<Events>> = None;
|
||||
for event in rx.iter() {
|
||||
match &event {
|
||||
Events::ExclusiveEvent(tx_event) => {
|
||||
tx_exclusive_event = tx_event.clone();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(tx_event) = &tx_exclusive_event {
|
||||
tx_event.send(event).unwrap();
|
||||
} else {
|
||||
tx.send(event).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn global_event_thread(rx_global: Receiver<Events>,
|
||||
tx: Sender<Events>) {
|
||||
std::thread::spawn(move || {
|
||||
for event in rx_global.iter() {
|
||||
tx.send(event).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn input_thread(tx: Sender<Events>, request_input: Receiver<()>) {
|
||||
fn input_thread(tx: Sender<Events>) {
|
||||
std::thread::spawn(move || {
|
||||
for _ in request_input.iter() {
|
||||
for input in stdin().events() {
|
||||
let input = input.unwrap();
|
||||
tx.send(Events::InputEvent(input)).unwrap();
|
||||
break;
|
||||
}
|
||||
for input in stdin().events() {
|
||||
let input = input.unwrap();
|
||||
tx.send(Events::InputEvent(input)).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue