add initial help screen + keybinding -> command parsing

still needs some more work, i.e. to show commands in help instead of parsed data
structures, but it's a start.

fixes #117
fixes #121
This commit is contained in:
Henrik Friedrichsen
2020-02-02 21:51:40 +01:00
parent bf2a72ad81
commit fa960a4eba
6 changed files with 64 additions and 5 deletions

View File

@@ -60,6 +60,7 @@ the `portaudio_backend` feature:
These keybindings are hardcoded for now. In the future it may be desirable to These keybindings are hardcoded for now. In the future it may be desirable to
have them configurable. have them configurable.
* `?` show help screen
* Navigate through the screens using the F-keys: * Navigate through the screens using the F-keys:
* `F1`: Queue * `F1`: Queue
* `c` clears the entire queue * `c` clears the entire queue

View File

@@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use command::{Command, GotoMode, MoveMode, SeekDirection, ShiftMode, TargetMode}; use command::{parse, Command, GotoMode, MoveMode, SeekDirection, ShiftMode, TargetMode};
use cursive::event::{Event, Key}; use cursive::event::{Event, Key};
use cursive::traits::View; use cursive::traits::View;
use cursive::views::ViewRef; use cursive::views::ViewRef;
@@ -33,10 +33,18 @@ impl CommandManager {
spotify: Arc<Spotify>, spotify: Arc<Spotify>,
queue: Arc<Queue>, queue: Arc<Queue>,
library: Arc<Library>, library: Arc<Library>,
bindings: Option<HashMap<String, Command>>, bindings: Option<HashMap<String, String>>,
) -> CommandManager { ) -> CommandManager {
let mut kb = Self::default_keybindings(); let mut kb = Self::default_keybindings();
kb.extend(bindings.unwrap_or_default());
for (key, command) in bindings.unwrap_or_default() {
if let Some(command) = parse(&command) {
info!("Custom keybinding: {} -> {:?}", key, command);
kb.insert(key, command);
} else {
error!("Invalid command for key {}: {}", key, command);
}
}
CommandManager { CommandManager {
aliases: HashMap::new(), aliases: HashMap::new(),
@@ -240,6 +248,7 @@ impl CommandManager {
kb.insert("F1".into(), Command::Focus("queue".into())); kb.insert("F1".into(), Command::Focus("queue".into()));
kb.insert("F2".into(), Command::Focus("search".into())); kb.insert("F2".into(), Command::Focus("search".into()));
kb.insert("F3".into(), Command::Focus("library".into())); kb.insert("F3".into(), Command::Focus("library".into()));
kb.insert("?".into(), Command::Focus("help".into()));
kb.insert("Backspace".into(), Command::Back); kb.insert("Backspace".into(), Command::Back);
kb.insert("o".into(), Command::Open(TargetMode::Selected)); kb.insert("o".into(), Command::Open(TargetMode::Selected));

View File

@@ -10,7 +10,7 @@ pub const CLIENT_ID: &str = "d420a117a32841c2b3474932e49fb54b";
#[derive(Clone, Serialize, Deserialize, Debug, Default)] #[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct Config { pub struct Config {
pub keybindings: Option<HashMap<String, Command>>, pub keybindings: Option<HashMap<String, String>>,
pub theme: Option<ConfigTheme>, pub theme: Option<ConfigTheme>,
pub use_nerdfont: Option<bool>, pub use_nerdfont: Option<bool>,
pub proxy: Option<String>, pub proxy: Option<String>,

View File

@@ -214,6 +214,8 @@ fn main() {
let queueview = ui::queue::QueueView::new(queue.clone(), library.clone()); let queueview = ui::queue::QueueView::new(queue.clone(), library.clone());
let helpview = ui::help::HelpView::new(cmd_manager.keybindings().clone());
let status = ui::statusbar::StatusBar::new( let status = ui::statusbar::StatusBar::new(
queue.clone(), queue.clone(),
library.clone(), library.clone(),
@@ -223,7 +225,8 @@ fn main() {
let mut layout = ui::layout::Layout::new(status, &event_manager, theme) let mut layout = ui::layout::Layout::new(status, &event_manager, theme)
.view("search", search.with_name("search"), "Search") .view("search", search.with_name("search"), "Search")
.view("library", libraryview.with_name("library"), "Library") .view("library", libraryview.with_name("library"), "Library")
.view("queue", queueview, "Queue"); .view("queue", queueview, "Queue")
.view("help", helpview, "Help");
// initial view is library // initial view is library
layout.set_view("library"); layout.set_view("library");

45
src/ui/help.rs Normal file
View File

@@ -0,0 +1,45 @@
use std::collections::HashMap;
use cursive::theme::Effect;
use cursive::utils::markup::StyledString;
use cursive::view::ViewWrapper;
use cursive::views::{ScrollView, TextView};
use command::Command;
use config::config_path;
use traits::ViewExt;
pub struct HelpView {
view: ScrollView<TextView>,
}
impl HelpView {
pub fn new(bindings: HashMap<String, Command>) -> HelpView {
let mut text = StyledString::styled("Keybindings\n\n", Effect::Bold);
let note = format!(
"Custom bindings can be set in {} within the [keybindings] section.\n\n",
config_path("config.toml").to_str().unwrap_or_default()
);
text.append(StyledString::styled(note, Effect::Italic));
let mut keys: Vec<&String> = bindings.keys().collect();
keys.sort();
for key in keys {
let command = serde_json::to_string(&bindings[key]).unwrap_or_default();
let binding = format!("{} -> {}\n", key, command);
text.append(binding);
}
HelpView {
view: ScrollView::new(TextView::new(text)),
}
}
}
impl ViewWrapper for HelpView {
wrap_impl!(self.view: ScrollView<TextView>);
}
impl ViewExt for HelpView {}

View File

@@ -1,6 +1,7 @@
pub mod album; pub mod album;
pub mod artist; pub mod artist;
pub mod contextmenu; pub mod contextmenu;
pub mod help;
pub mod layout; pub mod layout;
pub mod library; pub mod library;
pub mod listview; pub mod listview;