Skip to main content

Module input

Module input 

Source
Expand description

Manage keyboard/mouse-bindings while running minus.

Terminology in this module: We will call any keyboard/mouse event from the terminal as a binding and its associated predefined action as callback.

There are two ways to define binding in minus as you will see below.

§Description

This method offers a much improved and ergonomic API for defining bindings and callbacks. You use the HashedEventRegister for registering bindings and their associated callback. It provides functions like add_key_events and add_mouse_events which take &[&str] as its first argument and a callback cb as its second argument and maps all &str in the &[&str] to same callback function cb. Each &str of the &[&str] contains a description of the key/mouse binding needed to activate it. For example c-c means pressing a Ctrl+c on the keyboard. See Writing Binding Descriptions to know more on writing these descriptions.

§Example

use minus::input::{InputEvent, HashedEventRegister, crossterm_event::Event};

let mut input_register = HashedEventRegister::default();

input_register.add_key_events(&["down"], |_, ps| {
    InputEvent::UpdateUpperMark(ps.upper_mark.saturating_sub(1))
});

input_register.add_mouse_events(&["scroll:up"], |_, ps| {
    InputEvent::UpdateUpperMark(ps.upper_mark.saturating_sub(5))
});

input_register.add_resize_event(|ev, _| {
    let (cols, rows) = if let Event::Resize(cols, rows) = ev {
        (cols, rows)
    } else {
       unreachable!();
    };
    InputEvent::UpdateTermArea(cols as usize, rows as usize)
});

§Writing Binding Descriptions

§Defining Keybindings

The general syntax for defining keybindings is [MODIFIER]-[MODIFIER]-[MODIFIER]-{SINGLE KEY}

MODIFIERs include or or more of the Ctrl Alt and Shift keys. They are writeen with the shorthands c, m and s respectively.

SINGLE CHAR includes any key on the keyboard which is not a modifier like a, z, 1, F1 or enter. Each of these pieces are separated by a -.

Here are some examples

Key InputMean ing
aA literal a
ZA Z. Matched only when a caps lock is on
c-qCtrl+q
enterENTER key
c-m-pageupCtrl+Alt+PageUp
s-2Shift+2
backspaceBackspace Key
leftLeft Arrow key

§Defining Mouse Bindings

The general syntax for defining keybindings is [MODIFIER]-[MODIFIER]-[MODIFIER]-{MOUSE ACTION}

MODIFIERs include or or more of the Ctrl Alt and Shift keys which are pressed along with the mouse action. They are writeen with the shorthands c, m and s respectively.

MOUSE ACTION includes actions like pressing down the left mouse button or taking up the right mouse button. It also includes scrolling up/down or pressing the middle click.

Here are some examples

Key InputMean ing
left:upReleasing the left mouse button
right:downPressing the right mouse button
c-mid:downMiddle click in pressed along with Ctrl key
m-scroll:upScrolled down while pressing the Alt key

NOTE: Although minus’s description parser can correctly parse almost all if not all the events that you can possibly register, not all of them are correctly registered by crossterm itself. For example minus corrctly parses c-s-h as ctrl+shift-h but crossterm categorically recognizes it as ctrl+h when reading events from the terminal.

§Legacy method

This method relies heavily on the InputClassifier trait and end-applications were needed to manually copy the default definitions and make the required modifications yourself in this method. This lead to very messy and error-prone system for defining bindings and also required application authors to bring in the the underlying crossterm crate to define the events.

§Example

use minus::{input::{InputEvent, InputClassifier}, Pager, PagerState};
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};

struct CustomInputClassifier;
impl InputClassifier for CustomInputClassifier {
    fn classify_input(
        &self,
        ev: Event,
        ps: &PagerState
    ) -> Option<InputEvent> {
            match ev {
                Event::Key(KeyEvent {
                    code: KeyCode::Up,
                    modifiers: KeyModifiers::NONE,
                    ..
                })
                | Event::Key(KeyEvent {
                    code: KeyCode::Char('j'),
                    modifiers: KeyModifiers::NONE,
                    ..
                }) => Some(InputEvent::UpdateUpperMark
                      (ps.upper_mark.saturating_sub(1))),
                _ => None
        }
    }
}

let mut pager = Pager::new();
pager.set_input_classifier(
                Box::new(CustomInputClassifier)
            );

NOTE: Although you can define almost every combination of bindings that crossterm supports, not all of them are correctly registered by crossterm itself. For example you can define

Event::Key(KeyEvent {
    code: KeyCode::Char(`h`),
    modifiers: KeyModifiers::CONTROL | KeyModifiers::SHIFT,
    ..
})

but crossterm will not match to it as crossterm recognizes a ctrl+shift+h as ctrl+h when reading events from the terminal.

§Custom Actions on User Events

Sometimes you want to execute arbitrary code when a key/mouse action is pressed like fetching more data from a server but not necessarily sending it to minus. In these types of scenarios, you can leverage InputEvent::Ignore. When this is returned by a callback function, minus will execute your code but not do anything special for the event on its part.

input_register.add_key_events(&["f"], |_, ps| {
    fetch_data_from_server(...);
    InputEvent::Ignore
});

It can be used with the legacy method too.

struct CustomInputClassifier;
impl InputClassifier for CustomInputClassifier {
    fn classify_input(
        &self,
        ev: Event,
        ps: &PagerState
    ) -> Option<InputEvent> {
            match ev {
                Event::Key(KeyEvent {
                    code: KeyCode::Char('f'),
                    modifiers: KeyModifiers::NONE,
                    ..
                }) => {
                    fetch_data_from_server(...);
                    InputEvent::Ignore
                },
                _ => None
        }
    }
}

Modules§

crossterm_event
A module to read events.

Structs§

DefaultInputClassifierDeprecated
The default set of input definitions
HashedEventRegister
A hash store for events and it’s related callback

Enums§

InputEvent
Events handled by the minus pager.

Traits§

InputClassifierDeprecated
Classifies the input and returns the appropriate InputEvent

Functions§

generate_default_bindingsDeprecated
Insert the default set of actions into the HashedEventRegister