mirror of
https://github.com/alexpasmantier/television.git
synced 2025-07-28 22:01:39 +00:00
fix(bindings): remove legacy binding, replace with newer Key
This commit is contained in:
parent
bf3a22a7cf
commit
75b6d48372
@ -1,20 +1,16 @@
|
||||
use crate::{
|
||||
action::Action, channels::prototypes::ChannelPrototype,
|
||||
config::KeyBindings, errors::unknown_channel_exit, event::Key,
|
||||
};
|
||||
use colored::Colorize;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::{
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use tracing::{debug, error};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::{
|
||||
action::Action,
|
||||
channels::prototypes::ChannelPrototype,
|
||||
config::{Binding, KeyBindings},
|
||||
errors::unknown_channel_exit,
|
||||
};
|
||||
|
||||
/// A neat `HashMap` of channel prototypes indexed by their name.
|
||||
///
|
||||
/// This is used to store cable channel prototypes throughout the application
|
||||
@ -62,28 +58,9 @@ impl Cable {
|
||||
.iter()
|
||||
.filter_map(|(name, prototype)| {
|
||||
if let Some(keybindings) = &prototype.keybindings {
|
||||
if let Some(binding) = &keybindings.shortcut {
|
||||
// Convert Binding to Key for new architecture
|
||||
match binding {
|
||||
Binding::SingleKey(key) => Some((
|
||||
*key,
|
||||
Action::SwitchToChannel(name.clone()).into(),
|
||||
)),
|
||||
// For multiple keys, use the first one
|
||||
Binding::MultipleKeys(keys)
|
||||
if !keys.is_empty() =>
|
||||
{
|
||||
Some((
|
||||
keys[0],
|
||||
Action::SwitchToChannel(name.clone())
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
Binding::MultipleKeys(_) => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
keybindings.shortcut.as_ref().map(|key| {
|
||||
(*key, Action::SwitchToChannel(name.clone()).into())
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -96,13 +73,12 @@ impl Cable {
|
||||
/// Get a channel prototype's shortcut binding.
|
||||
///
|
||||
/// E.g. if the channel is "files" and the shortcut is "F1",
|
||||
/// this will return `Some(Binding::SingleKey("F1"))`.
|
||||
pub fn get_channel_shortcut(&self, channel_name: &str) -> Option<Binding> {
|
||||
// Get only what we need, clone at the end
|
||||
/// this will return `Some(Key::F(1))`.
|
||||
pub fn get_channel_shortcut(&self, channel_name: &str) -> Option<Key> {
|
||||
self.get(channel_name)
|
||||
.and_then(|prototype| prototype.keybindings.as_ref())
|
||||
.and_then(|keybindings| keybindings.shortcut.as_ref())
|
||||
.cloned()
|
||||
.copied()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
channels::prototypes::Template, config::Binding,
|
||||
channels::prototypes::Template,
|
||||
event::Key,
|
||||
screen::result_item::ResultItem,
|
||||
};
|
||||
use devicons::FileIcon;
|
||||
@ -172,7 +173,7 @@ impl ResultItem for Entry {
|
||||
self.match_ranges.as_deref()
|
||||
}
|
||||
|
||||
fn shortcut(&self) -> Option<&Binding> {
|
||||
fn shortcut(&self) -> Option<&Key> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::cli::parse_source_entry_delimiter;
|
||||
use crate::{
|
||||
config::{Binding, KeyBindings, ui},
|
||||
config::{KeyBindings, ui},
|
||||
event::Key,
|
||||
features::Features,
|
||||
screen::layout::{InputPosition, Orientation},
|
||||
};
|
||||
@ -161,7 +162,7 @@ impl CommandSpec {
|
||||
pub struct ChannelKeyBindings {
|
||||
/// Optional channel specific shortcut that, when pressed, switches directly to this channel.
|
||||
#[serde(default)]
|
||||
pub shortcut: Option<Binding>,
|
||||
pub shortcut: Option<Key>,
|
||||
/// Regular action -> binding mappings living at channel level.
|
||||
#[serde(flatten)]
|
||||
#[serde(default)]
|
||||
@ -169,7 +170,7 @@ pub struct ChannelKeyBindings {
|
||||
}
|
||||
|
||||
impl ChannelKeyBindings {
|
||||
pub fn channel_shortcut(&self) -> Option<&Binding> {
|
||||
pub fn channel_shortcut(&self) -> Option<&Key> {
|
||||
self.shortcut.as_ref()
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ use crate::{
|
||||
entry::into_ranges,
|
||||
prototypes::{BinaryRequirement, ChannelPrototype},
|
||||
},
|
||||
config::{Binding, ui::RemoteControlConfig},
|
||||
config::ui::RemoteControlConfig,
|
||||
event::Key,
|
||||
matcher::{Matcher, config::Config},
|
||||
screen::result_item::ResultItem,
|
||||
};
|
||||
@ -14,17 +15,17 @@ use devicons::FileIcon;
|
||||
pub struct CableEntry {
|
||||
pub channel_name: String,
|
||||
pub match_ranges: Option<Vec<(u32, u32)>>,
|
||||
pub shortcut: Option<Binding>,
|
||||
pub shortcut: Option<Key>,
|
||||
pub description: Option<String>,
|
||||
pub requirements: Vec<BinaryRequirement>,
|
||||
}
|
||||
|
||||
impl CableEntry {
|
||||
pub fn new(name: String, shortcut: Option<&Binding>) -> Self {
|
||||
pub fn new(name: String, shortcut: Option<&Key>) -> Self {
|
||||
CableEntry {
|
||||
channel_name: name,
|
||||
match_ranges: None,
|
||||
shortcut: shortcut.cloned(),
|
||||
shortcut: shortcut.copied(),
|
||||
description: None,
|
||||
requirements: Vec::new(),
|
||||
}
|
||||
@ -67,7 +68,7 @@ impl ResultItem for CableEntry {
|
||||
self.match_ranges.as_deref()
|
||||
}
|
||||
|
||||
fn shortcut(&self) -> Option<&crate::config::Binding> {
|
||||
fn shortcut(&self) -> Option<&Key> {
|
||||
self.shortcut.as_ref()
|
||||
}
|
||||
}
|
||||
|
@ -10,28 +10,6 @@ use std::hash::Hash;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
// Legacy binding structure for backward compatibility with shell integration
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Hash)]
|
||||
#[serde(untagged)]
|
||||
pub enum Binding {
|
||||
SingleKey(Key),
|
||||
MultipleKeys(Vec<Key>),
|
||||
}
|
||||
|
||||
impl Display for Binding {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Binding::SingleKey(key) => write!(f, "{key}"),
|
||||
Binding::MultipleKeys(keys) => {
|
||||
let keys_str: Vec<String> = keys
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
write!(f, "{}", keys_str.join(", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic bindings structure that can map any key type to actions
|
||||
/// Generic bindings structure that maps any key type to actions.
|
||||
|
@ -15,7 +15,7 @@ use std::{
|
||||
use tracing::{debug, warn};
|
||||
|
||||
pub use keybindings::{
|
||||
Binding, EventBindings, EventType, KeyBindings, merge_bindings,
|
||||
EventBindings, EventType, KeyBindings, merge_bindings,
|
||||
};
|
||||
pub use themes::Theme;
|
||||
pub use ui::UiConfig;
|
||||
@ -478,7 +478,7 @@ mod tests {
|
||||
|
||||
default_config.shell_integration.keybindings.insert(
|
||||
"command_history".to_string(),
|
||||
Binding::SingleKey(Key::from_str("ctrl-h").unwrap()),
|
||||
Key::from_str("ctrl-h").unwrap(),
|
||||
);
|
||||
default_config.shell_integration.merge_triggers();
|
||||
|
||||
@ -570,14 +570,14 @@ mod tests {
|
||||
|
||||
let config = Config::new(&config_env, None).unwrap();
|
||||
|
||||
let expected: rustc_hash::FxHashMap<String, Binding> = [
|
||||
let expected: rustc_hash::FxHashMap<String, Key> = [
|
||||
(
|
||||
"command_history".to_string(),
|
||||
Binding::SingleKey(Key::from_str("ctrl-[").unwrap()),
|
||||
Key::from_str("ctrl-[").unwrap(),
|
||||
),
|
||||
(
|
||||
"smart_autocomplete".to_string(),
|
||||
Binding::SingleKey(Key::from_str("ctrl-t").unwrap()),
|
||||
Key::from_str("ctrl-t").unwrap(),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::{config::Binding, event::Key, utils::hashmaps};
|
||||
use crate::{event::Key, utils::hashmaps};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -14,7 +14,7 @@ pub struct ShellIntegrationConfig {
|
||||
/// {channel: [commands]}
|
||||
pub channel_triggers: FxHashMap<String, Vec<String>>,
|
||||
pub fallback_channel: String,
|
||||
pub keybindings: FxHashMap<String, Binding>,
|
||||
pub keybindings: FxHashMap<String, Key>,
|
||||
}
|
||||
|
||||
impl Hash for ShellIntegrationConfig {
|
||||
@ -49,7 +49,7 @@ impl ShellIntegrationConfig {
|
||||
// (if any), extract the character triggers shell autocomplete
|
||||
pub fn get_shell_autocomplete_keybinding_character(&self) -> char {
|
||||
match self.keybindings.get(SMART_AUTOCOMPLETE_CONFIGURATION_KEY) {
|
||||
Some(binding) => extract_ctrl_char(binding)
|
||||
Some(&key) => extract_ctrl_char(key)
|
||||
.unwrap_or(DEFAULT_SHELL_AUTOCOMPLETE_KEY),
|
||||
None => DEFAULT_SHELL_AUTOCOMPLETE_KEY,
|
||||
}
|
||||
@ -59,21 +59,17 @@ impl ShellIntegrationConfig {
|
||||
// through tv
|
||||
pub fn get_command_history_keybinding_character(&self) -> char {
|
||||
match self.keybindings.get(COMMAND_HISTORY_CONFIGURATION_KEY) {
|
||||
Some(binding) => extract_ctrl_char(binding)
|
||||
.unwrap_or(DEFAULT_COMMAND_HISTORY_KEY),
|
||||
Some(&key) => {
|
||||
extract_ctrl_char(key).unwrap_or(DEFAULT_COMMAND_HISTORY_KEY)
|
||||
}
|
||||
None => DEFAULT_COMMAND_HISTORY_KEY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract an upper-case character from a `Binding` if it is a single CTRL key
|
||||
/// Extract an upper-case character from a `Key` if it is a single CTRL key
|
||||
/// (or CTRL-Space). Returns `None` otherwise.
|
||||
fn extract_ctrl_char(binding: &Binding) -> Option<char> {
|
||||
let key = match binding {
|
||||
Binding::SingleKey(k) => Some(k),
|
||||
Binding::MultipleKeys(keys) => keys.first(),
|
||||
}?;
|
||||
|
||||
fn extract_ctrl_char(key: Key) -> Option<char> {
|
||||
match key {
|
||||
Key::Ctrl(c) => Some(c.to_ascii_uppercase()),
|
||||
Key::CtrlSpace => Some(' '),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
action::{Action, Actions},
|
||||
config::{Binding, KeyBindings},
|
||||
config::KeyBindings,
|
||||
television::Mode,
|
||||
};
|
||||
use std::fmt::Display;
|
||||
@ -151,18 +151,6 @@ impl ActionMapping {
|
||||
}
|
||||
}
|
||||
|
||||
/// Unified key extraction function that works for both systems
|
||||
pub fn extract_keys_from_binding(binding: &Binding) -> Vec<String> {
|
||||
match binding {
|
||||
Binding::SingleKey(key) => {
|
||||
vec![key.to_string()]
|
||||
}
|
||||
Binding::MultipleKeys(keys) => {
|
||||
keys.iter().map(ToString::to_string).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract keys for a single action from the new Key->Action keybindings format
|
||||
pub fn find_keys_for_action(
|
||||
keybindings: &KeyBindings,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
config::Binding,
|
||||
event::Key,
|
||||
screen::{
|
||||
colors::ResultsColorscheme,
|
||||
constants::{DESELECTED_SYMBOL, POINTER_SYMBOL, SELECTED_SYMBOL},
|
||||
@ -40,7 +40,7 @@ pub trait ResultItem {
|
||||
}
|
||||
|
||||
/// Optional shortcut binding shown after the name (remote-control entries).
|
||||
fn shortcut(&self) -> Option<&Binding> {
|
||||
fn shortcut(&self) -> Option<&Key> {
|
||||
None
|
||||
}
|
||||
|
||||
@ -82,13 +82,7 @@ pub fn build_result_line<'a, T: ResultItem + ?Sized>(
|
||||
|
||||
let shortcut_extra: u16 = item
|
||||
.shortcut()
|
||||
.map(|b| match b {
|
||||
Binding::SingleKey(k) => 2 + k.to_string().len() as u16, // space + key
|
||||
Binding::MultipleKeys(keys) => keys
|
||||
.iter()
|
||||
.map(|k| 1 + k.to_string().len() as u16) // space + key
|
||||
.sum(),
|
||||
})
|
||||
.map(|k| 2 + k.to_string().len() as u16) // space + key
|
||||
.unwrap_or(0);
|
||||
|
||||
let item_max_width = area_width
|
||||
@ -126,25 +120,12 @@ pub fn build_result_line<'a, T: ResultItem + ?Sized>(
|
||||
}
|
||||
|
||||
// Show shortcut if present.
|
||||
if let Some(binding) = item.shortcut() {
|
||||
if let Some(key) = item.shortcut() {
|
||||
spans.push(Span::raw(" "));
|
||||
match binding {
|
||||
Binding::SingleKey(k) => spans.push(Span::styled(
|
||||
k.to_string(),
|
||||
Style::default().fg(match_fg),
|
||||
)),
|
||||
Binding::MultipleKeys(keys) => {
|
||||
for (i, k) in keys.iter().enumerate() {
|
||||
if i > 0 {
|
||||
spans.push(Span::raw(" "));
|
||||
}
|
||||
spans.push(Span::styled(
|
||||
k.to_string(),
|
||||
Style::default().fg(match_fg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
spans.push(Span::styled(
|
||||
key.to_string(),
|
||||
Style::default().fg(match_fg),
|
||||
));
|
||||
}
|
||||
|
||||
Line::from(spans)
|
||||
|
Loading…
x
Reference in New Issue
Block a user