async widget

This commit is contained in:
rabite 2019-02-12 22:55:16 +01:00
parent 1c500d91cf
commit 56d9c35215
12 changed files with 219 additions and 128 deletions

View File

@ -16,4 +16,8 @@ rayon = "1.0.3"
dirs-2 = "1.1.0" dirs-2 = "1.1.0"
users = "0.8" users = "0.8"
chrono = "0.4" chrono = "0.4"
libc = "*" libc = "*"
#[profile.release]
#debug = true
#lto = false

View File

@ -40,6 +40,18 @@ impl Coordinates {
&self.position &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 { pub fn top(&self) -> Position {
self.position().clone() self.position().clone()
} }

View File

@ -16,7 +16,7 @@ pub struct FileBrowser {
} }
impl Tabbable<FileBrowser> for FileBrowser { impl Tabbable<FileBrowser> for FileBrowser {
fn new_tab(&self) -> Self { fn new_tab(&self) -> FileBrowser {
FileBrowser::new().unwrap() FileBrowser::new().unwrap()
} }
@ -115,8 +115,12 @@ impl FileBrowser {
pub fn update_preview(&mut self) { pub fn update_preview(&mut self) {
if self.columns.get_main_widget().content.len() == 0 { return } if self.columns.get_main_widget().content.len() == 0 { return }
let file = self.columns.get_main_widget().selected_file().clone(); 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); preview.set_file(&file);
self.columns.preview = preview;
} }
pub fn fix_selection(&mut self) { pub fn fix_selection(&mut self) {
@ -188,18 +192,6 @@ impl FileBrowser {
} }
impl Widget for 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 { fn get_coordinates(&self) -> &Coordinates {
&self.columns.coordinates &self.columns.coordinates
} }

View File

@ -26,7 +26,7 @@ pub struct Files {
impl Index<usize> for Files { impl Index<usize> for Files {
type Output = File; type Output = File;
fn index(&self, pos: usize) -> &Self::Output { fn index(&self, pos: usize) -> &File {
&self.files[pos] &self.files[pos]
} }
} }

View File

@ -11,7 +11,7 @@ pub struct HBox<T: Widget> {
} }
impl<T> HBox<T> where T: Widget { impl<T> HBox<T> where T: Widget + PartialEq {
pub fn new() -> HBox<T> { pub fn new() -> HBox<T> {
HBox { coordinates: Coordinates::new(), HBox { coordinates: Coordinates::new(),
widgets: vec![], widgets: vec![],
@ -78,7 +78,7 @@ impl<T> HBox<T> where T: Widget {
impl<T> Widget for HBox<T> where T: Widget { impl<T> Widget for HBox<T> where T: Widget + PartialEq {
fn render_header(&self) -> String { fn render_header(&self) -> String {
self.active_widget().render_header() self.active_widget().render_header()
} }
@ -96,18 +96,6 @@ impl<T> Widget for HBox<T> where T: Widget {
}).collect() }).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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }

View File

@ -4,11 +4,12 @@ use unicode_width::UnicodeWidthStr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::io::Write; use std::io::Write;
//use std::sync::mpsc::{channel, Sender, Receiver};
use crate::coordinates::{Coordinates, Position, Size}; use crate::coordinates::{Coordinates, Position, Size};
use crate::files::{File, Files}; use crate::files::{File, Files};
use crate::term; use crate::term;
use crate::widget::Widget; use crate::widget::{Widget};
// Maybe also buffer drawlist for efficiency when it doesn't change every draw // Maybe also buffer drawlist for efficiency when it doesn't change every draw
@ -30,7 +31,7 @@ where
ListView<T>: Widget, ListView<T>: Widget,
T: Send, T: Send,
{ {
pub fn new(content: T) -> Self { pub fn new(content: T) -> ListView<T> {
let view = ListView::<T> { let view = ListView::<T> {
content: content, content: content,
selection: 0, selection: 0,
@ -81,7 +82,8 @@ where
let ysize = self.coordinates.ysize() as usize; let ysize = self.coordinates.ysize() as usize;
let mut offset = 0; let mut offset = 0;
while position + 2 >= ysize + offset { while position + 2
>= ysize + offset {
offset += 1 offset += 1
} }
@ -99,7 +101,7 @@ where
} else { (name.clone(), "".to_string()) }; } 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 sized_string = term::sized_string(&name, xsize);
let size_pos = xsize - (size.to_string().len() as u16 let size_pos = xsize - (size.to_string().len() as u16
+ unit.to_string().len() as u16); + unit.to_string().len() as u16);
@ -321,8 +323,8 @@ where
.arg("-c") .arg("-c")
.arg(&cmd) .arg(&cmd)
.status(); .status();
let mut bufout = std::io::BufWriter::new(std::io::stdout());
write!(std::io::stdout(), "{}{}", write!(bufout, "{}{}",
termion::style::Reset, termion::style::Reset,
termion::clear::All).unwrap(); termion::clear::All).unwrap();
@ -347,18 +349,6 @@ where
} }
impl Widget for ListView<Files> { impl Widget for ListView<Files> {
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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }
@ -376,7 +366,7 @@ impl Widget for ListView<Files> {
fn get_drawlist(&self) -> String { fn get_drawlist(&self) -> String {
let mut output = term::reset(); let mut output = term::reset();
let (_, ysize) = self.get_size().size(); let ysize = self.get_coordinates().ysize();
let (xpos, ypos) = self.coordinates.position().position(); let (xpos, ypos) = self.coordinates.position().position();
output += &self output += &self

View File

@ -1,4 +1,5 @@
#![feature(vec_remove_item)] #![feature(vec_remove_item)]
#![feature(trivial_bounds)]
extern crate termion; extern crate termion;
extern crate unicode_width; extern crate unicode_width;
@ -18,6 +19,7 @@ use termion::raw::IntoRawMode;
use termion::screen::AlternateScreen; use termion::screen::AlternateScreen;
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::marker::Send;
mod coordinates; mod coordinates;
mod file_browser; mod file_browser;
@ -32,12 +34,16 @@ mod win_main;
mod window; mod window;
mod hbox; mod hbox;
mod tabview; mod tabview;
mod async_widget;
use window::Window; use window::Window;
use async_widget::AsyncPlug;
use widget::Widget;
fn main() { fn main() {
let mut bufout = std::io::BufWriter::new(std::io::stdout());
// Need to do this here to actually turn terminal into raw mode... // 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()); let mut _stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());

View File

@ -1,7 +1,7 @@
use termion::event::Key; use termion::event::Key;
use crate::coordinates::{Coordinates, Position, Size}; use crate::coordinates::{Coordinates, Position, Size};
use crate::preview::Previewer; use crate::preview::AsyncPreviewer;
use crate::widget::Widget; use crate::widget::Widget;
use crate::hbox::HBox; use crate::hbox::HBox;
@ -10,21 +10,21 @@ pub struct MillerColumns<T> where T: Widget {
pub widgets: HBox<T>, pub widgets: HBox<T>,
// pub left: Option<T>, // pub left: Option<T>,
// pub main: Option<T>, // pub main: Option<T>,
pub preview: Previewer, pub preview: AsyncPreviewer,
pub ratio: (u16, u16, u16), pub ratio: (u16, u16, u16),
pub coordinates: Coordinates, pub coordinates: Coordinates,
} }
impl<T> MillerColumns<T> impl<T> MillerColumns<T>
where where
T: Widget, T: Widget + PartialEq,
{ {
pub fn new() -> Self { pub fn new() -> MillerColumns<T> {
Self { MillerColumns {
widgets: HBox::new(), widgets: HBox::new(),
coordinates: Coordinates::new(), coordinates: Coordinates::new(),
ratio: (20, 30, 50), ratio: (20, 30, 50),
preview: Previewer::new(), preview: AsyncPreviewer::new(),
} }
} }
@ -91,7 +91,6 @@ where
if len < 2 { if len < 2 {
return None; return None;
} }
self.widgets.widgets.get(len - 2)?.get_position();
self.widgets.widgets.get_mut(len - 2) self.widgets.widgets.get_mut(len - 2)
} }
pub fn get_main_widget(&self) -> &T { pub fn get_main_widget(&self) -> &T {
@ -105,19 +104,8 @@ where
impl<T> Widget for MillerColumns<T> impl<T> Widget for MillerColumns<T>
where where
T: Widget, 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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }

View File

@ -7,6 +7,7 @@ use crate::files::{File, Files, Kind};
use crate::listview::ListView; use crate::listview::ListView;
use crate::textview::TextView; use crate::textview::TextView;
use crate::widget::Widget; use crate::widget::Widget;
use crate::async_widget::AsyncPlug;
lazy_static! { lazy_static! {
@ -23,10 +24,130 @@ fn kill_procs() {
} }
fn is_current(file: &File) -> bool { 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<File>,
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<dyn Widget + Send>;
}
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<dyn Widget + Send>;
},
}
_ => {
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)] #[derive(PartialEq)]
pub struct Previewer { pub struct Previewer {
@ -129,18 +250,6 @@ impl Previewer {
} }
impl Widget for 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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }
@ -164,3 +273,31 @@ impl Widget for Previewer {
self.buffer.clone() 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()
}
}

View File

@ -10,15 +10,15 @@ pub trait Tabbable<T: Widget> {
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct TabView<T> where T: Widget { pub struct TabView<T> where T: Widget, T: Tabbable<T> {
widgets: Vec<T>, widgets: Vec<T>,
active: usize, active: usize,
coordinates: Coordinates coordinates: Coordinates
} }
impl<T> TabView<T> where T: Widget + Tabbable<T> { impl<T> TabView<T> where T: Widget, T: Tabbable<T> {
pub fn new() -> Self { pub fn new() -> TabView<T> {
Self { TabView {
widgets: vec![], widgets: vec![],
active: 0, active: 0,
coordinates: Coordinates::new() coordinates: Coordinates::new()
@ -67,7 +67,7 @@ impl<T> TabView<T> where T: Widget + Tabbable<T> {
} }
} }
impl<T> Widget for TabView<T> where T: Widget + Tabbable<T> + PartialEq { impl<T> Widget for TabView<T> where T: Widget + Tabbable<T> {
fn render_header(&self) -> String { fn render_header(&self) -> String {
let xsize = self.get_coordinates().xsize(); let xsize = self.get_coordinates().xsize();
let header = self.active_widget().render_header(); let header = self.active_widget().render_header();
@ -106,18 +106,6 @@ impl<T> Widget for TabView<T> where T: Widget + Tabbable<T> + PartialEq {
self.active_widget().get_drawlist() 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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }

View File

@ -31,18 +31,6 @@ impl TextView {
} }
impl Widget for 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 { fn get_coordinates(&self) -> &Coordinates {
&self.coordinates &self.coordinates
} }
@ -54,7 +42,7 @@ impl Widget for TextView {
"".to_string() "".to_string()
} }
fn refresh(&mut self) { 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(); let (xpos, ypos) = self.get_coordinates().position().position();
self.buffer = self.get_clearlist() + self.buffer = self.get_clearlist() +

View File

@ -2,18 +2,17 @@ use termion::event::{Event, Key, MouseEvent};
use crate::coordinates::{Coordinates, Position, Size}; use crate::coordinates::{Coordinates, Position, Size};
use std::io::Write; use std::io::{BufWriter, Write};
pub trait Widget: PartialEq {
//fn render(&self) -> Vec<String>; pub trait Widget {
fn get_size(&self) -> &Size;
fn get_position(&self) -> &Position;
fn set_size(&mut self, size: Size);
fn set_position(&mut self, position: Position);
fn get_coordinates(&self) -> &Coordinates; fn get_coordinates(&self) -> &Coordinates;
fn set_coordinates(&mut self, coordinates: &Coordinates); fn set_coordinates(&mut self, coordinates: &Coordinates);
fn render_header(&self) -> String; fn render_header(&self) -> String;
fn render_footer(&self) -> String { "".into() } fn render_footer(&self) -> String { "".into() }
fn refresh(&mut self);
fn get_drawlist(&self) -> String;
fn on_event(&mut self, event: Event) { fn on_event(&mut self, event: Event) {
match event { match event {
@ -62,7 +61,7 @@ pub trait Widget: PartialEq {
" ", " ",
crate::term::goto_xy(1, 1), crate::term::goto_xy(1, 1),
self.render_header(), 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 { fn get_clearlist(&self) -> String {
let (xpos, ypos) = self.get_position().position(); let (xpos, ypos) = self.get_coordinates().u16position();
let (xsize, ysize) = self.get_size().size(); let (xsize, ysize) = self.get_coordinates().u16size();
(ypos..ysize + 2) (ypos..ysize + 2)
.map(|line| { .map(|line| {
@ -97,8 +96,8 @@ pub trait Widget: PartialEq {
} }
fn get_redraw_empty_list(&self, lines: usize) -> String { fn get_redraw_empty_list(&self, lines: usize) -> String {
let (xpos, ypos) = self.get_position().position(); let (xpos, ypos) = self.get_coordinates().u16position();
let (xsize, ysize) = self.get_size().size(); let (xsize, ysize) = self.get_coordinates().u16size();
let start_y = lines + ypos as usize; let start_y = lines + ypos as usize;
(start_y..(ysize + 2) as usize) (start_y..(ysize + 2) as usize)
@ -121,6 +120,7 @@ pub trait Widget: PartialEq {
let ysize = coords.ysize(); let ysize = coords.ysize();
let clear = self.get_clearlist(); let clear = self.get_clearlist();
let pause = std::time::Duration::from_millis(5); let pause = std::time::Duration::from_millis(5);
let mut bufout = std::io::BufWriter::new(std::io::stdout());
for i in (0..10).rev() { for i in (0..10).rev() {
let coords = Coordinates { size: Size((xsize,ysize-i)), let coords = Coordinates { size: Size((xsize,ysize-i)),
@ -130,13 +130,11 @@ pub trait Widget: PartialEq {
}; };
self.set_coordinates(&coords); self.set_coordinates(&coords);
let buffer = self.get_drawlist(); let buffer = self.get_drawlist();
write!(std::io::stdout(), "{}{}", write!(bufout, "{}{}",
clear, buffer).unwrap(); clear, buffer).unwrap();
std::thread::sleep(pause); std::thread::sleep(pause);
} }
} }
fn refresh(&mut self);
fn get_drawlist(&self) -> String;
} }