Number input

This commit is contained in:
Arijit Basu 2021-03-15 14:49:30 +05:30
parent 53b18ae8f4
commit 98920637f9
No known key found for this signature in database
GPG Key ID: 7D7BF809E7378863
6 changed files with 112 additions and 112 deletions

2
Cargo.lock generated
View File

@ -1133,7 +1133,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xplr"
version = "0.1.12"
version = "0.1.13"
dependencies = [
"criterion",
"crossterm",

View File

@ -1,6 +1,6 @@
[package]
name = "xplr"
version = "0.1.12" # Update app.rs
version = "0.1.13" # Update app.rs
authors = ["Arijit Basu <sayanarijit@gmail.com>"]
edition = "2018"
description = "An experimental, minimal, configurable TUI file explorer, stealing ideas from nnn and fzf."

View File

@ -12,7 +12,7 @@ use std::io::BufReader;
use std::path::Path;
use std::path::PathBuf;
pub const VERSION: &str = "v0.1.12"; // Update Cargo.toml
pub const VERSION: &str = "v0.1.13"; // Update Cargo.toml
pub const UNSUPPORTED_STR: &str = "???";
pub const TOTAL_ROWS: usize = 50;
@ -300,6 +300,7 @@ pub struct App {
pub parsed_help_menu: Vec<(String, String)>,
pub show_hidden: bool,
pub task: Task,
pub number_input: usize,
}
impl App {
@ -311,6 +312,7 @@ impl App {
mode: Mode,
show_hidden: bool,
focus: Option<usize>,
number_input: usize,
) -> Result<Self, Error> {
let directory_buffer =
DirectoryBuffer::load(config, focus.or(Some(0)), &pwd, show_hidden, selected_paths)?;
@ -336,6 +338,7 @@ impl App {
parsed_help_menu,
show_hidden,
task: Task::NoOp,
number_input: number_input,
})
}
@ -348,6 +351,7 @@ impl App {
self.mode,
self.show_hidden,
self.directory_buffer.focus,
0,
)
}
@ -367,6 +371,20 @@ impl App {
mode,
self.show_hidden,
self.directory_buffer.focus,
0,
)
}
pub fn number_input(self, n: u8) -> Result<Self, Error> {
Self::new(
&self.config,
&self.directory_buffer.pwd,
&self.saved_buffers,
&self.selected_paths,
self.mode,
self.show_hidden,
self.directory_buffer.focus,
self.number_input * 10 + n as usize,
)
}
@ -379,6 +397,7 @@ impl App {
self.mode,
!self.show_hidden,
self.directory_buffer.focus,
0,
)
}
@ -397,6 +416,7 @@ impl App {
self.mode,
self.show_hidden,
focus,
0,
)
}
@ -415,6 +435,7 @@ impl App {
self.mode,
self.show_hidden,
focus,
0,
)
}
@ -429,10 +450,11 @@ impl App {
pub fn focus_next(self) -> Result<Self, Error> {
let len = self.directory_buffer.total;
let step = self.number_input.max(1);
let focus = self
.directory_buffer
.focus
.map(|f| (len - 1).min(f + 1))
.map(|f| (len.max(1) - 1).min(f + step))
.or(Some(0));
Self::new(
@ -443,18 +465,20 @@ impl App {
self.mode,
self.show_hidden,
focus,
0,
)
}
pub fn focus_previous(self) -> Result<Self, Error> {
let len = self.directory_buffer.total;
let step = self.number_input.max(1);
let focus = if len == 0 {
None
} else {
self.directory_buffer
.focus
.map(|f| Some(1.max(f) - 1))
.unwrap_or(Some(len - 1))
.map(|f| Some(step.max(f) - step))
.unwrap_or(Some(step.max(len) - step))
};
Self::new(
@ -465,6 +489,7 @@ impl App {
self.mode,
self.show_hidden,
focus,
0,
)
}
@ -493,6 +518,7 @@ impl App {
self.mode.clone(),
self.show_hidden,
focus,
0,
)
})
.unwrap_or_else(|| Ok(self.to_owned()))
@ -507,6 +533,7 @@ impl App {
self.mode.clone(),
self.show_hidden,
Some(idx.clone()),
0,
)
}
@ -519,6 +546,7 @@ impl App {
self.mode.clone(),
self.show_hidden,
Some(DirectoryBuffer::relative_focus(idx.clone())),
0,
)
}
@ -533,39 +561,51 @@ impl App {
self.directory_buffer
.focus
.map(|f| ((f as isize) + idx).min(0) as usize), // TODO: make it safer
0,
)
}
pub fn enter(self) -> Result<Self, Error> {
let pwd = self
.directory_buffer
.focused()
.map(|(p, _)| p)
.map(|p| {
if p.is_dir() {
p
} else {
self.directory_buffer.pwd.clone()
}
})
.unwrap_or_else(|| self.directory_buffer.pwd.clone());
pub fn enter(mut self) -> Result<Self, Error> {
let mut step = self.number_input.max(1);
while step > 0 {
let pwd = self
.directory_buffer
.focused()
.map(|(p, _)| p)
.map(|p| {
if p.is_dir() {
p
} else {
self.directory_buffer.pwd.clone()
}
})
.unwrap_or_else(|| self.directory_buffer.pwd.clone());
let focus = self.saved_buffers.get(&pwd).unwrap_or(&None);
let focus = self.saved_buffers.get(&pwd).unwrap_or(&None);
Self::new(
&self.config,
&pwd,
&self.saved_buffers,
&self.selected_paths,
self.mode,
self.show_hidden,
focus.clone(),
)
self = Self::new(
&self.config,
&pwd,
&self.saved_buffers,
&self.selected_paths,
self.mode,
self.show_hidden,
focus.clone(),
0,
)?;
step -= 1;
}
Ok(self)
}
pub fn back(self) -> Result<Self, Error> {
let pwd = self.directory_buffer.pwd.clone();
self.focus_path(&pwd)
pub fn back(mut self) -> Result<Self, Error> {
let mut step = self.number_input.max(1);
while step > 0 {
let pwd = self.directory_buffer.pwd.clone();
self = self.focus_path(&pwd)?;
step -= 1;
}
Ok(self)
}
pub fn select(self) -> Result<Self, Error> {
@ -587,6 +627,7 @@ impl App {
Mode::Select,
self.show_hidden,
self.directory_buffer.focus,
0,
)
}
@ -619,6 +660,7 @@ impl App {
mode,
self.show_hidden,
self.directory_buffer.focus,
0,
)
}
@ -638,6 +680,7 @@ impl App {
mode,
self.show_hidden,
self.directory_buffer.focus,
self.number_input,
)
}
@ -693,11 +736,15 @@ impl App {
}
pub fn actions_from_key(&self, key: &Key) -> Option<Vec<Action>> {
self.parsed_key_bindings.get(key).map(|(_, a)| a.to_owned())
match key {
Key::Number(n) => Some(vec![Action::NumberInput(*n)]),
key => self.parsed_key_bindings.get(key).map(|(_, a)| a.to_owned()),
}
}
pub fn handle(self, action: &Action) -> Result<Self, Error> {
match action {
Action::NumberInput(n) => self.number_input(*n),
Action::ToggleShowHidden => self.toggle_hidden(),
Action::Back => self.back(),
Action::Enter => self.enter(),
@ -763,6 +810,7 @@ pub fn create() -> Result<App, Error> {
Mode::Explore,
config.general.show_hidden,
None,
0,
)?;
if let Some(file) = file_to_focus {

View File

@ -43,6 +43,7 @@ impl Mode {
match (self, action) {
// Special
(_, Action::Terminate) => true,
(_, Action::NumberInput(_)) => true,
// Explore mode
(Self::Explore, Action::Back) => true,
@ -126,6 +127,7 @@ pub struct CommandConfig {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Action {
NumberInput(u8),
ToggleShowHidden,
Back,
Enter,

View File

@ -4,6 +4,8 @@ use termion::event::Key as TermionKey;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Key {
Number(u8),
Backspace,
Left,
Right,
@ -21,50 +23,6 @@ pub enum Key {
Tab,
Esc,
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
CtrlZero,
CtrlOne,
CtrlTwo,
CtrlThree,
CtrlFour,
CtrlFive,
CtrlSix,
CtrlSeven,
CtrlEight,
CtrlNine,
AltZero,
AltOne,
AltTwo,
AltThree,
AltFour,
AltFive,
AltSix,
AltSeven,
AltEight,
AltNine,
ShiftZero,
ShiftOne,
ShiftTwo,
ShiftThree,
ShiftFour,
ShiftFive,
ShiftSix,
ShiftSeven,
ShiftEight,
ShiftNine,
A,
B,
C,
@ -256,6 +214,17 @@ impl std::fmt::Display for Key {
impl Key {
pub fn from_termion_event(key: TermionKey) -> Self {
match key {
TermionKey::Char('0') => Key::Number(0),
TermionKey::Char('1') => Key::Number(1),
TermionKey::Char('2') => Key::Number(2),
TermionKey::Char('3') => Key::Number(3),
TermionKey::Char('4') => Key::Number(4),
TermionKey::Char('5') => Key::Number(5),
TermionKey::Char('6') => Key::Number(6),
TermionKey::Char('7') => Key::Number(7),
TermionKey::Char('8') => Key::Number(8),
TermionKey::Char('9') => Key::Number(9),
TermionKey::Backspace => Key::Backspace,
TermionKey::Left => Key::Left,
TermionKey::Right => Key::Right,
@ -273,39 +242,6 @@ impl Key {
TermionKey::Char('\t') => Key::Tab,
TermionKey::Esc => Key::Esc,
TermionKey::Char('0') => Key::Zero,
TermionKey::Char('1') => Key::One,
TermionKey::Char('2') => Key::Two,
TermionKey::Char('3') => Key::Three,
TermionKey::Char('4') => Key::Four,
TermionKey::Char('5') => Key::Five,
TermionKey::Char('6') => Key::Six,
TermionKey::Char('7') => Key::Seven,
TermionKey::Char('8') => Key::Eight,
TermionKey::Char('9') => Key::Nine,
TermionKey::Ctrl('0') => Key::CtrlZero,
TermionKey::Ctrl('1') => Key::CtrlOne,
TermionKey::Ctrl('2') => Key::CtrlTwo,
TermionKey::Ctrl('3') => Key::CtrlThree,
TermionKey::Ctrl('4') => Key::CtrlFour,
TermionKey::Ctrl('5') => Key::CtrlFive,
TermionKey::Ctrl('6') => Key::CtrlSix,
TermionKey::Ctrl('7') => Key::CtrlSeven,
TermionKey::Ctrl('8') => Key::CtrlEight,
TermionKey::Ctrl('9') => Key::CtrlNine,
TermionKey::Alt('0') => Key::AltZero,
TermionKey::Alt('1') => Key::AltOne,
TermionKey::Alt('2') => Key::AltTwo,
TermionKey::Alt('3') => Key::AltThree,
TermionKey::Alt('4') => Key::AltFour,
TermionKey::Alt('5') => Key::AltFive,
TermionKey::Alt('6') => Key::AltSix,
TermionKey::Alt('7') => Key::AltSeven,
TermionKey::Alt('8') => Key::AltEight,
TermionKey::Alt('9') => Key::AltNine,
TermionKey::Char('a') => Key::A,
TermionKey::Char('b') => Key::B,
TermionKey::Char('c') => Key::C,

View File

@ -2,7 +2,9 @@ use crate::app;
use handlebars::Handlebars;
use tui::backend::Backend;
use tui::layout::{Constraint as TUIConstraint, Direction, Layout};
use tui::widgets::{Block, Borders, Cell, List, ListItem, ListState, Row, Table, TableState};
use tui::widgets::{
Block, Borders, Cell, List, ListItem, ListState, Paragraph, Row, Table, TableState,
};
use tui::Frame;
pub fn draw<B: Backend>(
@ -105,7 +107,14 @@ pub fn draw<B: Backend>(
let left_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([TUIConstraint::Percentage(40), TUIConstraint::Percentage(60)].as_ref())
.constraints(
[
TUIConstraint::Percentage(40),
TUIConstraint::Percentage(50),
TUIConstraint::Min(1),
]
.as_ref(),
)
.split(chunks[1]);
let selected: Vec<ListItem> = app
@ -141,7 +150,12 @@ pub fn draw<B: Backend>(
)
.widths(&[TUIConstraint::Percentage(40), TUIConstraint::Percentage(60)]);
// Input box
let input_box = Paragraph::new(format!("> {}", &app.number_input))
.block(Block::default().borders(Borders::ALL).title(" input "));
f.render_stateful_widget(table, chunks[0], table_state);
f.render_stateful_widget(selected_list, left_chunks[0], list_state);
f.render_widget(help_menu, left_chunks[1]);
f.render_widget(input_box, left_chunks[2]);
}