mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-07 12:05:34 +00:00
type channels with an enum rather than a dyn trait
This commit is contained in:
parent
db3aa1ad49
commit
10f302546d
@ -56,7 +56,7 @@ use color_eyre::Result;
|
|||||||
use tokio::sync::{mpsc, Mutex};
|
use tokio::sync::{mpsc, Mutex};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use crate::channels::CliTvChannel;
|
use crate::channels::{AvailableChannel, CliTvChannel};
|
||||||
use crate::television::Television;
|
use crate::television::Television;
|
||||||
use crate::{
|
use crate::{
|
||||||
action::Action,
|
action::Action,
|
||||||
@ -84,7 +84,7 @@ pub struct App {
|
|||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
channel: CliTvChannel,
|
channel: AvailableChannel,
|
||||||
tick_rate: f64,
|
tick_rate: f64,
|
||||||
frame_rate: f64,
|
frame_rate: f64,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
|
@ -7,7 +7,7 @@ pub mod channels;
|
|||||||
mod env;
|
mod env;
|
||||||
mod files;
|
mod files;
|
||||||
mod git_repos;
|
mod git_repos;
|
||||||
mod stdin;
|
pub mod stdin;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
/// The interface that all television channels must implement.
|
/// The interface that all television channels must implement.
|
||||||
@ -97,6 +97,7 @@ pub enum AvailableChannel {
|
|||||||
Text(text::Channel),
|
Text(text::Channel),
|
||||||
Stdin(stdin::Channel),
|
Stdin(stdin::Channel),
|
||||||
Alias(alias::Channel),
|
Alias(alias::Channel),
|
||||||
|
Channel(channels::SelectionChannel),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: this could be generated by a derive macro
|
/// NOTE: this could be generated by a derive macro
|
||||||
@ -104,7 +105,7 @@ impl TryFrom<&Entry> for AvailableChannel {
|
|||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(entry: &Entry) -> Result<Self, Self::Error> {
|
fn try_from(entry: &Entry) -> Result<Self, Self::Error> {
|
||||||
match entry.name.as_ref() {
|
match entry.name.to_ascii_lowercase().as_ref() {
|
||||||
"env" => Ok(AvailableChannel::Env(env::Channel::default())),
|
"env" => Ok(AvailableChannel::Env(env::Channel::default())),
|
||||||
"files" => Ok(AvailableChannel::Files(files::Channel::default())),
|
"files" => Ok(AvailableChannel::Files(files::Channel::default())),
|
||||||
"gitrepos" => {
|
"gitrepos" => {
|
||||||
|
@ -8,7 +8,7 @@ use nucleo::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
channels::{CliTvChannel, TelevisionChannel},
|
channels::{AvailableChannel, CliTvChannel, TelevisionChannel},
|
||||||
entry::Entry,
|
entry::Entry,
|
||||||
fuzzy::MATCHER,
|
fuzzy::MATCHER,
|
||||||
previewers::PreviewType,
|
previewers::PreviewType,
|
||||||
@ -24,8 +24,6 @@ pub struct SelectionChannel {
|
|||||||
|
|
||||||
const NUM_THREADS: usize = 1;
|
const NUM_THREADS: usize = 1;
|
||||||
|
|
||||||
const CHANNEL_BLACKLIST: [CliTvChannel; 1] = [CliTvChannel::Stdin];
|
|
||||||
|
|
||||||
impl SelectionChannel {
|
impl SelectionChannel {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let matcher = Nucleo::new(
|
let matcher = Nucleo::new(
|
||||||
@ -36,9 +34,6 @@ impl SelectionChannel {
|
|||||||
);
|
);
|
||||||
let injector = matcher.injector();
|
let injector = matcher.injector();
|
||||||
for variant in CliTvChannel::value_variants() {
|
for variant in CliTvChannel::value_variants() {
|
||||||
if CHANNEL_BLACKLIST.contains(variant) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let _ = injector.push(*variant, |e, cols| {
|
let _ = injector.push(*variant, |e, cols| {
|
||||||
cols[0] = (*e).to_string().into();
|
cols[0] = (*e).to_string().into();
|
||||||
});
|
});
|
||||||
@ -55,6 +50,12 @@ impl SelectionChannel {
|
|||||||
const MATCHER_TICK_TIMEOUT: u64 = 2;
|
const MATCHER_TICK_TIMEOUT: u64 = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SelectionChannel {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TV_ICON: FileIcon = FileIcon {
|
const TV_ICON: FileIcon = FileIcon {
|
||||||
icon: '📺',
|
icon: '📺',
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use std::io::{stdout, IsTerminal, Write};
|
use std::io::{stdout, IsTerminal, Write};
|
||||||
|
|
||||||
|
use channels::AvailableChannel;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::channels::CliTvChannel;
|
use crate::channels::stdin::Channel as StdinChannel;
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
|
|
||||||
mod action;
|
mod action;
|
||||||
@ -36,10 +37,10 @@ async fn main() -> Result<()> {
|
|||||||
{
|
{
|
||||||
if is_readable_stdin() {
|
if is_readable_stdin() {
|
||||||
debug!("Using stdin channel");
|
debug!("Using stdin channel");
|
||||||
CliTvChannel::Stdin
|
AvailableChannel::Stdin(StdinChannel::default())
|
||||||
} else {
|
} else {
|
||||||
debug!("Using {:?} channel", args.channel);
|
debug!("Using {:?} channel", args.channel);
|
||||||
args.channel
|
args.channel.to_channel()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
args.tick_rate,
|
args.tick_rate,
|
||||||
|
@ -71,9 +71,8 @@ pub struct Television {
|
|||||||
|
|
||||||
impl Television {
|
impl Television {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(cli_channel: CliTvChannel) -> Self {
|
pub fn new(mut channel: AvailableChannel) -> Self {
|
||||||
let mut tv_channel = cli_channel.to_channel();
|
channel.find(EMPTY_STRING);
|
||||||
tv_channel.find(EMPTY_STRING);
|
|
||||||
|
|
||||||
let spinner = Spinner::default();
|
let spinner = Spinner::default();
|
||||||
let spinner_state = SpinnerState::from(&spinner);
|
let spinner_state = SpinnerState::from(&spinner);
|
||||||
@ -81,7 +80,7 @@ impl Television {
|
|||||||
Self {
|
Self {
|
||||||
action_tx: None,
|
action_tx: None,
|
||||||
config: Config::default(),
|
config: Config::default(),
|
||||||
channel: tv_channel,
|
channel,
|
||||||
current_pattern: EMPTY_STRING.to_string(),
|
current_pattern: EMPTY_STRING.to_string(),
|
||||||
mode: Mode::Channel,
|
mode: Mode::Channel,
|
||||||
input: Input::new(EMPTY_STRING.to_string()),
|
input: Input::new(EMPTY_STRING.to_string()),
|
||||||
@ -99,7 +98,7 @@ impl Television {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_channel(&mut self, channel: Box<dyn TelevisionChannel>) {
|
pub fn change_channel(&mut self, channel: AvailableChannel) {
|
||||||
self.reset_preview_scroll();
|
self.reset_preview_scroll();
|
||||||
self.reset_results_selection();
|
self.reset_results_selection();
|
||||||
self.current_pattern = EMPTY_STRING.to_string();
|
self.current_pattern = EMPTY_STRING.to_string();
|
||||||
@ -296,7 +295,8 @@ impl Television {
|
|||||||
Action::ScrollPreviewHalfPageUp => self.scroll_preview_up(20),
|
Action::ScrollPreviewHalfPageUp => self.scroll_preview_up(20),
|
||||||
Action::ToChannelSelection => {
|
Action::ToChannelSelection => {
|
||||||
self.mode = Mode::ChannelSelection;
|
self.mode = Mode::ChannelSelection;
|
||||||
let selection_channel = Box::new(SelectionChannel::new());
|
let selection_channel =
|
||||||
|
AvailableChannel::Channel(SelectionChannel::new());
|
||||||
self.change_channel(selection_channel);
|
self.change_channel(selection_channel);
|
||||||
}
|
}
|
||||||
Action::SelectEntry => {
|
Action::SelectEntry => {
|
||||||
@ -308,10 +308,12 @@ impl Television {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.send(Action::SelectAndExit)?,
|
.send(Action::SelectAndExit)?,
|
||||||
Mode::ChannelSelection => {
|
Mode::ChannelSelection => {
|
||||||
self.mode = Mode::Channel;
|
if let Ok(new_channel) =
|
||||||
let new_channel =
|
AvailableChannel::try_from(&entry)
|
||||||
AvailableChannel::from_entry(&entry)?;
|
{
|
||||||
self.change_channel(new_channel);
|
self.mode = Mode::Channel;
|
||||||
|
self.change_channel(new_channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ pub fn cli_channel_derive(input: TokenStream) -> TokenStream {
|
|||||||
impl_cli_channel(&ast)
|
impl_cli_channel(&ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VARIANT_BLACKLIST: [&str; 2] = ["Stdin", "Channel"];
|
||||||
|
|
||||||
fn impl_cli_channel(ast: &syn::DeriveInput) -> TokenStream {
|
fn impl_cli_channel(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
// check that the struct is an enum
|
// check that the struct is an enum
|
||||||
let variants = if let syn::Data::Enum(data_enum) = &ast.data {
|
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
|
// create the CliTvChannel enum
|
||||||
let cli_enum_variants = variants.iter().map(|variant| {
|
let cli_enum_variants = variants
|
||||||
let variant_name = &variant.ident;
|
.iter()
|
||||||
quote! {
|
.filter(|v| !VARIANT_BLACKLIST.contains(&v.ident.to_string().as_str()))
|
||||||
#variant_name
|
.map(|variant| {
|
||||||
}
|
let variant_name = &variant.ident;
|
||||||
});
|
quote! {
|
||||||
|
#variant_name
|
||||||
|
}
|
||||||
|
});
|
||||||
let cli_enum = quote! {
|
let cli_enum = quote! {
|
||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
use serde::{Deserialize, Serialize};
|
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
|
// 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;
|
let variant_name = &variant.ident;
|
||||||
|
|
||||||
// Get the inner type of the variant, assuming it is the first field of the variant
|
// 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 {
|
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 {
|
let variants = if let syn::Data::Enum(data_enum) = &ast.data {
|
||||||
&data_enum.variants
|
&data_enum.variants
|
||||||
} else {
|
} else {
|
||||||
panic!("#[derive(TvChannel)] is only defined for enums");
|
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!(
|
assert!(
|
||||||
!variants.is_empty(),
|
!variants.is_empty(),
|
||||||
"#[derive(TvChannel)] requires at least one variant"
|
"#[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
|
// Generate the trait implementation for the TelevisionChannel trait
|
||||||
// FIXME: fix this
|
|
||||||
let trait_impl = quote! {
|
let trait_impl = quote! {
|
||||||
impl TelevisionChannel for AvailableChannel {
|
impl TelevisionChannel for #enum_name {
|
||||||
fn find(&mut self, pattern: &str) {
|
fn find(&mut self, pattern: &str) {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
AvailableChannel::#variants(_) => {
|
#enum_name::#variant_names(ref mut channel) => {
|
||||||
self.find(pattern);
|
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<Entry> {
|
fn results(&mut self, num_entries: u32, offset: u32) -> Vec<Entry> {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
AvailableChannel::#variants(_) => {
|
#enum_name::#variant_names(ref mut channel) => {
|
||||||
self.results(num_entries, offset)
|
channel.results(num_entries, offset)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@ -134,8 +144,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream {
|
|||||||
fn get_result(&self, index: u32) -> Option<Entry> {
|
fn get_result(&self, index: u32) -> Option<Entry> {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
AvailableChannel::#variants(_) => {
|
#enum_name::#variant_names(ref channel) => {
|
||||||
self.get_result(index)
|
channel.get_result(index)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@ -144,8 +154,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream {
|
|||||||
fn result_count(&self) -> u32 {
|
fn result_count(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
AvailableChannel::#variants(_) => {
|
#enum_name::#variant_names(ref channel) => {
|
||||||
self.result_count()
|
channel.result_count()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@ -154,8 +164,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream {
|
|||||||
fn total_count(&self) -> u32 {
|
fn total_count(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
AvailableChannel::#variants(_) => {
|
#enum_name::#variant_names(ref channel) => {
|
||||||
self.total_count()
|
channel.total_count()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@ -164,8 +174,8 @@ fn impl_tv_channel(ast: &syn::DeriveInput) -> TokenStream {
|
|||||||
fn running(&self) -> bool {
|
fn running(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
AvailableChannel::#variants(_) => {
|
#enum_name::#variant_names(ref channel) => {
|
||||||
self.running()
|
channel.running()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user