From 56d9c3521599baef6ff1472c0c95fa07f17a5a67 Mon Sep 17 00:00:00 2001 From: rabite Date: Tue, 12 Feb 2019 22:55:16 +0100 Subject: [PATCH] async widget --- Cargo.toml | 6 +- src/coordinates.rs | 12 ++++ src/file_browser.rs | 20 ++---- src/files.rs | 2 +- src/hbox.rs | 16 +---- src/listview.rs | 28 +++----- src/main.rs | 8 ++- src/miller_columns.rs | 26 ++----- src/preview.rs | 163 ++++++++++++++++++++++++++++++++++++++---- src/tabview.rs | 22 ++---- src/textview.rs | 14 +--- src/widget.rs | 30 ++++---- 12 files changed, 219 insertions(+), 128 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2df43df..471ad1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,8 @@ rayon = "1.0.3" dirs-2 = "1.1.0" users = "0.8" chrono = "0.4" -libc = "*" \ No newline at end of file +libc = "*" + +#[profile.release] +#debug = true +#lto = false diff --git a/src/coordinates.rs b/src/coordinates.rs index d4dc914..5861f72 100644 --- a/src/coordinates.rs +++ b/src/coordinates.rs @@ -40,6 +40,18 @@ impl Coordinates { &self.position } + pub fn u16position(&self) -> (u16, u16) { + self.position.position() + } + + pub fn size(&self) -> &Size { + &self.size + } + + pub fn u16size(&self) -> (u16, u16) { + self.size.size() + } + pub fn top(&self) -> Position { self.position().clone() } diff --git a/src/file_browser.rs b/src/file_browser.rs index 667e708..a499c5b 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -16,7 +16,7 @@ pub struct FileBrowser { } impl Tabbable for FileBrowser { - fn new_tab(&self) -> Self { + fn new_tab(&self) -> FileBrowser { FileBrowser::new().unwrap() } @@ -115,8 +115,12 @@ impl FileBrowser { pub fn update_preview(&mut self) { if self.columns.get_main_widget().content.len() == 0 { return } let file = self.columns.get_main_widget().selected_file().clone(); - let preview = &mut self.columns.preview; + //let preview = &mut self.columns.preview; + let coords = self.columns.preview.get_coordinates(); + let mut preview = crate::preview::AsyncPreviewer::new(); + preview.set_coordinates(&coords); preview.set_file(&file); + self.columns.preview = preview; } pub fn fix_selection(&mut self) { @@ -188,18 +192,6 @@ impl FileBrowser { } impl Widget for FileBrowser { - fn get_size(&self) -> &Size { - &self.columns.get_size() - } - fn get_position(&self) -> &Position { - &self.columns.get_position() - } - fn set_size(&mut self, size: Size) { - self.columns.set_size(size); - } - fn set_position(&mut self, position: Position) { - self.columns.set_position(position); - } fn get_coordinates(&self) -> &Coordinates { &self.columns.coordinates } diff --git a/src/files.rs b/src/files.rs index 4bd0f45..03f0dc6 100644 --- a/src/files.rs +++ b/src/files.rs @@ -26,7 +26,7 @@ pub struct Files { impl Index for Files { type Output = File; - fn index(&self, pos: usize) -> &Self::Output { + fn index(&self, pos: usize) -> &File { &self.files[pos] } } diff --git a/src/hbox.rs b/src/hbox.rs index cdd7023..23c580b 100644 --- a/src/hbox.rs +++ b/src/hbox.rs @@ -11,7 +11,7 @@ pub struct HBox { } -impl HBox where T: Widget { +impl HBox where T: Widget + PartialEq { pub fn new() -> HBox { HBox { coordinates: Coordinates::new(), widgets: vec![], @@ -78,7 +78,7 @@ impl HBox where T: Widget { -impl Widget for HBox where T: Widget { +impl Widget for HBox where T: Widget + PartialEq { fn render_header(&self) -> String { self.active_widget().render_header() } @@ -96,18 +96,6 @@ impl Widget for HBox where T: Widget { }).collect() } - fn get_size(&self) -> &Size { - &self.coordinates.size - } - fn get_position(&self) -> &Position { - &self.coordinates.position - } - fn set_size(&mut self, size: Size) { - self.coordinates.size = size; - } - fn set_position(&mut self, position: Position) { - self.coordinates.position = position; - } fn get_coordinates(&self) -> &Coordinates { &self.coordinates } diff --git a/src/listview.rs b/src/listview.rs index 92e5111..cec6630 100644 --- a/src/listview.rs +++ b/src/listview.rs @@ -4,11 +4,12 @@ use unicode_width::UnicodeWidthStr; use std::path::{Path, PathBuf}; use std::io::Write; +//use std::sync::mpsc::{channel, Sender, Receiver}; use crate::coordinates::{Coordinates, Position, Size}; use crate::files::{File, Files}; use crate::term; -use crate::widget::Widget; +use crate::widget::{Widget}; // Maybe also buffer drawlist for efficiency when it doesn't change every draw @@ -30,7 +31,7 @@ where ListView: Widget, T: Send, { - pub fn new(content: T) -> Self { + pub fn new(content: T) -> ListView { let view = ListView:: { content: content, selection: 0, @@ -81,7 +82,8 @@ where let ysize = self.coordinates.ysize() as usize; let mut offset = 0; - while position + 2 >= ysize + offset { + while position + 2 + >= ysize + offset { offset += 1 } @@ -99,7 +101,7 @@ where } else { (name.clone(), "".to_string()) }; - let xsize = self.get_size().xsize(); + let xsize = self.get_coordinates().xsize(); let sized_string = term::sized_string(&name, xsize); let size_pos = xsize - (size.to_string().len() as u16 + unit.to_string().len() as u16); @@ -321,8 +323,8 @@ where .arg("-c") .arg(&cmd) .status(); - - write!(std::io::stdout(), "{}{}", + let mut bufout = std::io::BufWriter::new(std::io::stdout()); + write!(bufout, "{}{}", termion::style::Reset, termion::clear::All).unwrap(); @@ -347,18 +349,6 @@ where } impl Widget for ListView { - fn get_size(&self) -> &Size { - &self.coordinates.size - } - fn get_position(&self) -> &Position { - &self.coordinates.position - } - fn set_size(&mut self, size: Size) { - self.coordinates.size = size; - } - fn set_position(&mut self, position: Position) { - self.coordinates.position = position; - } fn get_coordinates(&self) -> &Coordinates { &self.coordinates } @@ -376,7 +366,7 @@ impl Widget for ListView { fn get_drawlist(&self) -> String { let mut output = term::reset(); - let (_, ysize) = self.get_size().size(); + let ysize = self.get_coordinates().ysize(); let (xpos, ypos) = self.coordinates.position().position(); output += &self diff --git a/src/main.rs b/src/main.rs index 2798311..602fb11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![feature(vec_remove_item)] +#![feature(trivial_bounds)] extern crate termion; extern crate unicode_width; @@ -18,6 +19,7 @@ use termion::raw::IntoRawMode; use termion::screen::AlternateScreen; use std::io::{stdout, Write}; +use std::marker::Send; mod coordinates; mod file_browser; @@ -32,12 +34,16 @@ mod win_main; mod window; mod hbox; mod tabview; +mod async_widget; use window::Window; +use async_widget::AsyncPlug; +use widget::Widget; fn main() { + let mut bufout = std::io::BufWriter::new(std::io::stdout()); // Need to do this here to actually turn terminal into raw mode... - let mut _screen = AlternateScreen::from(Box::new(stdout())); + let mut _screen = AlternateScreen::from(Box::new(bufout)); let mut _stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); diff --git a/src/miller_columns.rs b/src/miller_columns.rs index 4114326..66113c6 100644 --- a/src/miller_columns.rs +++ b/src/miller_columns.rs @@ -1,7 +1,7 @@ use termion::event::Key; use crate::coordinates::{Coordinates, Position, Size}; -use crate::preview::Previewer; +use crate::preview::AsyncPreviewer; use crate::widget::Widget; use crate::hbox::HBox; @@ -10,21 +10,21 @@ pub struct MillerColumns where T: Widget { pub widgets: HBox, // pub left: Option, // pub main: Option, - pub preview: Previewer, + pub preview: AsyncPreviewer, pub ratio: (u16, u16, u16), pub coordinates: Coordinates, } impl MillerColumns where - T: Widget, + T: Widget + PartialEq, { - pub fn new() -> Self { - Self { + pub fn new() -> MillerColumns { + MillerColumns { widgets: HBox::new(), coordinates: Coordinates::new(), ratio: (20, 30, 50), - preview: Previewer::new(), + preview: AsyncPreviewer::new(), } } @@ -91,7 +91,6 @@ where if len < 2 { return None; } - self.widgets.widgets.get(len - 2)?.get_position(); self.widgets.widgets.get_mut(len - 2) } pub fn get_main_widget(&self) -> &T { @@ -105,19 +104,8 @@ where impl Widget for MillerColumns where T: Widget, + T: PartialEq { - fn get_size(&self) -> &Size { - &self.coordinates.size - } - fn get_position(&self) -> &Position { - &self.coordinates.position - } - fn set_size(&mut self, size: Size) { - self.coordinates.size = size; - } - fn set_position(&mut self, position: Position) { - self.coordinates.position = position; - } fn get_coordinates(&self) -> &Coordinates { &self.coordinates } diff --git a/src/preview.rs b/src/preview.rs index d6bf31d..f6bad98 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -7,6 +7,7 @@ use crate::files::{File, Files, Kind}; use crate::listview::ListView; use crate::textview::TextView; use crate::widget::Widget; +use crate::async_widget::AsyncPlug; lazy_static! { @@ -23,10 +24,130 @@ fn kill_procs() { } fn is_current(file: &File) -> bool { - CURFILE.lock().unwrap().as_ref().unwrap() == file + true + //CURFILE.lock().unwrap().as_ref().unwrap() == file } +#[derive(PartialEq)] +pub struct AsyncPreviewer { + pub file: Option, + pub buffer: String, + pub coordinates: Coordinates, + pub async_plug: AsyncPlug +} +impl AsyncPreviewer { + pub fn new() -> AsyncPreviewer { + let textview = crate::textview::TextView { + lines: vec![], + buffer: "".to_string(), + coordinates: Coordinates::new(), + }; + let textview = Box::new(textview); + + AsyncPreviewer { + file: None, + buffer: String::new(), + coordinates: Coordinates::new(), + async_plug: AsyncPlug::new(textview) + } + } + pub fn set_file(&mut self, file: &File) { + let coordinates = self.coordinates.clone(); + let file = file.clone(); + let redraw = crate::term::reset() + &self.get_redraw_empty_list(0); + + self.async_plug.replace_widget(Box::new(move || { + kill_procs(); + let mut bufout = std::io::BufWriter::new(std::io::stdout()); + match &file.kind { + Kind::Directory => match Files::new_from_path(&file.path) { + Ok(files) => { + //if !is_current(&file) { return } + let len = files.len(); + //if len == 0 { return }; + let mut file_list = ListView::new(files); + file_list.set_coordinates(&coordinates); + file_list.refresh(); + //if !is_current(&file) { return } + file_list.animate_slide_up(); + return Box::new(file_list) as Box; + + } + Err(err) => { + write!(bufout, "{}", redraw).unwrap(); + let textview = crate::textview::TextView { + lines: vec![], + buffer: "".to_string(), + coordinates: Coordinates::new(), + }; + return Box::new(textview) as Box; + }, + } + _ => { + if file.get_mime() == Some("text".to_string()) { + let mut textview = TextView::new_from_file(&file); + //if !is_current(&file) { return } + textview.set_coordinates(&coordinates); + textview.refresh(); + //if !is_current(&file) { return } + textview.animate_slide_up(); + return Box::new(textview); + } else { + let process = + std::process::Command::new("scope.sh") + .arg(&file.name) + .arg("10".to_string()) + .arg("10".to_string()) + .arg("".to_string()) + .arg("false".to_string()) + .stdin(std::process::Stdio::null()) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::null()) + .spawn().unwrap(); + + // let pid = process.id(); + // PIDS.lock().unwrap().push(pid); + + //if !is_current(&file) { return } + + let output = process.wait_with_output(); + //if output.is_err() { return } + let output = output.unwrap(); + + let status = output.status.code(); + //if status.is_none() { return } + let status = status.unwrap(); + + if status == 0 || status == 5 && is_current(&file) { + let output = std::str::from_utf8(&output.stdout) + .unwrap() + .to_string(); + let mut textview = TextView { + lines: output.lines().map(|s| s.to_string()).collect(), + buffer: String::new(), + coordinates: Coordinates::new() }; + textview.set_coordinates(&coordinates); + textview.refresh(); + textview.animate_slide_up(); + return Box::new(textview); + } + + } + + write!(bufout, "{}", redraw).unwrap(); + //std::io::stdout().flush().unwrap(); + let textview = crate::textview::TextView { + lines: vec![], + buffer: "".to_string(), + coordinates: Coordinates::new(), + }; + return Box::new(textview); + } + } + })); + } +} #[derive(PartialEq)] pub struct Previewer { @@ -129,18 +250,6 @@ impl Previewer { } impl Widget for Previewer { - fn get_size(&self) -> &Size { - &self.coordinates.size - } - fn set_size(&mut self, size: Size) { - self.coordinates.size = size; - } - fn get_position(&self) -> &Position { - &self.coordinates.position - } - fn set_position(&mut self, pos: Position) { - self.coordinates.position = pos; - } fn get_coordinates(&self) -> &Coordinates { &self.coordinates } @@ -164,3 +273,31 @@ impl Widget for Previewer { self.buffer.clone() } } + + +impl Widget for AsyncPreviewer { + fn get_coordinates(&self) -> &Coordinates { + &self.coordinates + } + fn set_coordinates(&mut self, coordinates: &Coordinates) { + if self.coordinates == *coordinates { + return; + } + self.coordinates = coordinates.clone(); + self.async_plug.set_coordinates(&coordinates.clone()); + self.async_plug.refresh(); + } + fn render_header(&self) -> String { + "".to_string() + } + fn refresh(&mut self) { + let file = self.file.clone(); + if let Some(file) = file { + self.set_file(&file); + } + } + fn get_drawlist(&self) -> String { + self.async_plug.get_drawlist(); + "".to_string() + } +} diff --git a/src/tabview.rs b/src/tabview.rs index 59e5872..39286a0 100644 --- a/src/tabview.rs +++ b/src/tabview.rs @@ -10,15 +10,15 @@ pub trait Tabbable { #[derive(PartialEq)] -pub struct TabView where T: Widget { +pub struct TabView where T: Widget, T: Tabbable { widgets: Vec, active: usize, coordinates: Coordinates } -impl TabView where T: Widget + Tabbable { - pub fn new() -> Self { - Self { +impl TabView where T: Widget, T: Tabbable { + pub fn new() -> TabView { + TabView { widgets: vec![], active: 0, coordinates: Coordinates::new() @@ -67,7 +67,7 @@ impl TabView where T: Widget + Tabbable { } } -impl Widget for TabView where T: Widget + Tabbable + PartialEq { +impl Widget for TabView where T: Widget + Tabbable { fn render_header(&self) -> String { let xsize = self.get_coordinates().xsize(); let header = self.active_widget().render_header(); @@ -106,18 +106,6 @@ impl Widget for TabView where T: Widget + Tabbable + PartialEq { self.active_widget().get_drawlist() } - fn get_size(&self) -> &Size { - &self.coordinates.size - } - fn get_position(&self) -> &Position { - &self.coordinates.position - } - fn set_size(&mut self, size: Size) { - self.coordinates.size = size; - } - fn set_position(&mut self, position: Position) { - self.coordinates.position = position; - } fn get_coordinates(&self) -> &Coordinates { &self.coordinates } diff --git a/src/textview.rs b/src/textview.rs index ad76ca8..04e0fbf 100644 --- a/src/textview.rs +++ b/src/textview.rs @@ -31,18 +31,6 @@ impl TextView { } impl Widget for TextView { - fn get_size(&self) -> &Size { - &self.coordinates.size - } - fn set_size(&mut self, size: Size) { - self.coordinates.size = size; - } - fn get_position(&self) -> &Position { - &self.coordinates.position - } - fn set_position(&mut self, pos: Position) { - self.coordinates.position = pos; - } fn get_coordinates(&self) -> &Coordinates { &self.coordinates } @@ -54,7 +42,7 @@ impl Widget for TextView { "".to_string() } fn refresh(&mut self) { - let (xsize, ysize) = self.get_size().size(); + let (xsize, ysize) = self.get_coordinates().size().size(); let (xpos, ypos) = self.get_coordinates().position().position(); self.buffer = self.get_clearlist() + diff --git a/src/widget.rs b/src/widget.rs index 465d625..5cbcec6 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -2,18 +2,17 @@ use termion::event::{Event, Key, MouseEvent}; use crate::coordinates::{Coordinates, Position, Size}; -use std::io::Write; +use std::io::{BufWriter, Write}; -pub trait Widget: PartialEq { - //fn render(&self) -> Vec; - fn get_size(&self) -> &Size; - fn get_position(&self) -> &Position; - fn set_size(&mut self, size: Size); - fn set_position(&mut self, position: Position); + +pub trait Widget { fn get_coordinates(&self) -> &Coordinates; fn set_coordinates(&mut self, coordinates: &Coordinates); fn render_header(&self) -> String; fn render_footer(&self) -> String { "".into() } + fn refresh(&mut self); + fn get_drawlist(&self) -> String; + fn on_event(&mut self, event: Event) { match event { @@ -62,7 +61,7 @@ pub trait Widget: PartialEq { " ", crate::term::goto_xy(1, 1), self.render_header(), - xsize = self.get_size().xsize() as usize + xsize = self.get_coordinates().xsize() as usize ) } @@ -80,8 +79,8 @@ pub trait Widget: PartialEq { } fn get_clearlist(&self) -> String { - let (xpos, ypos) = self.get_position().position(); - let (xsize, ysize) = self.get_size().size(); + let (xpos, ypos) = self.get_coordinates().u16position(); + let (xsize, ysize) = self.get_coordinates().u16size(); (ypos..ysize + 2) .map(|line| { @@ -97,8 +96,8 @@ pub trait Widget: PartialEq { } fn get_redraw_empty_list(&self, lines: usize) -> String { - let (xpos, ypos) = self.get_position().position(); - let (xsize, ysize) = self.get_size().size(); + let (xpos, ypos) = self.get_coordinates().u16position(); + let (xsize, ysize) = self.get_coordinates().u16size(); let start_y = lines + ypos as usize; (start_y..(ysize + 2) as usize) @@ -121,6 +120,7 @@ pub trait Widget: PartialEq { let ysize = coords.ysize(); let clear = self.get_clearlist(); let pause = std::time::Duration::from_millis(5); + let mut bufout = std::io::BufWriter::new(std::io::stdout()); for i in (0..10).rev() { let coords = Coordinates { size: Size((xsize,ysize-i)), @@ -130,13 +130,11 @@ pub trait Widget: PartialEq { }; self.set_coordinates(&coords); let buffer = self.get_drawlist(); - write!(std::io::stdout(), "{}{}", + write!(bufout, "{}{}", clear, buffer).unwrap(); + std::thread::sleep(pause); } } - - fn refresh(&mut self); - fn get_drawlist(&self) -> String; }