Add key bindings to select and open links

This commit is contained in:
JRF 2022-08-29 19:00:42 -05:00
parent c09608d1f8
commit a1043eafd3
4 changed files with 66 additions and 32 deletions

17
Cargo.lock generated
View file

@ -185,6 +185,7 @@ dependencies = [
"edit", "edit",
"euphoxide", "euphoxide",
"log", "log",
"open",
"parking_lot", "parking_lot",
"rusqlite", "rusqlite",
"serde", "serde",
@ -612,6 +613,16 @@ version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]]
name = "open"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f23a407004a1033f53e93f9b45580d14de23928faad187384f891507c9b0c045"
dependencies = [
"pathdiff",
"windows-sys",
]
[[package]] [[package]]
name = "openssl-probe" name = "openssl-probe"
version = "0.1.5" version = "0.1.5"
@ -647,6 +658,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.1.0" version = "2.1.0"

View file

@ -12,6 +12,7 @@ crossterm = "0.25.0"
directories = "4.0.1" directories = "4.0.1"
edit = "0.1.4" edit = "0.1.4"
log = { version = "0.4.17", features = ["std"] } log = { version = "0.4.17", features = ["std"] }
open = "3.0.2"
parking_lot = "0.12.1" parking_lot = "0.12.1"
rusqlite = { version = "0.28.0", features = ["bundled", "time"] } rusqlite = { version = "0.28.0", features = ["bundled", "time"] }
serde = { version = "1.0.144", features = ["derive"] } serde = { version = "1.0.144", features = ["derive"] }

View file

@ -1,12 +1,8 @@
use std::io; use std::io;
use std::sync::Arc;
use crossterm::event::KeyCode; use crossterm::event::KeyCode;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::{ContentStyle, Stylize};
use parking_lot::FairMutex;
use toss::terminal::Terminal;
use crate::euph::Room;
use crate::ui::input::{key, InputEvent, KeyBindingsList, KeyEvent}; use crate::ui::input::{key, InputEvent, KeyBindingsList, KeyEvent};
use crate::ui::widgets::list::ListState; use crate::ui::widgets::list::ListState;
use crate::ui::widgets::popup::Popup; use crate::ui::widgets::popup::Popup;
@ -38,7 +34,7 @@ impl LinksState {
} }
pub fn widget(&self) -> BoxedWidget { pub fn widget(&self) -> BoxedWidget {
let mut list = self.list.widget(); let mut list = self.list.widget().focus(true);
for (id, link) in self.links.iter().enumerate() { for (id, link) in self.links.iter().enumerate() {
list.add_sel( list.add_sel(
id, id,
@ -50,20 +46,42 @@ impl LinksState {
Popup::new(list).title("Links").build() Popup::new(list).title("Links").build()
} }
pub fn list_key_bindings(&self, bindings: &mut KeyBindingsList) { pub fn open_link(&self) -> EventResult {
bindings.binding("esc", "close links popup") if let Some(id) = self.list.cursor() {
if let Some(link) = self.links.get(id) {
if let Err(error) = open::that(link) {
return EventResult::ErrorOpeningLink {
link: link.to_string(),
error,
};
}
}
}
EventResult::Handled
} }
pub fn handle_input_event( pub fn list_key_bindings(&self, bindings: &mut KeyBindingsList) {
&mut self, bindings.binding("esc", "close links popup");
terminal: &mut Terminal, bindings.binding("j/k, ↓/↑", "move cursor up/down");
crossterm_lock: &Arc<FairMutex<()>>, bindings.binding("g, home", "move cursor to top");
event: &InputEvent, bindings.binding("G, end", "move cursor to bottom");
room: &Option<Room>, bindings.binding("ctrl+y/e", "scroll up/down");
) -> EventResult { bindings.empty();
bindings.binding("enter", "open selected link");
}
pub fn handle_input_event(&mut self, event: &InputEvent) -> EventResult {
match event { match event {
key!(Esc) => EventResult::Close, key!(Esc) => return EventResult::Close,
_ => EventResult::NotHandled, key!('k') | key!(Up) => self.list.move_cursor_up(),
key!('j') | key!(Down) => self.list.move_cursor_down(),
key!('g') | key!(Home) => self.list.move_cursor_to_top(),
key!('G') | key!(End) => self.list.move_cursor_to_bottom(),
key!(Ctrl + 'y') => self.list.scroll_up(1),
key!(Ctrl + 'e') => self.list.scroll_down(1),
key!(Enter) => return self.open_link(),
_ => return EventResult::NotHandled,
} }
EventResult::Handled
} }
} }

View file

@ -464,23 +464,21 @@ impl EuphRoom {
} }
} }
} }
State::Links(links) => { State::Links(links) => match links.handle_input_event(event) {
match links.handle_input_event(terminal, crossterm_lock, event, &self.room) { links::EventResult::NotHandled => false,
links::EventResult::NotHandled => false, links::EventResult::Handled => true,
links::EventResult::Handled => true, links::EventResult::Close => {
links::EventResult::Close => { self.state = State::Normal;
self.state = State::Normal; true
true
}
links::EventResult::ErrorOpeningLink { link, error } => {
self.popups.push_front(RoomPopup::Error {
description: format!("Failed to open link: {link}"),
reason: format!("{error}"),
});
true
}
} }
} links::EventResult::ErrorOpeningLink { link, error } => {
self.popups.push_front(RoomPopup::Error {
description: format!("Failed to open link: {link}"),
reason: format!("{error}"),
});
true
}
},
} }
} }