summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2020-12-30 14:02:10 -0500
committerJiayi Zhao <jeff.no.zhao@gmail.com>2020-12-30 14:02:10 -0500
commite4faa16c8a7f2a51303ad3fe9f3891d8f7eabb82 (patch)
tree3d1be976d3a23d2aad667b1106668263cfd5ce6d
parent72f5e1eaf4c0fcbe39bd3f0d80cf9ab45d504057 (diff)
add resize notification support and preliminary mouse support
- currently scroll is hardmapped to cursor_up and cursor_down
-rw-r--r--Cargo.lock20
-rw-r--r--Cargo.toml1
-rw-r--r--src/config/keymap.rs124
-rw-r--r--src/context/context.rs12
-rw-r--r--src/run.rs38
-rw-r--r--src/ui/tui_backend.rs13
-rw-r--r--src/ui/views/tui_worker_view.rs19
-rw-r--r--src/ui/widgets/tui_menu.rs50
-rw-r--r--src/ui/widgets/tui_prompt.rs18
-rw-r--r--src/ui/widgets/tui_textfield.rs18
-rw-r--r--src/util/event.rs50
-rw-r--r--src/util/input_process.rs (renamed from src/util/worker.rs)14
-rw-r--r--src/util/key_mapping.rs66
-rw-r--r--src/util/mod.rs2
14 files changed, 265 insertions, 180 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 90d7f54..102391a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -192,6 +192,7 @@ dependencies = [
"serde",
"serde_derive",
"shell-words",
+ "signal-hook",
"structopt",
"termion",
"toml",
@@ -505,6 +506,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
[[package]]
+name = "signal-hook"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b3799fa361789a685db59e3986fb5f6f949e478728b9913c6759f7b014d0372"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "siphasher"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 12e12c2..d4f87d1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ rustyline = "^4"
serde = "^1"
serde_derive = "^1"
shell-words = "^1"
+signal-hook = "^0"
structopt = "^0"
termion = "^1"
trash = "^1"
diff --git a/src/config/keymap.rs b/src/config/keymap.rs
index e21efff..80f0a6f 100644
--- a/src/config/keymap.rs
+++ b/src/config/keymap.rs
@@ -2,27 +2,27 @@ use std::collections::{hash_map::Entry, HashMap};
use serde_derive::Deserialize;
-use termion::event::Key;
+use termion::event::{Event, Key, MouseEvent};
use super::{parse_to_config_file, ConfigStructure, Flattenable};
use crate::commands::{CommandKeybind, KeyCommand};
use crate::io::IOWorkerOptions;
-use crate::util::key_mapping::str_to_key;
+use crate::util::key_mapping::str_to_event;
use crate::KEYMAP_FILE;
#[derive(Debug)]
pub struct JoshutoCommandMapping {
- map: HashMap<Key, CommandKeybind>,
+ map: HashMap<Event, CommandKeybind>,
}
-impl std::convert::AsRef<HashMap<Key, CommandKeybind>> for JoshutoCommandMapping {
- fn as_ref(&self) -> &HashMap<Key, CommandKeybind> {
+impl std::convert::AsRef<HashMap<Event, CommandKeybind>> for JoshutoCommandMapping {
+ fn as_ref(&self) -> &HashMap<Event, CommandKeybind> {
&self.map
}
}
-impl std::convert::AsMut<HashMap<Key, CommandKeybind>> for JoshutoCommandMapping {
- fn as_mut(&mut self) -> &mut HashMap<Key, CommandKeybind> {
+impl std::convert::AsMut<HashMap<Event, CommandKeybind>> for JoshutoCommandMapping {
+ fn as_mut(&mut self) -> &mut HashMap<Event, CommandKeybind> {
&mut self.map
}
}
@@ -38,154 +38,154 @@ impl JoshutoCommandMapping {
let mut m = self;
let cmd = KeyCommand::CursorMoveUp(1);
- let keys = [Key::Up];
+ let keys = [Event::Key(Key::Up)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CursorMoveDown(1);
- let keys = [Key::Down];
+ let keys = [Event::Key(Key::Down)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::ParentDirectory;
- let keys = [Key::Left];
+ let keys = [Event::Key(Key::Left)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::OpenFile;
- let keys = [Key::Right];
+ let keys = [Event::Key(Key::Right)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::OpenFile;
- let keys = [Key::Char('\n')];
+ let keys = [Event::Key(Key::Char('\n'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CursorMoveHome;
- let keys = [Key::Home];
+ let keys = [Event::Key(Key::Home)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CursorMoveEnd;
- let keys = [Key::End];
+ let keys = [Event::Key(Key::End)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CursorMovePageUp;
- let keys = [Key::PageUp];
+ let keys = [Event::Key(Key::PageUp)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CursorMovePageDown;
- let keys = [Key::PageDown];
+ let keys = [Event::Key(Key::PageDown)];
insert_keycommand(&mut m, cmd, &keys)?;
// vim keys
let cmd = KeyCommand::CursorMoveUp(1);
- let keys = [Key::Char('k')];
+ let keys = [Event::Key(Key::Char('k'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CursorMoveDown(1);
- let keys = [Key::Char('j')];
+ let keys = [Event::Key(Key::Char('j'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::ParentDirectory;
- let keys = [Key::Char('h')];
+ let keys = [Event::Key(Key::Char('h'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::OpenFile;
- let keys = [Key::Char('l')];
+ let keys = [Event::Key(Key::Char('l'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::NewTab;
- let keys = [Key::Char('T')];
+ let keys = [Event::Key(Key::Char('T'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::NewTab;
- let keys = [Key::Ctrl('t')];
+ let keys = [Event::Key(Key::Ctrl('t'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CloseTab;
- let keys = [Key::Char('W')];
+ let keys = [Event::Key(Key::Char('W'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CloseTab;
- let keys = [Key::Ctrl('w')];
+ let keys = [Event::Key(Key::Ctrl('w'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CloseTab;
- let keys = [Key::Char('q')];
+ let keys = [Event::Key(Key::Char('q'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::ForceQuit;
- let keys = [Key::Char('Q')];
+ let keys = [Event::Key(Key::Char('Q'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::ReloadDirList;
- let keys = [Key::Char('R')];
+ let keys = [Event::Key(Key::Char('R'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::ToggleHiddenFiles;
- let keys = [Key::Char('z'), Key::Char('h')];
+ let keys = [Event::Key(Key::Char('z')), Event::Key(Key::Char('h'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::TabSwitch(1);
- let keys = [Key::Char('\t')];
+ let keys = [Event::Key(Key::Char('\t'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::TabSwitch(-1);
- let keys = [Key::BackTab];
+ let keys = [Event::Key(Key::BackTab)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::OpenFileWith;
- let keys = [Key::Char('r')];
+ let keys = [Event::Key(Key::Char('r'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CutFiles;
- let keys = [Key::Char('d'), Key::Char('d')];
+ let keys = [Event::Key(Key::Char('d')), Event::Key(Key::Char('d'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CopyFiles;
- let keys = [Key::Char('y'), Key::Char('y')];
+ let keys = [Event::Key(Key::Char('y')), Event::Key(Key::Char('y'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::PasteFiles(IOWorkerOptions::default());
- let keys = [Key::Char('p'), Key::Char('p')];
+ let keys = [Event::Key(Key::Char('p')), Event::Key(Key::Char('p'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::DeleteFiles;
- let keys = [Key::Delete];
+ let keys = [Event::Key(Key::Delete)];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::DeleteFiles;
- let keys = [Key::Char('D'), Key::Char('d')];
+ let keys = [Event::Key(Key::Char('D')), Event::Key(Key::Char('d'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::RenameFileAppend;
- let keys = [Key::Char('a')];
+ let keys = [Event::Key(Key::Char('a'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::RenameFilePrepend;
- let keys = [Key::Char('A')];
+ let keys = [Event::Key(Key::Char('A'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CommandLine("search ".to_string(), "".to_string());
- let keys = [Key::Char('/')];
+ let keys = [Event::Key(Key::Char('/'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::SearchNext;
- let keys = [Key::Char('n')];
+ let keys = [Event::Key(Key::Char('n'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::SearchPrev;
- let keys = [Key::Char('N')];
+ let keys = [Event::Key(Key::Char('N'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::BulkRename;
- let keys = [Key::Char('b'), Key::Char('b')];
+ let keys = [Event::Key(Key::Char('b')), Event::Key(Key::Char('b'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::SetMode;
- let keys = [Key::Char('=')];
+ let keys = [Event::Key(Key::Char('='))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CommandLine("".to_string(), "".to_string());
- let keys = [Key::Char(';')];
+ let keys = [Event::Key(Key::Char(';'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CommandLine("mkdir ".to_string(), "".to_string());
- let keys = [Key::Char('m'), Key::Char('k')];
+ let keys = [Event::Key(Key::Char('m')), Event::Key(Key::Char('k'))];
insert_keycommand(&mut m, cmd, &keys)?;
let cmd = KeyCommand::CommandLine("rename ".to_string(), "".to_string());
- let keys = [Key::Char('c'), Key::Char('w')];
+ let keys = [Event::Key(Key::Char('c')), Event::Key(Key::Char('w'))];
insert_keycommand(&mut m, cmd, &keys)?;
Ok(())
@@ -197,9 +197,7 @@ impl std::default::Default for JoshutoCommandMapping {
let mut m = Self {
map: HashMap::new(),
};
-
let _ = m.default_res();
-
m
}
}
@@ -229,18 +227,18 @@ impl Flattenable<JoshutoCommandMapping> for JoshutoRawCommandMapping {
for m in self.mapcommand {
match KeyCommand::parse_command(m.command.as_str()) {
Ok(command) => {
- let keycodes: Vec<Key> = m
+ let events: Vec<Event> = m
.keys
.iter()
- .filter_map(|s| str_to_key(s.as_str()))
+ .filter_map(|s| str_to_event(s.as_str()))
.collect();
- if keycodes.len() != m.keys.len() {
- eprintln!("Failed to parse keycodes: {:?}", m.keys);
+ if events.len() != m.keys.len() {
+ eprintln!("Failed to parse events: {:?}", m.keys);
continue;
}
- let result = insert_keycommand(&mut keymaps, command, &keycodes);
+ let result = insert_keycommand(&mut keymaps, command, &events);
match result {
Ok(_) => {}
Err(e) => eprintln!("{}", e),
@@ -256,18 +254,16 @@ impl Flattenable<JoshutoCommandMapping> for JoshutoRawCommandMapping {
fn insert_keycommand(
keymap: &mut JoshutoCommandMapping,
keycommand: KeyCommand,
- keycodes: &[Key],
+ events: &[Event],
) -> Result<(), String> {
- let keycode_len = keycodes.len();
-
- if keycode_len == 0 {
+ let num_events = events.len();
+ if num_events == 0 {
return Ok(());
}
- let key = keycodes[0];
-
- if keycode_len == 1 {
- match keymap.as_mut().entry(key) {
+ let event = events[0].clone();
+ if num_events == 1 {
+ match keymap.as_mut().entry(event) {
Entry::Occupied(_) => {
return Err(format!("Error: Keybindings ambiguous for {}", keycommand))
}
@@ -276,16 +272,16 @@ fn insert_keycommand(
return Ok(());
}
- match keymap.as_mut().entry(key) {
+ match keymap.as_mut().entry(event) {
Entry::Occupied(mut entry) => match entry.get_mut() {
CommandKeybind::CompositeKeybind(ref mut m) => {
- insert_keycommand(m, keycommand, &keycodes[1..])
+ insert_keycommand(m, keycommand, &events[1..])
}
_ => Err(format!("Error: Keybindings ambiguous for {}", keycommand)),
},
Entry::Vacant(entry) => {
let mut new_map = JoshutoCommandMapping::new();
- let result = insert_keycommand(&mut new_map, keycommand, &keycodes[1..]);
+ let result = insert_keycommand(&mut new_map, keycommand, &events[1..]);
if result.is_ok() {
let composite_command = CommandKeybind::CompositeKeybind(new_map);
entry.insert(composite_command);
diff --git a/src/context/context.rs b/src/context/context.rs
index bb5a512..574b7af 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -6,7 +6,7 @@ use std::thread;
use crate::config;
use crate::context::{LocalStateContext, TabContext};
use crate::io::{IOWorkerObserver, IOWorkerProgress, IOWorkerThread};
-use crate::util::event::{Event, Events};
+use crate::util::event::{Events, JoshutoEvent};
pub struct JoshutoContext {
pub exit: bool,
@@ -61,10 +61,10 @@ impl JoshutoContext {
}
// event related
- pub fn poll_event(&self) -> Result<Event, mpsc::RecvError> {
+ pub fn poll_event(&self) -> Result<JoshutoEvent, mpsc::RecvError> {
self.events.next()
}
- pub fn get_event_tx(&self) -> mpsc::Sender<Event> {
+ pub fn get_event_tx(&self) -> mpsc::Sender<JoshutoEvent> {
self.events.event_tx.clone()
}
pub fn flush_event(&self) {
@@ -134,17 +134,17 @@ impl JoshutoContext {
let worker_handle = thread::spawn(move || worker.start(wtx));
// relay worker info to event loop
while let Ok(progress) = wrx.recv() {
- let _ = tx.send(Event::IOWorkerProgress(progress));
+ let _ = tx.send(JoshutoEvent::IOWorkerProgress(progress));
}
let result = worker_handle.join();
match result {
Ok(res) => {
- let _ = tx.send(Event::IOWorkerResult(res));
+ let _ = tx.send(JoshutoEvent::IOWorkerResult(res));
}
Err(_) => {
let err = std::io::Error::new(std::io::ErrorKind::Other, "Sending Error");
- let _ = tx.send(Event::IOWorkerResult(Err(err)));
+ let _ = tx.send(JoshutoEvent::IOWorkerResult(Err(err)));
}
}
});
diff --git a/src/run.rs b/src/run.rs
index 11ef0e2..19d2486 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -1,13 +1,15 @@
-use crate::commands::{CommandKeybind, JoshutoRunnable};
+use termion::event::{Event, MouseButton, MouseEvent};
+
+use crate::commands::{CommandKeybind, JoshutoRunnable, KeyCommand};
use crate::config::{JoshutoCommandMapping, JoshutoConfig};
use crate::context::JoshutoContext;
use crate::tab::JoshutoTab;
use crate::ui;
use crate::ui::views::TuiView;
use crate::ui::widgets::TuiCommandMenu;
-use crate::util::event::Event;
+use crate::util::event::JoshutoEvent;
+use crate::util::input_process;
use crate::util::load_child::LoadChild;
-use crate::util::worker;
pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io::Result<()> {
let mut backend: ui::TuiBackend = ui::TuiBackend::new()?;
@@ -34,21 +36,34 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io:
Ok(event) => event,
Err(_) => return Ok(()), // TODO
};
-
match event {
- Event::IOWorkerProgress(res) => {
- worker::process_worker_progress(&mut context, res);
- }
- Event::IOWorkerResult(res) => {
- worker::process_finished_worker(&mut context, res);
+ JoshutoEvent::Termion(Event::Mouse(event)) => {
+ let command = match event {
+ MouseEvent::Press(MouseButton::WheelUp, _, _) => {
+ Some(KeyCommand::CursorMoveUp(1))
+ }
+ MouseEvent::Press(MouseButton::WheelDown, _, _) => {
+ Some(KeyCommand::CursorMoveDown(1))
+ }
+ e => None,
+ };
+ match command {
+ Some(c) => {
+ if let Err(e) = c.execute(&mut context, &mut backend) {
+ context.push_msg(e.to_string());
+ }
+ }
+ None => context.push_msg(format!("Unmapped input: {:?}", event)),
+ }
+ context.flush_event();
}
- Event::Input(key) => {
+ JoshutoEvent::Termion(key) => {
if !context.message_queue_ref().is_empty() {
context.pop_msg();
}
match keymap_t.as_ref().get(&key) {
None => {
- context.push_msg(format!("Unknown keycode: {:?}", key));
+ context.push_msg(format!("Unmapped input: {:?}", key));
}
Some(CommandKeybind::SimpleKeybind(command)) => {
if let Err(e) = command.execute(&mut context, &mut backend) {
@@ -70,6 +85,7 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io:
}
context.flush_event();
}
+ event => input_process::process_noninteractive(event, &mut context),
}
}
diff --git a/src/ui/tui_backend.rs b/src/ui/tui_backend.rs
index 2294737..6a42a5f 100644
--- a/src/ui/tui_backend.rs
+++ b/src/ui/tui_backend.rs
@@ -1,20 +1,23 @@
use std::io::stdout;
use std::io::Write;
+use termion::input::MouseTerminal;
use termion::raw::{IntoRawMode, RawTerminal};
use termion::screen::AlternateScreen;
use tui::backend::TermionBackend;
use tui::widgets::Widget;
+pub type JoshutoTerminal =
+ tui::Terminal<TermionBackend<MouseTerminal<AlternateScreen<RawTerminal<std::io::Stdout>>>>>;
+
pub struct TuiBackend {
- pub terminal:
- Option<tui::Terminal<TermionBackend<AlternateScreen<RawTerminal<std::io::Stdout>>>>>,
+ pub terminal: Option<JoshutoTerminal>,
}
impl TuiBackend {
pub fn new() -> std::io::Result<Self> {
let stdout = std::io::stdout().into_raw_mode()?;
- let mut alt_screen = AlternateScreen::from(stdout);
+ let mut alt_screen = MouseTerminal::from(AlternateScreen::from(stdout));
// clears the screen of artifacts
write!(alt_screen, "{}", termion::clear::All)?;
@@ -36,9 +39,7 @@ impl TuiBackend {
});
}
- pub fn terminal_mut(
- &mut self,
- ) -> &mut tui::Terminal<TermionBackend<AlternateScreen<RawTerminal<std::io::Stdout>>>> {
+ pub fn terminal_mut(&mut self) -> &mut JoshutoTerminal {
self.terminal.as_mut().unwrap()
}
diff --git a/src/ui/views/tui_worker_view.rs b/src/ui/views/tui_worker_view.rs
index 536c45a..58eaef2 100644
--- a/src/ui/views/tui_worker_view.rs
+++ b/src/ui/views/tui_worker_view.rs
@@ -1,12 +1,12 @@
-use termion::event::Key;
+use termion::event::{Event, Key};
use tui::layout::Rect;
use crate::context::JoshutoContext;
use crate::ui::widgets::TuiWorker;
use crate::ui::TuiBackend;
-use crate::util::event::Event;
-use crate::util::worker;
+use crate::util::event::JoshutoEvent;
+use crate::util::input_process;
pub struct TuiWorkerView {}
@@ -33,21 +33,16 @@ impl TuiWorkerView {
if let Ok(event) = context.poll_event() {
match event {
- Event::IOWorkerProgress(res) => {
- worker::process_worker_progress(context, res);
- }
- Event::IOWorkerResult(res) => {
- worker::process_finished_worker(context, res);
- }
- Event::Input(key) => {
- match key {
- Key::Esc => {
+ JoshutoEvent::Termion(event) => {
+ match event {
+ Event::Key(Key::Esc) => {
break;
}
_ => {}
}
context.flush_event();
}
+ event => input_process::process_noninteractive(event, context),
};
}
}
diff --git a/src/ui/widgets/tui_menu.rs b/src/ui/widgets/tui_menu.rs
index d8fc148..38eed64 100644
--- a/src/ui/widgets/tui_menu.rs
+++ b/src/ui/widgets/tui_menu.rs
@@ -1,6 +1,6 @@
use std::iter::Iterator;
-use termion::event::Key;
+use termion::event::{Event, Key};
use tui::buffer::Buffer;
use tui::layout::Rect;
use tui::style::{Color, Style};
@@ -11,42 +11,15 @@ use crate::config::JoshutoCommandMapping;
use crate::context::JoshutoContext;
use crate::ui::views::TuiView;
use crate::ui::TuiBackend;
-use crate::util::event::Event;
-use crate::util::worker;
+use crate::util::event::JoshutoEvent;
+use crate::util::input_process;
+use crate::util::key_mapping::ToString;
const BORDER_HEIGHT: usize = 1;
const BOTTOM_MARGIN: usize = 1;
pub struct TuiCommandMenu;
-trait ToString {
- fn to_string(&self) -> String;
-}
-
-impl ToString for Key {
- fn to_string(&self) -> String {
- match *self {
- Key::Char(c) => format!("{}", c),
- Key::Ctrl(c) => format!("ctrl+{}", c),
- Key::Left => "arrow_left".to_string(),
- Key::Right => "arrow_right".to_string(),
- Key::Up => "arrow_up".to_string(),
- Key::Down => "arrow_down".to_string(),
- Key::Backspace => "backspace".to_string(),
- Key::Home => "home".to_string(),
- Key::End => "end".to_string(),
- Key::PageUp => "page_up".to_string(),
- Key::PageDown => "page_down".to_string(),
- Key::BackTab => "backtab".to_string(),
- Key::Insert => "insert".to_string(),
- Key::Delete => "delete".to_string(),
- Key::Esc => "escape".to_string(),
- Key::F(i) => format!("f{}", i),
- k => format!("{:?}", k),
- }
- }
-}
-
impl TuiCommandMenu {
pub fn new() -> Self {
Self {}
@@ -107,16 +80,10 @@ impl TuiCommandMenu {
if let Ok(event) = context.poll_event() {
match event {
- Event::IOWorkerProgress(res) => {
- worker::process_worker_progress(context, res);
- }
- Event::IOWorkerResult(res) => {
- worker::process_finished_worker(context, res);
- }
- Event::Input(key) => {
- match key {
- Key::Esc => return None,
- key => match map.as_ref().get(&key) {
+ JoshutoEvent::Termion(event) => {
+ match event {
+ Event::Key(Key::Esc) => return None,
+ event => match map.as_ref().get(&event) {
Some(CommandKeybind::SimpleKeybind(s)) => {
return Some(s);
}
@@ -128,6 +95,7 @@ impl TuiCommandMenu {
}
context.flush_event();
}
+ event => input_process::process_noninteractive(event, context),
}
}
}
diff --git a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs
index f520de9..c4d0c1c 100644
--- a/src/ui/widgets/tui_prompt.rs
+++ b/src/ui/widgets/tui_prompt.rs
@@ -1,4 +1,4 @@
-use termion::event::Key;
+use termion::event::{Event, Key};
use tui::layout::Rect;
use tui::style::{Color, Style};
use tui::text::Span;
@@ -7,8 +7,8 @@ use tui::widgets::{Clear, Paragraph, Wrap};
use crate::context::JoshutoContext;
use crate::ui::views::TuiView;
use crate::ui::TuiBackend;
-use crate::util::event::Event;
-use crate::util::worker;
+use crate::util::event::JoshutoEvent;
+use crate::util::input_process;
pub struct TuiPrompt<'a> {
prompt: &'a str,
@@ -56,15 +56,13 @@ impl<'a> TuiPrompt<'a> {
if let Ok(event) = context.poll_event() {
match event {
- Event::IOWorkerProgress(res) => {
- worker::process_worker_progress(context, res);
- }
- Event::IOWorkerResult(res) => {
- worker::process_finished_worker(context, res);
- }
- Event::Input(key) => {
+ JoshutoEvent::Termion(Event::Key(key)) => {
return key;
}
+ JoshutoEvent::Termion(_) => {
+ context.flush_event();
+ }
+ event => input_process::process_noninteractive(event, context),
};
}
}
diff --git a/src/ui/widgets/tui_textfield.rs b/src/ui/widgets/tui_textfield.rs
index c70c079..d6e9371 100644
--- a/src/ui/widgets/tui_textfield.rs
+++ b/src/ui/widgets/tui_textfield.rs
@@ -1,7 +1,7 @@
use rustyline::completion::{Candidate, Completer, FilenameCompleter, Pair};
use rustyline::line_buffer;
-use termion::event::Key;
+use termion::event::{Event, Key};
use tui::layout::Rect;
use tui::style::{Color, Modifier, Style};
use tui::text::{Span, Spans};
@@ -11,8 +11,8 @@ use crate::context::JoshutoContext;
use crate::ui::views::TuiView;
use crate::ui::widgets::TuiMenu;
use crate::ui::TuiBackend;
-use crate::util::event::Event;
-use crate::util::worker;
+use crate::util::event::JoshutoEvent;
+use crate::util::input_process;
struct CompletionTracker {
pub index: usize,
@@ -159,13 +159,7 @@ impl<'a> TuiTextField<'a> {
if let Ok(event) = context.poll_event() {
match event {
- Event::IOWorkerProgress(res) => {
- worker::process_worker_progress(context, res);
- }
- Event::IOWorkerResult(res) => {
- worker::process_finished_worker(context, res);
- }
- Event::Input(key) => {
+ JoshutoEvent::Termion(Event::Key(key)) => {
match key {
Key::Backspace => {
if line_buffer.backspace(1) {
@@ -243,6 +237,10 @@ impl<'a> TuiTextField<'a> {
}
context.flush_event();
}
+ JoshutoEvent::Termion(_) => {
+ context.flush_event();
+ }
+ event => input_process::process_noninteractive(event, context),
};
}
}
diff --git a/src/util/event.rs b/src/util/event.rs
index 9e7f120..4d79035 100644
--- a/src/util/event.rs
+++ b/src/util/event.rs
@@ -2,16 +2,21 @@ use std::io;
use std::sync::mpsc;
use std::thread;
-use termion::event::Key;
+use signal_hook::consts::signal;
+use signal_hook::iterator::exfiltrator::SignalOnly;
+use signal_hook::iterator::SignalsInfo;
+
+use termion::event::Event;
use termion::input::TermRead;
use crate::io::IOWorkerProgress;
#[derive(Debug)]
-pub enum Event {
- Input(Key),
+pub enum JoshutoEvent {
+ Termion(Event),
IOWorkerProgress(IOWorkerProgress),
IOWorkerResult(io::Result<IOWorkerProgress>),
+ Signal(i32),
// Filesystem(notify::Result),
}
@@ -27,10 +32,9 @@ impl Default for Config {
/// A small event handler that wrap termion input and tick events. Each event
/// type is handled in its own thread and returned to a common `Receiver`
pub struct Events {
- pub event_tx: mpsc::Sender<Event>,
- event_rx: mpsc::Receiver<Event>,
+ pub event_tx: mpsc::Sender<JoshutoEvent>,
+ event_rx: mpsc::Receiver<JoshutoEvent>,
pub input_tx: mpsc::SyncSender<()>,
- fileio_handle: thread::JoinHandle<()>,
}
impl Events {
@@ -42,15 +46,28 @@ impl Events {
let (input_tx, input_rx) = mpsc::sync_channel(1);
let (event_tx, event_rx) = mpsc::channel();
+ // signal thread
let event_tx2 = event_tx.clone();
+ let _ = thread::spawn(move || {
+ let sigs = vec![signal::SIGWINCH];
+ let mut signals = SignalsInfo::<SignalOnly>::new(&sigs).unwrap();
+ for signal in &mut signals {
+ if let Err(e) = event_tx2.send(JoshutoEvent::Signal(signal)) {
+ eprintln!("Signal thread send err: {:#?}", e);
+ return;
+ }
+ }
+ });
- let fileio_handle = thread::spawn(move || {
+ // input thread
+ let event_tx2 = event_tx.clone();
+ let _ = thread::spawn(move || {
let stdin = io::stdin();
- let mut keys = stdin.keys();
- match keys.next() {
- Some(key) => match key {
- Ok(key) => {
- if let Err(e) = event_tx2.send(Event::Input(key)) {
+ let mut events = stdin.events();
+ match events.next() {
+ Some(event) => match event {
+ Ok(event) => {
+ if let Err(e) = event_tx2.send(JoshutoEvent::Termion(event)) {
eprintln!("Input thread send err: {:#?}", e);
return;
}
@@ -61,9 +78,9 @@ impl Events {
}
while input_rx.recv().is_ok() {
- if let Some(key) = keys.next() {
- if let Ok(key) = key {
- if let Err(e) = event_tx2.send(Event::Input(key)) {
+ if let Some(event) = events.next() {
+ if let Ok(event) = event {
+ if let Err(e) = event_tx2.send(JoshutoEvent::Termion(event)) {
eprintln!("Input thread send err: {:#?}", e);
return;
}
@@ -76,11 +93,10 @@ impl Events {
event_tx,
event_rx,
input_tx,
- fileio_handle,
}
}
- pub fn next(&self) -> Result<Event, mpsc::RecvError> {
+ pub fn next(&self) -> Result<JoshutoEvent, mpsc::RecvError> {
let event = self.event_rx.recv()?;
Ok(event)
}
diff --git a/src/util/worker.rs b/src/util/input_process.rs
index f3631fd..362d87b 100644
--- a/src/util/worker.rs
+++ b/src/util/input_process.rs
@@ -1,8 +1,20 @@
+use signal_hook::consts::signal;
+
use crate::context::JoshutoContext;
use crate::history::DirectoryHistory;
use crate::io::{FileOp, IOWorkerProgress};
+use crate::ui;
+use crate::util::event::JoshutoEvent;
+use crate::util::format;
-use super::format;
+pub fn process_noninteractive(event: JoshutoEvent, context: &mut JoshutoContext) {
+ match event {
+ JoshutoEvent::IOWorkerProgress(res) => process_worke