Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add focus keybindings to the config #79

Merged
merged 3 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions docs/configuration/keybindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The key setting can be a simple character or a non-character key
These are the supported non-character keys (lower-/uppercase doesn't matter);

| Key | Config Name |
| ---------------- | -------------- |
|------------------|----------------|
| ++insert++ | `insert` |
| ++delete++ | `delete` |
| ++home++ | `home` |
Expand All @@ -23,14 +23,28 @@ These are the supported non-character keys (lower-/uppercase doesn't matter);

### Mode

The following modes are supported

| Key | Config Name |
|----------------|-------------|
| | `normal` |
| ++shift++ | `shit` |
| ++alt++ | `alt` |
| ++alt+shift++ | `altshift` |
| ++ctrl++ | `ctrl` |
| ++ctrl+shift++ | `ctrlshift` |
| ++ctrl+alt++ | `ctrlalt` |

## Supported Actions

| Action | Default Keybinding | Changeable Since |
| ------ | ------------------ | ---------------------------------------- |
| Down | ++down++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Up | ++up++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Left | ++left++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Right | ++right++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Action | Config Name | Default Keybinding | Changeable Since |
|-------------------------|--------------|--------------------|-------------------------------------------|
| Scroll Down | `down` | ++down++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Scroll Up | `up` | ++up++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Scroll / Select Left | `left` | ++left++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Scroll / Select Right | `right` | ++right++ | [:octicons-tag-24: 0.5.0][release-0.5.0] |
| Focus the next view | `focus_next` | ++tab++ | :fontawesome-solid-microchip: pre-release |
| Focus the previous view | `focus_prev` | ++shift+tab++ | :fontawesome-solid-microchip: pre-release |

## Sample Remap

Expand Down
60 changes: 48 additions & 12 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,15 @@ pub struct Features {
pub toc: bool,
}

#[derive(Clone)]
pub struct Keybindings {
pub down: Option<Event>,
pub up: Option<Event>,
pub left: Option<Event>,
pub right: Option<Event>,
pub down: Event,
pub up: Event,
pub left: Event,
pub right: Event,

pub focus_next: Event,
pub focus_prev: Event,
}

pub struct Settings {
Expand Down Expand Up @@ -233,6 +237,9 @@ struct UserKeybindings {
up: Option<UserKeybinding>,
left: Option<UserKeybinding>,
right: Option<UserKeybinding>,

focus_next: Option<UserKeybinding>,
focus_prev: Option<UserKeybinding>,
}

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -274,10 +281,13 @@ impl Config {
toc: true,
},
keybindings: Keybindings {
down: None,
up: None,
left: None,
right: None,
down: Event::Key(Key::Down),
up: Event::Key(Key::Up),
left: Event::Key(Key::Left),
right: Event::Key(Key::Right),

focus_next: Event::Key(Key::Tab),
focus_prev: Event::Shift(Key::Tab),
},
settings: Settings {
toc: TocSettings {
Expand Down Expand Up @@ -578,7 +588,7 @@ impl Config {
keybinding.mode.as_ref().unwrap_or(&"normal".to_string()),
) {
Ok(event_key) => {
self.keybindings.down = Some(event_key);
self.keybindings.down = event_key;
}
Err(error) => {
log::warn!("{:?}", error)
Expand All @@ -591,7 +601,7 @@ impl Config {
keybinding.mode.as_ref().unwrap_or(&"normal".to_string()),
) {
Ok(event_key) => {
self.keybindings.up = Some(event_key);
self.keybindings.up = event_key;
}
Err(error) => {
log::warn!("{:?}", error)
Expand All @@ -604,7 +614,7 @@ impl Config {
keybinding.mode.as_ref().unwrap_or(&"normal".to_string()),
) {
Ok(event_key) => {
self.keybindings.left = Some(event_key);
self.keybindings.left = event_key;
}
Err(error) => {
log::warn!("{:?}", error)
Expand All @@ -617,7 +627,33 @@ impl Config {
keybinding.mode.as_ref().unwrap_or(&"normal".to_string()),
) {
Ok(event_key) => {
self.keybindings.right = Some(event_key);
self.keybindings.right = event_key;
}
Err(error) => {
log::warn!("{:?}", error)
}
}
}
if let Some(keybinding) = &user_keybindings.focus_next {
match parse_keybinding(
&keybinding.key,
keybinding.mode.as_ref().unwrap_or(&"normal".to_string()),
) {
Ok(event_key) => {
self.keybindings.focus_next = event_key;
}
Err(error) => {
log::warn!("{:?}", error)
}
}
}
if let Some(keybinding) = &user_keybindings.focus_prev {
match parse_keybinding(
&keybinding.key,
keybinding.mode.as_ref().unwrap_or(&"normal".to_string()),
) {
Ok(event_key) => {
self.keybindings.focus_prev = event_key;
}
Err(error) => {
log::warn!("{:?}", error)
Expand Down
10 changes: 8 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ extern crate anyhow;
extern crate lazy_static;
extern crate log;

#[macro_use]
extern crate cursive;

use crate::config::CONFIG;
use cursive::align::HAlign;
use cursive::backends;
use cursive::direction::Orientation;
use cursive::theme::*;
use cursive::traits::*;
use cursive::view::Resizable;
Expand All @@ -13,6 +18,7 @@ use cursive_buffered_backend::BufferedBackend;
use std::fs;
use std::io::Write;

use crate::ui::RootLayout;
use crate::wiki::search::SearchResult;

pub mod cli;
Expand Down Expand Up @@ -125,9 +131,9 @@ fn start_application() {
.with_name("logo_view")
.full_screen();

let article_layout = override_keybindings!(LinearLayout::horizontal()
let article_layout = RootLayout::new(Orientation::Horizontal, CONFIG.keybindings.clone())
.child(Dialog::around(logo_view))
.with_name("article_layout"));
.with_name("article_layout");

// Add a fullscreen layer, containing the search bar and the article view
siv.add_fullscreen_layer(
Expand Down
40 changes: 22 additions & 18 deletions src/ui/article/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ use crate::wiki::{
};
use crate::{
config::{self, TocPosition, CONFIG},
ui, view_with_theme,
ui::{self, RootLayout},
view_with_theme,
};

use anyhow::{bail, Context, Result};
use cursive::align::HAlign;
use cursive::direction::Orientation;
use cursive::view::{Nameable, Scrollable};
use cursive::views::{Dialog, LinearLayout, TextView};
use cursive::views::{Dialog, TextView};
use cursive::Cursive;

mod content;
Expand Down Expand Up @@ -98,21 +100,23 @@ pub fn on_link_submit(siv: &mut Cursive, target: String) {
siv.add_layer(
// create a dialog that asks the user for confirmation whether he really wants to open this
// link
Dialog::around(TextView::new(format!(
"Do you want to open the article '{}'?",
target_human
)))
.button("Yep", move |s| {
log::info!("on_link_submit - user said yes :) continuing...");
// the human wants us to open the link for him... we will comply...
open_link(s, target.clone())
})
.button("Nope", move |s| {
log::info!("on_link_submit - said no :/ aborting...");
// so he doesn't want us to open the link... delete the whole dialog and pretend it
// didn't happen
s.pop_layer();
}),
RootLayout::new(Orientation::Vertical, CONFIG.keybindings.clone()).child(
Dialog::around(TextView::new(format!(
"Do you want to open the article '{}'?",
target_human
)))
.button("Yep", move |s| {
log::info!("on_link_submit - user said yes :) continuing...");
// the human wants us to open the link for him... we will comply...
open_link(s, target.clone())
})
.button("Nope", move |s| {
log::info!("on_link_submit - said no :/ aborting...");
// so he doesn't want us to open the link... delete the whole dialog and pretend it
// didn't happen
s.pop_layer();
}),
),
);

log::info!("on_link_submit finished successfully");
Expand Down Expand Up @@ -204,7 +208,7 @@ fn display_article(siv: &mut Cursive, article: Article) -> Result<()> {
};

// add the article view to the screen
let result = siv.call_on_name("article_layout", |view: &mut LinearLayout| {
let result = siv.call_on_name("article_layout", |view: &mut RootLayout| {
if CONFIG.features.toc && has_toc {
view.insert_child(
index,
Expand Down
2 changes: 2 additions & 0 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
pub mod article;
pub mod models;
mod root;
pub mod search;
mod theme_view;
pub mod toc;
pub mod utils;

pub type ThemedView<T> = theme_view::ThemedView<T>;
pub type RootLayout = root::RootLayout;
67 changes: 67 additions & 0 deletions src/ui/root.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::config::Keybindings;
use cursive::direction::Orientation;
use cursive::event::{Event, EventResult, Key};
use cursive::view::{IntoBoxedView, View, ViewWrapper};
use cursive::views::LinearLayout;
use cursive::Vec2;

pub struct RootLayout {
layout: LinearLayout,
keybindings: Keybindings,
}

impl RootLayout {
pub fn new(orientation: Orientation, keybindings: Keybindings) -> Self {
RootLayout {
layout: LinearLayout::new(orientation),
keybindings,
}
}

pub fn child<V: IntoBoxedView + 'static>(mut self, view: V) -> Self {
self.add_child(view);
self
}

pub fn insert_child<V: IntoBoxedView + 'static>(&mut self, i: usize, view: V) {
self.layout.insert_child(i, view);
}

pub fn add_child<V: IntoBoxedView + 'static>(&mut self, view: V) {
self.layout.add_child(view);
}

pub fn remove_child(&mut self, i: usize) -> Option<Box<dyn View>> {
self.layout.remove_child(i)
}

pub fn find_child_from_name(&mut self, name: &str) -> Option<usize> {
self.layout.find_child_from_name(name)
}
}

impl ViewWrapper for RootLayout {
wrap_impl!(self.layout: LinearLayout);

fn wrap_on_event(&mut self, ch: Event) -> EventResult {
match ch {
// movement
key if key == self.keybindings.up => self.layout.on_event(Event::Key(Key::Up)),
key if key == self.keybindings.down => self.layout.on_event(Event::Key(Key::Down)),
key if key == self.keybindings.left => self.layout.on_event(Event::Key(Key::Left)),
key if key == self.keybindings.right => self.layout.on_event(Event::Key(Key::Right)),

// focus
key if key == self.keybindings.focus_next => self.layout.on_event(Event::Key(Key::Tab)),
key if key == self.keybindings.focus_prev => {
self.layout.on_event(Event::Shift(Key::Tab))
}

_ => self.layout.on_event(ch),
}
}

fn wrap_layout(&mut self, size: Vec2) {
self.layout.layout(size);
}
}
38 changes: 22 additions & 16 deletions src/ui/search.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::{
config, override_keybindings, ui, view_with_theme,
config,
ui::{self, RootLayout},
view_with_theme,
wiki::search::{
SearchBuilder, SearchMetadata, SearchProperties, SearchResult, SearchSortOrder,
},
Orientation, CONFIG,
};

use anyhow::{Context, Result};
Expand Down Expand Up @@ -99,22 +102,25 @@ pub fn on_search(siv: &mut Cursive, search_query: String) {
}

// create the search results layout
let search_results_layout = LinearLayout::horizontal()
.child(view_with_theme!(
config::CONFIG.theme.search_results,
Dialog::around(override_keybindings!(LinearLayout::vertical()
.child(
search_results_view
.with_name("search_results_view")
.scrollable()
.min_height(10)
let search_results_layout =
RootLayout::new(Orientation::Horizontal, CONFIG.keybindings.clone())
.child(view_with_theme!(
config::CONFIG.theme.search_results,
Dialog::around(
LinearLayout::vertical()
.child(
search_results_view
.with_name("search_results_view")
.scrollable()
.min_height(10)
)
.child(search_continue_button),
)
.child(search_continue_button)),)
))
.child(view_with_theme!(
config::CONFIG.theme.search_preview,
Dialog::around(search_results_preview)
));
))
.child(view_with_theme!(
config::CONFIG.theme.search_preview,
Dialog::around(search_results_preview)
));
log::debug!("created the search results layout");

// finally, add the whole thing as a new layer
Expand Down
Loading