diff --git a/benches/main/ui.rs b/benches/main/ui.rs index 5828636..8ef118b 100644 --- a/benches/main/ui.rs +++ b/benches/main/ui.rs @@ -9,7 +9,7 @@ use ratatui::style::Color; use ratatui::widgets::{Block, BorderType, Borders, ListDirection, Padding}; use ratatui::Terminal; use television::action::Action; -use television::channels::cable::CableChannelPrototype; +use television::channels::cable::prototypes::CableChannelPrototype; use television::channels::entry::into_ranges; use television::channels::entry::{Entry, PreviewType}; use television::channels::OnAir; diff --git a/television/cable.rs b/television/cable.rs index c2c98a0..d4fda31 100644 --- a/television/cable.rs +++ b/television/cable.rs @@ -2,11 +2,13 @@ use std::path::PathBuf; use rustc_hash::FxHashMap; -use crate::channels::cable::{CableChannelPrototype, CableChannels}; use anyhow::Result; use tracing::{debug, error}; -use crate::config::get_config_dir; +use crate::{ + channels::cable::prototypes::{CableChannelPrototype, CableChannels}, + config::get_config_dir, +}; /// Just a proxy struct to deserialize prototypes #[derive(Debug, serde::Deserialize, Default)] diff --git a/television/channels/cable.rs b/television/channels/cable.rs index 7731627..4479098 100644 --- a/television/channels/cable.rs +++ b/television/channels/cable.rs @@ -1,33 +1,20 @@ -use rustc_hash::FxHashMap; -use std::{ - fmt::{self, Display, Formatter}, - ops::Deref, -}; - use std::collections::HashSet; use std::io::{BufRead, BufReader}; use std::process::Stdio; -use anyhow::Result; -use regex::Regex; +use preview::{parse_preview_kind, PreviewKind}; +use prototypes::{CableChannelPrototype, DEFAULT_DELIMITER}; use rustc_hash::{FxBuildHasher, FxHashSet}; use tracing::debug; +use crate::channels::entry::{Entry, PreviewCommand, PreviewType}; use crate::channels::OnAir; use crate::matcher::Matcher; use crate::matcher::{config::Config, injector::Injector}; use crate::utils::command::shell_command; -use crate::{ - cable::ChannelPrototypes, - channels::entry::{Entry, PreviewCommand, PreviewType}, -}; -#[derive(Debug, Clone, PartialEq)] -pub enum PreviewKind { - Command(PreviewCommand), - Builtin(PreviewType), - None, -} +pub mod preview; +pub mod prototypes; #[allow(dead_code)] pub struct Channel { @@ -69,17 +56,6 @@ impl From for Channel { } } -pub fn parse_preview_kind(command: &PreviewCommand) -> Result { - debug!("Parsing preview kind for command: {:?}", command); - let re = Regex::new(r"^\:(\w+)\:$").unwrap(); - if let Some(captures) = re.captures(&command.command) { - let preview_type = PreviewType::try_from(&captures[1])?; - Ok(PreviewKind::Builtin(preview_type)) - } else { - Ok(PreviewKind::Command(command.clone())) - } -} - impl Channel { pub fn new( name: &str, @@ -234,94 +210,3 @@ impl OnAir for Channel { self.preview_kind != PreviewKind::None } } - -#[derive(Clone, Debug, serde::Deserialize, PartialEq)] -pub struct CableChannelPrototype { - pub name: String, - pub source_command: String, - #[serde(default)] - pub interactive: bool, - pub preview_command: Option, - #[serde(default = "default_delimiter")] - pub preview_delimiter: Option, -} - -impl CableChannelPrototype { - pub fn new( - name: &str, - source_command: &str, - interactive: bool, - preview_command: Option, - preview_delimiter: Option, - ) -> Self { - Self { - name: name.to_string(), - source_command: source_command.to_string(), - interactive, - preview_command, - preview_delimiter, - } - } -} - -const DEFAULT_PROTOTYPE_NAME: &str = "files"; -const DEFAULT_SOURCE_COMMAND: &str = "fd -t f"; -const DEFAULT_PREVIEW_COMMAND: &str = ":files:"; - -impl Default for CableChannelPrototype { - fn default() -> Self { - Self { - name: DEFAULT_PROTOTYPE_NAME.to_string(), - source_command: DEFAULT_SOURCE_COMMAND.to_string(), - interactive: false, - preview_command: Some(DEFAULT_PREVIEW_COMMAND.to_string()), - preview_delimiter: Some(DEFAULT_DELIMITER.to_string()), - } - } -} - -pub const DEFAULT_DELIMITER: &str = " "; - -#[allow(clippy::unnecessary_wraps)] -fn default_delimiter() -> Option { - Some(DEFAULT_DELIMITER.to_string()) -} - -impl Display for CableChannelPrototype { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -#[derive(Debug, serde::Deserialize)] -pub struct CableChannels(pub FxHashMap); - -impl Deref for CableChannels { - type Target = FxHashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[cfg(unix)] -const DEFAULT_CABLE_CHANNELS_FILE: &str = - include_str!("../../cable/unix-channels.toml"); -#[cfg(not(unix))] -const DEFAULT_CABLE_CHANNELS_FILE: &str = - include_str!("../../cable/windows-channels.toml"); - -impl Default for CableChannels { - /// Fallback to the default cable channels specification (the template file - /// included in the repo). - fn default() -> Self { - let pts = - toml::from_str::(DEFAULT_CABLE_CHANNELS_FILE) - .expect("Unable to parse default cable channels"); - let mut channels = FxHashMap::default(); - for prototype in pts.prototypes { - channels.insert(prototype.name.clone(), prototype); - } - CableChannels(channels) - } -} diff --git a/television/channels/cable/preview.rs b/television/channels/cable/preview.rs new file mode 100644 index 0000000..fb897c3 --- /dev/null +++ b/television/channels/cable/preview.rs @@ -0,0 +1,34 @@ +use anyhow::Result; +use regex::Regex; +use tracing::debug; + +use crate::channels::entry::{PreviewCommand, PreviewType}; + +#[derive(Debug, Clone, PartialEq)] +pub enum PreviewKind { + Command(PreviewCommand), + Builtin(PreviewType), + None, +} + +/// Parses the preview command to determine if it is a built-in (i.e. ":files:") or custom command. +/// +/// # Example: +/// ``` +/// use television::channels::entry::{PreviewCommand, PreviewType}; +/// use television::channels::cable::preview::{parse_preview_kind, PreviewKind}; +/// +/// let command = PreviewCommand::new("cat {0}", ":"); +/// let preview_kind = parse_preview_kind(&command).unwrap(); +/// assert_eq!(preview_kind, PreviewKind::Command(command)); +/// ``` +pub fn parse_preview_kind(command: &PreviewCommand) -> Result { + debug!("Parsing preview kind for command: {:?}", command); + let re = Regex::new(r"^\:(\w+)\:$").unwrap(); + if let Some(captures) = re.captures(&command.command) { + let preview_type = PreviewType::try_from(&captures[1])?; + Ok(PreviewKind::Builtin(preview_type)) + } else { + Ok(PreviewKind::Command(command.clone())) + } +} diff --git a/television/channels/cable/prototypes.rs b/television/channels/cable/prototypes.rs new file mode 100644 index 0000000..b36051b --- /dev/null +++ b/television/channels/cable/prototypes.rs @@ -0,0 +1,98 @@ +use rustc_hash::FxHashMap; +use std::{ + fmt::{self, Display, Formatter}, + ops::Deref, +}; + +use crate::cable::ChannelPrototypes; + +#[derive(Clone, Debug, serde::Deserialize, PartialEq)] +pub struct CableChannelPrototype { + pub name: String, + pub source_command: String, + #[serde(default)] + pub interactive: bool, + pub preview_command: Option, + #[serde(default = "default_delimiter")] + pub preview_delimiter: Option, +} + +impl CableChannelPrototype { + pub fn new( + name: &str, + source_command: &str, + interactive: bool, + preview_command: Option, + preview_delimiter: Option, + ) -> Self { + Self { + name: name.to_string(), + source_command: source_command.to_string(), + interactive, + preview_command, + preview_delimiter, + } + } +} + +const DEFAULT_PROTOTYPE_NAME: &str = "files"; +const DEFAULT_SOURCE_COMMAND: &str = "fd -t f"; +const DEFAULT_PREVIEW_COMMAND: &str = ":files:"; + +impl Default for CableChannelPrototype { + fn default() -> Self { + Self { + name: DEFAULT_PROTOTYPE_NAME.to_string(), + source_command: DEFAULT_SOURCE_COMMAND.to_string(), + interactive: false, + preview_command: Some(DEFAULT_PREVIEW_COMMAND.to_string()), + preview_delimiter: Some(DEFAULT_DELIMITER.to_string()), + } + } +} + +pub const DEFAULT_DELIMITER: &str = " "; + +#[allow(clippy::unnecessary_wraps)] +fn default_delimiter() -> Option { + Some(DEFAULT_DELIMITER.to_string()) +} + +impl Display for CableChannelPrototype { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +#[derive(Debug, serde::Deserialize)] +pub struct CableChannels(pub FxHashMap); + +impl Deref for CableChannels { + type Target = FxHashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[cfg(unix)] +const DEFAULT_CABLE_CHANNELS_FILE: &str = + include_str!("../../../cable/unix-channels.toml"); +#[cfg(not(unix))] +const DEFAULT_CABLE_CHANNELS_FILE: &str = + include_str!("../../cable/windows-channels.toml"); + +impl Default for CableChannels { + /// Fallback to the default cable channels specification (the template file + /// included in the repo). + fn default() -> Self { + let pts = + toml::from_str::(DEFAULT_CABLE_CHANNELS_FILE) + .expect("Unable to parse default cable channels"); + let mut channels = FxHashMap::default(); + for prototype in pts.prototypes { + channels.insert(prototype.name.clone(), prototype); + } + CableChannels(channels) + } +} diff --git a/television/channels/remote_control.rs b/television/channels/remote_control.rs index 1f85a30..c91cfd1 100644 --- a/television/channels/remote_control.rs +++ b/television/channels/remote_control.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::channels::cable::CableChannels; +use crate::channels::cable::prototypes::CableChannels; use crate::channels::entry::{Entry, PreviewType}; use crate::channels::{OnAir, TelevisionChannel}; use crate::matcher::{config::Config, Matcher}; diff --git a/television/cli/mod.rs b/television/cli/mod.rs index a9f1f8b..7e8cbe6 100644 --- a/television/cli/mod.rs +++ b/television/cli/mod.rs @@ -4,8 +4,13 @@ use std::path::Path; use anyhow::{anyhow, Result}; use tracing::debug; -use crate::channels::cable::{parse_preview_kind, CableChannels, PreviewKind}; -use crate::channels::{cable::CableChannelPrototype, entry::PreviewCommand}; +use crate::channels::cable::{ + preview::parse_preview_kind, preview::PreviewKind, + prototypes::CableChannels, +}; +use crate::channels::{ + cable::prototypes::CableChannelPrototype, entry::PreviewCommand, +}; use crate::cli::args::{Cli, Command}; use crate::config::{KeyBindings, DEFAULT_CHANNEL}; use crate::{ diff --git a/television/main.rs b/television/main.rs index 88c2ca0..d6b3592 100644 --- a/television/main.rs +++ b/television/main.rs @@ -6,7 +6,9 @@ use std::process::exit; use anyhow::Result; use clap::Parser; use television::cable; -use television::channels::cable::{CableChannels, PreviewKind}; +use television::channels::cable::{ + preview::PreviewKind, prototypes::CableChannels, +}; use television::utils::clipboard::CLIPBOARD; use tracing::{debug, error, info}; @@ -186,7 +188,8 @@ pub fn determine_channel( mod tests { use rustc_hash::FxHashMap; use television::{ - cable::load_cable_channels, channels::cable::CableChannelPrototype, + cable::load_cable_channels, + channels::cable::prototypes::CableChannelPrototype, }; use super::*; diff --git a/tests/app.rs b/tests/app.rs index c463007..5886388 100644 --- a/tests/app.rs +++ b/tests/app.rs @@ -3,7 +3,7 @@ use std::{collections::HashSet, path::PathBuf, time::Duration}; use television::{ action::Action, app::{App, AppOptions}, - channels::{cable::CableChannelPrototype, TelevisionChannel}, + channels::{cable::prototypes::CableChannelPrototype, TelevisionChannel}, config::default_config_from_file, }; use tokio::{task::JoinHandle, time::timeout};