Show help menu

pull/3/head
Arijit Basu 3 years ago
parent 7beaec1763
commit 669151c70e
No known key found for this signature in database
GPG Key ID: 7D7BF809E7378863

@ -8,13 +8,13 @@ Example usage:
```bash ```bash
# Edit file # Edit file
vim $(xplr) vim "$(xplr)"
# Copy file(s) # Copy file(s)
cp $(xplr) $(xplr) cp "$(xplr)" "$(xplr)/"
# Search and move file # Search and move file
mv $(fzf) $(xplr) mv "$(fzf)" "$(xplr)/"
``` ```

@ -254,6 +254,26 @@ pub struct DirectoryItemMetadata {
pub total: usize, pub total: usize,
} }
pub fn parse_help_menu<'a>(
kb: impl Iterator<Item = (&'a Key, &'a (String, Vec<Action>))>,
) -> Vec<(String, String)> {
let mut m = kb
.map(|(k, a)| {
(
a.0.clone(),
serde_yaml::to_string(k)
.unwrap()
.strip_prefix("---")
.unwrap_or_default()
.trim()
.to_string(),
)
})
.collect::<Vec<(String, String)>>();
m.sort();
m
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct App { pub struct App {
pub version: String, pub version: String,
@ -263,6 +283,7 @@ pub struct App {
pub selected_paths: HashSet<PathBuf>, pub selected_paths: HashSet<PathBuf>,
pub mode: Mode, pub mode: Mode,
pub parsed_key_bindings: HashMap<Key, (String, Vec<Action>)>, pub parsed_key_bindings: HashMap<Key, (String, Vec<Action>)>,
pub parsed_help_menu: Vec<(String, String)>,
pub show_hidden: bool, pub show_hidden: bool,
pub call: Option<CommandConfig>, pub call: Option<CommandConfig>,
pub result: Option<String>, pub result: Option<String>,
@ -289,6 +310,8 @@ impl App {
let parsed_key_bindings = config.key_bindings.clone().filtered(&mode); let parsed_key_bindings = config.key_bindings.clone().filtered(&mode);
let parsed_help_menu = parse_help_menu(parsed_key_bindings.iter());
Ok(Self { Ok(Self {
version: VERSION.into(), version: VERSION.into(),
config: config.to_owned(), config: config.to_owned(),
@ -297,6 +320,7 @@ impl App {
selected_paths: selected_paths.to_owned(), selected_paths: selected_paths.to_owned(),
mode, mode,
parsed_key_bindings, parsed_key_bindings,
parsed_help_menu,
show_hidden, show_hidden,
result: None, result: None,
call: None, call: None,
@ -526,8 +550,8 @@ impl App {
} }
pub fn back(self) -> Result<Self, Error> { pub fn back(self) -> Result<Self, Error> {
let app = self.clone(); let pwd = self.directory_buffer.pwd.clone();
self.focus_path(&app.directory_buffer.pwd) self.focus_path(&pwd)
} }
pub fn select(self) -> Result<Self, Error> { pub fn select(self) -> Result<Self, Error> {
@ -541,10 +565,15 @@ impl App {
}) })
.unwrap_or_else(|| self.selected_paths.clone()); .unwrap_or_else(|| self.selected_paths.clone());
let mut app = self; Self::new(
app.selected_paths = selected_paths; &self.config,
app.mode = Mode::Select; &self.directory_buffer.pwd,
Ok(app) &self.saved_buffers,
&selected_paths,
Mode::Select,
self.show_hidden,
self.directory_buffer.focus,
)
} }
pub fn toggle_selection(self) -> Result<Self, Error> { pub fn toggle_selection(self) -> Result<Self, Error> {
@ -568,16 +597,34 @@ impl App {
Mode::Select Mode::Select
}; };
let mut app = self; Self::new(
app.selected_paths = selected_paths; &self.config,
app.mode = mode; &self.directory_buffer.pwd,
Ok(app) &self.saved_buffers,
&selected_paths,
mode,
self.show_hidden,
self.directory_buffer.focus,
)
} }
pub fn enter_submode(self, submode: &String) -> Result<Self, Error> { pub fn enter_submode(self, submode: &String) -> Result<Self, Error> {
let mut app = self; let mode = match self.mode {
app.mode = Mode::ExploreSubmode(submode.clone()); Mode::Explore => Mode::ExploreSubmode(submode.clone()),
Ok(app) Mode::ExploreSubmode(_) => Mode::ExploreSubmode(submode.clone()),
Mode::Select => Mode::SelectSubmode(submode.clone()),
Mode::SelectSubmode(_) => Mode::SelectSubmode(submode.clone()),
};
Self::new(
&self.config,
&self.directory_buffer.pwd,
&self.saved_buffers,
&self.selected_paths,
mode,
self.show_hidden,
self.directory_buffer.focus,
)
} }
pub fn print_focused(self) -> Result<Self, Error> { pub fn print_focused(self) -> Result<Self, Error> {

@ -1,5 +1,5 @@
use termion::event::Key as TermionKey;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use termion::event::Key as TermionKey;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -246,6 +246,12 @@ pub enum Key {
NotSupported, NotSupported,
} }
impl std::fmt::Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl Key { impl Key {
pub fn from_termion_event(key: TermionKey) -> Self { pub fn from_termion_event(key: TermionKey) -> Self {
match key { match key {

@ -48,7 +48,15 @@ fn main() -> Result<(), Error> {
let mut list_state = ListState::default(); let mut list_state = ListState::default();
term::enable_raw_mode().unwrap(); term::enable_raw_mode().unwrap();
terminal.draw(|f| ui::draw(&app, &hb, f, &mut table_state, &mut list_state))?; terminal.draw(|f| {
ui::draw(
&app,
&hb,
f,
&mut table_state,
&mut list_state,
)
})?;
let mut result = Ok(()); let mut result = Ok(());
'outer: for key in keys { 'outer: for key in keys {
@ -56,8 +64,15 @@ fn main() -> Result<(), Error> {
for action in actions.iter() { for action in actions.iter() {
app = match app.handle(action) { app = match app.handle(action) {
Ok(mut a) => { Ok(mut a) => {
terminal terminal.draw(|f| {
.draw(|f| ui::draw(&a, &hb, f, &mut table_state, &mut list_state))?; ui::draw(
&a,
&hb,
f,
&mut table_state,
&mut list_state,
)
})?;
if let Some(result) = a.result.clone() { if let Some(result) = a.result.clone() {
term::disable_raw_mode().unwrap(); term::disable_raw_mode().unwrap();
@ -89,7 +104,13 @@ fn main() -> Result<(), Error> {
terminal = Terminal::new(backend)?; terminal = Terminal::new(backend)?;
a = a.refresh()?; a = a.refresh()?;
terminal.draw(|f| { terminal.draw(|f| {
ui::draw(&a, &hb, f, &mut table_state, &mut list_state) ui::draw(
&a,
&hb,
f,
&mut table_state,
&mut list_state,
)
})?; })?;
}; };

@ -102,7 +102,11 @@ pub fn draw<B: Backend>(
.focus .focus
.map(app::DirectoryBuffer::relative_focus), .map(app::DirectoryBuffer::relative_focus),
); );
f.render_stateful_widget(table, chunks[0], table_state);
let left_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([TUIConstraint::Percentage(40), TUIConstraint::Percentage(60)].as_ref())
.split(chunks[1]);
let selected: Vec<ListItem> = app let selected: Vec<ListItem> = app
.selected_paths .selected_paths
@ -120,5 +124,20 @@ pub fn draw<B: Backend>(
.borders(Borders::ALL) .borders(Borders::ALL)
.title(format!(" Selected ({}) ", selected_count)), .title(format!(" Selected ({}) ", selected_count)),
); );
f.render_stateful_widget(selected_list, chunks[1], list_state);
// Help menu
let help_menu_rows: Vec<Row> = app
.parsed_help_menu
.clone()
.iter()
.map(|(h, k)| Row::new(vec![Cell::from(h.to_string()), Cell::from(k.to_string())]))
.collect();
let help_menu = Table::new(help_menu_rows)
.block(Block::default().borders(Borders::ALL).title(" Help "))
.widths(&[TUIConstraint::Percentage(40), TUIConstraint::Percentage(60)]);
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]);
} }

Loading…
Cancel
Save