diff --git a/crates/television/app.rs b/crates/television/app.rs index 74447ea..bc638d7 100644 --- a/crates/television/app.rs +++ b/crates/television/app.rs @@ -56,7 +56,7 @@ use color_eyre::Result; use tokio::sync::{mpsc, Mutex}; use tracing::{debug, info}; -use crate::channels::CliTvChannel; +use crate::channels::{AvailableChannel, CliTvChannel}; use crate::television::Television; use crate::{ action::Action, @@ -84,7 +84,7 @@ pub struct App { impl App { pub fn new( - channel: CliTvChannel, + channel: AvailableChannel, tick_rate: f64, frame_rate: f64, ) -> Result { diff --git a/crates/television/channels.rs b/crates/television/channels.rs index 3b71fb9..930fe3f 100644 --- a/crates/television/channels.rs +++ b/crates/television/channels.rs @@ -7,7 +7,7 @@ pub mod channels; mod env; mod files; mod git_repos; -mod stdin; +pub mod stdin; mod text; /// The interface that all television channels must implement. @@ -97,6 +97,7 @@ pub enum AvailableChannel { Text(text::Channel), Stdin(stdin::Channel), Alias(alias::Channel), + Channel(channels::SelectionChannel), } /// NOTE: this could be generated by a derive macro @@ -104,7 +105,7 @@ impl TryFrom<&Entry> for AvailableChannel { type Error = String; fn try_from(entry: &Entry) -> Result { - match entry.name.as_ref() { + match entry.name.to_ascii_lowercase().as_ref() { "env" => Ok(AvailableChannel::Env(env::Channel::default())), "files" => Ok(AvailableChannel::Files(files::Channel::default())), "gitrepos" => { diff --git a/crates/television/channels/channels.rs b/crates/television/channels/channels.rs index 86eb5b7..8b36c53 100644 --- a/crates/television/channels/channels.rs +++ b/crates/television/channels/channels.rs @@ -8,7 +8,7 @@ use nucleo::{ }; use crate::{ - channels::{CliTvChannel, TelevisionChannel}, + channels::{AvailableChannel, CliTvChannel, TelevisionChannel}, entry::Entry, fuzzy::MATCHER, previewers::PreviewType, @@ -24,8 +24,6 @@ pub struct SelectionChannel { const NUM_THREADS: usize = 1; -const CHANNEL_BLACKLIST: [CliTvChannel; 1] = [CliTvChannel::Stdin]; - impl SelectionChannel { pub fn new() -> Self { let matcher = Nucleo::new( @@ -36,9 +34,6 @@ impl SelectionChannel { ); let injector = matcher.injector(); for variant in CliTvChannel::value_variants() { - if CHANNEL_BLACKLIST.contains(variant) { - continue; - } let _ = injector.push(*variant, |e, cols| { cols[0] = (*e).to_string().into(); }); @@ -55,6 +50,12 @@ impl SelectionChannel { const MATCHER_TICK_TIMEOUT: u64 = 2; } +impl Default for SelectionChannel { + fn default() -> Self { + Self::new() + } +} + const TV_ICON: FileIcon = FileIcon { icon: '📺', color: "#ffffff", diff --git a/crates/television/main.rs b/crates/television/main.rs index 1131fd8..877f8cc 100644 --- a/crates/television/main.rs +++ b/crates/television/main.rs @@ -1,11 +1,12 @@ use std::io::{stdout, IsTerminal, Write}; +use channels::AvailableChannel; use clap::Parser; use color_eyre::Result; use tracing::{debug, info}; use crate::app::App; -use crate::channels::CliTvChannel; +use crate::channels::stdin::Channel as StdinChannel; use crate::cli::Cli; mod action; @@ -36,10 +37,10 @@ async fn main() -> Result<()> { { if is_readable_stdin() { debug!("Using stdin channel"); - CliTvChannel::Stdin + AvailableChannel::Stdin(StdinChannel::default()) } else { debug!("Using {:?} channel", args.channel); - args.channel + args.channel.to_channel() } }, args.tick_rate, diff --git a/crates/television/television.rs b/crates/television/television.rs index a9bcda9..3899e42 100644 --- a/crates/television/television.rs +++ b/crates/television/television.rs @@ -71,9 +71,8 @@ pub struct Television { impl Television { #[must_use] - pub fn new(cli_channel: CliTvChannel) -> Self { - let mut tv_channel = cli_channel.to_channel(); - tv_channel.find(EMPTY_STRING); + pub fn new(mut channel: AvailableChannel) -> Self { + channel.find(EMPTY_STRING); let spinner = Spinner::default(); let spinner_state = SpinnerState::from(&spinner); @@ -81,7 +80,7 @@ impl Television { Self { action_tx: None, config: Config::default(), - channel: tv_channel, + channel, current_pattern: EMPTY_STRING.to_string(), mode: Mode::Channel, input: Input::new(EMPTY_STRING.to_string()), @@ -99,7 +98,7 @@ impl Television { } } - pub fn change_channel(&mut self, channel: Box) { + pub fn change_channel(&mut self, channel: AvailableChannel) { self.reset_preview_scroll(); self.reset_results_selection(); self.current_pattern = EMPTY_STRING.to_string(); @@ -296,7 +295,8 @@ impl Television { Action::ScrollPreviewHalfPageUp => self.scroll_preview_up(20), Action::ToChannelSelection => { self.mode = Mode::ChannelSelection; - let selection_channel = Box::new(SelectionChannel::new()); + let selection_channel = + AvailableChannel::Channel(SelectionChannel::new()); self.change_channel(selection_channel); } Action::SelectEntry => { @@ -308,10 +308,12 @@ impl Television { .unwrap() .send(Action::SelectAndExit)?, Mode::ChannelSelection => { - self.mode = Mode::Channel; - let new_channel = - AvailableChannel::from_entry(&entry)?; - self.change_channel(new_channel); + if let Ok(new_channel) = + AvailableChannel::try_from(&entry) + { + self.mode = Mode::Channel; + self.change_channel(new_channel); + } } } } diff --git a/crates/television_derive/src/lib.rs b/crates/television_derive/src/lib.rs index 4934162..1b2c839 100644 --- a/crates/television_derive/src/lib.rs +++ b/crates/television_derive/src/lib.rs @@ -11,6 +11,8 @@ pub fn cli_channel_derive(input: TokenStream) -> TokenStream { impl_cli_channel(&ast) } +const VARIANT_BLACKLIST: [&str; 2] = ["Stdin", "Channel"]; + fn impl_cli_channel(ast: &syn::DeriveInput) -> TokenStream { // check that the struct is an enum let variants = if let syn::Data::Enum(data_enum) = &ast.data { @@ -26,12 +28,15 @@ fn impl_cli_channel(ast: &syn::DeriveInput) -> TokenStream { ); // create the CliTvChannel enum - let cli_enum_variants = variants.iter().map(|variant| { - let variant_name = &variant.ident; - quote! { - #variant_name - } - }); + let cli_enum_variants = variants + .iter() + .filter(|v| !VARIANT_BLACKLIST.contains(&v.ident.to_string().as_str())) + .map(|variant| { + let variant_name = &variant.ident; + quote! { + #variant_name + } + }); let cli_enum = quote! { use clap::ValueEnum; use serde::{Deserialize, Serialize}; @@ -46,7 +51,9 @@ fn impl_cli_channel(ast: &syn::DeriveInput) -> TokenStream { }; // Generate the match arms for the `to_channel` method - let arms = variants.iter().map(|variant| { + let arms = variants.iter().filter( + |variant| !VARIANT_BLACKLIST.contains(&variant.ident.to_string().as_str()), + ).map(|variant| { let variant_name = &variant.ident; // Get the inner type of the variant, assuming it is the first field of the variant @@ -94,28 +101,31 @@ pub fn tv_channel_derive(input: TokenStream) -> TokenStream { } fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream { - // check that the struct is an enum + // Ensure the struct is an enum let variants = if let syn::Data::Enum(data_enum) = &ast.data { &data_enum.variants } else { panic!("#[derive(TvChannel)] is only defined for enums"); }; - // check that the enum has at least one variant + // Ensure the enum has at least one variant assert!( !variants.is_empty(), "#[derive(TvChannel)] requires at least one variant" ); + let enum_name = &ast.ident; + + let variant_names: Vec<_> = variants.iter().map(|v| &v.ident).collect(); + // Generate the trait implementation for the TelevisionChannel trait - // FIXME: fix this let trait_impl = quote! { - impl TelevisionChannel for AvailableChannel { + impl TelevisionChannel for #enum_name { fn find(&mut self, pattern: &str) { match self { #( - AvailableChannel::#variants(_) => { - self.find(pattern); + #enum_name::#variant_names(ref mut channel) => { + channel.find(pattern); } )* } @@ -124,8 +134,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream { fn results(&mut self, num_entries: u32, offset: u32) -> Vec { match self { #( - AvailableChannel::#variants(_) => { - self.results(num_entries, offset) + #enum_name::#variant_names(ref mut channel) => { + channel.results(num_entries, offset) } )* } @@ -134,8 +144,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream { fn get_result(&self, index: u32) -> Option { match self { #( - AvailableChannel::#variants(_) => { - self.get_result(index) + #enum_name::#variant_names(ref channel) => { + channel.get_result(index) } )* } @@ -144,8 +154,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream { fn result_count(&self) -> u32 { match self { #( - AvailableChannel::#variants(_) => { - self.result_count() + #enum_name::#variant_names(ref channel) => { + channel.result_count() } )* } @@ -154,8 +164,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream { fn total_count(&self) -> u32 { match self { #( - AvailableChannel::#variants(_) => { - self.total_count() + #enum_name::#variant_names(ref channel) => { + channel.total_count() } )* } @@ -164,8 +174,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream { fn running(&self) -> bool { match self { #( - AvailableChannel::#variants(_) => { - self.running() + #enum_name::#variant_names(ref channel) => { + channel.running() } )* }