summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrabite <rabite@posteo.de>2019-03-19 01:08:22 +0100
committerrabite <rabite@posteo.de>2019-03-19 14:38:15 +0100
commit161ba5ac3f38733b45c0167cb1e29f0be6059775 (patch)
tree794ec2517c71f6e6e3b9c572ebcc0e2fca66c3f4
parentc719ec7a3cb6ca3d2346f48dc11d2e0d5ee10d36 (diff)
handle terminal resizing
-rw-r--r--Cargo.toml1
-rw-r--r--src/bookmarks.rs31
-rw-r--r--src/coordinates.rs8
-rw-r--r--src/fail.rs8
-rw-r--r--src/file_browser.rs38
-rw-r--r--src/foldview.rs56
-rw-r--r--src/hbox.rs8
-rw-r--r--src/listview.rs10
-rw-r--r--src/main.rs1
-rw-r--r--src/miller_columns.rs9
-rw-r--r--src/preview.rs28
-rw-r--r--src/proclist.rs99
-rw-r--r--src/tabview.rs11
-rw-r--r--src/term.rs34
-rw-r--r--src/widget.rs56
15 files changed, 354 insertions, 44 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 3a94f37..ff594f2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,7 @@ failure = "0.1.5"
failure_derive = "0.1.1"
notify = "4.0.9"
parse-ansi = "0.1.6"
+signal-notify = "0.1.3"
#[profile.release]
#debug = true
diff --git a/src/bookmarks.rs b/src/bookmarks.rs
index a561841..379565e 100644
--- a/src/bookmarks.rs
+++ b/src/bookmarks.rs
@@ -4,6 +4,7 @@ use std::collections::HashMap;
use crate::fail::{HResult, HError, ErrorLog};
use crate::widget::{Widget, WidgetCore};
+use crate::coordinates::Coordinates;
use crate::files::{Files, File};
use crate::term;
@@ -68,19 +69,25 @@ pub struct BMPopup {
impl BMPopup {
pub fn new(core: &WidgetCore) -> BMPopup {
- let bmpopup = BMPopup {
+ let mut bmpopup = BMPopup {
core: core.clone(),
bookmarks: Bookmarks::new(),
bookmark_path: None,
add_mode: false
};
+ bmpopup.set_coordinates(&core.coordinates).log();
bmpopup
}
pub fn pick(&mut self, cwd: String) -> HResult<String> {
self.bookmark_path = Some(cwd);
self.refresh()?;
- self.popup()?;
+ match self.popup() {
+ Ok(_) => {},
+ Err(HError::PopupFinnished) => {},
+ err @ Err(HError::TerminalResizedError) => err?,
+ err @ Err(_) => err?,
+ }
self.clear()?;
let bookmark = self.bookmark_path.take();
@@ -120,16 +127,24 @@ impl Widget for BMPopup {
Ok(&mut self.core)
}
fn refresh(&mut self) -> HResult<()> {
- let tysize = crate::term::ysize();
- let txsize = crate::term::xsize();
- let len = self.bookmarks.mapping.len() as u16;
- let ysize = tysize - (len + 1);
+ Ok(())
+ }
- self.core.coordinates.set_position(1, ysize);
- self.core.coordinates.set_size(txsize, len+1);
+ fn resize(&mut self) -> HResult<()> {
+ HError::terminal_resized()
+ }
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ let (xsize, ysize) = coordinates.size_u();
+ let len = self.bookmarks.mapping.len();
+ let ysize = ysize.saturating_sub( len + 1 );
+
+ self.core.coordinates.set_size_u(xsize.saturating_sub(1), len);
+ self.core.coordinates.set_position_u(1, ysize+2);
Ok(())
}
+
fn get_drawlist(&self) -> HResult<String> {
let ypos = self.get_coordinates()?.ypos();
diff --git a/src/coordinates.rs b/src/coordinates.rs
index 3a76030..735286a 100644
--- a/src/coordinates.rs
+++ b/src/coordinates.rs
@@ -32,6 +32,10 @@ impl Coordinates {
self.size.0 = (x, y);
}
+ pub fn set_size_u(&mut self, x: usize, y: usize) {
+ self.size.0 = ((x+1) as u16, (y+1) as u16);
+ }
+
pub fn set_xsize(&mut self, x: u16) {
(self.size.0).0 = x;
}
@@ -44,6 +48,10 @@ impl Coordinates {
self.position.0 = (x, y);
}
+ pub fn set_position_u(&mut self, x: usize, y: usize) {
+ self.position.0 = ((x+1) as u16, (y+1) as u16);
+ }
+
pub fn set_xpos(&mut self, x: u16) {
(self.position.0).0 = x;
}
diff --git a/src/fail.rs b/src/fail.rs
index edbd0b2..97cbd62 100644
--- a/src/fail.rs
+++ b/src/fail.rs
@@ -66,7 +66,9 @@ pub enum HError {
#[fail(display = "Empty input!")]
MiniBufferEmptyInput,
#[fail(display = "Undefined key: {:?}", key)]
- WidgetUndefinedKeyError{key: Key}
+ WidgetUndefinedKeyError{key: Key},
+ #[fail(display = "Terminal has been resized!")]
+ TerminalResizedError,
}
impl HError {
@@ -109,6 +111,10 @@ impl HError {
Err(HError::PreviewFailed{ file: name,
backtrace: Backtrace::new() })
}
+
+ pub fn terminal_resized<T>() -> HResult<T> {
+ Err(HError::TerminalResizedError)
+ }
}
diff --git a/src/file_browser.rs b/src/file_browser.rs
index 831f96b..51bf72f 100644
--- a/src/file_browser.rs
+++ b/src/file_browser.rs
@@ -20,6 +20,7 @@ use crate::proclist::ProcView;
use crate::bookmarks::BMPopup;
use crate::term::ScreenExt;
use crate::foldview::LogView;
+use crate::coordinates::Coordinates;
#[derive(PartialEq)]
pub enum FileBrowserWidgets {
@@ -40,6 +41,12 @@ impl Widget for FileBrowserWidgets {
FileBrowserWidgets::Previewer(widget) => widget.get_core_mut()
}
}
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ match self {
+ FileBrowserWidgets::FileList(widget) => widget.set_coordinates(coordinates),
+ FileBrowserWidgets::Previewer(widget) => widget.set_coordinates(coordinates),
+ }
+ }
fn refresh(&mut self) -> HResult<()> {
match self {
FileBrowserWidgets::FileList(widget) => widget.refresh(),
@@ -335,13 +342,28 @@ impl FileBrowser {
Ok(())
}
- pub fn goto_bookmark(&mut self) -> HResult<()> {
- let cwd = match self.prev_cwd.as_ref() {
+ fn get_boomark(&mut self) -> HResult<String> {
+ let cwd = &match self.prev_cwd.as_ref() {
Some(cwd) => cwd,
None => &self.cwd
}.path.to_string_lossy().to_string();
- let path = self.bookmarks.lock()?.pick(cwd)?;
+ loop {
+ let bookmark = self.bookmarks.lock()?.pick(cwd.to_string());
+
+ if let Err(HError::TerminalResizedError) = bookmark {
+ self.core.screen.clear();
+ self.resize();
+ self.refresh();
+ self.draw();
+ continue;
+ }
+ return bookmark;
+ }
+ }
+
+ pub fn goto_bookmark(&mut self) -> HResult<()> {
+ let path = self.get_boomark()?;
let path = File::new_from_path(&PathBuf::from(path))?;
self.main_widget_goto(&path)?;
Ok(())
@@ -727,6 +749,16 @@ impl Widget for FileBrowser {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ self.columns.set_coordinates(&coordinates).log();
+ self.proc_view.lock()?.set_coordinates(&coordinates).log();
+ self.log_view.lock()?.set_coordinates(&coordinates).log();
+ self.bookmarks.lock()?.set_coordinates(&coordinates).log();
+ Ok(())
+ }
+
fn render_header(&self) -> HResult<String> {
let xsize = self.get_coordinates()?.xsize();
let file = self.selected_file()?;
diff --git a/src/foldview.rs b/src/foldview.rs
index 32d98e1..74c8f9e 100644
--- a/src/foldview.rs
+++ b/src/foldview.rs
@@ -5,7 +5,7 @@ use chrono::{DateTime, Local};
use crate::term;
use crate::widget::Widget;
use crate::listview::{ListView, Listable};
-use crate::fail::{HResult, HError};
+use crate::fail::{HResult, HError, ErrorLog};
use crate::dirty::Dirtyable;
pub type LogView = ListView<Vec<LogEntry>>;
@@ -79,6 +79,8 @@ impl From<&HError> for LogEntry {
pub trait FoldableWidgetExt {
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
+ fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
+ fn render_footer(&self) -> HResult<String> { Ok("".to_string()) }
}
impl FoldableWidgetExt for ListView<Vec<LogEntry>> {
@@ -88,6 +90,43 @@ impl FoldableWidgetExt for ListView<Vec<LogEntry>> {
}
Ok(())
}
+
+ fn render_header(&self) -> HResult<String> {
+ let (xsize, _) = self.core.coordinates.size_u();
+ let current = self.current_fold().unwrap_or(0);
+ let num = self.content.len();
+ let hint = format!("{} / {}", current, num);
+ let hint_xpos = xsize - hint.len();
+ let header = format!("Logged entries: {}{}{}",
+ num,
+ term::goto_xy_u(hint_xpos, 0),
+ hint);
+ Ok(header)
+ }
+
+ fn render_footer(&self) -> HResult<String> {
+ let current = self.current_fold()?;
+ if let Some(logentry) = self.content.get(current) {
+ let (xsize, ysize) = self.core.coordinates.size_u();
+ let (_, ypos) = self.core.coordinates.position_u();
+ let description = logentry.description();
+ let lines = logentry.lines();
+ let start_pos = self.fold_start_pos(current);
+ let selection = self.get_selection();
+ let current_line = (selection - start_pos) + 1;
+ let line_hint = format!("{} / {}", current_line, lines);
+ let hint_xpos = xsize - line_hint.len();
+ let hint_ypos = ysize + ypos + 1;
+
+ let footer = format!("LogEntry: {}{}{}{}{}",
+ description,
+ term::reset(),
+ term::status_bg(),
+ term::goto_xy_u(hint_xpos, hint_ypos),
+ line_hint);
+ Ok(footer)
+ } else { Ok("No log entries".to_string()) }
+ }
}
trait LogList {
@@ -151,7 +190,7 @@ where
ListView<Vec<F>>: FoldableWidgetExt {
fn toggle_fold(&mut self) -> HResult<()> {
- let fold = self.current_fold();
+ let fold = self.current_fold()?;
let fold_pos = self.fold_start_pos(fold);
self.content[fold].toggle_fold();
@@ -173,7 +212,7 @@ where
})
}
- fn current_fold(&self) -> usize {
+ fn current_fold(&self) -> Option<usize> {
let pos = self.get_selection();
let fold_lines = self
@@ -194,7 +233,7 @@ where
} else {
(lines + current_fold_lines, None)
}
- }}).1.unwrap()
+ }}).1
}
}
@@ -220,6 +259,15 @@ where
.flatten()
.collect()
}
+
+ fn render_header(&self) -> HResult<String> {
+ FoldableWidgetExt::render_header(self)
+ }
+
+ fn render_footer(&self) -> HResult<String> {
+ FoldableWidgetExt::render_footer(self)
+ }
+
fn on_refresh(&mut self) -> HResult<()> {
FoldableWidgetExt::on_refresh(self)
}
diff --git a/src/hbox.rs b/src/hbox.rs
index 7982333..49b9c47 100644
--- a/src/hbox.rs
+++ b/src/hbox.rs
@@ -118,6 +118,12 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ self.resize_children()
+ }
+
fn render_header(&self) -> HResult<String> {
self.active_widget().render_header()
}
@@ -125,7 +131,7 @@ impl<T> Widget for HBox<T> where T: Widget + PartialEq {
fn refresh(&mut self) -> HResult<()> {
self.resize_children().log();
for child in &mut self.widgets {
- child.refresh()?
+ child.refresh().log();
}
Ok(())
}
diff --git a/src/listview.rs b/src/listview.rs
index 58e7a3c..1c6f620 100644
--- a/src/listview.rs
+++ b/src/listview.rs
@@ -12,6 +12,8 @@ use crate::dirty::Dirtyable;
pub trait Listable {
fn len(&self) -> usize;
fn render(&self) -> Vec<String>;
+ fn render_header(&self) -> HResult<String> { Ok("".to_string()) }
+ fn render_footer(&self) -> HResult<String> { Ok("".to_string()) }
fn on_refresh(&mut self) -> HResult<()> { Ok(()) }
fn on_key(&mut self, _key: Key) -> HResult<()> { Ok(()) }
}
@@ -304,6 +306,7 @@ impl ListView<Files>
fn toggle_tag(&mut self) -> HResult<()> {
self.selected_file_mut().toggle_tag()?;
self.move_down();
+ self.core.set_dirty();
Ok(())
}
@@ -412,6 +415,13 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
Ok(())
}
+ fn render_header(&self) -> HResult<String> {
+ Listable::render_header(self)
+ }
+
+ fn render_footer(&self) -> HResult<String> {
+ Listable::render_footer(self)
+ }
fn get_drawlist(&self) -> HResult<String> {
let mut output = term::reset();
diff --git a/src/main.rs b/src/main.rs
index ddf7d4e..3973908 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,6 +18,7 @@ extern crate rayon;
extern crate libc;
extern crate notify;
extern crate parse_ansi;
+extern crate signal_notify;
use failure::Fail;
diff --git a/src/miller_columns.rs b/src/miller_columns.rs
index ca621e4..db1daba 100644
--- a/src/miller_columns.rs
+++ b/src/miller_columns.rs
@@ -93,9 +93,14 @@ where
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ self.widgets.set_coordinates(&coordinates)
+ }
+
fn refresh(&mut self) -> HResult<()> {
- self.widgets.refresh().log();
- Ok(())
+ self.widgets.refresh()
}
fn get_drawlist(&self) -> HResult<String> {
diff --git a/src/preview.rs b/src/preview.rs
index 17663b2..9965229 100644
--- a/src/preview.rs
+++ b/src/preview.rs
@@ -6,6 +6,7 @@ use crate::files::{File, Files, Kind};
use crate::listview::ListView;
use crate::textview::TextView;
use crate::widget::{Widget, WidgetCore};
+use crate::coordinates::Coordinates;
use crate::fail::{HResult, HError, ErrorLog};
@@ -189,12 +190,29 @@ impl<T: Widget + Send + 'static> Widget for WillBeWidget<T> {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ if let Ok(widget) = self.widget() {
+ let mut widget = widget.lock()?;
+ let widget = widget.as_mut()?;
+ widget.set_coordinates(&coordinates)?;
+ }
+ Ok(())
+ }
+
fn refresh(&mut self) -> HResult<()> {
+ let coords = self.get_coordinates()?;
if let Ok(widget) = self.widget() {
let mut widget = widget.lock()?;
let widget = widget.as_mut()?;
- widget.set_coordinates(self.get_coordinates()?).log();
- widget.refresh().log();
+
+ if widget.get_coordinates()? != coords {
+ widget.set_coordinates(self.get_coordinates()?)?;
+ widget.refresh()?;
+ } else {
+ widget.refresh()?;
+ }
}
Ok(())
}
@@ -427,6 +445,12 @@ impl Widget for Previewer {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ self.widget.set_coordinates(&coordinates)
+ }
+
fn refresh(&mut self) -> HResult<()> {
self.widget.refresh()
}
diff --git a/src/proclist.rs b/src/proclist.rs
index f05612f..f36ede4 100644
--- a/src/proclist.rs
+++ b/src/proclist.rs
@@ -10,6 +10,7 @@ use unicode_width::UnicodeWidthStr;
use crate::listview::{Listable, ListView};
use crate::textview::TextView;
use crate::widget::{Widget, Events, WidgetCore};
+use crate::coordinates::Coordinates;
use crate::hbox::HBox;
use crate::preview::WillBeWidget;
use crate::fail::{HResult, HError, ErrorLog};
@@ -227,7 +228,13 @@ pub struct ProcView {
}
impl HBox<ProcViewWidgets> {
- fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
+ fn get_listview(&self) -> &ListView<Vec<Process>> {
+ match &self.widgets[0] {
+ ProcViewWidgets::List(listview) => listview,
+ _ => unreachable!()
+ }
+ }
+ fn get_listview_mut(&mut self) -> &mut ListView<Vec<Process>> {
match &mut self.widgets[0] {
ProcViewWidgets::List(listview) => listview,
_ => unreachable!()
@@ -259,22 +266,26 @@ impl ProcView {
}
}
- fn get_listview(&mut self) -> &mut ListView<Vec<Process>> {
+ fn get_listview(& self) -> & ListView<Vec<Process>> {
self.hbox.get_listview()
}
+ fn get_listview_mut(&mut self) -> &mut ListView<Vec<Process>> {
+ self.hbox.get_listview_mut()
+ }
+
fn get_textview(&mut self) -> &mut WillBeWidget<TextView> {
self.hbox.get_textview()
}
pub fn run_proc(&mut self, cmd: &str) -> HResult<()> {
- self.get_listview().run_proc(cmd)?;
+ self.get_listview_mut().run_proc(cmd)?;
Ok(())
}
pub fn remove_proc(&mut self) -> HResult<()> {
- if self.get_listview().content.len() == 0 { return Ok(()) }
- self.get_listview().remove_proc()?;
+ if self.get_listview_mut().content.len() == 0 { return Ok(()) }
+ self.get_listview_mut().remove_proc()?;
self.get_textview().change_to(Box::new(move |_, core| {
let mut textview = TextView::new_blank(&core);
textview.refresh().log();
@@ -285,10 +296,10 @@ impl ProcView {
}
fn show_output(&mut self) -> HResult<()> {
- if Some(self.get_listview().get_selection()) == self.viewing {
+ if Some(self.get_listview_mut().get_selection()) == self.viewing {
return Ok(());
}
- let output = self.get_listview().selected_proc()?.output.lock()?.clone();
+ let output = self.get_listview_mut().selected_proc()?.output.lock()?.clone();
self.get_textview().change_to(Box::new(move |_, core| {
let mut textview = TextView::new_blank(&core);
@@ -296,7 +307,7 @@ impl ProcView {
textview.animate_slide_up().log();
Ok(textview)
})).log();
- self.viewing = Some(self.get_listview().get_selection());
+ self.viewing = Some(self.get_listview_mut().get_selection());
Ok(())
}
@@ -343,11 +354,75 @@ impl Widget for ProcView {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ self.hbox.core.coordinates = coordinates.clone();
+ self.hbox.set_coordinates(&coordinates)
+ }
+
+ fn render_header(&self) -> HResult<String> {
+ let listview = self.get_listview();
+ let procs_num = listview.len();
+ let procs_running = listview
+ .content
+ .iter()
+ .filter(|proc| proc.status.lock().unwrap().is_none())
+ .count();
+
+ let header = format!("Running processes: {} / {}",
+ procs_running,
+ procs_num);
+ Ok(header)
+ }
+
+ fn render_footer(&self) -> HResult<String> {
+ let listview = self.get_listview();
+ let selection = listview.get_selection();
+
+ if let Some(proc) = listview.content.get(selection) {
+ let cmd = &proc.cmd;
+ let pid = proc.handle.lock()?.id();
+ let proc_status = proc.status.lock()?;
+ let proc_success = proc.success.lock()?;
+
+ let procinfo = if proc_status.is_some() {
+ let color_success =
+ if let Some(_) = *proc_success {
+ format!("{}successfully", term::color_green())
+ } else {
+ format!("{}unsuccessfully", term::color_red())
+ };
+
+ let color_status =
+ if let Some(success) = *proc_success {
+ if success {
+ format!("{}{}", term::color_green(), proc_status.unwrap())
+ } else {
+ format!("{}{}", term::color_red(), proc_status.unwrap())
+ }
+ } else { "wtf".to_string() };
+
+ let procinfo = format!("Process: {}:{} exited {}{}{} with status: {}",
+ cmd,
+ pid,
+ color_success,
+ term::reset(),
+ term::status_bg(),
+ color_status);
+ procinfo
+ } else { "still running".to_string() };
+
+ let footer = format!("{}: {}", cmd, procinfo);
+
+ Ok(footer)
+ } else { Ok("No proccesses".to_string()) }
+ }
+
fn refresh(&mut self) -> HResult<()> {
self.hbox.refresh().log();
self.show_output().log();
- self.get_listview().refresh().log();
+ self.get_listview_mut().refresh().log();
self.get_textview().refresh().log();
Ok(())
@@ -359,12 +434,12 @@ impl Widget for ProcView {
match key {
Key::Char('w') => { return Err(HError::PopupFinnished) }
Key::Char('d') => { self.remove_proc()? }
- Key::Char('k') => { self.get_listview().kill_proc()? }
+ Key::Char('k') => { self.get_listview_mut().kill_proc()? }
Key::Up | Key::Char('p') => {
- self.get_listview().move_up();
+ self.get_listview_mut().move_up();
}
Key::Down | Key::Char('n') => {
- self.get_listview().move_down();
+ self.get_listview_mut().move_down();
}
Key::Char('f') => { self.toggle_follow().log(); }
Key::Ctrl('n') => { self.scroll_down().log(); },
diff --git a/src/tabview.rs b/src/tabview.rs
index e8dc748..524a469 100644
--- a/src/tabview.rs
+++ b/src/tabview.rs
@@ -2,6 +2,8 @@ use termion::event::Key;
use crate::widget::{Widget, WidgetCore};
use crate::fail::{HResult, ErrorLog};
+use crate::coordinates::Coordinates;
+use crate::dirty::Dirtyable;
pub trait Tabbable {
fn new_tab(&mut self) -> HResult<()>;
@@ -105,6 +107,15 @@ impl<T> Widget for TabView<T> where T: Widget, TabView<T>: Tabbable {
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
+
+ fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
+ self.core.coordinates = coordinates.clone();
+ for widget in &mut self.widgets {
+ widget.set_coordinates(coordinates).log();
+ }
+ Ok(())
+ }
+
fn render_header(&self) -> HResult<String> {
let xsize = self.get_coordinates()?.xsize();
let header = self.active_tab_().render_header()?;
diff --git a/src/term.rs b/src/term.rs
index 94e0c5d..abedbba 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -1,5 +1,5 @@
use std::io::{Stdout, Write, BufWriter};
-use std::sync::{Arc, Mutex};
+use std::sync::{Arc, Mutex, RwLock};
use termion;
use termion::screen::AlternateScreen;
@@ -14,7 +14,8 @@ pub type TermMode = AlternateScreen<MouseTerminal<RawTerminal<BufWriter<Stdout>>
#[derive(Clone)]
pub struct Screen {
- screen: Arc<Mutex<Option<TermMode>>>
+ screen: Arc<Mutex<Option<TermMode>>>,
+ size: Arc<RwLock<Option<(usize, usize)>>>
}
impl Screen {
@@ -25,7 +26,8 @@ impl Screen {
screen.cursor_hide()?;
Ok(Screen {
- screen: Arc::new(Mutex::new(Some(screen)))
+ screen: Arc::new(Mutex::new(Some(screen))),
+ size: Arc::new(RwLock::new(None))
})
}
@@ -43,6 +45,19 @@ impl Screen {
*self.screen.lock()? = Some(screen);
Ok(())
}
+
+ pub fn set_size(&self, size: (usize, usize)) -> HResult<()> {
+ *self.size.write()? = Some(size);
+ Ok(())
+ }
+
+ pub fn is_resized(&self) -> HResult<(usize, usize)> {
+ Ok(self.size.read()?.clone()?)
+ }
+
+ pub fn take_size(&self) -> HResult<(usize, usize)> {
+ Ok(self.size.write()?.take()?)
+ }
}
impl Write for Screen {
@@ -70,7 +85,9 @@ pub trait ScreenExt: Write {
Ok(())
}
fn clear(&mut self) -> HResult<()> {
- write!(self, "{}", termion::clear::All)?;
+ write!(self, "{}{}",
+ termion::style::Reset,
+ termion::clear::All)?;
Ok(())
}
fn write_str(&mut self, str: &str) -> HResult<()> {
@@ -83,6 +100,10 @@ pub trait ScreenExt: Write {
write!(self, "{}", goto_xy(x + 1, y + 1))?;
Ok(())
}
+ fn size(&self) -> HResult<(usize, usize)> {
+ let (xsize, ysize) = termion::terminal_size()?;
+ Ok(((xsize-1) as usize, (ysize-1) as usize))
+ }
fn xsize(&self) -> HResult<usize> {
let (xsize, _) = termion::terminal_size()?;
Ok((xsize - 1) as usize)
@@ -116,6 +137,11 @@ pub fn ysize() -> u16 {
ysize
}
+pub fn size() -> HResult<(usize, usize)> {
+ let (xsize, ysize) = termion::terminal_size()?;
+ Ok(((xsize-1) as usize, (ysize-1) as usize))
+}
+
pub fn sized_string(string: &str, xsize: u16) -> String {
string.chars().fold("".to_string(), |acc, ch| {
let width: usize = unicode_width::UnicodeWidthStr::width_cjk(acc.as_str());
diff --git a/src/widget.rs b/src/widget.rs
index 1d48bdf..1610596 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -11,6 +11,7 @@ use crate::minibuffer::MiniBuffer;
use crate::term;
use crate::term::{Screen, ScreenExt};
use crate::dirty::{Dirtyable, DirtyBit};
+use crate::signal_notify::{notify, Signal};
use std::io::stdin;
@@ -18,6 +19,7 @@ use std::io::stdin;
pub enum Events {
InputEvent(Event),
WidgetReady,
+ TerminalResized,
ExclusiveEvent(Option<Sender<Events>>),
InputEnabled(bool),
RequestInput,
@@ -52,12 +54,14 @@ pub struct WidgetCore {
pub event_sender: Sender<Events>,
event_receiver: Arc<Mutex<Option<Receiver<Events>>>>,
pub status_bar_content: Arc<Mutex<Option<String>>>,
+ term_size: (usize, usize),
dirty: DirtyBit
}
impl WidgetCore {
pub fn new() -> HResult<WidgetCore> {
let screen = Screen::new()?;
+ let (xsize, ysize) = screen.size()?;
let coords = Coordinates::new_at(term::xsize(),
term::ysize() - 2,
1,
@@ -72,6 +76,7 @@ impl WidgetCore {
event_sender: sender,
event_receiver: Arc::new(Mutex::new(Some(receiver))),
status_bar_content: status_bar_content,
+ term_size: (xsize, ysize),
dirty: DirtyBit::new() };
let minibuffer = MiniBuffer::new(&core);
@@ -106,11 +111,10 @@ pub trait Widget {
Ok(&self.get_core()?.coordinates)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
- let widget_coords = &mut self.get_core_mut()?.coordinates;
- if widget_coords != coordinates {
- *widget_coords = coordinates.clone();
- self.get_core_mut()?.set_dirty();
- self.refresh()?;
+ let core = &mut self.get_core_mut()?;
+ if &core.coordinates != coordinates {
+ core.coordinates = coordinates.clone();
+ core.set_dirty();
}
Ok(())
}
@@ -259,6 +263,13 @@ pub trait Widget {
Events::Status(status) => {
self.show_status(&status).log();
}
+ Events::TerminalResized => {
+ self.screen()?.clear().log();
+ match self.resize() {
+ err @ Err(HError::TerminalResizedError) => err?,
+ _ => {}
+ }
+ }
_ => {}
}
self.refresh().log();
@@ -313,7 +324,7 @@ pub trait Widget {
let (tx_internal_event, rx_internal_event) = channel();
let rx_global_event = self.get_core()?.event_receiver.lock()?.take()?;
- dispatch_events(tx_internal_event, rx_global_event);
+ dispatch_events(tx_internal_event, rx_global_event, self.screen()?);
for event in rx_internal_event.iter() {
match event {
@@ -327,8 +338,13 @@ pub trait Widget {
Events::Status(status) => {
self.show_status(&status).log();
}
+ Events::TerminalResized => {
+ self.screen()?.clear().log();
+ }
_ => {}
}
+ self.resize().log();
+ self.screen()?.take_size().ok();
self.refresh().ok();
self.draw().ok();
}
@@ -387,14 +403,26 @@ pub trait Widget {
let mut screen = self.screen()?;
screen.write_str(s)
}
+
+ fn resize(&mut self) -> HResult<()> {
+ if let Ok((xsize, ysize)) = self.screen()?.is_resized() {
+ let mut coords = self.get_core()?.coordinates.clone();
+ coords.set_size_u(xsize, ysize-2);
+ self.set_coordinates(&coords)?;
+ }
+ Ok(())
+ }
}
-fn dispatch_events(tx_internal: Sender<Events>, rx_global: Receiver<Events>) {
+fn dispatch_events(tx_internal: Sender<Events>,
+ rx_global: Receiver<Events>,
+ screen: Screen) {
let (tx_event, rx_event) = channel();
let (tx_input_req, rx_input_req) = channel();
input_thread(tx_event.clone(), rx_input_req);
event_thread(rx_global, tx_event.clone());
+ signal_thread(tx_event.clone());
std::thread::spawn(move || {
let mut tx_exclusive_event: Option<Sender<Events>> = None;
@@ -415,6 +443,11 @@ fn dispatch_events(tx_internal: Sender<Events>, rx_global: Receiver<Events>) {
}
continue;
}
+ Events::TerminalResized => {
+ if let Ok(size) = term::size() {
+ screen.set_size(size).log();
+ }
+ }
_ => {}
}
if let Some(tx_exclusive) = &tx_exclusive_event {