From 11db510eb31f887fe3fa6d7b9189d571e4977104 Mon Sep 17 00:00:00 2001 From: Alexandre Pasmantier Date: Sun, 4 May 2025 01:50:39 +0200 Subject: [PATCH] wip: a checkpoint with stdin as a regular channel which compiles --- benches/main/ui.rs | 8 ++--- television/app.rs | 20 +++++------- television/channels/mod.rs | 3 +- television/channels/preview.rs | 35 +++++++++----------- television/channels/remote_control.rs | 10 +++--- television/main.rs | 47 ++++++++++----------------- television/preview/previewer.rs | 11 +++++++ television/television.rs | 39 +++++++++++----------- 8 files changed, 81 insertions(+), 92 deletions(-) diff --git a/benches/main/ui.rs b/benches/main/ui.rs index d5689f7..73e081f 100644 --- a/benches/main/ui.rs +++ b/benches/main/ui.rs @@ -14,7 +14,7 @@ use television::{ channels::{ cable::prototypes::CableChannelPrototype, entry::{into_ranges, Entry}, - OnAir, TelevisionChannel, + OnAir, }, config::{Config, ConfigEnv}, screen::{colors::ResultsColorscheme, results::build_results_list}, @@ -472,10 +472,7 @@ pub fn draw(c: &mut Criterion) { let backend = TestBackend::new(width, height); let terminal = Terminal::new(backend).unwrap(); let (tx, _) = tokio::sync::mpsc::unbounded_channel(); - let mut channel = TelevisionChannel::Cable( - CableChannelPrototype::default().into(), - ); - channel.find("television"); + let channel = CableChannelPrototype::default(); // Wait for the channel to finish loading let mut tv = Television::new( tx, @@ -487,6 +484,7 @@ pub fn draw(c: &mut Criterion) { false, CableChannelPrototypes::default(), ); + tv.find("television"); for _ in 0..5 { // tick the matcher let _ = tv.channel.results(10, 0); diff --git a/television/app.rs b/television/app.rs index 95c46c3..329eb17 100644 --- a/television/app.rs +++ b/television/app.rs @@ -4,8 +4,10 @@ use anyhow::Result; use tokio::sync::mpsc; use tracing::{debug, trace}; -use crate::channels::cable::prototypes::CableChannelPrototypes; -use crate::channels::{entry::Entry, OnAir, TelevisionChannel}; +use crate::channels::cable::prototypes::{ + CableChannelPrototype, CableChannelPrototypes, +}; +use crate::channels::{entry::Entry, OnAir}; use crate::config::{default_tick_rate, Config}; use crate::keymap::Keymap; use crate::render::UiState; @@ -97,8 +99,6 @@ pub struct App { /// Render task handle render_task: Option>>, options: AppOptions, - /// The cable channels that are available. - cable_channels: CableChannelPrototypes, } /// The outcome of an action. @@ -138,7 +138,7 @@ const ACTION_BUF_SIZE: usize = 8; impl App { pub fn new( - channel: TelevisionChannel, + channel_prototype: CableChannelPrototype, config: Config, input: Option, options: AppOptions, @@ -154,7 +154,7 @@ impl App { let (ui_state_tx, ui_state_rx) = mpsc::unbounded_channel(); let television = Television::new( action_tx.clone(), - channel, + channel_prototype, config, input, options.no_remote, @@ -178,7 +178,6 @@ impl App { ui_state_tx, render_task: None, options, - cable_channels, } } @@ -443,14 +442,13 @@ impl App { #[cfg(test)] mod test { use super::*; - use crate::channels::cable::Channel as CableChannel; #[test] fn test_maybe_select_1() { let mut app = App::new( - TelevisionChannel::Cable(CableChannel::new( - "random", "cat", false, None, - )), + CableChannelPrototype::new( + "random", "cat", false, None, None, None, + ), Config::default(), None, AppOptions::default(), diff --git a/television/channels/mod.rs b/television/channels/mod.rs index 0021c13..e39fc79 100644 --- a/television/channels/mod.rs +++ b/television/channels/mod.rs @@ -1,5 +1,6 @@ use crate::channels::entry::Entry; use anyhow::Result; +use cable::prototypes::CableChannelPrototype; use rustc_hash::FxHashSet; use television_derive::Broadcast; @@ -130,7 +131,7 @@ pub enum TelevisionChannel { } impl TelevisionChannel { - pub fn zap(&self, channel_name: &str) -> Result { + pub fn zap(&self, channel_name: &str) -> Result { match self { TelevisionChannel::RemoteControl(remote_control) => { remote_control.zap(channel_name) diff --git a/television/channels/preview.rs b/television/channels/preview.rs index a95ee88..4c7b936 100644 --- a/television/channels/preview.rs +++ b/television/channels/preview.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use super::entry::Entry; +use super::{cable::prototypes::DEFAULT_DELIMITER, entry::Entry}; use crate::channels::cable::prototypes::CableChannelPrototype; use lazy_regex::{regex, Lazy, Regex}; @@ -62,26 +62,23 @@ impl PreviewCommand { } } -impl TryFrom<&CableChannelPrototype> for PreviewCommand { - type Error = anyhow::Error; +impl From<&CableChannelPrototype> for Option { + fn from(value: &CableChannelPrototype) -> Self { + if let Some(command) = value.preview_command.as_ref() { + let delimiter = value + .preview_delimiter + .as_ref() + .map_or(DEFAULT_DELIMITER, |v| v); - fn try_from(value: &CableChannelPrototype) -> Result { - let command = value - .preview_command - .as_ref() - .expect("Preview command is not set."); + let offset_expr = value.preview_offset.clone(); - let delimiter = value - .preview_delimiter - .as_ref() - .expect("Preview delimiter is not set"); - - let offset_expr = value.preview_offset.clone(); - - // FIXME: handle offset here (side note: we don't want to reparse the offset - // expression for each entry, so maybe just parse it once and try to store it - // as some sort of function we can call later on - Ok(PreviewCommand::new(command, delimiter, offset_expr)) + // FIXME: handle offset here (side note: we don't want to reparse the offset + // expression for each entry, so maybe just parse it once and try to store it + // as some sort of function we can call later on + Some(PreviewCommand::new(command, delimiter, offset_expr)) + } else { + None + } } } diff --git a/television/channels/remote_control.rs b/television/channels/remote_control.rs index dd11fb7..5cf95f0 100644 --- a/television/channels/remote_control.rs +++ b/television/channels/remote_control.rs @@ -2,13 +2,13 @@ use std::collections::HashSet; use crate::channels::cable::prototypes::CableChannelPrototypes; use crate::channels::entry::Entry; -use crate::channels::{OnAir, TelevisionChannel}; +use crate::channels::OnAir; use crate::matcher::{config::Config, Matcher}; use anyhow::Result; use devicons::FileIcon; use rustc_hash::{FxBuildHasher, FxHashSet}; -use super::cable; +use super::cable::prototypes::CableChannelPrototype; pub struct RemoteControl { matcher: Matcher, @@ -38,15 +38,13 @@ impl RemoteControl { } } - pub fn zap(&self, channel_name: &str) -> Result { + pub fn zap(&self, channel_name: &str) -> Result { match self .cable_channels .as_ref() .and_then(|channels| channels.get(channel_name).cloned()) { - Some(prototype) => { - Ok(TelevisionChannel::Cable(cable::Channel::from(prototype))) - } + Some(prototype) => Ok(prototype), None => Err(anyhow::anyhow!( "No channel or cable channel prototype found for {}", channel_name diff --git a/television/main.rs b/television/main.rs index 61bcebe..49857ed 100644 --- a/television/main.rs +++ b/television/main.rs @@ -14,9 +14,6 @@ use television::utils::clipboard::CLIPBOARD; use tracing::{debug, error, info}; use television::app::{App, AppOptions}; -use television::channels::{ - stdin::Channel as StdinChannel, TelevisionChannel, -}; use television::cli::{ args::{Cli, Command}, guess_channel_from_prompt, list_channels, PostProcessedCli, @@ -164,22 +161,22 @@ pub fn determine_channel( ) -> Result { if readable_stdin { debug!("Using stdin channel"); - Ok(TelevisionChannel::Stdin(StdinChannel::new( - args.preview_kind, - ))) + Ok(CableChannelPrototype::new( + "STDIN", "cat", false, None, None, None, + )) } else if let Some(prompt) = args.autocomplete_prompt { debug!("Using autocomplete prompt: {:?}", prompt); - let channel = guess_channel_from_prompt( + let channel_prototype = guess_channel_from_prompt( &prompt, &config.shell_integration.commands, &config.shell_integration.fallback_channel, cable_channels, )?; - debug!("Using guessed channel: {:?}", channel); - Ok(TelevisionChannel::Cable(channel.into())) + debug!("Using guessed channel: {:?}", channel_prototype); + Ok(channel_prototype) } else { debug!("Using {:?} channel", args.channel); - Ok(TelevisionChannel::Cable(args.channel.into())) + Ok(args.channel) } } @@ -188,9 +185,7 @@ mod tests { use rustc_hash::FxHashMap; use television::{ cable::load_cable_channels, - channels::{ - cable::prototypes::CableChannelPrototype, preview::PreviewType, - }, + channels::cable::prototypes::CableChannelPrototype, }; use super::*; @@ -199,7 +194,7 @@ mod tests { args: &PostProcessedCli, config: &Config, readable_stdin: bool, - expected_channel: &TelevisionChannel, + expected_channel: &CableChannelPrototype, cable_channels: Option, ) { let channels: CableChannelPrototypes = cable_channels @@ -209,11 +204,9 @@ mod tests { .unwrap(); assert_eq!( - channel.name(), - expected_channel.name(), + channel.name, expected_channel.name, "Expected {:?} but got {:?}", - expected_channel.name(), - channel.name() + expected_channel.name, channel.name ); } @@ -230,7 +223,9 @@ mod tests { &args, &config, true, - &TelevisionChannel::Stdin(StdinChannel::new(PreviewType::None)), + &CableChannelPrototype::new( + "STDIN", "cat", false, None, None, None, + ), None, ); } @@ -238,11 +233,8 @@ mod tests { #[tokio::test] async fn test_determine_channel_autocomplete_prompt() { let autocomplete_prompt = Some("cd".to_string()); - let expected_channel = TelevisionChannel::Cable( - CableChannelPrototype::new( - "dirs", "ls {}", false, None, None, None, - ) - .into(), + let expected_channel = CableChannelPrototype::new( + "dirs", "ls {}", false, None, None, None, ); let args = PostProcessedCli { autocomplete_prompt, @@ -286,12 +278,7 @@ mod tests { &args, &config, false, - &TelevisionChannel::Cable( - CableChannelPrototype::new( - "dirs", "", false, None, None, None, - ) - .into(), - ), + &CableChannelPrototype::new("dirs", "", false, None, None, None), None, ); } diff --git a/television/preview/previewer.rs b/television/preview/previewer.rs index 6767e55..65a33ff 100644 --- a/television/preview/previewer.rs +++ b/television/preview/previewer.rs @@ -1,3 +1,4 @@ +use crate::channels::cable::prototypes::CableChannelPrototype; use crate::preview::{Preview, PreviewContent}; use crate::utils::cache::RingSet; use crate::utils::command::shell_command; @@ -150,3 +151,13 @@ pub fn try_preview( concurrent_tasks.fetch_sub(1, Ordering::Relaxed); in_flight_previews.lock().remove(&entry.name); } + +impl From<&CableChannelPrototype> for Option { + fn from(value: &CableChannelPrototype) -> Self { + if let Some(preview_command) = value.into() { + Some(Previewer::new(preview_command)) + } else { + None + } + } +} diff --git a/television/television.rs b/television/television.rs index 9492c77..2af6f52 100644 --- a/television/television.rs +++ b/television/television.rs @@ -2,7 +2,10 @@ use crate::{ action::Action, cable::load_cable_channels, channels::{ - cable::{prototypes::CableChannelPrototypes, Channel as CableChannel}, + cable::{ + prototypes::{CableChannelPrototype, CableChannelPrototypes}, + Channel as CableChannel, + }, entry::{Entry, ENTRY_PLACEHOLDER}, remote_control::RemoteControl, // stdin::Channel as StdinChannel, @@ -46,7 +49,7 @@ pub enum MatchingMode { pub struct Television { action_tx: UnboundedSender, pub config: Config, - pub channel: TelevisionChannel, + pub channel: CableChannel, pub remote_control: Option, pub mode: Mode, pub current_pattern: String, @@ -68,7 +71,7 @@ impl Television { #[must_use] pub fn new( action_tx: UnboundedSender, - mut channel: TelevisionChannel, + channel_prototype: CableChannelPrototype, mut config: Config, input: Option, no_remote: bool, @@ -81,17 +84,8 @@ impl Television { results_picker = results_picker.inverted(); } - let previewer = match &channel { - // TelevisionChannel::Stdin(StdinChannel { - // preview_command: command, - // .. - // }) | - TelevisionChannel::Cable(CableChannel { - preview_command: command, - .. - }) => command.clone().map(Previewer::new), - _ => None, - }; + let previewer: Option = (&channel_prototype).into(); + let mut channel: CableChannel = channel_prototype.into(); let app_metadata = AppMetadata::new( env!("CARGO_PKG_VERSION").to_string(), @@ -166,7 +160,7 @@ impl Television { pub fn dump_context(&self) -> Ctx { let channel_state = ChannelState::new( - self.channel.name(), + self.channel.name.clone(), self.channel.selected_entries().clone(), self.channel.total_count(), self.channel.running(), @@ -193,20 +187,24 @@ impl Television { } pub fn current_channel(&self) -> String { - self.channel.name() + self.channel.name.clone() } - pub fn change_channel(&mut self, channel: TelevisionChannel) { + pub fn change_channel( + &mut self, + channel_prototype: CableChannelPrototype, + ) { self.preview_state.reset(); - self.preview_state.enabled = channel.supports_preview(); + self.preview_state.enabled = + channel_prototype.preview_command.is_some(); self.reset_picker_selection(); self.reset_picker_input(); self.current_pattern = EMPTY_STRING.to_string(); self.channel.shutdown(); - self.channel = channel; + self.channel = channel_prototype.into(); } - fn find(&mut self, pattern: &str) { + pub fn find(&mut self, pattern: &str) { match self.mode { Mode::Channel => { self.channel.find( @@ -530,6 +528,7 @@ impl Television { .remote_control .as_ref() .unwrap() + // FIXME: is the TelevisionChannel enum still worth it? .zap(entry.name.as_str())?; // this resets the RC picker self.reset_picker_selection();