summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2020-02-24 13:45:36 -0500
committerJiayi Zhao <jeff.no.zhao@gmail.com>2020-02-24 14:05:16 -0500
commit72111d986965861fa694f8a111b712fdad76b6bc (patch)
treee26951aee33dccb5986f8861e4594231cfc9d8a4 /src
parentd38dcdbbee44187bdb605dbf9bbf9c6c6d3e4f35 (diff)
fix open_file_with
- fix event to not consume the first few inputs on switching to a terminal program
Diffstat (limited to 'src')
-rw-r--r--src/commands/mod.rs6
-rw-r--r--src/commands/open_file.rs83
-rw-r--r--src/commands/rename_file.rs4
-rw-r--r--src/config/mimetype.rs76
-rw-r--r--src/fs/dirlist.rs6
-rw-r--r--src/run.rs3
-rw-r--r--src/ui/tui_backend.rs24
-rw-r--r--src/ui/widgets/tui_menu.rs7
-rw-r--r--src/ui/widgets/tui_prompt.rs3
-rw-r--r--src/ui/widgets/tui_textfield.rs49
-rw-r--r--src/util/event.rs24
11 files changed, 153 insertions, 132 deletions
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 724b5ad..6d31197 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -27,7 +27,7 @@ pub use self::cursor_move::{
pub use self::delete_files::DeleteFiles;
pub use self::file_ops::{CopyFiles, CutFiles, PasteFiles};
pub use self::new_directory::NewDirectory;
-pub use self::open_file::OpenFile; //, OpenFileWith};
+pub use self::open_file::{OpenFile, OpenFileWith};
pub use self::parent_directory::ParentDirectory;
pub use self::quit::ForceQuit;
pub use self::quit::Quit;
@@ -156,9 +156,7 @@ pub fn from_args(command: String, args: Vec<String>) -> JoshutoResult<Box<dyn Jo
"new_tab" => Ok(Box::new(self::NewTab::new())),
"open_file" => Ok(Box::new(self::OpenFile::new())),
- /*
- "open_file_with" => Ok(Box::new(self::OpenFileWith::new())),
- */
+ "open_file_with" => Ok(Box::new(self::OpenFileWith::new())),
"paste_files" => {
let mut options = Options::default();
for arg in args {
diff --git a/src/commands/open_file.rs b/src/commands/open_file.rs
index f41ee7e..2a900e0 100644
--- a/src/commands/open_file.rs
+++ b/src/commands/open_file.rs
@@ -55,7 +55,9 @@ impl OpenFile {
} else if let Some(paths) = filepaths {
let options = Self::get_options(paths[0]);
if options.len() > 0 {
+ backend.terminal_drop();
options[0].execute_with(&paths)?;
+ backend.terminal_restore();
} else {
}
}
@@ -77,7 +79,7 @@ impl JoshutoRunnable for OpenFile {
Ok(())
}
}
-/*
+
#[derive(Clone, Debug)]
pub struct OpenFileWith;
@@ -89,55 +91,43 @@ impl OpenFileWith {
"open_file_with"
}
- pub fn open_with(paths: &[&PathBuf]) -> std::io::Result<()> {
- const PROMPT: &str = ":open_with ";
-
+ pub fn open_with(context: &JoshutoContext, backend: &mut TuiBackend, paths: &[&PathBuf]) -> std::io::Result<()> {
let mimetype_options: Vec<&JoshutoMimetypeEntry> = OpenFile::get_options(&paths[0]);
- let user_input: Option<String> = {
- let (term_rows, term_cols) = ui::getmaxyx();
-
- let option_size = mimetype_options.len();
- let display_win = window::JoshutoPanel::new(
- option_size as i32 + 2,
- term_cols,
- (term_rows as usize - option_size - 2, 0),
- );
-
- let mut display_vec: Vec<String> = Vec::with_capacity(option_size);
- for (i, val) in mimetype_options.iter().enumerate() {
- display_vec.push(format!(" {}\t{}", i, val));
- }
- display_vec.sort();
- display_win.move_to_top();
- ui::display_menu(&display_win, &display_vec);
- ncurses::doupdate();
-
- let textfield =
- JoshutoTextField::new(1, term_cols, (term_rows as usize - 1, 0), PROMPT, "", "");
- textfield.readline()
- };
- ncurses::doupdate();
+ let mut textfield = TuiTextField::default()
+ .prompt(":")
+ .prefix("open_with ");
+ let user_input: Option<String> = textfield.get_input(backend, &context);
match user_input.as_ref() {
None => Ok(()),
- Some(user_input) if user_input.is_empty() => Ok(()),
Some(user_input) => match user_input.parse::<usize>() {
Ok(n) if n >= mimetype_options.len() => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"option does not exist".to_owned(),
)),
- Ok(n) => mimetype_options[n].execute_with(paths),
+ Ok(n) => {
+ backend.terminal_drop();
+ let res = mimetype_options[n].execute_with(paths);
+ backend.terminal_restore()?;
+ res
+ }
Err(_) => {
let mut args_iter = user_input.split_whitespace();
+ args_iter.next();
match args_iter.next() {
- Some(cmd) => JoshutoMimetypeEntry::new(String::from(cmd))
- .add_args(args_iter)
- .execute_with(paths),
+ Some(cmd) => {
+ backend.terminal_drop();
+ let res = JoshutoMimetypeEntry::new(String::from(cmd))
+ .args(args_iter)
+ .execute_with(paths);
+ backend.terminal_restore()?;
+ res
+ }
None => Ok(()),
}
}
- },
+ }
}
}
}
@@ -151,20 +141,21 @@ impl std::fmt::Display for OpenFileWith {
}
impl JoshutoRunnable for OpenFileWith {
- fn execute(&self, context: &mut JoshutoContext, _: &mut TuiBackend) -> JoshutoResult<()> {
- let curr_list = &context.tabs[context.curr_tab_index].curr_list;
- match curr_list.index {
- None => {
- return Err(JoshutoError::new(
- JoshutoErrorKind::IONotFound,
- String::from("No files selected"),
- ))
+ fn execute(&self, context: &mut JoshutoContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
+ let paths = match &context.tabs[context.curr_tab_index].curr_list_ref() {
+ Some(curr_list) => {
+ curr_list.get_selected_paths()
}
- Some(_) => {}
+ None => vec![],
+ };
+
+ if paths.is_empty() {
+ return Err(JoshutoError::new(
+ JoshutoErrorKind::IONotFound,
+ String::from("No files selected"),
+ ))
}
- let paths = curr_list.get_selected_paths();
- Self::open_with(&paths)?;
+ Self::open_with(context, backend, &paths)?;
Ok(())
}
}
-*/
diff --git a/src/commands/rename_file.rs b/src/commands/rename_file.rs
index 763a638..8d666d3 100644
--- a/src/commands/rename_file.rs
+++ b/src/commands/rename_file.rs
@@ -79,7 +79,7 @@ impl RenameFileAppend {
&self,
context: &mut JoshutoContext,
backend: &mut TuiBackend,
- file_name: String,
+ file_name: &str,
) -> JoshutoResult<()> {
let prefix;
let suffix;
@@ -115,7 +115,7 @@ impl JoshutoRunnable for RenameFileAppend {
}
if let Some(file_name) = file_name {
- self.rename_file(context, backend, file_name)?;
+ self.rename_file(context, backend, file_name.as_str())?;
}
Ok(())
}
diff --git a/src/config/mimetype.rs b/src/config/mimetype.rs
index 507b165..a4d6c44 100644
--- a/src/config/mimetype.rs
+++ b/src/config/mimetype.rs
@@ -14,78 +14,76 @@ const fn default_false() -> bool {
#[derive(Debug, Deserialize)]
pub struct JoshutoMimetypeEntry {
- command: String,
- #[serde(default)]
- args: Vec<String>,
- #[serde(default = "default_false")]
- fork: bool,
- #[serde(default = "default_false")]
- silent: bool,
- #[serde(default = "default_false")]
- confirm_exit: bool,
+ #[serde(rename = "command")]
+ _command: String,
+ #[serde(default, rename = "args")]
+ _args: Vec<String>,
+ #[serde(default, rename = "fork")]
+ _fork: bool,
+ #[serde(default, rename = "silent")]
+ _silent: bool,
+ #[serde(default, rename = "confirm_exit")]
+ _confirm_exit: bool,
}
-#[allow(dead_code)]
impl JoshutoMimetypeEntry {
pub fn new(command: String) -> Self {
Self {
- command,
- args: Vec::new(),
- fork: false,
- silent: false,
- confirm_exit: false,
+ _command: command,
+ _args: Vec::new(),
+ _fork: false,
+ _silent: false,
+ _confirm_exit: false,
}
}
- pub fn add_arg<S: std::convert::Into<String>>(&mut self, arg: S) -> &mut Self {
- self.args.push(arg.into());
+ pub fn arg<S: std::convert::Into<String>>(mut self, arg: S) -> Self {
+ self._args.push(arg.into());
self
}
- pub fn add_args<I, S>(&mut self, args: I) -> &mut Self
+ pub fn args<I, S>(mut self, args: I) -> Self
where
- I: IntoIterator<Item = S>,
+ I: Iterator<Item = S>,
S: std::convert::Into<String>,
{
- for arg in args {
- self.args.push(arg.into());
- }
+ args.for_each(|arg| self._args.push(arg.into()));
self
}
- pub fn set_fork(&mut self, set: bool) -> &mut Self {
- self.fork = set;
+ pub fn fork(mut self, fork: bool) -> Self {
+ self._fork = fork;
self
}
- pub fn set_silent(&mut self, set: bool) -> &mut Self {
- self.silent = set;
+ pub fn silent(mut self, silent: bool) -> Self {
+ self._silent = silent;
self
}
- pub fn set_confirm_exit(&mut self, set: bool) -> &mut Self {
- self.confirm_exit = set;
+ pub fn set_confirm_exit(mut self, confirm_exit: bool) -> Self {
+ self._confirm_exit = confirm_exit;
self
}
pub fn get_command(&self) -> &str {
- &self.command
+ self._command.as_str()
}
pub fn get_args(&self) -> &[String] {
- &self.args
+ &self._args
}
pub fn get_fork(&self) -> bool {
- self.fork
+ self._fork
}
pub fn get_silent(&self) -> bool {
- self.silent
+ self._silent
}
pub fn get_confirm_exit(&self) -> bool {
- self.confirm_exit
+ self._confirm_exit
}
pub fn execute_with(&self, paths: &[&PathBuf]) -> std::io::Result<()> {
@@ -112,6 +110,18 @@ impl JoshutoMimetypeEntry {
}
}
+impl std::default::Default for JoshutoMimetypeEntry {
+ fn default() -> Self {
+ Self {
+ _command: "".to_string(),
+ _args: Vec::new(),
+ _fork: false,
+ _silent: false,
+ _confirm_exit: false,
+ }
+ }
+}
+
impl std::fmt::Display for JoshutoMimetypeEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.get_command()).unwrap();
diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs
index cf53457..c099442 100644
--- a/src/fs/dirlist.rs
+++ b/src/fs/dirlist.rs
@@ -92,13 +92,13 @@ impl JoshutoDirList {
pub fn get_selected_paths(&self) -> Vec<&path::PathBuf> {
let vec: Vec<&path::PathBuf> = self.selected_entries().map(|e| e.file_path()).collect();
- if vec.is_empty() {
+ if !vec.is_empty() {
+ vec
+ } else {
match self.get_curr_ref() {
Some(s) => vec![s.file_path()],
_ => vec![],
}
- } else {
- vec
}
}
diff --git a/src/run.rs b/src/run.rs
index c532941..bb33c65 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -36,16 +36,13 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io:
let worker = context.worker_queue.pop_front().unwrap();
io_handle = {
let event_tx = context.events.event_tx.clone();
- let sync_tx = context.events.sync_tx.clone();
let thread = thread::spawn(move || {
worker.start();
while let Ok(evt) = worker.recv() {
let _ = event_tx.send(evt);
- let _ = sync_tx.send(());
}
worker.handle.join();
let _ = event_tx.send(Event::IOWorkerResult);
- let _ = sync_tx.send(());
});
Some(thread)
};
diff --git a/src/ui/tui_backend.rs b/src/ui/tui_backend.rs
index 446d1c0..498e3f6 100644
--- a/src/ui/tui_backend.rs
+++ b/src/ui/tui_backend.rs
@@ -1,10 +1,13 @@
+use std::io::Write;
+use std::io::stdout;
+
use termion::raw::{IntoRawMode, RawTerminal};
use termion::screen::AlternateScreen;
use tui::backend::TermionBackend;
use tui::widgets::Widget;
pub struct TuiBackend {
- pub terminal: tui::Terminal<TermionBackend<AlternateScreen<RawTerminal<std::io::Stdout>>>>,
+ pub terminal: Option<tui::Terminal<TermionBackend<AlternateScreen<RawTerminal<std::io::Stdout>>>>>,
}
impl TuiBackend {
@@ -14,16 +17,31 @@ impl TuiBackend {
let backend = TermionBackend::new(stdout);
let mut terminal = tui::Terminal::new(backend)?;
terminal.hide_cursor()?;
- Ok(Self { terminal })
+ Ok(Self { terminal: Some(terminal) })
}
pub fn render<W>(&mut self, widget: &mut W)
where
W: Widget,
{
- self.terminal.draw(|mut frame| {
+ self.terminal_mut().draw(|mut frame| {
let rect = frame.size();
widget.render(&mut frame, rect);
});
}
+
+ pub fn terminal_mut(&mut self) -> &mut tui::Terminal<TermionBackend<AlternateScreen<RawTerminal<std::io::Stdout>>>> {
+ self.terminal.as_mut().unwrap()
+ }
+
+ pub fn terminal_drop(&mut self) {
+ let _ = self.terminal.take();
+ stdout().flush();
+ }
+
+ pub fn terminal_restore(&mut self) -> std::io::Result<()> {
+ let mut new_backend = TuiBackend::new()?;
+ std::mem::swap(&mut self.terminal, &mut new_backend.terminal);
+ Ok(())
+ }
}
diff --git a/src/ui/widgets/tui_menu.rs b/src/ui/widgets/tui_menu.rs
index 9dde1fe..fdd291e 100644
--- a/src/ui/widgets/tui_menu.rs
+++ b/src/ui/widgets/tui_menu.rs
@@ -31,9 +31,10 @@ impl TuiCommandMenu {
m: &'a JoshutoCommandMapping,
) -> Option<&'a Box<dyn JoshutoCommand>> {
let mut map: &JoshutoCommandMapping = &m;
+ let mut terminal = backend.terminal_mut();
loop {
- backend.terminal.draw(|mut frame| {
+ terminal.draw(|mut frame| {
let f_size = frame.size();
{
@@ -101,6 +102,10 @@ impl<'a> TuiMenu<'a> {
pub fn new(options: &'a Vec<&str>) -> Self {
Self { options }
}
+
+ pub fn len(&self) -> usize {
+ self.options.len()
+ }
}
const LONG_SPACE: &str = " ";
diff --git a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs
index 21526f3..c01965a 100644
--- a/src/ui/widgets/tui_prompt.rs
+++ b/src/ui/widgets/tui_prompt.rs
@@ -20,8 +20,9 @@ impl<'a> TuiPrompt<'a> {
}
pub fn get_key(&mut self, backend: &mut TuiBackend, context: &JoshutoContext) -> Key {
+ let mut terminal = backend.terminal_mut();
loop {
- backend.terminal.draw(|mut frame| {
+ terminal.draw(|mut frame| {
let f_size = frame.size();
if f_size.height == 0 {
return;
diff --git a/src/ui/widgets/tui_textfield.rs b/src/ui/widgets/tui_textfield.rs
index 9dbbad3..6d89b14 100644
--- a/src/ui/widgets/tui_textfield.rs
+++ b/src/ui/widgets/tui_textfield.rs
@@ -9,7 +9,7 @@ use tui::backend::Backend;
use tui::layout::Rect;
use tui::style::{Color, Style};
use tui::widgets::{Block, Borders, List, Paragraph, Text, Widget};
-use unicode_width::UnicodeWidthStr;
+use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
use crate::context::JoshutoContext;
use crate::ui::TuiBackend;
@@ -77,25 +77,25 @@ impl<'a> TuiTextField<'a> {
._prefix
.char_indices()
.last()
- .map(|(i, c)| i)
+ .map(|(i, c)| i + c.width().unwrap_or(0))
.unwrap_or(0);
line_buffer.insert_str(0, self._prefix);
- line_buffer.insert_str(line_buffer.len(), self._suffix);
+ line_buffer.insert_str(char_idx, self._suffix);
line_buffer.set_pos(char_idx);
- backend.terminal.show_cursor();
- let mut cursor_xpos = line_buffer.pos() + 1;
+ let mut terminal = backend.terminal_mut();;
+ terminal.show_cursor();
+ let mut cursor_xpos = self._prefix.len() + 1;
{
- let frame = backend.terminal.get_frame();
+ let frame = terminal.get_frame();
let f_size = frame.size();
- backend
- .terminal
+ terminal
.set_cursor(cursor_xpos as u16, f_size.height - 1);
}
loop {
- backend.terminal.draw(|mut frame| {
+ terminal.draw(|mut frame| {
let f_size = frame.size();
if f_size.height == 0 {
return;
@@ -107,15 +107,21 @@ impl<'a> TuiTextField<'a> {
view.render(&mut frame, f_size);
}
- let top_rect = Rect {
- x: 0,
- y: 0,
- width: f_size.width,
- height: 1,
- };
-
if let Some(menu) = self._menu.as_mut() {
- menu.render(&mut frame, top_rect);
+ let menu_len = menu.len();
+ let menu_y = if menu_len + 1 > f_size.height as usize {
+ 0
+ } else {
+ (f_size.height as usize - menu_len - 1) as u16
+ };
+
+ let rect = Rect {
+ x: 0,
+ y: menu_y,
+ width: f_size.width,
+ height: menu_len as u16,
+ };
+ menu.render(&mut frame, rect);
}
let cmd_prompt_style = Style::default().fg(Color::LightGreen);
@@ -170,7 +176,7 @@ impl<'a> TuiTextField<'a> {
Event::Input(Key::Up) => {}
Event::Input(Key::Down) => {}
Event::Input(Key::Esc) => {
- backend.terminal.hide_cursor();
+ terminal.hide_cursor();
return None;
}
Event::Input(Key::Char('\t')) => {
@@ -213,14 +219,13 @@ impl<'a> TuiTextField<'a> {
}
cursor_xpos = line_buffer.pos() + 1;
{
- let frame = backend.terminal.get_frame();
+ let frame = terminal.get_frame();
let f_size = frame.size();
- backend
- .terminal
+ terminal
.set_cursor(cursor_xpos as u16, f_size.height - 1);
}
}
- backend.terminal.hide_cursor();
+ terminal.hide_cursor();
if line_buffer.as_str().is_empty() {
None
} else {
diff --git a/src/util/event.rs b/src/util/event.rs
index c6f8b85..5a76702 100644
--- a/src/util/event.rs
+++ b/src/util/event.rs
@@ -28,7 +28,6 @@ pub struct Events {
pub event_tx: mpsc::Sender<Event>,
event_rx: mpsc::Receiver<Event>,
pub sync_tx: mpsc::SyncSender<()>,
- sync_rx: mpsc::Receiver<()>,
// fileio_handle: thread::JoinHandle<()>,
}
@@ -46,23 +45,21 @@ impl Events {
let (event_tx, event_rx) = mpsc::channel();
{
- let sync_tx = sync_tx.clone();
let event_tx = event_tx.clone();
thread::spawn(move || {
let stdin = io::stdin();
let mut keys = stdin.keys();
- while let Some(evt) = keys.next() {
- match evt {
- Ok(key) => {
- if let Err(e) = event_tx.send(Event::Input(key)) {
- eprintln!("[{}] Input thread send err: {:#?}", prefix, e);
- return;
- }
- if let Err(_) = sync_tx.send(()) {
- return;
+ while let Ok(_) = sync_rx.recv() {
+ if let Some(evt) = keys.next() {
+ match evt {
+ Ok(key) => {
+ if let Err(e) = event_tx.send(Event::Input(key)) {
+ eprintln!("[{}] Input thread send err: {:#?}", prefix, e);
+ return;
+ }
}
+ _ => {}
}
- _ => {}
}
}
})
@@ -72,14 +69,13 @@ impl Events {
event_tx,
event_rx,
sync_tx,
- sync_rx,
prefix,
}
}
pub fn next(&self) -> Result<Event, mpsc::RecvError> {
+ self.sync_tx.try_send(());
let event = self.event_rx.recv()?;
- self.sync_rx.recv()?;
Ok(event)
}
/*