mirror of https://github.com/bobwen-dev/hunter
moved window stuff to widget itself
This commit is contained in:
parent
e2acef5ddf
commit
eb5a86b7cd
35
src/fail.rs
35
src/fail.rs
|
@ -1,5 +1,6 @@
|
|||
use failure;
|
||||
use failure::Fail;
|
||||
use failure::Backtrace;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -28,21 +29,45 @@ pub enum HError {
|
|||
#[fail(display = "Was None!")]
|
||||
NoneError,
|
||||
#[fail(display = "Not ready yet!")]
|
||||
WillBeNotReady,
|
||||
WillBeNotReady(Backtrace),
|
||||
#[fail(display = "No widget found")]
|
||||
NoWidgetError,
|
||||
NoWidgetError(Backtrace),
|
||||
#[fail(display = "Path: {:?} not in this directory: {:?}", path, dir)]
|
||||
WrongDirectoryError{ path: PathBuf, dir: PathBuf },
|
||||
#[fail(display = "Widget finnished")]
|
||||
PopupFinnished,
|
||||
#[fail(display = "Input finnished")]
|
||||
InputFinnished,
|
||||
#[fail(display = "No completions found")]
|
||||
NoCompletionsError,
|
||||
#[fail(display = "No more history")]
|
||||
NoHistoryError
|
||||
NoHistoryError,
|
||||
#[fail(display = "No core for widget")]
|
||||
NoWidgetCoreError(Backtrace),
|
||||
#[fail(display = "No header for widget")]
|
||||
NoHeaderError,
|
||||
}
|
||||
|
||||
pub trait ErrorLog where Self: Sized {
|
||||
fn log(self) {}
|
||||
}
|
||||
|
||||
impl<T> ErrorLog for HResult<T> {
|
||||
fn log(self) {
|
||||
if let Err(err) = self {
|
||||
eprintln!("{:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// impl From<&HError> for HError {
|
||||
// fn from(error: &HError) -> Self {
|
||||
// dbg!(&error);
|
||||
// (error.clone())
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<std::io::Error> for HError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
dbg!(&error);
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
use termion::event::Key;
|
||||
use notify::{INotifyWatcher, Watcher, DebouncedEvent, RecursiveMode};
|
||||
|
||||
use std::error::Error;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::time::Duration;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::files::{File, Files};
|
||||
use crate::listview::ListView;
|
||||
use crate::miller_columns::MillerColumns;
|
||||
use crate::widget::Widget;
|
||||
use crate::tabview::{TabView, Tabbable};
|
||||
use crate::preview::WillBeWidget;
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::window::{Events, send_event};
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::widget::{Events, WidgetCore};
|
||||
use crate::proclist::ProcView;
|
||||
|
||||
|
||||
|
@ -24,6 +22,7 @@ use crate::proclist::ProcView;
|
|||
pub struct FileBrowser {
|
||||
pub columns: MillerColumns<WillBeWidget<ListView<Files>>>,
|
||||
pub cwd: File,
|
||||
core: WidgetCore,
|
||||
watcher: INotifyWatcher,
|
||||
watches: Vec<PathBuf>,
|
||||
dir_events: Arc<Mutex<Vec<DebouncedEvent>>>,
|
||||
|
@ -31,22 +30,24 @@ pub struct FileBrowser {
|
|||
}
|
||||
|
||||
impl Tabbable for TabView<FileBrowser> {
|
||||
fn new_tab(&mut self) {
|
||||
let mut tab = FileBrowser::new().unwrap();
|
||||
fn new_tab(&mut self) -> HResult<()> {
|
||||
let mut tab = FileBrowser::new_cored(&self.active_tab_().core)?;
|
||||
|
||||
let proc_view = self.active_tab_().proc_view.clone();
|
||||
tab.proc_view = proc_view;
|
||||
|
||||
self.push_widget(tab);
|
||||
self.push_widget(tab)?;
|
||||
self.active += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close_tab(&mut self) {
|
||||
self.close_tab_();
|
||||
fn close_tab(&mut self) -> HResult<()> {
|
||||
self.close_tab_()
|
||||
}
|
||||
|
||||
fn next_tab(&mut self) {
|
||||
fn next_tab(&mut self) -> HResult<()> {
|
||||
self.next_tab_();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_tab_names(&self) -> Vec<Option<String>> {
|
||||
|
@ -66,18 +67,18 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
self.active_tab_mut_()
|
||||
}
|
||||
|
||||
fn on_next_tab(&mut self) {
|
||||
self.active_tab_mut().refresh();
|
||||
fn on_next_tab(&mut self) -> HResult<()> {
|
||||
self.active_tab_mut().refresh()
|
||||
}
|
||||
|
||||
fn on_key_sub(&mut self, key: Key) {
|
||||
fn on_key_sub(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Char('!') => {
|
||||
let tab_dirs = self.widgets.iter().map(|w| w.cwd.clone())
|
||||
.collect::<Vec<_>>();
|
||||
self.widgets[self.active].exec_cmd(tab_dirs).ok();
|
||||
self.widgets[self.active].exec_cmd(tab_dirs)
|
||||
}
|
||||
_ => { self.active_tab_mut().on_key(key).ok(); }
|
||||
_ => { self.active_tab_mut().on_key(key) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,11 +87,13 @@ impl Tabbable for TabView<FileBrowser> {
|
|||
|
||||
|
||||
|
||||
fn watch_dir(rx: Receiver<DebouncedEvent>, dir_events: Arc<Mutex<Vec<DebouncedEvent>>>) {
|
||||
fn watch_dir(rx: Receiver<DebouncedEvent>,
|
||||
dir_events: Arc<Mutex<Vec<DebouncedEvent>>>,
|
||||
sender: Sender<Events>) {
|
||||
std::thread::spawn(move || {
|
||||
for event in rx.iter() {
|
||||
dir_events.lock().unwrap().push(event);
|
||||
send_event(Events::WidgetReady).unwrap();
|
||||
sender.send(Events::WidgetReady).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -100,24 +103,23 @@ fn watch_dir(rx: Receiver<DebouncedEvent>, dir_events: Arc<Mutex<Vec<DebouncedEv
|
|||
|
||||
|
||||
impl FileBrowser {
|
||||
pub fn new() -> Result<FileBrowser, Box<Error>> {
|
||||
pub fn new_cored(core: &WidgetCore) -> HResult<FileBrowser> {
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
let coords = Coordinates::new_at(crate::term::xsize(),
|
||||
crate::term::ysize() - 2,
|
||||
1,
|
||||
2);
|
||||
let coords = core.coordinates.clone();
|
||||
let core_ = core.clone();
|
||||
|
||||
let mut miller = MillerColumns::new();
|
||||
miller.set_coordinates(&coords);
|
||||
let mut miller = MillerColumns::new(core);
|
||||
miller.set_coordinates(&coords)?;
|
||||
|
||||
|
||||
let (_, main_coords, _) = miller.calculate_coordinates();
|
||||
|
||||
let main_path: std::path::PathBuf = cwd.ancestors().take(1).map(|path| std::path::PathBuf::from(path)).collect();
|
||||
let main_widget = WillBeWidget::new(Box::new(move |_| {
|
||||
let mut list = ListView::new(Files::new_from_path(&main_path).unwrap());
|
||||
list.set_coordinates(&main_coords);
|
||||
list.animate_slide_up();
|
||||
let main_widget = WillBeWidget::new(&core, Box::new(move |_| {
|
||||
let mut list = ListView::new(&core_,
|
||||
Files::new_from_path(&main_path).unwrap());
|
||||
list.set_coordinates(&main_coords).log();
|
||||
list.animate_slide_up().log();
|
||||
Ok(list)
|
||||
}));
|
||||
|
||||
|
@ -129,13 +131,14 @@ impl FileBrowser {
|
|||
|
||||
let (tx_watch, rx_watch) = channel();
|
||||
let watcher = INotifyWatcher::new(tx_watch, Duration::from_secs(2)).unwrap();
|
||||
watch_dir(rx_watch, dir_events.clone());
|
||||
watch_dir(rx_watch, dir_events.clone(), core.get_sender());
|
||||
|
||||
let mut proc_view = ProcView::new();
|
||||
proc_view.set_coordinates(&coords);
|
||||
let mut proc_view = ProcView::new(core);
|
||||
proc_view.set_coordinates(&coords).log();
|
||||
|
||||
Ok(FileBrowser { columns: miller,
|
||||
cwd: cwd,
|
||||
core: core.clone(),
|
||||
watcher: watcher,
|
||||
watches: vec![],
|
||||
dir_events: dir_events,
|
||||
|
@ -145,16 +148,17 @@ impl FileBrowser {
|
|||
pub fn enter_dir(&mut self) -> HResult<()> {
|
||||
let file = self.selected_file()?;
|
||||
let (_, coords, _) = self.columns.calculate_coordinates();
|
||||
let core = self.core.clone();
|
||||
|
||||
match file.read_dir() {
|
||||
Ok(files) => {
|
||||
std::env::set_current_dir(&file.path).unwrap();
|
||||
self.cwd = file.clone();
|
||||
let view = WillBeWidget::new(Box::new(move |_| {
|
||||
let view = WillBeWidget::new(&core.clone(), Box::new(move |_| {
|
||||
let files = files.clone();
|
||||
let mut list = ListView::new(files);
|
||||
list.set_coordinates(&coords);
|
||||
list.animate_slide_up();
|
||||
let mut list = ListView::new(&core, files);
|
||||
list.set_coordinates(&coords).log();
|
||||
list.animate_slide_up().log();
|
||||
Ok(list)
|
||||
}));
|
||||
self.columns.push_widget(view);
|
||||
|
@ -167,12 +171,12 @@ impl FileBrowser {
|
|||
match status {
|
||||
Ok(status) =>
|
||||
self.show_status(&format!("\"{}\" exited with {}",
|
||||
"rifle", status)),
|
||||
"rifle", status)).log(),
|
||||
Err(err) =>
|
||||
self.show_status(&format!("Can't run this \"{}\": {}",
|
||||
"rifle", err))
|
||||
"rifle", err)).log()
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -185,8 +189,7 @@ impl FileBrowser {
|
|||
self.cwd = new_cwd;
|
||||
}
|
||||
|
||||
self.refresh();
|
||||
Ok(())
|
||||
self.refresh()
|
||||
}
|
||||
|
||||
pub fn update_preview(&mut self) -> HResult<()> {
|
||||
|
@ -207,10 +210,12 @@ impl FileBrowser {
|
|||
let cwd = self.selected_file()?.clone();
|
||||
if let Ok(grand_parent) = cwd.grand_parent_as_file() {
|
||||
let (coords, _, _) = self.columns.calculate_coordinates();
|
||||
let left_view = WillBeWidget::new(Box::new(move |_| {
|
||||
let core = self.core.clone();
|
||||
let left_view = WillBeWidget::new(&self.core, Box::new(move |_| {
|
||||
let mut view
|
||||
= ListView::new(Files::new_from_path(&grand_parent.path)?);
|
||||
view.set_coordinates(&coords);
|
||||
= ListView::new(&core,
|
||||
Files::new_from_path(&grand_parent.path)?);
|
||||
view.set_coordinates(&coords).log();
|
||||
Ok(view)
|
||||
}));
|
||||
self.columns.prepend_widget(left_view);
|
||||
|
@ -341,17 +346,19 @@ impl FileBrowser {
|
|||
let dir = std::path::PathBuf::from(&dir);
|
||||
let left_dir = std::path::PathBuf::from(&dir);
|
||||
let (left_coords, main_coords, _) = self.columns.calculate_coordinates();
|
||||
let mcore = self.core.clone();
|
||||
let lcore = self.core.clone();
|
||||
|
||||
let middle = WillBeWidget::new(Box::new(move |_| {
|
||||
let middle = WillBeWidget::new(&self.core, Box::new(move |_| {
|
||||
let files = Files::new_from_path(&dir.clone())?;
|
||||
let mut listview = ListView::new(files);
|
||||
listview.set_coordinates(&main_coords);
|
||||
let mut listview = ListView::new(&mcore, files);
|
||||
listview.set_coordinates(&main_coords).log();
|
||||
Ok(listview)
|
||||
}));
|
||||
let left = WillBeWidget::new(Box::new(move |_| {
|
||||
let left = WillBeWidget::new(&self.core, Box::new(move |_| {
|
||||
let files = Files::new_from_path(&left_dir.parent()?)?;
|
||||
let mut listview = ListView::new(files);
|
||||
listview.set_coordinates(&left_coords);
|
||||
let mut listview = ListView::new(&lcore, files);
|
||||
listview.set_coordinates(&left_coords).log();
|
||||
Ok(listview)
|
||||
}));
|
||||
self.columns.push_widget(left);
|
||||
|
@ -373,7 +380,7 @@ impl FileBrowser {
|
|||
|
||||
let cmd = self.minibuffer("exec:")?;
|
||||
|
||||
self.show_status(&format!("Running: \"{}\"", &cmd));
|
||||
self.show_status(&format!("Running: \"{}\"", &cmd)).log();
|
||||
|
||||
let mut cmd = if file_names.len() == 0 {
|
||||
cmd.replace("$s", &format!("{}", &filename))
|
||||
|
@ -397,35 +404,28 @@ impl FileBrowser {
|
|||
}
|
||||
|
||||
impl Widget for FileBrowser {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.columns.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.columns.set_coordinates(coordinates);
|
||||
self.proc_view.lock().unwrap().set_coordinates(coordinates);
|
||||
self.refresh();
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
if self.main_widget().is_err() { return "".to_string() }
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
let file = self.selected_file().unwrap();
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
let xsize = self.get_coordinates()?.xsize();
|
||||
let file = self.selected_file()?;
|
||||
let name = &file.name;
|
||||
|
||||
let color = if file.is_dir() || file.color.is_none() {
|
||||
crate::term::highlight_color() } else {
|
||||
crate::term::from_lscolor(file.color.as_ref().unwrap()) };
|
||||
|
||||
let path = file.path.parent().unwrap().to_string_lossy().to_string();
|
||||
let path = file.path.parent()?.to_string_lossy().to_string();
|
||||
|
||||
let pretty_path = format!("{}/{}{}", path, &color, name );
|
||||
let sized_path = crate::term::sized_string(&pretty_path, xsize);
|
||||
sized_path
|
||||
Ok(sized_path)
|
||||
}
|
||||
fn render_footer(&self) -> String {
|
||||
if self.main_widget().is_err() { return "".to_string() }
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
let ypos = self.get_coordinates().position().y();
|
||||
let file = self.selected_file().unwrap();
|
||||
fn render_footer(&self) -> HResult<String> {
|
||||
let xsize = self.get_coordinates()?.xsize();
|
||||
let ypos = self.get_coordinates()?.position().y();
|
||||
let file = self.selected_file()?;
|
||||
|
||||
let permissions = file.pretty_print_permissions().unwrap_or("NOPERMS".into());
|
||||
let user = file.pretty_user().unwrap_or("NOUSER".into());
|
||||
|
@ -433,8 +433,8 @@ impl Widget for FileBrowser {
|
|||
let mtime = file.pretty_mtime().unwrap_or("NOMTIME".into());
|
||||
|
||||
|
||||
let selection = (*self.main_widget().as_ref().unwrap().lock().unwrap()).as_ref().unwrap().get_selection();
|
||||
let file_count = (*self.main_widget().unwrap().lock().unwrap()).as_ref().unwrap().content.len();
|
||||
let selection = (*self.main_widget().as_ref().unwrap().lock()?).as_ref()?.get_selection();
|
||||
let file_count = (*self.main_widget()?.lock()?).as_ref()?.content.len();
|
||||
let file_count = format!("{}", file_count);
|
||||
let digits = file_count.len();
|
||||
let file_count = format!("{:digits$}/{:digits$}",
|
||||
|
@ -442,42 +442,44 @@ impl Widget for FileBrowser {
|
|||
file_count,
|
||||
digits = digits);
|
||||
let count_xpos = xsize - file_count.len() as u16;
|
||||
let count_ypos = ypos + self.get_coordinates().ysize();
|
||||
let count_ypos = ypos + self.get_coordinates()?.ysize();
|
||||
|
||||
format!("{} {}:{} {} {} {}", permissions, user, group, mtime,
|
||||
crate::term::goto_xy(count_xpos, count_ypos), file_count)
|
||||
Ok(format!("{} {}:{} {} {} {}", permissions, user, group, mtime,
|
||||
crate::term::goto_xy(count_xpos, count_ypos), file_count))
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
self.handle_dir_events().ok();
|
||||
self.columns.refresh();
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
//self.proc_view.lock()?.set_coordinates(self.get_coordinates()?);
|
||||
self.handle_dir_events()?;
|
||||
self.columns.refresh().ok();
|
||||
self.fix_left().ok();
|
||||
self.fix_selection().ok();
|
||||
self.set_cwd().ok();
|
||||
self.update_watches().ok();
|
||||
self.update_preview().ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
if self.columns.get_left_widget().is_err() {
|
||||
self.columns.get_clearlist() + &self.columns.get_drawlist()
|
||||
Ok(self.columns.get_clearlist()? + &self.columns.get_drawlist()?)
|
||||
} else {
|
||||
self.columns.get_drawlist()
|
||||
Ok(self.columns.get_drawlist()?)
|
||||
}
|
||||
}
|
||||
|
||||
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(); },
|
||||
Key::Char('/') => { self.turbo_cd()?; },
|
||||
Key::Char('Q') => { self.quit_with_dir()?; },
|
||||
Key::Right | Key::Char('f') => { self.enter_dir()?; },
|
||||
Key::Left | Key::Char('b') => { self.go_back()?; },
|
||||
Key::Char('w') => {
|
||||
self.proc_view.lock()?.popup().ok();
|
||||
self.proc_view.lock()?.popup()?;
|
||||
}
|
||||
,
|
||||
_ => { self.columns.get_main_widget_mut()?.on_key(key).ok(); },
|
||||
_ => { self.columns.get_main_widget_mut()?.on_key(key)?; },
|
||||
}
|
||||
self.update_preview().ok();
|
||||
self.update_preview()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,18 @@ use std::cmp::{Ord, Ordering};
|
|||
use std::ops::Index;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use lscolors::LsColors;
|
||||
use mime_detective;
|
||||
use users;
|
||||
use chrono::TimeZone;
|
||||
use failure::Error;
|
||||
use notify::{INotifyWatcher, Watcher, DebouncedEvent, RecursiveMode};
|
||||
use notify::DebouncedEvent;
|
||||
|
||||
use crate::fail::{HResult, HError};
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
|
||||
|
||||
lazy_static! {
|
||||
|
@ -200,7 +201,7 @@ impl Files {
|
|||
DebouncedEvent::Write(path) | DebouncedEvent::Chmod(path) => {
|
||||
self.path_in_here(&path)?;
|
||||
let file = self.find_file_with_path(&path)?;
|
||||
file.reload_meta();
|
||||
file.reload_meta()?;
|
||||
},
|
||||
DebouncedEvent::Remove(path) => {
|
||||
self.path_in_here(&path)?;
|
||||
|
|
62
src/hbox.rs
62
src/hbox.rs
|
@ -1,20 +1,20 @@
|
|||
use termion::event::{Event};
|
||||
|
||||
use crate::widget::Widget;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::coordinates::{Coordinates, Size, Position};
|
||||
use crate::fail::HResult;
|
||||
use crate::fail::{HResult, ErrorLog};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct HBox<T: Widget> {
|
||||
pub coordinates: Coordinates,
|
||||
pub core: WidgetCore,
|
||||
pub widgets: Vec<T>,
|
||||
pub active: Option<usize>,
|
||||
}
|
||||
|
||||
|
||||
impl<T> HBox<T> where T: Widget + PartialEq {
|
||||
pub fn new() -> HBox<T> {
|
||||
HBox { coordinates: Coordinates::new(),
|
||||
pub fn new(core: &WidgetCore) -> HBox<T> {
|
||||
HBox { core: core.clone(),
|
||||
widgets: vec![],
|
||||
active: None
|
||||
}
|
||||
|
@ -27,34 +27,35 @@ impl<T> HBox<T> where T: Widget + PartialEq {
|
|||
|w|
|
||||
self.calculate_coordinates(w)).collect();
|
||||
for (widget, coord) in self.widgets.iter_mut().zip(coords.iter()) {
|
||||
widget.set_coordinates(coord);
|
||||
widget.set_coordinates(coord).log();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_widget(&mut self, widget: T) where T: PartialEq {
|
||||
self.widgets.push(widget);
|
||||
self.resize_children();
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
pub fn pop_widget(&mut self) -> Option<T> {
|
||||
let widget = self.widgets.pop();
|
||||
self.resize_children();
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
widget
|
||||
}
|
||||
|
||||
pub fn prepend_widget(&mut self, widget: T) {
|
||||
self.widgets.insert(0, widget);
|
||||
self.resize_children();
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
pub fn calculate_coordinates(&self, widget: &T)
|
||||
pub fn calculate_coordinates(&self, widget: &T)
|
||||
-> Coordinates where T: PartialEq {
|
||||
let xsize = self.coordinates.xsize();
|
||||
let ysize = self.coordinates.ysize();
|
||||
let top = self.coordinates.top().y();
|
||||
let coordinates = self.get_coordinates().unwrap();
|
||||
let xsize = coordinates.xsize();
|
||||
let ysize = coordinates.ysize();
|
||||
let top = coordinates.top().y();
|
||||
|
||||
let pos = self.widgets.iter().position(|w | w == widget).unwrap();
|
||||
let num = self.widgets.len();
|
||||
|
@ -69,7 +70,7 @@ impl<T> HBox<T> where T: Widget + PartialEq {
|
|||
top))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn active_widget(&self) -> &T {
|
||||
&self.widgets.last().unwrap()
|
||||
}
|
||||
|
@ -80,35 +81,32 @@ impl<T> HBox<T> where T: Widget + PartialEq {
|
|||
|
||||
|
||||
impl<T> Widget for HBox<T> where T: Widget + PartialEq {
|
||||
fn render_header(&self) -> String {
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
self.active_widget().render_header()
|
||||
}
|
||||
|
||||
fn refresh(&mut self) {
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.resize_children();
|
||||
for child in &mut self.widgets {
|
||||
child.refresh();
|
||||
child.refresh()?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
self.widgets.iter().map(|child| {
|
||||
child.get_drawlist()
|
||||
}).collect()
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
Ok(self.widgets.iter().map(|child| {
|
||||
child.get_drawlist().unwrap()
|
||||
}).collect())
|
||||
}
|
||||
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if self.coordinates == *coordinates {
|
||||
return;
|
||||
}
|
||||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
}
|
||||
fn on_event(&mut self, event: Event) -> HResult<()> {
|
||||
self.widgets.last_mut()?.on_event(event).ok();
|
||||
self.widgets.last_mut()?.on_event(event)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
116
src/listview.rs
116
src/listview.rs
|
@ -3,17 +3,16 @@ use unicode_width::UnicodeWidthStr;
|
|||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::files::{File, Files};
|
||||
use crate::fail::HResult;
|
||||
use crate::fail::{HResult, ErrorLog};
|
||||
use crate::term;
|
||||
use crate::widget::{Widget};
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
|
||||
pub trait Listable {
|
||||
fn len(&self) -> usize;
|
||||
fn render(&self) -> Vec<String>;
|
||||
fn on_refresh(&mut self) {}
|
||||
fn on_key(&mut self, _key: Key) {}
|
||||
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
|
||||
fn on_key(&mut self, _key: Key) -> HResult<()> { Ok(()) }
|
||||
}
|
||||
|
||||
impl Listable for ListView<Files> {
|
||||
|
@ -25,26 +24,27 @@ impl Listable for ListView<Files> {
|
|||
self.render()
|
||||
}
|
||||
|
||||
fn on_refresh(&mut self) {
|
||||
let visible_file_num = self.selection + self.get_coordinates().ysize() as usize;
|
||||
fn on_refresh(&mut self) -> HResult<()> {
|
||||
let visible_file_num = self.selection + self.get_coordinates()?.ysize() as usize;
|
||||
self.content.meta_upto(visible_file_num);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Up | Key::Char('p') => {
|
||||
self.move_up();
|
||||
self.refresh();
|
||||
self.refresh()?;
|
||||
}
|
||||
Key::Char('P') => { for _ in 0..10 { self.move_up() } self.refresh(); }
|
||||
Key::Char('N') => { for _ in 0..10 { self.move_down() } self.refresh(); }
|
||||
Key::Char('P') => { for _ in 0..10 { self.move_up() } self.refresh()?; }
|
||||
Key::Char('N') => { for _ in 0..10 { self.move_down() } self.refresh()?; }
|
||||
Key::Down | Key::Char('n') => {
|
||||
self.move_down();
|
||||
self.refresh();
|
||||
self.refresh()?;
|
||||
},
|
||||
Key::Ctrl('s') => { self.find_file().ok(); }
|
||||
Key::Left => self.goto_grand_parent(),
|
||||
Key::Right => self.goto_selected(),
|
||||
Key::Left => self.goto_grand_parent()?,
|
||||
Key::Right => self.goto_selected()?,
|
||||
Key::Char(' ') => self.multi_select_file(),
|
||||
Key::Char('h') => self.toggle_hidden(),
|
||||
Key::Char('r') => self.reverse_sort(),
|
||||
|
@ -52,8 +52,9 @@ impl Listable for ListView<Files> {
|
|||
Key::Char('K') => self.select_next_mtime(),
|
||||
Key::Char('k') => self.select_prev_mtime(),
|
||||
Key::Char('d') => self.toggle_dirs_first(),
|
||||
_ => self.bad(Event::Key(key))
|
||||
_ => { self.bad(Event::Key(key))?; }
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ pub struct ListView<T> where ListView<T>: Listable
|
|||
selection: usize,
|
||||
offset: usize,
|
||||
buffer: Vec<String>,
|
||||
coordinates: Coordinates,
|
||||
core: WidgetCore,
|
||||
seeking: bool,
|
||||
}
|
||||
|
||||
|
@ -74,17 +75,14 @@ where
|
|||
ListView<T>: Widget,
|
||||
ListView<T>: Listable
|
||||
{
|
||||
pub fn new(content: T) -> ListView<T> {
|
||||
pub fn new(core: &WidgetCore, content: T) -> ListView<T> {
|
||||
let view = ListView::<T> {
|
||||
content: content,
|
||||
lines: 0,
|
||||
selection: 0,
|
||||
offset: 0,
|
||||
buffer: Vec::new(),
|
||||
coordinates: Coordinates {
|
||||
size: Size((1, 1)),
|
||||
position: Position((1, 1)),
|
||||
},
|
||||
core: core.clone(),
|
||||
seeking: false
|
||||
};
|
||||
view
|
||||
|
@ -104,7 +102,7 @@ where
|
|||
}
|
||||
pub fn move_down(&mut self) {
|
||||
let lines = self.lines;
|
||||
let y_size = self.coordinates.ysize() as usize;
|
||||
let y_size = self.get_coordinates().unwrap().ysize() as usize;
|
||||
|
||||
if self.lines == 0 || self.selection == lines - 1 {
|
||||
return;
|
||||
|
@ -123,7 +121,7 @@ where
|
|||
}
|
||||
|
||||
fn set_selection(&mut self, position: usize) {
|
||||
let ysize = self.coordinates.ysize() as usize;
|
||||
let ysize = self.get_coordinates().unwrap().ysize() as usize;
|
||||
let mut offset = 0;
|
||||
|
||||
while position + 2
|
||||
|
@ -145,7 +143,7 @@ where
|
|||
} else { (name.clone(), "".to_string()) };
|
||||
|
||||
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
let xsize = self.get_coordinates().unwrap().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);
|
||||
|
@ -202,30 +200,29 @@ impl ListView<Files>
|
|||
self.selected_file().grand_parent()
|
||||
}
|
||||
|
||||
pub fn goto_grand_parent(&mut self) {
|
||||
pub fn goto_grand_parent(&mut self) -> HResult<()> {
|
||||
match self.grand_parent() {
|
||||
Some(grand_parent) => self.goto_path(&grand_parent),
|
||||
None => self.show_status("Can't go further!"),
|
||||
None => { self.show_status("Can't go further!") },
|
||||
}
|
||||
}
|
||||
|
||||
fn goto_selected(&mut self) {
|
||||
fn goto_selected(&mut self) -> HResult<()> {
|
||||
let path = self.selected_file().path();
|
||||
|
||||
self.goto_path(&path);
|
||||
self.goto_path(&path)
|
||||
}
|
||||
|
||||
pub fn goto_path(&mut self, path: &Path) {
|
||||
pub fn goto_path(&mut self, path: &Path) -> HResult<()> {
|
||||
match crate::files::Files::new_from_path(path) {
|
||||
Ok(files) => {
|
||||
self.content = files;
|
||||
self.selection = 0;
|
||||
self.offset = 0;
|
||||
self.refresh();
|
||||
self.refresh()
|
||||
}
|
||||
Err(err) => {
|
||||
self.show_status(&format!("Can't open this path: {}", err));
|
||||
return;
|
||||
self.show_status(&format!("Can't open this path: {}", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,8 +242,8 @@ impl ListView<Files>
|
|||
self.content.cycle_sort();
|
||||
self.content.sort();
|
||||
self.select_file(&file);
|
||||
self.refresh();
|
||||
self.show_status(&format!("Sorting by: {}", self.content.sort));
|
||||
self.refresh().log();
|
||||
self.show_status(&format!("Sorting by: {}", self.content.sort)).log();
|
||||
}
|
||||
|
||||
fn reverse_sort(&mut self) {
|
||||
|
@ -254,8 +251,8 @@ impl ListView<Files>
|
|||
self.content.reverse_sort();
|
||||
self.content.sort();
|
||||
self.select_file(&file);
|
||||
self.refresh();
|
||||
self.show_status(&format!("Reversed sorting by: {}", self.content.sort));
|
||||
self.refresh().log();
|
||||
self.show_status(&format!("Reversed sorting by: {}", self.content.sort)).log();
|
||||
}
|
||||
|
||||
fn select_next_mtime(&mut self) {
|
||||
|
@ -283,7 +280,7 @@ impl ListView<Files>
|
|||
self.select_file(&file);
|
||||
self.seeking = true;
|
||||
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
fn select_prev_mtime(&mut self) {
|
||||
|
@ -310,7 +307,7 @@ impl ListView<Files>
|
|||
self.select_file(&file);
|
||||
self.seeking = true;
|
||||
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
fn toggle_hidden(&mut self) {
|
||||
|
@ -318,7 +315,7 @@ impl ListView<Files>
|
|||
self.content.toggle_hidden();
|
||||
self.content.reload_files();
|
||||
self.select_file(&file);
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
fn toggle_dirs_first(&mut self) {
|
||||
|
@ -326,15 +323,16 @@ impl ListView<Files>
|
|||
self.content.dirs_first = !self.content.dirs_first;
|
||||
self.content.sort();
|
||||
self.select_file(&file);
|
||||
self.refresh();
|
||||
self.show_status(&format!("Direcories first: {}", self.content.dirs_first));
|
||||
self.refresh().log();
|
||||
self.show_status(&format!("Direcories first: {}",
|
||||
self.content.dirs_first)).log();
|
||||
}
|
||||
|
||||
fn multi_select_file(&mut self) {
|
||||
let file = self.selected_file_mut();
|
||||
file.toggle_selection();
|
||||
self.move_down();
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
fn find_file(&mut self) -> HResult<()> {
|
||||
|
@ -352,7 +350,7 @@ impl ListView<Files>
|
|||
}
|
||||
|
||||
fn render(&self) -> Vec<String> {
|
||||
let ysize = self.get_coordinates().ysize() as usize;
|
||||
let ysize = self.get_coordinates().unwrap().ysize() as usize;
|
||||
let offset = self.offset;
|
||||
self.content
|
||||
.files
|
||||
|
@ -366,29 +364,26 @@ impl ListView<Files>
|
|||
|
||||
|
||||
impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if self.coordinates == *coordinates {
|
||||
return;
|
||||
}
|
||||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
self.on_refresh();
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.on_refresh().log();
|
||||
self.lines = self.len();
|
||||
if self.selection >= self.lines && self.selection != 0 {
|
||||
self.selection -= 1;
|
||||
}
|
||||
self.buffer = self.render();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
let mut output = term::reset();
|
||||
let (xpos, ypos) = self.coordinates.position().position();
|
||||
let (xpos, ypos) = self.get_coordinates().unwrap().position().position();
|
||||
|
||||
output += &self
|
||||
.buffer
|
||||
|
@ -410,16 +405,15 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
|
|||
})
|
||||
.collect::<String>();
|
||||
|
||||
output += &self.get_redraw_empty_list(self.buffer.len());
|
||||
output += &self.get_redraw_empty_list(self.buffer.len())?;
|
||||
|
||||
output
|
||||
Ok(output)
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
format!("{} files", self.len())
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
Ok(format!("{} files", self.len()))
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
Listable::on_key(self, key);
|
||||
Ok(())
|
||||
Listable::on_key(self, key)
|
||||
}
|
||||
}
|
||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -18,6 +18,8 @@ extern crate rayon;
|
|||
extern crate libc;
|
||||
extern crate notify;
|
||||
|
||||
use failure::Fail;
|
||||
|
||||
use termion::input::MouseTerminal;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::screen::AlternateScreen;
|
||||
|
@ -34,7 +36,6 @@ mod term;
|
|||
mod textview;
|
||||
mod widget;
|
||||
mod win_main;
|
||||
mod window;
|
||||
mod hbox;
|
||||
mod tabview;
|
||||
mod async_widget;
|
||||
|
@ -45,23 +46,41 @@ mod proclist;
|
|||
|
||||
|
||||
|
||||
use window::Window;
|
||||
|
||||
use widget::{Widget, WidgetCore};
|
||||
use term::ScreenExt;
|
||||
use fail::HResult;
|
||||
use file_browser::FileBrowser;
|
||||
use tabview::TabView;
|
||||
|
||||
fn main() {
|
||||
fn main() -> HResult<()> {
|
||||
match run() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
eprintln!("{:?}\n{:?}", err, err.cause());
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> HResult<()> {
|
||||
let 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(bufout));
|
||||
let mut _stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
|
||||
let mut screen = AlternateScreen::from(bufout);
|
||||
let mut _stdout = MouseTerminal::from(stdout().into_raw_mode()?);
|
||||
screen.cursor_hide()?;
|
||||
screen.flush()?;
|
||||
|
||||
let core = WidgetCore::new()?;
|
||||
|
||||
let filebrowser = crate::file_browser::FileBrowser::new().unwrap();
|
||||
let mut tabview = crate::tabview::TabView::new();
|
||||
tabview.push_widget(filebrowser);
|
||||
let filebrowser = FileBrowser::new_cored(&core)?;
|
||||
let mut tabview = TabView::new(&core);
|
||||
tabview.push_widget(filebrowser)?;
|
||||
|
||||
let mut win = Window::new(tabview);
|
||||
win.draw();
|
||||
win.handle_input();
|
||||
tabview.handle_input()?;
|
||||
|
||||
write!(_stdout, "{}", termion::cursor::Show).unwrap();
|
||||
screen.cursor_show()?;
|
||||
screen.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,43 +1,44 @@
|
|||
use termion::event::Key;
|
||||
use failure::Backtrace;
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::preview::Previewer;
|
||||
use crate::widget::Widget;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::hbox::HBox;
|
||||
use crate::fail::{HError, HResult};
|
||||
use crate::fail::{HError, HResult, ErrorLog};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct MillerColumns<T> where T: Widget {
|
||||
pub widgets: HBox<T>,
|
||||
pub core: WidgetCore,
|
||||
// pub left: Option<T>,
|
||||
// pub main: Option<T>,
|
||||
//pub preview: AsyncPreviewer,
|
||||
pub preview: Previewer,
|
||||
pub ratio: (u16, u16, u16),
|
||||
pub coordinates: Coordinates,
|
||||
}
|
||||
|
||||
impl<T> MillerColumns<T>
|
||||
where
|
||||
T: Widget + PartialEq,
|
||||
{
|
||||
pub fn new() -> MillerColumns<T> {
|
||||
pub fn new(core: &WidgetCore) -> MillerColumns<T> {
|
||||
MillerColumns {
|
||||
widgets: HBox::new(),
|
||||
coordinates: Coordinates::new(),
|
||||
widgets: HBox::new(core),
|
||||
core: core.clone(),
|
||||
ratio: (20, 30, 50),
|
||||
preview: Previewer::new()
|
||||
preview: Previewer::new(core)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_widget(&mut self, widget: T) {
|
||||
self.widgets.push_widget(widget);
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
|
||||
pub fn pop_widget(&mut self) -> Option<T> {
|
||||
let widget = self.widgets.pop_widget();
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
widget
|
||||
}
|
||||
|
||||
|
@ -46,14 +47,15 @@ where
|
|||
}
|
||||
|
||||
pub fn calculate_coordinates(&self) -> (Coordinates, Coordinates, Coordinates) {
|
||||
let xsize = self.coordinates.xsize();
|
||||
let ysize = self.coordinates.ysize();
|
||||
let top = self.coordinates.top().y();
|
||||
let coordinates = self.get_coordinates().unwrap();
|
||||
let xsize = coordinates.xsize();
|
||||
let ysize = coordinates.ysize();
|
||||
let top = coordinates.top().y();
|
||||
let ratio = self.ratio;
|
||||
|
||||
let left_xsize = xsize * ratio.0 / 100;
|
||||
let left_size = Size((left_xsize, ysize));
|
||||
let left_pos = self.coordinates.top();
|
||||
let left_pos = coordinates.top();
|
||||
|
||||
let main_xsize = xsize * ratio.1 / 100;
|
||||
let main_size = Size((main_xsize, ysize));
|
||||
|
@ -84,7 +86,7 @@ where
|
|||
pub fn get_left_widget(&self) -> HResult<&T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
if len < 2 {
|
||||
return Err(HError::NoWidgetError);
|
||||
return Err(HError::NoWidgetError(Backtrace::new()));
|
||||
}
|
||||
let widget = self.widgets.widgets.get(len - 2)?;
|
||||
Ok(widget)
|
||||
|
@ -92,7 +94,7 @@ where
|
|||
pub fn get_left_widget_mut(&mut self) -> HResult<&mut T> {
|
||||
let len = self.widgets.widgets.len();
|
||||
if len < 2 {
|
||||
return Err(HError::NoWidgetError);
|
||||
return Err(HError::NoWidgetError(Backtrace::new()));
|
||||
}
|
||||
let widget = self.widgets.widgets.get_mut(len - 2)?;
|
||||
Ok(widget)
|
||||
|
@ -112,51 +114,39 @@ where
|
|||
T: Widget,
|
||||
T: PartialEq
|
||||
{
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if self.coordinates == *coordinates {
|
||||
return;
|
||||
}
|
||||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
let (left_coords, main_coords, preview_coords) = self.calculate_coordinates();
|
||||
|
||||
if let Ok(left_widget) = self.get_left_widget_mut() {
|
||||
left_widget.set_coordinates(&left_coords);
|
||||
left_widget.set_coordinates(&left_coords).log();
|
||||
}
|
||||
|
||||
if let Ok(main_widget) = self.get_main_widget_mut() {
|
||||
main_widget.set_coordinates(&main_coords);
|
||||
main_widget.set_coordinates(&main_coords).log();
|
||||
}
|
||||
|
||||
let preview_widget = &mut self.preview;
|
||||
preview_widget.set_coordinates(&preview_coords);
|
||||
preview_widget.set_coordinates(&preview_coords)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
let left_widget = match self.get_left_widget() {
|
||||
Ok(widget) => widget.get_drawlist(),
|
||||
Err(_) => "".into(),
|
||||
};
|
||||
let main_widget = self.get_main_widget();
|
||||
match main_widget {
|
||||
Ok(main_widget) => {
|
||||
let preview = self.preview.get_drawlist();
|
||||
format!("{}{}{}", main_widget.get_drawlist(), left_widget, preview)
|
||||
}
|
||||
Err(_) => "".to_string()
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
let left_widget = self.get_left_widget()?;
|
||||
let main_widget = self.get_main_widget()?;
|
||||
let preview = self.preview.get_drawlist()?;
|
||||
Ok(format!("{}{}{}",
|
||||
main_widget.get_drawlist()?,
|
||||
left_widget.get_drawlist()?,
|
||||
preview))
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
self.get_main_widget_mut().unwrap().on_key(key);
|
||||
Ok(())
|
||||
self.get_main_widget_mut().unwrap().on_key(key)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@ use termion::event::Key;
|
|||
use std::io::{stdout, Write};
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::widget::Widget;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::term;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MiniBuffer {
|
||||
coordinates: Coordinates,
|
||||
core: WidgetCore,
|
||||
query: String,
|
||||
input: String,
|
||||
position: usize,
|
||||
|
@ -18,12 +19,14 @@ pub struct MiniBuffer {
|
|||
}
|
||||
|
||||
impl MiniBuffer {
|
||||
pub fn new() -> MiniBuffer {
|
||||
pub fn new(core: &WidgetCore) -> MiniBuffer {
|
||||
let xsize = crate::term::xsize();
|
||||
let ysize = crate::term::ysize();
|
||||
let coordinates = Coordinates::new_at(xsize, 1, 1, ysize);
|
||||
let mut core = core.clone();
|
||||
core.coordinates = coordinates;
|
||||
MiniBuffer {
|
||||
coordinates: coordinates,
|
||||
core: core,
|
||||
query: String::new(),
|
||||
input: String::new(),
|
||||
position: 0,
|
||||
|
@ -283,26 +286,23 @@ pub fn find_files(comp_name: String) -> HResult<Vec<String>> {
|
|||
}
|
||||
|
||||
impl Widget for MiniBuffer {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
let (xpos, ypos) = self.get_coordinates().u16position();
|
||||
format!("{}{}{}: {}",
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
||||
Ok(format!("{}{}{}: {}",
|
||||
crate::term::goto_xy(xpos, ypos),
|
||||
termion::clear::CurrentLine,
|
||||
self.query,
|
||||
self.input)
|
||||
self.input))
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
|
|
201
src/preview.rs
201
src/preview.rs
|
@ -1,14 +1,15 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use failure::Backtrace;
|
||||
|
||||
use crate::files::{File, Files, Kind};
|
||||
use crate::listview::ListView;
|
||||
use crate::textview::TextView;
|
||||
use crate::widget::Widget;
|
||||
use crate::fail::HError;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
|
||||
|
||||
|
||||
type HResult<T> = Result<T, HError>;
|
||||
type HClosure<T> = Box<Fn(Arc<Mutex<bool>>) -> Result<T, HError> + Send>;
|
||||
type WidgetO = Box<dyn Widget + Send>;
|
||||
|
||||
|
@ -63,8 +64,8 @@ impl<T: Send + 'static> WillBe<T> where {
|
|||
let got_thing = closure(stale);
|
||||
match got_thing {
|
||||
Ok(got_thing) => {
|
||||
*thing.try_lock().unwrap() = Some(got_thing);
|
||||
*state.try_lock().unwrap() = State::Is;
|
||||
*thing.lock().unwrap() = Some(got_thing);
|
||||
*state.lock().unwrap() = State::Is;
|
||||
match *on_ready_fn.lock().unwrap() {
|
||||
Some(ref on_ready) => { on_ready(thing.clone()).ok(); },
|
||||
None => {}
|
||||
|
@ -76,14 +77,14 @@ impl<T: Send + 'static> WillBe<T> where {
|
|||
}
|
||||
|
||||
pub fn set_stale(&mut self) -> HResult<()> {
|
||||
*self.stale.try_lock()? = true;
|
||||
*self.stale.lock()? = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check(&self) -> HResult<()> {
|
||||
match *self.state.try_lock()? {
|
||||
match *self.state.lock()? {
|
||||
State::Is => Ok(()),
|
||||
_ => Err(HError::WillBeNotReady)
|
||||
_ => Err(HError::WillBeNotReady(Backtrace::new()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,15 +94,16 @@ impl<T: Send + 'static> WillBe<T> where {
|
|||
if self.check().is_ok() {
|
||||
fun(self.thing.clone())?;
|
||||
} else {
|
||||
*self.on_ready.try_lock()? = Some(fun);
|
||||
*self.on_ready.lock()? = Some(fun);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Widget + Send> PartialEq for WillBeWidget<W> {
|
||||
impl<W: Widget + Send + 'static> PartialEq for WillBeWidget<W> {
|
||||
fn eq(&self, other: &WillBeWidget<W>) -> bool {
|
||||
if self.coordinates == other.coordinates {
|
||||
if self.get_coordinates().unwrap() ==
|
||||
other.get_coordinates().unwrap() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -111,19 +113,20 @@ impl<W: Widget + Send> PartialEq for WillBeWidget<W> {
|
|||
|
||||
pub struct WillBeWidget<T: Widget + Send> {
|
||||
willbe: WillBe<T>,
|
||||
coordinates: Coordinates
|
||||
core: WidgetCore
|
||||
}
|
||||
|
||||
impl<T: Widget + Send + 'static> WillBeWidget<T> {
|
||||
pub fn new(closure: HClosure<T>) -> WillBeWidget<T> {
|
||||
pub fn new(core: &WidgetCore, closure: HClosure<T>) -> WillBeWidget<T> {
|
||||
let sender = core.get_sender();
|
||||
let mut willbe = WillBe::new_become(Box::new(move |stale| closure(stale)));
|
||||
willbe.on_ready(Box::new(|_| {
|
||||
crate::window::send_event(crate::window::Events::WidgetReady)?;
|
||||
willbe.on_ready(Box::new(move |_| {
|
||||
sender.send(crate::widget::Events::WidgetReady)?;
|
||||
Ok(()) })).ok();
|
||||
|
||||
WillBeWidget {
|
||||
willbe: willbe,
|
||||
coordinates: Coordinates::new()
|
||||
core: core.clone()
|
||||
}
|
||||
}
|
||||
pub fn set_stale(&mut self) -> HResult<()> {
|
||||
|
@ -147,49 +150,36 @@ impl<T: Widget + Send + 'static> WillBeWidget<T> {
|
|||
//}
|
||||
|
||||
impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.coordinates = coordinates.clone();
|
||||
|
||||
{
|
||||
if self.willbe.check().is_err() { return }
|
||||
let widget = self.widget().unwrap();
|
||||
let mut widget = widget.try_lock().unwrap();
|
||||
let widget = widget.as_mut().unwrap();
|
||||
widget.set_coordinates(&coordinates.clone());
|
||||
}
|
||||
|
||||
self.refresh();
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
let widget = self.widget()?;
|
||||
let mut widget = widget.lock()?;
|
||||
let widget = widget.as_mut()?;
|
||||
widget.set_coordinates(self.get_coordinates()?).log();
|
||||
widget.refresh()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
if self.willbe.check().is_err() { return }
|
||||
let widget = self.widget().unwrap();
|
||||
let mut widget = widget.try_lock().unwrap();
|
||||
let widget = widget.as_mut().unwrap();
|
||||
widget.refresh();
|
||||
}
|
||||
fn get_drawlist(&self) -> String {
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
if self.willbe.check().is_err() {
|
||||
let clear = self.get_clearlist();
|
||||
let (xpos, ypos) = self.get_coordinates().u16position();
|
||||
let clear = self.get_clearlist()?;
|
||||
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
||||
let pos = crate::term::goto_xy(xpos, ypos);
|
||||
return clear + &pos + "..."
|
||||
return Ok(clear + &pos + "...")
|
||||
}
|
||||
let widget = self.widget().unwrap();
|
||||
let widget = widget.try_lock().unwrap();
|
||||
let widget = widget.as_ref().unwrap();
|
||||
let widget = self.widget()?;
|
||||
let widget = widget.lock()?;
|
||||
let widget = widget.as_ref()?;
|
||||
widget.get_drawlist()
|
||||
}
|
||||
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();
|
||||
let widget = self.widget()?;
|
||||
let mut widget = widget.lock()?;
|
||||
let widget = widget.as_mut()?;
|
||||
widget.on_key(key)
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +187,8 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
|
|||
|
||||
impl PartialEq for Previewer {
|
||||
fn eq(&self, other: &Previewer) -> bool {
|
||||
if self.widget.coordinates == other.widget.coordinates {
|
||||
if self.widget.get_coordinates().unwrap() ==
|
||||
other.widget.get_coordinates().unwrap() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -207,59 +198,61 @@ impl PartialEq for Previewer {
|
|||
|
||||
pub struct Previewer {
|
||||
widget: WillBeWidget<Box<dyn Widget + Send>>,
|
||||
core: WidgetCore,
|
||||
file: Option<File>
|
||||
}
|
||||
|
||||
|
||||
impl Previewer {
|
||||
pub fn new() -> Previewer {
|
||||
let willbe = WillBeWidget::new(Box::new(move |_| {
|
||||
Ok(Box::new(crate::textview::TextView::new_blank())
|
||||
pub fn new(core: &WidgetCore) -> Previewer {
|
||||
let core_ = core.clone();
|
||||
let willbe = WillBeWidget::new(&core, Box::new(move |_| {
|
||||
Ok(Box::new(crate::textview::TextView::new_blank(&core_))
|
||||
as Box<dyn Widget + Send>)
|
||||
}));
|
||||
Previewer { widget: willbe,
|
||||
core: core.clone(),
|
||||
file: None}
|
||||
}
|
||||
|
||||
fn become_preview(&mut self,
|
||||
widget: HResult<WillBeWidget<WidgetO>>) {
|
||||
let coordinates = self.get_coordinates().clone();
|
||||
let coordinates = self.get_coordinates().unwrap().clone();
|
||||
self.widget = widget.unwrap();
|
||||
self.set_coordinates(&coordinates);
|
||||
self.widget.set_coordinates(&coordinates).ok();
|
||||
}
|
||||
|
||||
pub fn set_file(&mut self, file: &File) {
|
||||
if Some(file) == self.file.as_ref() { return }
|
||||
self.file = Some(file.clone());
|
||||
|
||||
let coordinates = self.get_coordinates().clone();
|
||||
let coordinates = self.get_coordinates().unwrap().clone();
|
||||
let file = file.clone();
|
||||
let core = self.core.clone();
|
||||
|
||||
self.widget.set_stale().ok();
|
||||
|
||||
self.become_preview(Ok(WillBeWidget::new(Box::new(move |stale| {
|
||||
self.become_preview(Ok(WillBeWidget::new(&self.core, Box::new(move |stale| {
|
||||
kill_proc().unwrap();
|
||||
|
||||
let file = file.clone();
|
||||
|
||||
if file.kind == Kind::Directory {
|
||||
let preview = Previewer::preview_dir(&file, &coordinates, stale.clone());
|
||||
let preview = Previewer::preview_dir(&file, &core, stale.clone());
|
||||
return preview;
|
||||
}
|
||||
|
||||
if file.get_mime() == Some("text".to_string()) {
|
||||
return Previewer::preview_text(&file, &coordinates, stale.clone())
|
||||
return Previewer::preview_text(&file, &core, stale.clone())
|
||||
}
|
||||
|
||||
let preview = Previewer::preview_external(&file,
|
||||
&coordinates,
|
||||
stale.clone());
|
||||
let preview = Previewer::preview_external(&file, &core, stale.clone());
|
||||
if preview.is_ok() { return preview; }
|
||||
else {
|
||||
let mut blank = Box::new(TextView::new_blank());
|
||||
blank.set_coordinates(&coordinates);
|
||||
blank.refresh();
|
||||
blank.animate_slide_up();
|
||||
let mut blank = Box::new(TextView::new_blank(&core));
|
||||
blank.set_coordinates(&coordinates).log();
|
||||
blank.refresh().log();
|
||||
blank.animate_slide_up().log();
|
||||
return Ok(blank)
|
||||
}
|
||||
}))));
|
||||
|
@ -276,40 +269,41 @@ impl Previewer {
|
|||
Err(HError::PreviewFailed { file: file.name.clone() })
|
||||
}
|
||||
|
||||
fn preview_dir(file: &File, coordinates: &Coordinates, stale: Arc<Mutex<bool>>)
|
||||
fn preview_dir(file: &File, core: &WidgetCore, stale: Arc<Mutex<bool>>)
|
||||
-> Result<WidgetO, HError> {
|
||||
let files = Files::new_from_path_cancellable(&file.path,
|
||||
stale.clone())?;
|
||||
let len = files.len();
|
||||
|
||||
|
||||
if len == 0 || is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
|
||||
let mut file_list = ListView::new(files);
|
||||
file_list.set_coordinates(&coordinates);
|
||||
file_list.refresh();
|
||||
let mut file_list = ListView::new(&core, files);
|
||||
file_list.set_coordinates(&core.coordinates)?;
|
||||
file_list.refresh()?;
|
||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
file_list.animate_slide_up();
|
||||
file_list.animate_slide_up()?;
|
||||
Ok(Box::new(file_list) as Box<dyn Widget + Send>)
|
||||
}
|
||||
|
||||
fn preview_text(file: &File, coordinates: &Coordinates, stale: Arc<Mutex<bool>>)
|
||||
fn preview_text(file: &File, core: &WidgetCore, stale: Arc<Mutex<bool>>)
|
||||
-> HResult<WidgetO> {
|
||||
let lines = coordinates.ysize() as usize;
|
||||
let lines = core.coordinates.ysize() as usize;
|
||||
let mut textview
|
||||
= TextView::new_from_file_limit_lines(&file,
|
||||
lines);
|
||||
= TextView::new_from_file_limit_lines(&core,
|
||||
&file,
|
||||
lines)?;
|
||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
|
||||
textview.set_coordinates(&coordinates);
|
||||
textview.refresh();
|
||||
textview.set_coordinates(&core.coordinates)?;
|
||||
textview.refresh()?;
|
||||
|
||||
if is_stale(&stale)? { return Previewer::preview_failed(&file) }
|
||||
|
||||
textview.animate_slide_up();
|
||||
textview.animate_slide_up()?;
|
||||
Ok(Box::new(textview))
|
||||
}
|
||||
|
||||
fn preview_external(file: &File, coordinates: &Coordinates, stale: Arc<Mutex<bool>>)
|
||||
fn preview_external(file: &File, core: &WidgetCore, stale: Arc<Mutex<bool>>)
|
||||
-> Result<Box<dyn Widget + Send>, HError> {
|
||||
let process =
|
||||
std::process::Command::new("scope.sh")
|
||||
|
@ -349,10 +343,10 @@ impl Previewer {
|
|||
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();
|
||||
core: core.clone()};
|
||||
textview.set_coordinates(&core.coordinates).log();
|
||||
textview.refresh().log();
|
||||
textview.animate_slide_up().log();
|
||||
return Ok(Box::new(textview))
|
||||
}
|
||||
Err(HError::PreviewFailed{file: file.name.clone()})
|
||||
|
@ -363,22 +357,16 @@ impl Previewer {
|
|||
|
||||
|
||||
impl Widget for Previewer {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.widget.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if self.widget.coordinates == *coordinates {
|
||||
return;
|
||||
}
|
||||
self.widget.set_coordinates(coordinates);
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.widget.refresh()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
self.widget.refresh();
|
||||
}
|
||||
fn get_drawlist(&self) -> String {
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
self.widget.get_drawlist()
|
||||
}
|
||||
}
|
||||
|
@ -538,23 +526,16 @@ impl Widget for Previewer {
|
|||
|
||||
|
||||
impl<T> Widget for Box<T> where T: Widget + ?Sized {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
(**self).get_coordinates()
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok((**self).get_core()?)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if (**self).get_coordinates() == coordinates {
|
||||
return;
|
||||
}
|
||||
(**self).set_coordinates(&coordinates);
|
||||
(**self).refresh();
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
(**self).render_header()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
(**self).refresh()
|
||||
}
|
||||
fn get_drawlist(&self) -> String {
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
(**self).get_drawlist()
|
||||
}
|
||||
}
|
||||
|
|
135
src/proclist.rs
135
src/proclist.rs
|
@ -1,7 +1,6 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::process::Child;
|
||||
use std::process::Stdio;
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
use termion::event::Key;
|
||||
|
@ -10,10 +9,9 @@ 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::widget::{Widget, Events, WidgetCore};
|
||||
use crate::preview::WillBeWidget;
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::term;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -22,7 +20,9 @@ struct Process {
|
|||
handle: Arc<Mutex<Child>>,
|
||||
output: Arc<Mutex<String>>,
|
||||
status: Arc<Mutex<Option<i32>>>,
|
||||
success: Arc<Mutex<Option<bool>>>
|
||||
success: Arc<Mutex<Option<bool>>>,
|
||||
sender: Sender<Events>
|
||||
|
||||
}
|
||||
|
||||
impl Process {
|
||||
|
@ -31,6 +31,7 @@ impl Process {
|
|||
let output = self.output.clone();
|
||||
let status = self.status.clone();
|
||||
let success = self.success.clone();
|
||||
let sender = self.sender.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let stdout = handle.lock().unwrap().stdout.take().unwrap();
|
||||
|
@ -41,7 +42,7 @@ impl Process {
|
|||
Ok(0) => break,
|
||||
Ok(_) => {
|
||||
output.lock().unwrap().push_str(&line);
|
||||
send_event(Events::WidgetReady).unwrap();
|
||||
sender.send(Events::WidgetReady).unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
dbg!(err);
|
||||
|
@ -63,7 +64,7 @@ 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)
|
||||
self.render_proc(proc).unwrap()
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
@ -75,14 +76,16 @@ impl ListView<Vec<Process>> {
|
|||
.arg(cmd)
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(unsafe { Stdio::from_raw_fd(2) })
|
||||
//.stderr(unsafe { Stdio::from_raw_fd(2) })
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.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))
|
||||
success: Arc::new(Mutex::new(None)),
|
||||
sender: self.get_core()?.get_sender()
|
||||
};
|
||||
proc.read_proc()?;
|
||||
self.content.push(proc);
|
||||
|
@ -107,13 +110,13 @@ impl ListView<Vec<Process>> {
|
|||
self.content.get_mut(selection)
|
||||
}
|
||||
|
||||
pub fn render_proc(&self, proc: &Process) -> String {
|
||||
pub fn render_proc(&self, proc: &Process) -> HResult<String> {
|
||||
let status = match *proc.status.lock().unwrap() {
|
||||
Some(status) => format!("{}", status),
|
||||
None => "<R>".to_string()
|
||||
};
|
||||
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
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();
|
||||
|
@ -124,7 +127,7 @@ impl ListView<Vec<Process>> {
|
|||
_ => { status }
|
||||
};
|
||||
|
||||
format!(
|
||||
Ok(format!(
|
||||
"{}{}{}{}{}{}",
|
||||
termion::cursor::Save,
|
||||
format!("{}{}{:padding$}{}",
|
||||
|
@ -136,24 +139,25 @@ impl ListView<Vec<Process>> {
|
|||
termion::cursor::Restore,
|
||||
termion::cursor::Right(status_pos),
|
||||
term::highlight_color(),
|
||||
color_status
|
||||
)
|
||||
color_status))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcView {
|
||||
coordinates: Coordinates,
|
||||
core: WidgetCore,
|
||||
proc_list: ListView<Vec<Process>>,
|
||||
textview: Option<WillBeWidget<TextView>>,
|
||||
textview: WillBeWidget<TextView>,
|
||||
viewing: Option<usize>
|
||||
}
|
||||
|
||||
impl ProcView {
|
||||
pub fn new() -> ProcView {
|
||||
pub fn new(core: &WidgetCore) -> ProcView {
|
||||
let tcore = core.clone();
|
||||
let textview = Box::new(move |_| Ok(TextView::new_blank(&tcore)));
|
||||
ProcView {
|
||||
coordinates: Coordinates::new(),
|
||||
proc_list: ListView::new(vec![]),
|
||||
textview: None,
|
||||
core: core.clone(),
|
||||
proc_list: ListView::new(&core, vec![]),
|
||||
textview: WillBeWidget::new(&core, textview),
|
||||
viewing: None
|
||||
}
|
||||
}
|
||||
|
@ -166,16 +170,17 @@ impl ProcView {
|
|||
pub fn remove_proc(&mut self) -> HResult<()> {
|
||||
let (_, coords) = self.calculate_coordinates();
|
||||
let coords2 = coords.clone();
|
||||
let mut core = self.core.clone();
|
||||
core.coordinates = coords;
|
||||
|
||||
self.proc_list.remove_proc()?;
|
||||
self.textview = Some(WillBeWidget::new(Box::new(move |_| {
|
||||
let mut textview = TextView::new_blank();
|
||||
textview.set_coordinates(&coords);
|
||||
textview.refresh();
|
||||
textview.animate_slide_up();
|
||||
self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| {
|
||||
let mut textview = TextView::new_blank(&core);
|
||||
textview.refresh().log();
|
||||
textview.animate_slide_up().log();
|
||||
Ok(textview)
|
||||
})));
|
||||
self.textview.as_mut().unwrap().set_coordinates(&coords2);
|
||||
}));
|
||||
self.textview.set_coordinates(&coords2).log();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -185,29 +190,29 @@ impl ProcView {
|
|||
}
|
||||
let output = self.proc_list.selected_proc()?.output.lock()?.clone();
|
||||
let (_, coords) = self.calculate_coordinates();
|
||||
let coords2 = coords.clone();
|
||||
let mut core = self.core.clone();
|
||||
core.coordinates = coords;
|
||||
|
||||
self.textview = Some(WillBeWidget::new(Box::new(move |_| {
|
||||
let mut textview = TextView::new_blank();
|
||||
textview.set_coordinates(&coords);
|
||||
textview.set_text(&output);
|
||||
textview.animate_slide_up();
|
||||
self.textview = WillBeWidget::new(&core.clone(), Box::new(move |_| {
|
||||
let mut textview = TextView::new_blank(&core);
|
||||
textview.set_text(&output).log();
|
||||
textview.animate_slide_up().log();
|
||||
Ok(textview)
|
||||
})));
|
||||
self.textview.as_mut().unwrap().set_coordinates(&coords2);
|
||||
}));
|
||||
self.viewing = Some(self.proc_list.get_selection());
|
||||
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 coordinates = self.get_coordinates().unwrap();
|
||||
let xsize = coordinates.xsize();
|
||||
let ysize = coordinates.ysize();
|
||||
let top = 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 left_pos = coordinates.top();
|
||||
|
||||
let main_xsize = xsize * ratio.1 / 100;
|
||||
let main_size = Size((main_xsize, ysize));
|
||||
|
@ -224,7 +229,6 @@ impl ProcView {
|
|||
size: main_size,
|
||||
position: main_pos,
|
||||
};
|
||||
|
||||
(left_coords, main_coords)
|
||||
}
|
||||
|
||||
|
@ -232,36 +236,25 @@ impl ProcView {
|
|||
}
|
||||
|
||||
impl Widget for ProcView {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.coordinates = coordinates.clone();
|
||||
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
let (lcoord, rcoord) = self.calculate_coordinates();
|
||||
self.proc_list.set_coordinates(&lcoord);
|
||||
if let Some(textview) = &mut self.textview {
|
||||
textview.set_coordinates(&rcoord);
|
||||
}
|
||||
self.proc_list.set_coordinates(&lcoord).log();
|
||||
self.textview.set_coordinates(&rcoord).log();
|
||||
|
||||
self.refresh();
|
||||
self.show_output().log();
|
||||
self.proc_list.refresh().log();
|
||||
self.textview.refresh().log();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
self.show_output();
|
||||
self.proc_list.refresh();
|
||||
if let Some(textview) = &mut self.textview {
|
||||
textview.refresh();
|
||||
}
|
||||
}
|
||||
fn get_drawlist(&self) -> String {
|
||||
if let Some(textview) = &self.textview {
|
||||
self.proc_list.get_drawlist() + &textview.get_drawlist()
|
||||
} else {
|
||||
self.proc_list.get_drawlist()
|
||||
}
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
Ok(self.proc_list.get_drawlist()? + &self.textview.get_drawlist()?)
|
||||
}
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
|
@ -270,18 +263,14 @@ impl Widget for ProcView {
|
|||
Key::Char('k') => { self.proc_list.kill_proc()? }
|
||||
Key::Up | Key::Char('p') => {
|
||||
self.proc_list.move_up();
|
||||
self.proc_list.refresh();
|
||||
self.show_output().ok();
|
||||
}
|
||||
Key::Down | Key::Char('n') => {
|
||||
self.proc_list.move_down();
|
||||
self.proc_list.refresh();
|
||||
self.show_output().ok();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.refresh();
|
||||
self.draw()?;
|
||||
self.refresh().log();
|
||||
self.draw().log();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
use termion::event::Key;
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::widget::Widget;
|
||||
use crate::fail::HResult;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::fail::{HResult, ErrorLog};
|
||||
|
||||
pub trait Tabbable {
|
||||
fn new_tab(&mut self);
|
||||
fn close_tab(&mut self);
|
||||
fn next_tab(&mut self);
|
||||
fn on_next_tab(&mut self);
|
||||
fn new_tab(&mut self) -> HResult<()>;
|
||||
fn close_tab(&mut self) -> HResult<()>;
|
||||
fn next_tab(&mut self) -> HResult<()>;
|
||||
fn on_next_tab(&mut self) -> HResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn get_tab_names(&self) -> Vec<Option<String>>;
|
||||
fn active_tab(&self) -> &dyn Widget;
|
||||
fn active_tab_mut(&mut self) -> &mut dyn Widget;
|
||||
fn on_key_sub(&mut self, key: Key);
|
||||
fn on_key(&mut self, key: Key) {
|
||||
fn on_key_sub(&mut self, key: Key) -> HResult<()>;
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
Key::Ctrl('t') => { self.new_tab(); },
|
||||
Key::Ctrl('t') => self.new_tab(),
|
||||
Key::Ctrl('w') => self.close_tab(),
|
||||
Key::Char('\t') => self.next_tab(),
|
||||
_ => self.on_key_sub(key)
|
||||
|
@ -28,27 +29,27 @@ pub trait Tabbable {
|
|||
pub struct TabView<T> where T: Widget, TabView<T>: Tabbable {
|
||||
pub widgets: Vec<T>,
|
||||
pub active: usize,
|
||||
coordinates: Coordinates
|
||||
core: WidgetCore
|
||||
}
|
||||
|
||||
impl<T> TabView<T> where T: Widget, TabView<T>: Tabbable {
|
||||
pub fn new() -> TabView<T> {
|
||||
pub fn new(core: &WidgetCore) -> TabView<T> {
|
||||
TabView {
|
||||
widgets: vec![],
|
||||
active: 0,
|
||||
coordinates: Coordinates::new()
|
||||
core: core.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_widget(&mut self, widget: T) {
|
||||
pub fn push_widget(&mut self, widget: T) -> HResult<()> {
|
||||
self.widgets.push(widget);
|
||||
self.refresh();
|
||||
self.refresh()
|
||||
}
|
||||
|
||||
pub fn pop_widget(&mut self) -> Option<T> {
|
||||
let widget = self.widgets.pop();
|
||||
self.refresh();
|
||||
widget
|
||||
pub fn pop_widget(&mut self) -> HResult<T> {
|
||||
let widget = self.widgets.pop()?;
|
||||
self.refresh()?;
|
||||
Ok(widget)
|
||||
}
|
||||
|
||||
pub fn active_tab_(&self) -> &T {
|
||||
|
@ -59,11 +60,10 @@ impl<T> TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
&mut self.widgets[self.active]
|
||||
}
|
||||
|
||||
pub fn close_tab_(&mut self) {
|
||||
if self.active == 0 { return }
|
||||
if self.active + 1 >= self.widgets.len() { self.active -= 1 }
|
||||
|
||||
self.pop_widget();
|
||||
pub fn close_tab_(&mut self) -> HResult<()> {
|
||||
self.pop_widget()?;
|
||||
self.active -= 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn next_tab_(&mut self) {
|
||||
|
@ -72,14 +72,17 @@ impl<T> TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
} else {
|
||||
self.active += 1
|
||||
}
|
||||
self.on_next_tab();
|
||||
self.on_next_tab().log();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
|
||||
fn render_header(&self) -> String {
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
let header = self.active_tab_().render_header();
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
let xsize = self.get_coordinates()?.xsize();
|
||||
let header = self.active_tab_().render_header()?;
|
||||
let tab_names = self.get_tab_names();
|
||||
let mut nums_length = 0;
|
||||
let tabnums = (0..self.widgets.len()).map(|num| {
|
||||
|
@ -100,38 +103,28 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
|
|||
|
||||
let nums_pos = xsize - nums_length as u16;
|
||||
|
||||
format!("{}{}{}{}",
|
||||
Ok(format!("{}{}{}{}",
|
||||
header,
|
||||
crate::term::header_color(),
|
||||
crate::term::goto_xy(nums_pos, 1),
|
||||
tabnums)
|
||||
tabnums))
|
||||
}
|
||||
|
||||
fn render_footer(&self) -> String {
|
||||
fn render_footer(&self) -> HResult<String>
|
||||
{
|
||||
self.active_tab_().render_footer()
|
||||
}
|
||||
|
||||
fn refresh(&mut self) {
|
||||
self.active_tab_mut().refresh();
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
self.active_tab_mut().refresh()
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
self.active_tab_().get_drawlist()
|
||||
}
|
||||
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
if self.coordinates == *coordinates {
|
||||
return;
|
||||
}
|
||||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
}
|
||||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
Tabbable::on_key(self, key);
|
||||
Ok(())
|
||||
Tabbable::on_key(self, key)?;
|
||||
self.refresh()
|
||||
}
|
||||
}
|
||||
|
|
30
src/term.rs
30
src/term.rs
|
@ -1,20 +1,36 @@
|
|||
use std::io::{Stdout, Write};
|
||||
use std::io::{Stdout, Write, BufWriter};
|
||||
|
||||
use termion;
|
||||
use termion::screen::AlternateScreen;
|
||||
|
||||
use crate::fail::HResult;
|
||||
|
||||
pub trait ScreenExt: Write {
|
||||
fn cursor_hide(&mut self) {
|
||||
write!(self, "{}", termion::cursor::Hide).unwrap();
|
||||
fn cursor_hide(&mut self) -> HResult<()> {
|
||||
write!(self, "{}", termion::cursor::Hide)?;
|
||||
self.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
fn cursor_show(&mut self) {
|
||||
write!(self, "{}", termion::cursor::Show).unwrap();
|
||||
fn cursor_show(&mut self) -> HResult<()> {
|
||||
write!(self, "{}", termion::cursor::Show)?;
|
||||
self.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
fn reset(&mut self) {
|
||||
write!(self, "{}", termion::style::Reset).unwrap();
|
||||
fn reset(&mut self) -> HResult<()> {
|
||||
write!(self, "{}", termion::style::Reset)?;
|
||||
self.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
fn write_str(&mut self, str: &str) -> HResult<()> {
|
||||
write!(self, "{}", str)?;
|
||||
self.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ScreenExt for AlternateScreen<Box<Stdout>> {}
|
||||
impl ScreenExt for AlternateScreen<Stdout> {}
|
||||
impl ScreenExt for AlternateScreen<BufWriter<Stdout>> {}
|
||||
|
||||
pub fn xsize() -> u16 {
|
||||
let (xsize, _) = termion::terminal_size().unwrap();
|
||||
|
|
|
@ -1,77 +1,79 @@
|
|||
use std::io::BufRead;
|
||||
|
||||
use crate::coordinates::{Coordinates};
|
||||
use crate::files::File;
|
||||
use crate::term::sized_string;
|
||||
use crate::widget::Widget;
|
||||
use crate::widget::{Widget, WidgetCore};
|
||||
use crate::fail::HResult;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct TextView {
|
||||
pub lines: Vec<String>,
|
||||
pub buffer: String,
|
||||
pub coordinates: Coordinates,
|
||||
pub core: WidgetCore
|
||||
}
|
||||
|
||||
impl TextView {
|
||||
pub fn new_blank() -> TextView {
|
||||
pub fn new_blank(core: &WidgetCore) -> TextView {
|
||||
TextView {
|
||||
lines: vec![],
|
||||
buffer: String::new(),
|
||||
coordinates: Coordinates::new()
|
||||
core: core.clone()
|
||||
}
|
||||
}
|
||||
pub fn new_from_file(file: &File) -> TextView {
|
||||
let file = std::fs::File::open(&file.path).unwrap();
|
||||
pub fn new_from_file(core: &WidgetCore, file: &File) -> HResult<TextView> {
|
||||
let file = std::fs::File::open(&file.path)?;
|
||||
let file = std::io::BufReader::new(file);
|
||||
let lines = file.lines().map(|line|
|
||||
line.unwrap()
|
||||
.replace("\t", " ")).collect();
|
||||
Ok(line?
|
||||
.replace("\t", " ")))
|
||||
.filter_map(|l: HResult<String>| l.ok())
|
||||
.collect();
|
||||
|
||||
TextView {
|
||||
Ok(TextView {
|
||||
lines: lines,
|
||||
buffer: String::new(),
|
||||
coordinates: Coordinates::new(),
|
||||
}
|
||||
core: core.clone()
|
||||
})
|
||||
}
|
||||
pub fn new_from_file_limit_lines(file: &File, num: usize) -> TextView {
|
||||
pub fn new_from_file_limit_lines(core: &WidgetCore,
|
||||
file: &File,
|
||||
num: usize) -> HResult<TextView> {
|
||||
let file = std::fs::File::open(&file.path).unwrap();
|
||||
let file = std::io::BufReader::new(file);
|
||||
let lines = file.lines()
|
||||
.take(num)
|
||||
.map(|line|
|
||||
line.unwrap()
|
||||
.replace("\t", " ")).collect();
|
||||
Ok(line?
|
||||
.replace("\t", " ")))
|
||||
.filter_map(|l: HResult<String>| l.ok())
|
||||
.collect();
|
||||
|
||||
TextView {
|
||||
Ok(TextView {
|
||||
lines: lines,
|
||||
buffer: String::new(),
|
||||
coordinates: Coordinates::new(),
|
||||
}
|
||||
core: core.clone()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, text: &str) {
|
||||
pub fn set_text(&mut self, text: &str) -> HResult<()> {
|
||||
let lines = text.lines().map(|l| l.to_string()).collect();
|
||||
self.lines = lines;
|
||||
self.refresh();
|
||||
self.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for TextView {
|
||||
fn get_coordinates(&self) -> &Coordinates {
|
||||
&self.coordinates
|
||||
fn get_core(&self) -> HResult<&WidgetCore> {
|
||||
Ok(&self.core)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) {
|
||||
self.coordinates = coordinates.clone();
|
||||
self.refresh();
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Ok(&mut self.core)
|
||||
}
|
||||
fn render_header(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
fn refresh(&mut self) {
|
||||
let (xsize, ysize) = self.get_coordinates().size().size();
|
||||
let (xpos, ypos) = self.get_coordinates().position().position();
|
||||
fn refresh(&mut self) -> HResult<()> {
|
||||
let (xsize, ysize) = self.get_coordinates()?.size().size();
|
||||
let (xpos, ypos) = self.get_coordinates()?.position().position();
|
||||
|
||||
self.buffer = self.get_clearlist() +
|
||||
self.buffer = self.get_clearlist()? +
|
||||
&self
|
||||
.lines
|
||||
.iter()
|
||||
|
@ -85,9 +87,10 @@ impl Widget for TextView {
|
|||
sized_string(&line, xsize))
|
||||
})
|
||||
.collect::<String>();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_drawlist(&self) -> String {
|
||||
self.buffer.clone()
|
||||
fn get_drawlist(&self) -> HResult<String> {
|
||||
Ok(self.buffer.clone())
|
||||
}
|
||||
}
|
||||
|
|
325
src/widget.rs
325
src/widget.rs
|
@ -1,28 +1,115 @@
|
|||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
|
||||
use termion::event::{Event, Key, MouseEvent};
|
||||
use termion::input::TermRead;
|
||||
use termion::screen::AlternateScreen;
|
||||
use failure::Backtrace;
|
||||
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::fail::{HResult, HError};
|
||||
use crate::window::{send_event, Events};
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::minibuffer::MiniBuffer;
|
||||
use crate::term;
|
||||
use crate::term::ScreenExt;
|
||||
|
||||
use std::io::{BufWriter, Write, stdin};
|
||||
use std::io::{BufWriter, stdin, stdout, Stdout};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Events {
|
||||
InputEvent(Event),
|
||||
WidgetReady,
|
||||
ExclusiveEvent(Option<Sender<Events>>),
|
||||
}
|
||||
|
||||
impl PartialEq for WidgetCore {
|
||||
fn eq(&self, other: &WidgetCore) -> bool {
|
||||
if self.coordinates == other.coordinates {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for WidgetCore {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
let output = format!("{:?}{:?}{:?}",
|
||||
self.coordinates,
|
||||
self.minibuffer,
|
||||
self.status_bar_content);
|
||||
formatter.write_str(&output)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WidgetCore {
|
||||
pub screen: Arc<Mutex<AlternateScreen<BufWriter<Stdout>>>>,
|
||||
pub coordinates: Coordinates,
|
||||
pub minibuffer: Arc<Mutex<Option<MiniBuffer>>>,
|
||||
pub event_sender: Sender<Events>,
|
||||
event_receiver: Arc<Mutex<Option<Receiver<Events>>>>,
|
||||
pub status_bar_content: Arc<Mutex<Option<String>>>
|
||||
}
|
||||
|
||||
impl WidgetCore {
|
||||
pub fn new() -> HResult<WidgetCore> {
|
||||
let screen = AlternateScreen::from(BufWriter::new(stdout()));
|
||||
let coords = Coordinates::new_at(term::xsize(),
|
||||
term::ysize() - 2,
|
||||
1,
|
||||
2);
|
||||
let (sender, receiver) = channel();
|
||||
let status_bar_content = Arc::new(Mutex::new(None));
|
||||
|
||||
let core = WidgetCore {
|
||||
screen: Arc::new(Mutex::new(screen)),
|
||||
coordinates: coords,
|
||||
minibuffer: Arc::new(Mutex::new(None)),
|
||||
event_sender: sender,
|
||||
event_receiver: Arc::new(Mutex::new(Some(receiver))),
|
||||
status_bar_content: status_bar_content };
|
||||
|
||||
let minibuffer = MiniBuffer::new(&core);
|
||||
*core.minibuffer.lock().unwrap() = Some(minibuffer);
|
||||
Ok(core)
|
||||
}
|
||||
|
||||
pub fn get_sender(&self) -> Sender<Events> {
|
||||
self.event_sender.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Widget {
|
||||
fn get_widget(&self) -> Box<dyn Widget> {
|
||||
Box::new(crate::textview::TextView::new_blank())
|
||||
Box::new(crate::textview::TextView::new_blank(self.get_core().unwrap()))
|
||||
}
|
||||
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 get_core(&self) -> HResult<&WidgetCore> {
|
||||
Err(HError::NoWidgetCoreError(Backtrace::new()))
|
||||
}
|
||||
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
|
||||
Err(HError::NoWidgetCoreError(Backtrace::new()))
|
||||
}
|
||||
fn get_coordinates(&self) -> HResult<&Coordinates> {
|
||||
Ok(&self.get_core()?.coordinates)
|
||||
}
|
||||
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
|
||||
self.get_core_mut()?.coordinates = coordinates.clone();
|
||||
self.refresh()?;
|
||||
Ok(())
|
||||
}
|
||||
fn render_header(&self) -> HResult<String> {
|
||||
Err(HError::NoHeaderError)
|
||||
}
|
||||
fn render_footer(&self) -> HResult<String> {
|
||||
Err(HError::NoHeaderError)
|
||||
}
|
||||
fn refresh(&mut self) -> HResult<()>;
|
||||
fn get_drawlist(&self) -> HResult<String>;
|
||||
fn after_draw(&self) -> HResult<()> { Ok(()) }
|
||||
|
||||
|
||||
|
||||
fn on_event(&mut self, event: Event) -> HResult<()> {
|
||||
match event {
|
||||
Event::Key(Key::Char('q')) => panic!("It's your fault!"),
|
||||
|
@ -34,67 +121,59 @@ pub trait Widget {
|
|||
|
||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||
match key {
|
||||
_ => self.bad(Event::Key(key)),
|
||||
_ => { self.bad(Event::Key(key)).unwrap() },
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_mouse(&mut self, event: MouseEvent) -> HResult<()> {
|
||||
match event {
|
||||
_ => self.bad(Event::Mouse(event)),
|
||||
_ => { self.bad(Event::Mouse(event)).unwrap() },
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_wtf(&mut self, event: Vec<u8>) -> HResult<()> {
|
||||
match event {
|
||||
_ => self.bad(Event::Unsupported(event)),
|
||||
_ => { self.bad(Event::Unsupported(event)).unwrap() },
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_status(&self, status: &str) {
|
||||
crate::window::show_status(status);
|
||||
fn bad(&mut self, event: Event) -> HResult<()> {
|
||||
self.show_status(&format!("Stop the nasty stuff!! {:?} does nothing!", event))
|
||||
}
|
||||
|
||||
fn minibuffer(&self, query: &str) -> HResult<String> {
|
||||
crate::window::minibuffer(query)
|
||||
}
|
||||
|
||||
fn bad(&mut self, event: Event) {
|
||||
self.show_status(&format!("Stop the nasty stuff!! {:?} does nothing!", event));
|
||||
}
|
||||
|
||||
fn get_header_drawlist(&mut self) -> String {
|
||||
format!(
|
||||
fn get_header_drawlist(&mut self) -> HResult<String> {
|
||||
Ok(format!(
|
||||
"{}{}{:xsize$}{}{}",
|
||||
crate::term::goto_xy(1, 1),
|
||||
crate::term::header_color(),
|
||||
" ",
|
||||
crate::term::goto_xy(1, 1),
|
||||
self.render_header(),
|
||||
xsize = self.get_coordinates().xsize() as usize
|
||||
)
|
||||
self.render_header()?,
|
||||
xsize = self.get_coordinates()?.xsize() as usize
|
||||
))
|
||||
}
|
||||
|
||||
fn get_footer_drawlist(&mut self) -> String {
|
||||
let xsize = self.get_coordinates().xsize();
|
||||
fn get_footer_drawlist(&mut self) -> HResult<String> {
|
||||
let xsize = self.get_coordinates()?.xsize();
|
||||
let ypos = crate::term::ysize();
|
||||
format!(
|
||||
Ok(format!(
|
||||
"{}{}{:xsize$}{}{}",
|
||||
crate::term::goto_xy(1, ypos),
|
||||
crate::term::header_color(),
|
||||
" ",
|
||||
crate::term::goto_xy(1, ypos),
|
||||
self.render_footer(),
|
||||
xsize = xsize as usize)
|
||||
self.render_footer()?,
|
||||
xsize = xsize as usize))
|
||||
}
|
||||
|
||||
fn get_clearlist(&self) -> String {
|
||||
let (xpos, ypos) = self.get_coordinates().u16position();
|
||||
let (xsize, ysize) = self.get_coordinates().u16size();
|
||||
fn get_clearlist(&self) -> HResult<String> {
|
||||
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
||||
let (xsize, ysize) = self.get_coordinates()?.u16size();
|
||||
|
||||
(ypos..ysize + 2)
|
||||
Ok((ypos..ysize + 2)
|
||||
.map(|line| {
|
||||
format!(
|
||||
"{}{}{:xsize$}",
|
||||
|
@ -104,15 +183,15 @@ pub trait Widget {
|
|||
xsize = xsize as usize
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn get_redraw_empty_list(&self, lines: usize) -> String {
|
||||
let (xpos, ypos) = self.get_coordinates().u16position();
|
||||
let (xsize, ysize) = self.get_coordinates().u16size();
|
||||
fn get_redraw_empty_list(&self, lines: usize) -> HResult<String> {
|
||||
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)
|
||||
Ok((start_y..(ysize + 2) as usize)
|
||||
.map(|i| {
|
||||
format!(
|
||||
"{}{:xsize$}",
|
||||
|
@ -121,30 +200,21 @@ pub trait Widget {
|
|||
xsize = xsize as usize
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn draw(&self) -> HResult<()> {
|
||||
let drawlist = self.get_drawlist();
|
||||
let mut bufout = BufWriter::new(std::io::stdout());
|
||||
|
||||
write!(bufout, "{}", drawlist)?;
|
||||
bufout.flush()?;
|
||||
Ok(())
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn popup(&mut self) -> HResult<()> {
|
||||
self.run_widget();
|
||||
send_event(Events::ExclusiveEvent(None))?;
|
||||
self.run_widget().log();
|
||||
self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_widget(&mut self) -> HResult<()> {
|
||||
let (tx_event, rx_event) = channel();
|
||||
send_event(Events::ExclusiveEvent(Some(tx_event)))?;
|
||||
self.get_core()?.get_sender().send(Events::ExclusiveEvent(Some(tx_event)))?;
|
||||
|
||||
self.clear()?;
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
self.draw()?;
|
||||
|
||||
for event in rx_event.iter() {
|
||||
|
@ -155,32 +225,31 @@ pub trait Widget {
|
|||
}
|
||||
}
|
||||
Events::WidgetReady => {
|
||||
self.refresh();
|
||||
self.refresh().log();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.draw();
|
||||
self.after_draw();
|
||||
self.draw().log();
|
||||
self.after_draw().log();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear(&self) -> HResult<()> {
|
||||
let clearlist = self.get_clearlist();
|
||||
write!(std::io::stdout(), "{}", clearlist)?;
|
||||
std::io::stdout().flush()?;
|
||||
Ok(())
|
||||
let clearlist = self.get_clearlist()?;
|
||||
self.write_to_screen(&clearlist)
|
||||
}
|
||||
|
||||
fn animate_slide_up(&mut self) {
|
||||
let coords = self.get_coordinates().clone();
|
||||
fn animate_slide_up(&mut self) -> HResult<()> {
|
||||
let coords = self.get_coordinates()?.clone();
|
||||
let xpos = coords.position().x();
|
||||
let ypos = coords.position().y();
|
||||
let xsize = coords.xsize();
|
||||
let ysize = coords.ysize();
|
||||
let clear = self.get_clearlist();
|
||||
let clear = self.get_clearlist()?;
|
||||
let pause = std::time::Duration::from_millis(5);
|
||||
let mut bufout = BufWriter::new(std::io::stdout());
|
||||
|
||||
self.write_to_screen(&clear).log();
|
||||
|
||||
for i in (0..10).rev() {
|
||||
let coords = Coordinates { size: Size((xsize,ysize-i)),
|
||||
|
@ -188,13 +257,123 @@ pub trait Widget {
|
|||
((xpos,
|
||||
ypos+i))
|
||||
};
|
||||
self.set_coordinates(&coords);
|
||||
let buffer = self.get_drawlist();
|
||||
write!(bufout, "{}{}",
|
||||
clear, buffer).unwrap();
|
||||
bufout.flush().ok();
|
||||
self.set_coordinates(&coords).log();
|
||||
let buffer = self.get_drawlist()?;
|
||||
self.write_to_screen(&buffer).log();
|
||||
|
||||
std::thread::sleep(pause);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw(&mut self) -> HResult<()> {
|
||||
let output =
|
||||
self.get_drawlist().unwrap_or("".to_string()) +
|
||||
&self.get_header_drawlist().unwrap_or("".to_string()) +
|
||||
&self.get_footer_drawlist().unwrap_or("".to_string());
|
||||
self.write_to_screen(&output).log();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_input(&mut self) -> HResult<()> {
|
||||
let (tx_event, rx_event) = channel();
|
||||
let (tx_internal_event, rx_internal_event) = channel();
|
||||
let rx_global_event = self.get_core()?.event_receiver.lock()?.take()?;
|
||||
|
||||
input_thread(tx_event.clone());
|
||||
global_event_thread(rx_global_event, tx_event.clone());
|
||||
dispatch_events(rx_event, tx_internal_event);
|
||||
|
||||
for event in rx_internal_event.iter() {
|
||||
match event {
|
||||
Events::InputEvent(event) => {
|
||||
self.on_event(event).ok();
|
||||
self.draw().ok();
|
||||
},
|
||||
_ => {
|
||||
self.refresh().ok();
|
||||
self.draw().ok();
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_status(&self) -> HResult<()> {
|
||||
let xsize = term::xsize() as u16;
|
||||
let status = &self.get_core()?.status_bar_content;
|
||||
|
||||
let status = status.lock()?;
|
||||
|
||||
self.write_to_screen(
|
||||
&format!(
|
||||
"{}{}{:xsize$}{}{}",
|
||||
term::move_bottom(),
|
||||
term::status_bg(),
|
||||
" ",
|
||||
term::move_bottom(),
|
||||
status.as_ref()?,
|
||||
xsize = xsize as usize
|
||||
)).log();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_status(&self, status: &str) -> HResult<()> {
|
||||
{
|
||||
let mut status_content = self.get_core()?.status_bar_content.lock()?;
|
||||
*status_content = Some(status.to_string());
|
||||
}
|
||||
self.draw_status()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn minibuffer(&self, query: &str) -> HResult<String> {
|
||||
let answer = self.get_core()?.minibuffer.lock()?.as_mut()?.query(query);
|
||||
let mut screen = self.get_core()?.screen.lock()?;
|
||||
screen.cursor_hide().log();
|
||||
answer
|
||||
}
|
||||
|
||||
fn write_to_screen(&self, s: &str) -> HResult<()> {
|
||||
let mut screen = self.get_core()?.screen.lock()?;
|
||||
screen.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
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>) {
|
||||
std::thread::spawn(move || {
|
||||
for input in stdin().events() {
|
||||
let input = input.unwrap();
|
||||
tx.send(Events::InputEvent(input)).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
374
src/window.rs
374
src/window.rs
|
@ -1,214 +1,214 @@
|
|||
use std::io::{stdin, stdout, Stdout, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
// use std::io::{stdin, stdout, Stdout, Write};
|
||||
// use std::sync::{Arc, Mutex};
|
||||
// use std::sync::mpsc::{Sender, Receiver, channel};
|
||||
|
||||
use termion::event::Event;
|
||||
use termion::input::TermRead;
|
||||
use termion::screen::AlternateScreen;
|
||||
// use termion::event::Event;
|
||||
// use termion::input::TermRead;
|
||||
// use termion::screen::AlternateScreen;
|
||||
|
||||
use crate::term;
|
||||
use crate::term::ScreenExt;
|
||||
// use crate::term;
|
||||
// use crate::term::ScreenExt;
|
||||
|
||||
use crate::coordinates::{Coordinates, Position, Size};
|
||||
use crate::widget::Widget;
|
||||
use crate::minibuffer::MiniBuffer;
|
||||
use crate::fail::HResult;
|
||||
// use crate::coordinates::{Coordinates, Position, Size};
|
||||
// use crate::widget::Widget;
|
||||
// use crate::minibuffer::MiniBuffer;
|
||||
// use crate::fail::HResult;
|
||||
|
||||
lazy_static! {
|
||||
static ref TX_EVENT: Arc<Mutex<Option<Sender<Events>>>> = { Arc::new(Mutex::new(None)) };
|
||||
static ref MINIBUFFER: Arc<Mutex<MiniBuffer>>
|
||||
= Arc::new(Mutex::new(MiniBuffer::new()));
|
||||
}
|
||||
// lazy_static! {
|
||||
// static ref TX_EVENT: Arc<Mutex<Option<Sender<Events>>>> = { Arc::new(Mutex::new(None)) };
|
||||
// static ref MINIBUFFER: Arc<Mutex<MiniBuffer>>
|
||||
// = Arc::new(Mutex::new(MiniBuffer::new()));
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Events {
|
||||
InputEvent(Event),
|
||||
WidgetReady,
|
||||
ExclusiveEvent(Option<Sender<Events>>),
|
||||
}
|
||||
// #[derive(Debug)]
|
||||
// pub enum Events {
|
||||
// InputEvent(Event),
|
||||
// WidgetReady,
|
||||
// ExclusiveEvent(Option<Sender<Events>>),
|
||||
// }
|
||||
|
||||
pub struct Window<T>
|
||||
where
|
||||
T: Widget,
|
||||
{
|
||||
pub selection: usize,
|
||||
pub widget: T,
|
||||
pub status: Arc<Mutex<Option<String>>>,
|
||||
pub screen: AlternateScreen<Box<Stdout>>,
|
||||
pub coordinates: Coordinates,
|
||||
}
|
||||
// pub struct Window<T>
|
||||
// where
|
||||
// T: Widget,
|
||||
// {
|
||||
// pub selection: usize,
|
||||
// pub widget: T,
|
||||
// pub status: Arc<Mutex<Option<String>>>,
|
||||
// pub screen: AlternateScreen<Box<Stdout>>,
|
||||
// pub coordinates: Coordinates,
|
||||
// }
|
||||
|
||||
impl<T> Window<T>
|
||||
where
|
||||
T: Widget,
|
||||
{
|
||||
pub fn new(widget: T) -> Window<T> {
|
||||
let mut screen = AlternateScreen::from(Box::new(stdout()));
|
||||
screen.cursor_hide();
|
||||
let (xsize, ysize) = termion::terminal_size().unwrap();
|
||||
let mut win = Window::<T> {
|
||||
selection: 0,
|
||||
widget: widget,
|
||||
status: STATUS_BAR_CONTENT.clone(),
|
||||
screen: screen,
|
||||
coordinates: Coordinates {
|
||||
size: Size((xsize, ysize)),
|
||||
position: Position((1, 1)),
|
||||
},
|
||||
};
|
||||
// impl<T> Window<T>
|
||||
// where
|
||||
// T: Widget,
|
||||
// {
|
||||
// pub fn new(widget: T) -> Window<T> {
|
||||
// let mut screen = AlternateScreen::from(Box::new(stdout()));
|
||||
// screen.cursor_hide();
|
||||
// let (xsize, ysize) = termion::terminal_size().unwrap();
|
||||
// let mut win = Window::<T> {
|
||||
// selection: 0,
|
||||
// widget: widget,
|
||||
// status: STATUS_BAR_CONTENT.clone(),
|
||||
// screen: screen,
|
||||
// coordinates: Coordinates {
|
||||
// size: Size((xsize, ysize)),
|
||||
// position: Position((1, 1)),
|
||||
// },
|
||||
// };
|
||||
|
||||
win.widget.set_coordinates(&Coordinates {
|
||||
size: Size((xsize, ysize - 2)),
|
||||
position: Position((1, 2)),
|
||||
});
|
||||
win.widget.refresh();
|
||||
win
|
||||
}
|
||||
// win.widget.set_coordinates(&Coordinates {
|
||||
// size: Size((xsize, ysize - 2)),
|
||||
// position: Position((1, 2)),
|
||||
// });
|
||||
// win.widget.refresh();
|
||||
// win
|
||||
// }
|
||||
|
||||
pub fn draw(&mut self) {
|
||||
let output = self.widget.get_drawlist() + &self.widget.get_header_drawlist()
|
||||
+ &self.widget.get_footer_drawlist();
|
||||
self.screen.write(output.as_ref()).unwrap();
|
||||
// pub fn draw(&mut self) {
|
||||
// let output = self.widget.get_drawlist() + &self.widget.get_header_drawlist()
|
||||
// + &self.widget.get_footer_drawlist();
|
||||
// self.screen.write(output.as_ref()).unwrap();
|
||||
|
||||
self.screen.flush().unwrap();
|
||||
}
|
||||
// self.screen.flush().unwrap();
|
||||
// }
|
||||
|
||||
// pub fn show_status(status: &str) {
|
||||
// show_status(status);
|
||||
// }
|
||||
// // pub fn show_status(status: &str) {
|
||||
// // show_status(status);
|
||||
// // }
|
||||
|
||||
// pub fn draw_status() {
|
||||
// draw_status();
|
||||
// }
|
||||
// // pub fn draw_status() {
|
||||
// // draw_status();
|
||||
// // }
|
||||
|
||||
// pub fn clear_status() {
|
||||
// Self::show_status("");
|
||||
// }
|
||||
// // pub fn clear_status() {
|
||||
// // Self::show_status("");
|
||||
// // }
|
||||
|
||||
|
||||
pub fn handle_input(&mut self) {
|
||||
let (tx_event, rx_event) = 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();
|
||||
// pub fn handle_input(&mut self) {
|
||||
// let (tx_event, rx_event) = 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();
|
||||
|
||||
input_thread(tx_event.clone());
|
||||
global_event_thread(rx_global_event, tx_event.clone());
|
||||
dispatch_events(rx_event, tx_internal_event);
|
||||
// input_thread(tx_event.clone());
|
||||
// global_event_thread(rx_global_event, tx_event.clone());
|
||||
// dispatch_events(rx_event, tx_internal_event);
|
||||
|
||||
for event in rx_internal_event.iter() {
|
||||
match event {
|
||||
Events::InputEvent(event) => {
|
||||
self.widget.on_event(event);
|
||||
self.screen.cursor_hide();
|
||||
self.draw();
|
||||
},
|
||||
_ => {
|
||||
self.widget.refresh();
|
||||
self.draw();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for event in rx_internal_event.iter() {
|
||||
// match event {
|
||||
// Events::InputEvent(event) => {
|
||||
// self.widget.on_event(event);
|
||||
// self.screen.cursor_hide();
|
||||
// self.draw();
|
||||
// },
|
||||
// _ => {
|
||||
// self.widget.refresh();
|
||||
// self.draw();
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
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 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 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>) {
|
||||
std::thread::spawn(move || {
|
||||
for input in stdin().events() {
|
||||
let input = input.unwrap();
|
||||
tx.send(Events::InputEvent(input)).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
// fn input_thread(tx: Sender<Events>) {
|
||||
// std::thread::spawn(move || {
|
||||
// for input in stdin().events() {
|
||||
// let input = input.unwrap();
|
||||
// tx.send(Events::InputEvent(input)).unwrap();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
pub fn send_event(event: Events) -> HResult<()> {
|
||||
let tx = TX_EVENT.lock()?.clone()?.clone();
|
||||
tx.send(event)?;
|
||||
Ok(())
|
||||
}
|
||||
// pub fn send_event(event: Events) -> HResult<()> {
|
||||
// let tx = TX_EVENT.lock()?.clone()?.clone();
|
||||
// tx.send(event)?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
impl<T> Drop for Window<T>
|
||||
where
|
||||
T: Widget,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
// When done, restore the defaults to avoid messing with the terminal.
|
||||
self.screen
|
||||
.write(
|
||||
format!(
|
||||
"{}{}{}{}{}",
|
||||
termion::screen::ToMainScreen,
|
||||
termion::clear::All,
|
||||
termion::style::Reset,
|
||||
termion::cursor::Show,
|
||||
termion::cursor::Goto(1, 1)
|
||||
)
|
||||
.as_ref(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
// impl<T> Drop for Window<T>
|
||||
// where
|
||||
// T: Widget,
|
||||
// {
|
||||
// fn drop(&mut self) {
|
||||
// // When done, restore the defaults to avoid messing with the terminal.
|
||||
// self.screen
|
||||
// .write(
|
||||
// format!(
|
||||
// "{}{}{}{}{}",
|
||||
// termion::screen::ToMainScreen,
|
||||
// termion::clear::All,
|
||||
// termion::style::Reset,
|
||||
// termion::cursor::Show,
|
||||
// termion::cursor::Goto(1, 1)
|
||||
// )
|
||||
// .as_ref(),
|
||||
// )
|
||||
// .unwrap();
|
||||
// }
|
||||
// }
|
||||
|
||||
lazy_static! {
|
||||
static ref STATUS_BAR_CONTENT: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
|
||||
}
|
||||
// lazy_static! {
|
||||
// static ref STATUS_BAR_CONTENT: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
|
||||
// }
|
||||
|
||||
pub fn draw_status() {
|
||||
let xsize = term::xsize() as u16;
|
||||
let status = STATUS_BAR_CONTENT.try_lock().unwrap().clone();
|
||||
// pub fn draw_status() {
|
||||
// let xsize = term::xsize() as u16;
|
||||
// let status = STATUS_BAR_CONTENT.try_lock().unwrap().clone();
|
||||
|
||||
status.or(Some("".to_string())).and_then(|status| {
|
||||
write!(
|
||||
stdout(),
|
||||
"{}{}{:xsize$}{}{}",
|
||||
term::move_bottom(),
|
||||
term::status_bg(),
|
||||
" ",
|
||||
term::move_bottom(),
|
||||
status,
|
||||
xsize = xsize as usize
|
||||
)
|
||||
.ok()
|
||||
});
|
||||
stdout().flush().unwrap();
|
||||
}
|
||||
// status.or(Some("".to_string())).and_then(|status| {
|
||||
// write!(
|
||||
// stdout(),
|
||||
// "{}{}{:xsize$}{}{}",
|
||||
// term::move_bottom(),
|
||||
// term::status_bg(),
|
||||
// " ",
|
||||
// term::move_bottom(),
|
||||
// status,
|
||||
// xsize = xsize as usize
|
||||
// )
|
||||
// .ok()
|
||||
// });
|
||||
// stdout().flush().unwrap();
|
||||
// }
|
||||
|
||||
pub fn show_status(status: &str) {
|
||||
{
|
||||
let mut status_content = STATUS_BAR_CONTENT.try_lock().unwrap();
|
||||
*status_content = Some(status.to_string());
|
||||
}
|
||||
draw_status();
|
||||
}
|
||||
// pub fn show_status(status: &str) {
|
||||
// {
|
||||
// let mut status_content = STATUS_BAR_CONTENT.try_lock().unwrap();
|
||||
// *status_content = Some(status.to_string());
|
||||
// }
|
||||
// draw_status();
|
||||
// }
|
||||
|
||||
pub fn minibuffer(query: &str) -> HResult<String> {
|
||||
MINIBUFFER.lock()?.query(query)
|
||||
}
|
||||
// pub fn minibuffer(query: &str) -> HResult<String> {
|
||||
// MINIBUFFER.lock()?.query(query)
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue