mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-07 12:05:34 +00:00
refactor(passthrough)!: drop support for unused passthrough keybindings
BREAKING CHANGE: the CLI `passthrough_keybindings` are no longer available. This feature wasn't used anywhere to my knowledge (github search) and was adding unnecessary complexity to the code.
This commit is contained in:
parent
8b267bb1ff
commit
911cc248ac
@ -51,10 +51,6 @@ pub enum Action {
|
|||||||
#[serde(alias = "select_entry")]
|
#[serde(alias = "select_entry")]
|
||||||
#[serde(alias = "confirm_selection")]
|
#[serde(alias = "confirm_selection")]
|
||||||
ConfirmSelection,
|
ConfirmSelection,
|
||||||
/// Select the entry currently under the cursor and pass the key that was pressed
|
|
||||||
/// through to be handled the parent process.
|
|
||||||
#[serde(alias = "select_passthrough")]
|
|
||||||
SelectPassthrough(String),
|
|
||||||
/// Select the entry currently under the cursor and exit the application.
|
/// Select the entry currently under the cursor and exit the application.
|
||||||
#[serde(alias = "select_and_exit")]
|
#[serde(alias = "select_and_exit")]
|
||||||
SelectAndExit,
|
SelectAndExit,
|
||||||
|
@ -4,11 +4,9 @@ use anyhow::Result;
|
|||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
use crate::channels::entry::Entry;
|
use crate::channels::entry::{Entry, PreviewType};
|
||||||
use crate::channels::TelevisionChannel;
|
use crate::channels::TelevisionChannel;
|
||||||
use crate::config::{
|
use crate::config::Config;
|
||||||
merge_keybindings, parse_key, Binding, Config, KeyBindings,
|
|
||||||
};
|
|
||||||
use crate::keymap::Keymap;
|
use crate::keymap::Keymap;
|
||||||
use crate::render::UiState;
|
use crate::render::UiState;
|
||||||
use crate::television::{Mode, Television};
|
use crate::television::{Mode, Television};
|
||||||
@ -62,7 +60,6 @@ pub struct App {
|
|||||||
pub enum ActionOutcome {
|
pub enum ActionOutcome {
|
||||||
Entries(FxHashSet<Entry>),
|
Entries(FxHashSet<Entry>),
|
||||||
Input(String),
|
Input(String),
|
||||||
Passthrough(FxHashSet<Entry>, String),
|
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +67,6 @@ pub enum ActionOutcome {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AppOutput {
|
pub struct AppOutput {
|
||||||
pub selected_entries: Option<FxHashSet<Entry>>,
|
pub selected_entries: Option<FxHashSet<Entry>>,
|
||||||
pub passthrough: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ActionOutcome> for AppOutput {
|
impl From<ActionOutcome> for AppOutput {
|
||||||
@ -78,19 +74,15 @@ impl From<ActionOutcome> for AppOutput {
|
|||||||
match outcome {
|
match outcome {
|
||||||
ActionOutcome::Entries(entries) => Self {
|
ActionOutcome::Entries(entries) => Self {
|
||||||
selected_entries: Some(entries),
|
selected_entries: Some(entries),
|
||||||
passthrough: None,
|
|
||||||
},
|
},
|
||||||
ActionOutcome::Input(input) => Self {
|
ActionOutcome::Input(input) => Self {
|
||||||
selected_entries: None,
|
selected_entries: Some(FxHashSet::from_iter([Entry::new(
|
||||||
passthrough: Some(input),
|
input,
|
||||||
},
|
PreviewType::None,
|
||||||
ActionOutcome::Passthrough(entries, key) => Self {
|
)])),
|
||||||
selected_entries: Some(entries),
|
|
||||||
passthrough: Some(key),
|
|
||||||
},
|
},
|
||||||
ActionOutcome::None => Self {
|
ActionOutcome::None => Self {
|
||||||
selected_entries: None,
|
selected_entries: None,
|
||||||
passthrough: None,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +95,6 @@ impl App {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
channel: TelevisionChannel,
|
channel: TelevisionChannel,
|
||||||
config: Config,
|
config: Config,
|
||||||
passthrough_keybindings: &[String],
|
|
||||||
input: Option<String>,
|
input: Option<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (action_tx, action_rx) = mpsc::unbounded_channel();
|
let (action_tx, action_rx) = mpsc::unbounded_channel();
|
||||||
@ -111,21 +102,7 @@ impl App {
|
|||||||
let (_, event_rx) = mpsc::unbounded_channel();
|
let (_, event_rx) = mpsc::unbounded_channel();
|
||||||
let (event_abort_tx, _) = mpsc::unbounded_channel();
|
let (event_abort_tx, _) = mpsc::unbounded_channel();
|
||||||
let tick_rate = config.application.tick_rate;
|
let tick_rate = config.application.tick_rate;
|
||||||
let keybindings = merge_keybindings(config.keybindings.clone(), {
|
let keymap = Keymap::from(&config.keybindings);
|
||||||
&KeyBindings::from(passthrough_keybindings.iter().filter_map(
|
|
||||||
|s| match parse_key(s) {
|
|
||||||
Ok(key) => Some((
|
|
||||||
Action::SelectPassthrough(s.to_string()),
|
|
||||||
Binding::SingleKey(key),
|
|
||||||
)),
|
|
||||||
Err(e) => {
|
|
||||||
debug!("Failed to parse keybinding: {}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
))
|
|
||||||
});
|
|
||||||
let keymap = Keymap::from(&keybindings);
|
|
||||||
|
|
||||||
debug!("{:?}", keymap);
|
debug!("{:?}", keymap);
|
||||||
let (ui_state_tx, ui_state_rx) = mpsc::unbounded_channel();
|
let (ui_state_tx, ui_state_rx) = mpsc::unbounded_channel();
|
||||||
@ -346,20 +323,6 @@ impl App {
|
|||||||
self.television.current_pattern.clone(),
|
self.television.current_pattern.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Action::SelectPassthrough(passthrough) => {
|
|
||||||
self.should_quit = true;
|
|
||||||
self.render_tx.send(RenderingTask::Quit)?;
|
|
||||||
if let Some(entries) = self
|
|
||||||
.television
|
|
||||||
.get_selected_entries(Some(Mode::Channel))
|
|
||||||
{
|
|
||||||
return Ok(ActionOutcome::Passthrough(
|
|
||||||
entries,
|
|
||||||
passthrough,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return Ok(ActionOutcome::None);
|
|
||||||
}
|
|
||||||
Action::ClearScreen => {
|
Action::ClearScreen => {
|
||||||
self.render_tx.send(RenderingTask::ClearScreen)?;
|
self.render_tx.send(RenderingTask::ClearScreen)?;
|
||||||
}
|
}
|
||||||
|
@ -66,14 +66,6 @@ pub struct Cli {
|
|||||||
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
|
#[arg(short, long, value_name = "STRING", verbatim_doc_comment)]
|
||||||
pub keybindings: Option<String>,
|
pub keybindings: Option<String>,
|
||||||
|
|
||||||
/// Passthrough keybindings (comma separated, e.g. "q,ctrl-w,ctrl-t")
|
|
||||||
///
|
|
||||||
/// These keybindings will trigger selection of the current entry and be
|
|
||||||
/// passed through to stdout along with the entry to be handled by the
|
|
||||||
/// parent process.
|
|
||||||
#[arg(long, value_name = "STRING", verbatim_doc_comment)]
|
|
||||||
pub passthrough_keybindings: Option<String>,
|
|
||||||
|
|
||||||
/// Input text to pass to the channel to prefill the prompt.
|
/// Input text to pass to the channel to prefill the prompt.
|
||||||
///
|
///
|
||||||
/// This can be used to provide a default value for the prompt upon
|
/// This can be used to provide a default value for the prompt upon
|
||||||
|
@ -24,7 +24,6 @@ pub struct PostProcessedCli {
|
|||||||
pub no_preview: bool,
|
pub no_preview: bool,
|
||||||
pub tick_rate: Option<f64>,
|
pub tick_rate: Option<f64>,
|
||||||
pub frame_rate: Option<f64>,
|
pub frame_rate: Option<f64>,
|
||||||
pub passthrough_keybindings: Vec<String>,
|
|
||||||
pub input: Option<String>,
|
pub input: Option<String>,
|
||||||
pub command: Option<Command>,
|
pub command: Option<Command>,
|
||||||
pub working_directory: Option<String>,
|
pub working_directory: Option<String>,
|
||||||
@ -40,7 +39,6 @@ impl Default for PostProcessedCli {
|
|||||||
no_preview: false,
|
no_preview: false,
|
||||||
tick_rate: None,
|
tick_rate: None,
|
||||||
frame_rate: None,
|
frame_rate: None,
|
||||||
passthrough_keybindings: Vec::new(),
|
|
||||||
input: None,
|
input: None,
|
||||||
command: None,
|
command: None,
|
||||||
working_directory: None,
|
working_directory: None,
|
||||||
@ -52,21 +50,16 @@ impl Default for PostProcessedCli {
|
|||||||
|
|
||||||
impl From<Cli> for PostProcessedCli {
|
impl From<Cli> for PostProcessedCli {
|
||||||
fn from(cli: Cli) -> Self {
|
fn from(cli: Cli) -> Self {
|
||||||
|
// parse literal keybindings passed through the CLI
|
||||||
let keybindings: Option<KeyBindings> = cli.keybindings.map(|kb| {
|
let keybindings: Option<KeyBindings> = cli.keybindings.map(|kb| {
|
||||||
parse_keybindings(&kb)
|
parse_keybindings_literal(&kb, CLI_KEYBINDINGS_DELIMITER)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
cli_parsing_error_exit(&e.to_string());
|
cli_parsing_error_exit(&e.to_string());
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
let passthrough_keybindings = cli
|
// parse the preview command if provided
|
||||||
.passthrough_keybindings
|
|
||||||
.unwrap_or_default()
|
|
||||||
.split(',')
|
|
||||||
.map(std::string::ToString::to_string)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let preview_kind = cli
|
let preview_kind = cli
|
||||||
.preview
|
.preview
|
||||||
.map(|preview| PreviewCommand {
|
.map(|preview| PreviewCommand {
|
||||||
@ -110,7 +103,6 @@ impl From<Cli> for PostProcessedCli {
|
|||||||
no_preview: cli.no_preview,
|
no_preview: cli.no_preview,
|
||||||
tick_rate: cli.tick_rate,
|
tick_rate: cli.tick_rate,
|
||||||
frame_rate: cli.frame_rate,
|
frame_rate: cli.frame_rate,
|
||||||
passthrough_keybindings,
|
|
||||||
input: cli.input,
|
input: cli.input,
|
||||||
command: cli.command,
|
command: cli.command,
|
||||||
working_directory,
|
working_directory,
|
||||||
@ -147,7 +139,7 @@ impl ParsedCliChannel {
|
|||||||
|
|
||||||
const CLI_KEYBINDINGS_DELIMITER: char = ';';
|
const CLI_KEYBINDINGS_DELIMITER: char = ';';
|
||||||
|
|
||||||
/// Parse the keybindings string into a hashmap of key -> action.
|
/// Parse a keybindings literal into a `KeyBindings` struct.
|
||||||
///
|
///
|
||||||
/// The formalism used is the same as the one used in the configuration file:
|
/// The formalism used is the same as the one used in the configuration file:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
@ -155,9 +147,12 @@ const CLI_KEYBINDINGS_DELIMITER: char = ';';
|
|||||||
/// ```
|
/// ```
|
||||||
/// Parsing it globally consists of splitting by the delimiter, reconstructing toml key-value pairs
|
/// Parsing it globally consists of splitting by the delimiter, reconstructing toml key-value pairs
|
||||||
/// and parsing that using logic already implemented in the configuration module.
|
/// and parsing that using logic already implemented in the configuration module.
|
||||||
fn parse_keybindings(cli_keybindings: &str) -> Result<KeyBindings> {
|
fn parse_keybindings_literal(
|
||||||
|
cli_keybindings: &str,
|
||||||
|
delimiter: char,
|
||||||
|
) -> Result<KeyBindings> {
|
||||||
let toml_definition = cli_keybindings
|
let toml_definition = cli_keybindings
|
||||||
.split(CLI_KEYBINDINGS_DELIMITER)
|
.split(delimiter)
|
||||||
.fold(String::new(), |acc, kb| acc + kb + "\n");
|
.fold(String::new(), |acc, kb| acc + kb + "\n");
|
||||||
|
|
||||||
toml::from_str(&toml_definition).map_err(|e| anyhow!(e))
|
toml::from_str(&toml_definition).map_err(|e| anyhow!(e))
|
||||||
@ -323,7 +318,6 @@ mod tests {
|
|||||||
tick_rate: Some(50.0),
|
tick_rate: Some(50.0),
|
||||||
frame_rate: Some(60.0),
|
frame_rate: Some(60.0),
|
||||||
keybindings: None,
|
keybindings: None,
|
||||||
passthrough_keybindings: Some("q,ctrl-w,ctrl-t".to_string()),
|
|
||||||
input: None,
|
input: None,
|
||||||
command: None,
|
command: None,
|
||||||
working_directory: Some("/home/user".to_string()),
|
working_directory: Some("/home/user".to_string()),
|
||||||
@ -345,10 +339,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(post_processed_cli.tick_rate, Some(50.0));
|
assert_eq!(post_processed_cli.tick_rate, Some(50.0));
|
||||||
assert_eq!(post_processed_cli.frame_rate, Some(60.0));
|
assert_eq!(post_processed_cli.frame_rate, Some(60.0));
|
||||||
assert_eq!(
|
|
||||||
post_processed_cli.passthrough_keybindings,
|
|
||||||
vec!["q".to_string(), "ctrl-w".to_string(), "ctrl-t".to_string()]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
post_processed_cli.working_directory,
|
post_processed_cli.working_directory,
|
||||||
Some("/home/user".to_string())
|
Some("/home/user".to_string())
|
||||||
@ -366,7 +356,6 @@ mod tests {
|
|||||||
tick_rate: Some(50.0),
|
tick_rate: Some(50.0),
|
||||||
frame_rate: Some(60.0),
|
frame_rate: Some(60.0),
|
||||||
keybindings: None,
|
keybindings: None,
|
||||||
passthrough_keybindings: None,
|
|
||||||
input: None,
|
input: None,
|
||||||
command: None,
|
command: None,
|
||||||
working_directory: None,
|
working_directory: None,
|
||||||
@ -396,7 +385,6 @@ mod tests {
|
|||||||
tick_rate: Some(50.0),
|
tick_rate: Some(50.0),
|
||||||
frame_rate: Some(60.0),
|
frame_rate: Some(60.0),
|
||||||
keybindings: None,
|
keybindings: None,
|
||||||
passthrough_keybindings: None,
|
|
||||||
input: None,
|
input: None,
|
||||||
command: None,
|
command: None,
|
||||||
working_directory: None,
|
working_directory: None,
|
||||||
@ -421,7 +409,6 @@ mod tests {
|
|||||||
tick_rate: Some(50.0),
|
tick_rate: Some(50.0),
|
||||||
frame_rate: Some(60.0),
|
frame_rate: Some(60.0),
|
||||||
keybindings: None,
|
keybindings: None,
|
||||||
passthrough_keybindings: None,
|
|
||||||
input: None,
|
input: None,
|
||||||
command: None,
|
command: None,
|
||||||
working_directory: None,
|
working_directory: None,
|
||||||
@ -449,7 +436,6 @@ mod tests {
|
|||||||
"quit=\"esc\";select_next_entry=[\"down\",\"ctrl-j\"]"
|
"quit=\"esc\";select_next_entry=[\"down\",\"ctrl-j\"]"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
),
|
),
|
||||||
passthrough_keybindings: None,
|
|
||||||
input: None,
|
input: None,
|
||||||
command: None,
|
command: None,
|
||||||
working_directory: None,
|
working_directory: None,
|
||||||
|
@ -65,16 +65,12 @@ async fn main() -> Result<()> {
|
|||||||
CLIPBOARD.with(<_>::default);
|
CLIPBOARD.with(<_>::default);
|
||||||
|
|
||||||
debug!("Creating application...");
|
debug!("Creating application...");
|
||||||
let mut app =
|
let mut app = App::new(channel, config, args.input);
|
||||||
App::new(channel, config, &args.passthrough_keybindings, args.input);
|
|
||||||
stdout().flush()?;
|
stdout().flush()?;
|
||||||
let output = app.run(stdout().is_terminal(), false).await?;
|
let output = app.run(stdout().is_terminal(), false).await?;
|
||||||
info!("{:?}", output);
|
info!("App output: {:?}", output);
|
||||||
let stdout_handle = stdout().lock();
|
let stdout_handle = stdout().lock();
|
||||||
let mut bufwriter = BufWriter::new(stdout_handle);
|
let mut bufwriter = BufWriter::new(stdout_handle);
|
||||||
if let Some(passthrough) = output.passthrough {
|
|
||||||
writeln!(bufwriter, "{passthrough}")?;
|
|
||||||
}
|
|
||||||
if let Some(entries) = output.selected_entries {
|
if let Some(entries) = output.selected_entries {
|
||||||
for entry in &entries {
|
for entry in &entries {
|
||||||
writeln!(bufwriter, "{}", entry.stdout_repr())?;
|
writeln!(bufwriter, "{}", entry.stdout_repr())?;
|
||||||
|
@ -30,10 +30,9 @@ fn setup_app() -> (
|
|||||||
television::channels::files::Channel::new(vec![target_dir]),
|
television::channels::files::Channel::new(vec![target_dir]),
|
||||||
);
|
);
|
||||||
let config = default_config_from_file().unwrap();
|
let config = default_config_from_file().unwrap();
|
||||||
let passthrough_keybindings = Vec::new();
|
|
||||||
let input = None;
|
let input = None;
|
||||||
|
|
||||||
let mut app = App::new(channel, config, &passthrough_keybindings, input);
|
let mut app = App::new(channel, config, input);
|
||||||
|
|
||||||
// retrieve the app's action channel handle in order to send a quit action
|
// retrieve the app's action channel handle in order to send a quit action
|
||||||
let tx = app.action_tx.clone();
|
let tx = app.action_tx.clone();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user