diff --git a/benches/main/ui.rs b/benches/main/ui.rs index 5be7f17..d5689f7 100644 --- a/benches/main/ui.rs +++ b/benches/main/ui.rs @@ -8,12 +8,12 @@ use ratatui::prelude::{Line, Style}; use ratatui::style::Color; use ratatui::widgets::{Block, BorderType, Borders, ListDirection, Padding}; use ratatui::Terminal; +use television::channels::cable::prototypes::CableChannelPrototypes; use television::{ action::Action, channels::{ cable::prototypes::CableChannelPrototype, entry::{into_ranges, Entry}, - preview::PreviewType, OnAir, TelevisionChannel, }, config::{Config, ConfigEnv}, @@ -37,7 +37,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#7e8e91", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/README.md".to_string(), @@ -49,7 +48,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#dddddd", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/re.pyi".to_string(), @@ -61,7 +59,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/io.pyi".to_string(), @@ -73,7 +70,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/gc.pyi".to_string(), @@ -85,7 +81,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/uu.pyi".to_string(), @@ -97,7 +92,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/nt.pyi".to_string(), @@ -109,7 +103,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/dis.pyi".to_string(), @@ -121,7 +114,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/imp.pyi".to_string(), @@ -133,7 +125,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/bdb.pyi".to_string(), @@ -145,7 +136,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/abc.pyi".to_string(), @@ -157,7 +147,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/cgi.pyi".to_string(), @@ -169,7 +158,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/bz2.pyi".to_string(), @@ -181,7 +169,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/grp.pyi".to_string(), @@ -193,7 +180,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/ast.pyi".to_string(), @@ -205,7 +191,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/csv.pyi".to_string(), @@ -217,7 +202,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/pdb.pyi".to_string(), @@ -229,7 +213,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/pwd.pyi".to_string(), @@ -241,7 +224,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/ssl.pyi".to_string(), @@ -253,7 +235,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/tty.pyi".to_string(), @@ -265,7 +246,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/nis.pyi".to_string(), @@ -277,7 +257,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/pty.pyi".to_string(), @@ -289,7 +268,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/cmd.pyi".to_string(), @@ -301,7 +279,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/tests/utils.py".to_string(), @@ -313,7 +290,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/pyproject.toml".to_string(), @@ -325,7 +301,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#9c4221", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/MAINTAINERS.md".to_string(), @@ -337,7 +312,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#dddddd", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/enum.pyi".to_string(), @@ -349,7 +323,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/hmac.pyi".to_string(), @@ -361,7 +334,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/uuid.pyi".to_string(), @@ -373,7 +345,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/glob.pyi".to_string(), @@ -385,7 +356,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/_ast.pyi".to_string(), @@ -397,7 +367,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/_csv.pyi".to_string(), @@ -409,7 +378,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/code.pyi".to_string(), @@ -421,7 +389,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/spwd.pyi".to_string(), @@ -433,7 +400,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/_msi.pyi".to_string(), @@ -445,7 +411,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, }, Entry { name: "typeshed/stdlib/time.pyi".to_string(), @@ -456,7 +421,6 @@ pub fn draw_results_list(c: &mut Criterion) { color: "#ffbc03", }), line_number: None, - preview_type: PreviewType::Files, name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])), value_match_ranges: None, }, @@ -514,7 +478,14 @@ pub fn draw(c: &mut Criterion) { channel.find("television"); // Wait for the channel to finish loading let mut tv = Television::new( - tx, channel, config, None, false, false, false, + tx, + channel, + config, + None, + false, + false, + false, + CableChannelPrototypes::default(), ); for _ in 0..5 { // tick the matcher diff --git a/television/app.rs b/television/app.rs index 95ba068..95c46c3 100644 --- a/television/app.rs +++ b/television/app.rs @@ -4,6 +4,7 @@ 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::config::{default_tick_rate, Config}; use crate::keymap::Keymap; @@ -96,6 +97,8 @@ 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. @@ -139,6 +142,7 @@ impl App { config: Config, input: Option, options: AppOptions, + cable_channels: CableChannelPrototypes, ) -> Self { let (action_tx, action_rx) = mpsc::unbounded_channel(); let (render_tx, render_rx) = mpsc::unbounded_channel(); @@ -156,6 +160,7 @@ impl App { options.no_remote, options.no_help, options.exact, + CableChannelPrototypes(cable_channels.clone()), ); Self { @@ -173,6 +178,7 @@ impl App { ui_state_tx, render_task: None, options, + cable_channels, } } @@ -198,7 +204,7 @@ impl App { // Event loop if !headless { debug!("Starting backend event loop"); - let event_loop = EventLoop::new(self.options.tick_rate, true); + let event_loop = EventLoop::new(self.options.tick_rate); self.event_rx = event_loop.rx; self.event_abort_tx = event_loop.abort_tx; } @@ -437,15 +443,18 @@ impl App { #[cfg(test)] mod test { use super::*; - use crate::channels::stdin::Channel as StdinChannel; + use crate::channels::cable::Channel as CableChannel; #[test] fn test_maybe_select_1() { let mut app = App::new( - TelevisionChannel::Stdin(StdinChannel::new(None)), + TelevisionChannel::Cable(CableChannel::new( + "random", "cat", false, None, + )), Config::default(), None, AppOptions::default(), + CableChannelPrototypes::default(), ); app.television .results_picker diff --git a/television/cable.rs b/television/cable.rs index 7c16c2e..cb3de75 100644 --- a/television/cable.rs +++ b/television/cable.rs @@ -6,7 +6,9 @@ use anyhow::Result; use tracing::{debug, error}; use crate::{ - channels::cable::prototypes::{CableChannelPrototype, CableChannels}, + channels::cable::prototypes::{ + CableChannelPrototype, CableChannelPrototypes, + }, config::get_config_dir, }; @@ -40,7 +42,7 @@ const DEFAULT_CABLE_CHANNELS: &str = /// ├── my_channels.toml /// └── windows_channels.toml /// ``` -pub fn load_cable_channels() -> Result { +pub fn load_cable_channels() -> Result { let config_dir = get_config_dir(); // list all files in the config directory @@ -95,7 +97,7 @@ pub fn load_cable_channels() -> Result { { cable_channels.insert(prototype.name.clone(), prototype); } - Ok(CableChannels(cable_channels)) + Ok(CableChannelPrototypes(cable_channels)) } fn is_cable_file_format

(p: P) -> bool diff --git a/television/channels/cable.rs b/television/channels/cable.rs index 4710cd5..ddb50d0 100644 --- a/television/channels/cable.rs +++ b/television/channels/cable.rs @@ -18,7 +18,7 @@ pub struct Channel { pub name: String, matcher: Matcher, entries_command: String, - preview_command: Option, + pub preview_command: Option, selected_entries: FxHashSet, crawl_handle: tokio::task::JoinHandle<()>, } @@ -29,7 +29,7 @@ impl Default for Channel { "files", "find . -type f", false, - Some(PreviewCommand::new("cat {}", ":")), + Some(PreviewCommand::new("cat {}", ":", None)), ) } } @@ -46,6 +46,7 @@ impl From for Channel { &prototype .preview_delimiter .unwrap_or(DEFAULT_DELIMITER.to_string()), + prototype.preview_offset, )), None => None, }, diff --git a/television/channels/cable/prototypes.rs b/television/channels/cable/prototypes.rs index e5f139b..8d28931 100644 --- a/television/channels/cable/prototypes.rs +++ b/television/channels/cable/prototypes.rs @@ -106,9 +106,11 @@ impl Display for CableChannelPrototype { /// in a way that facilitates answering questions like "what's the prototype /// for `files`?" or "does this channel exist?". #[derive(Debug, serde::Deserialize)] -pub struct CableChannels(pub FxHashMap); +pub struct CableChannelPrototypes( + pub FxHashMap, +); -impl Deref for CableChannels { +impl Deref for CableChannelPrototypes { type Target = FxHashMap; fn deref(&self) -> &Self::Target { @@ -127,18 +129,18 @@ const DEFAULT_CABLE_CHANNELS_FILE: &str = const DEFAULT_CABLE_CHANNELS_FILE: &str = include_str!("../../cable/windows-channels.toml"); -impl Default for CableChannels { +impl Default for CableChannelPrototypes { /// Fallback to the default cable channels specification (the template file /// included in the repo). fn default() -> Self { - let pts = toml::from_str::( + let s = 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); + let mut prototypes = FxHashMap::default(); + for prototype in s.prototypes { + prototypes.insert(prototype.name.clone(), prototype); } - CableChannels(channels) + CableChannelPrototypes(prototypes) } } diff --git a/television/channels/mod.rs b/television/channels/mod.rs index 7eec13f..0021c13 100644 --- a/television/channels/mod.rs +++ b/television/channels/mod.rs @@ -7,7 +7,7 @@ pub mod cable; pub mod entry; pub mod preview; pub mod remote_control; -pub mod stdin; +// pub mod stdin; /// The interface that all television channels must implement. /// @@ -118,7 +118,7 @@ pub enum TelevisionChannel { /// The standard input channel. /// /// This channel allows to search through whatever is passed through stdin. - Stdin(stdin::Channel), + // Stdin(stdin::Channel), /// The remote control channel. /// /// This channel allows to switch between different channels. @@ -142,7 +142,7 @@ impl TelevisionChannel { pub fn name(&self) -> String { match self { TelevisionChannel::Cable(channel) => channel.name.clone(), - TelevisionChannel::Stdin(_) => String::from("Stdin"), + // TelevisionChannel::Stdin(_) => String::from("Stdin"), TelevisionChannel::RemoteControl(_) => String::from("Remote"), } } diff --git a/television/channels/preview.rs b/television/channels/preview.rs index 2539fd0..a95ee88 100644 --- a/television/channels/preview.rs +++ b/television/channels/preview.rs @@ -1,8 +1,8 @@ use std::fmt::Display; -use lazy_regex::{regex, Lazy, Regex}; - use super::entry::Entry; +use crate::channels::cable::prototypes::CableChannelPrototype; +use lazy_regex::{regex, Lazy, Regex}; static CMD_RE: &Lazy = regex!(r"\{(\d+)\}"); @@ -10,13 +10,19 @@ static CMD_RE: &Lazy = regex!(r"\{(\d+)\}"); pub struct PreviewCommand { pub command: String, pub delimiter: String, + pub offset_expr: Option, } impl PreviewCommand { - pub fn new(command: &str, delimiter: &str) -> Self { + pub fn new( + command: &str, + delimiter: &str, + offset_expr: Option, + ) -> Self { Self { command: command.to_string(), delimiter: delimiter.to_string(), + offset_expr, } } @@ -29,6 +35,7 @@ impl PreviewCommand { /// let command = PreviewCommand { /// command: "something {} {2} {0}".to_string(), /// delimiter: ":".to_string(), + /// offset_expr: None, /// }; /// let entry = Entry::new("a:given:entry:to:preview".to_string()); /// @@ -55,6 +62,29 @@ impl PreviewCommand { } } +impl TryFrom<&CableChannelPrototype> for PreviewCommand { + type Error = anyhow::Error; + + fn try_from(value: &CableChannelPrototype) -> Result { + let command = value + .preview_command + .as_ref() + .expect("Preview command is not set."); + + 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)) + } +} + impl Display for PreviewCommand { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{self:?}") @@ -71,6 +101,7 @@ mod tests { let command = PreviewCommand { command: "something {} {2} {0}".to_string(), delimiter: ":".to_string(), + offset_expr: None, }; let entry = Entry::new("an:entry:to:preview".to_string()); let formatted_command = command.format_with(&entry); @@ -86,6 +117,7 @@ mod tests { let command = PreviewCommand { command: "something".to_string(), delimiter: ":".to_string(), + offset_expr: None, }; let entry = Entry::new("an:entry:to:preview".to_string()); let formatted_command = command.format_with(&entry); @@ -98,6 +130,7 @@ mod tests { let command = PreviewCommand { command: "something {}".to_string(), delimiter: ":".to_string(), + offset_expr: None, }; let entry = Entry::new("an:entry:to:preview".to_string()); let formatted_command = command.format_with(&entry); @@ -110,6 +143,7 @@ mod tests { let command = PreviewCommand { command: "something {0} -t {2}".to_string(), delimiter: ":".to_string(), + offset_expr: None, }; let entry = Entry::new("an:entry:to:preview".to_string()); let formatted_command = command.format_with(&entry); diff --git a/television/channels/remote_control.rs b/television/channels/remote_control.rs index f32484d..dd11fb7 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::prototypes::CableChannels; +use crate::channels::cable::prototypes::CableChannelPrototypes; use crate::channels::entry::Entry; use crate::channels::{OnAir, TelevisionChannel}; use crate::matcher::{config::Config, Matcher}; @@ -12,19 +12,19 @@ use super::cable; pub struct RemoteControl { matcher: Matcher, - cable_channels: Option, + cable_channels: Option, selected_entries: FxHashSet, } const NUM_THREADS: usize = 1; impl RemoteControl { - pub fn new(cable_channels: Option) -> Self { + pub fn new(cable_channels: Option) -> Self { let matcher = Matcher::new(Config::default().n_threads(NUM_THREADS)); let injector = matcher.injector(); for c in cable_channels .as_ref() - .unwrap_or(&CableChannels::default()) + .unwrap_or(&CableChannelPrototypes::default()) .keys() { let () = injector.push(c.clone(), |e, cols| { diff --git a/television/channels/stdin.rs b/television/channels/stdin.rs index c29af12..c2d12fb 100644 --- a/television/channels/stdin.rs +++ b/television/channels/stdin.rs @@ -13,7 +13,7 @@ use crate::matcher::{config::Config, injector::Injector, Matcher}; pub struct Channel { matcher: Matcher, - preview_command: Option, + pub preview_command: Option, selected_entries: FxHashSet, instream_handle: std::thread::JoinHandle<()>, } diff --git a/television/cli/mod.rs b/television/cli/mod.rs index 6a56035..29ec7f7 100644 --- a/television/cli/mod.rs +++ b/television/cli/mod.rs @@ -5,7 +5,7 @@ use anyhow::{anyhow, Result}; use tracing::debug; use crate::channels::cable::prototypes::{ - CableChannelPrototype, CableChannels, + CableChannelPrototype, CableChannelPrototypes, }; use crate::channels::preview::PreviewCommand; use crate::cli::args::{Cli, Command}; @@ -76,6 +76,8 @@ impl From for PostProcessedCli { let preview_command = cli.preview.map(|preview| PreviewCommand { command: preview, delimiter: cli.delimiter.clone(), + // TODO: add the --preview-offset option to the CLI + offset_expr: None, }); let channel: CableChannelPrototype; @@ -170,7 +172,7 @@ fn parse_keybindings_literal( pub fn parse_channel( channel: &str, - cable_channels: &CableChannels, + cable_channels: &CableChannelPrototypes, ) -> Result { // try to parse the channel as a cable channel match cable_channels @@ -215,7 +217,7 @@ pub fn guess_channel_from_prompt( prompt: &str, command_mapping: &FxHashMap, fallback_channel: &str, - cable_channels: &CableChannels, + cable_channels: &CableChannelPrototypes, ) -> Result { debug!("Guessing channel from prompt: {}", prompt); // git checkout -qf @@ -317,7 +319,8 @@ mod tests { post_processed_cli.preview_command, Some(PreviewCommand { command: "bat -n --color=always {}".to_string(), - delimiter: ":".to_string() + delimiter: ":".to_string(), + offset_expr: None, }) ); assert_eq!(post_processed_cli.tick_rate, None); @@ -377,7 +380,7 @@ mod tests { /// Returns a tuple containing a command mapping and a fallback channel. fn guess_channel_from_prompt_setup<'a>( - ) -> (FxHashMap, &'a str, CableChannels) { + ) -> (FxHashMap, &'a str, CableChannelPrototypes) { let mut command_mapping = FxHashMap::default(); command_mapping.insert("vim".to_string(), "files".to_string()); command_mapping.insert("export".to_string(), "env".to_string()); diff --git a/television/event.rs b/television/event.rs index 8727feb..dd043dd 100644 --- a/television/event.rs +++ b/television/event.rs @@ -115,9 +115,7 @@ impl Display for Key { #[allow(clippy::module_name_repetitions)] pub struct EventLoop { pub rx: mpsc::UnboundedReceiver>, - //tx: mpsc::UnboundedSender>, pub abort_tx: mpsc::UnboundedSender<()>, - //tick_rate: std::time::Duration, } struct PollFuture { @@ -162,8 +160,7 @@ fn flush_existing_events() { } impl EventLoop { - // FIXME: this init parameter doesn't seem to be used anymore - pub fn new(tick_rate: f64, init: bool) -> Self { + pub fn new(tick_rate: f64) -> Self { let (tx, rx) = mpsc::unbounded_channel(); let tick_interval = Duration::from_secs_f64(1.0 / tick_rate); @@ -171,55 +168,52 @@ impl EventLoop { flush_existing_events(); - if init { - //let mut reader = crossterm::event::EventStream::new(); - tokio::spawn(async move { - loop { - let delay = tokio::time::sleep(tick_interval); - let event_available = poll_event(tick_interval); + tokio::spawn(async move { + loop { + let delay = tokio::time::sleep(tick_interval); + let event_available = poll_event(tick_interval); - tokio::select! { - // if we receive a message on the abort channel, stop the event loop - _ = abort_recv.recv() => { - tx.send(Event::Closed).unwrap_or_else(|_| warn!("Unable to send Closed event")); - tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); - break; - }, - _ = signal::ctrl_c() => { - debug!("Received SIGINT"); - tx.send(Event::Input(Key::Ctrl('c'))).unwrap_or_else(|_| warn!("Unable to send Ctrl-C event")); - }, - // if `delay` completes, pass to the next event "frame" - () = delay => { - tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); - }, - // if the receiver dropped the channel, stop the event loop - () = tx.closed() => break, - // if an event was received, process it - _ = event_available => { - let maybe_event = crossterm::event::read(); - match maybe_event { - Ok(crossterm::event::Event::Key(key)) => { - let key = convert_raw_event_to_key(key); - tx.send(Event::Input(key)).unwrap_or_else(|_| warn!("Unable to send {:?} event", key)); - }, - Ok(crossterm::event::Event::FocusLost) => { - tx.send(Event::FocusLost).unwrap_or_else(|_| warn!("Unable to send FocusLost event")); - }, - Ok(crossterm::event::Event::FocusGained) => { - tx.send(Event::FocusGained).unwrap_or_else(|_| warn!("Unable to send FocusGained event")); - }, - Ok(crossterm::event::Event::Resize(x, y)) => { - let (_, (new_x, new_y)) = flush_resize_events((x, y)); - tx.send(Event::Resize(new_x, new_y)).unwrap_or_else(|_| warn!("Unable to send Resize event")); - }, - _ => {} - } + tokio::select! { + // if we receive a message on the abort channel, stop the event loop + _ = abort_recv.recv() => { + tx.send(Event::Closed).unwrap_or_else(|_| warn!("Unable to send Closed event")); + tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); + break; + }, + _ = signal::ctrl_c() => { + debug!("Received SIGINT"); + tx.send(Event::Input(Key::Ctrl('c'))).unwrap_or_else(|_| warn!("Unable to send Ctrl-C event")); + }, + // if `delay` completes, pass to the next event "frame" + () = delay => { + tx.send(Event::Tick).unwrap_or_else(|_| warn!("Unable to send Tick event")); + }, + // if the receiver dropped the channel, stop the event loop + () = tx.closed() => break, + // if an event was received, process it + _ = event_available => { + let maybe_event = crossterm::event::read(); + match maybe_event { + Ok(crossterm::event::Event::Key(key)) => { + let key = convert_raw_event_to_key(key); + tx.send(Event::Input(key)).unwrap_or_else(|_| warn!("Unable to send {:?} event", key)); + }, + Ok(crossterm::event::Event::FocusLost) => { + tx.send(Event::FocusLost).unwrap_or_else(|_| warn!("Unable to send FocusLost event")); + }, + Ok(crossterm::event::Event::FocusGained) => { + tx.send(Event::FocusGained).unwrap_or_else(|_| warn!("Unable to send FocusGained event")); + }, + Ok(crossterm::event::Event::Resize(x, y)) => { + let (_, (new_x, new_y)) = flush_resize_events((x, y)); + tx.send(Event::Resize(new_x, new_y)).unwrap_or_else(|_| warn!("Unable to send Resize event")); + }, + _ => {} } } } - }); - } + } + }); Self { //tx, diff --git a/television/main.rs b/television/main.rs index a8d09cd..61bcebe 100644 --- a/television/main.rs +++ b/television/main.rs @@ -7,7 +7,9 @@ use anyhow::Result; use clap::Parser; use crossterm::terminal::enable_raw_mode; use television::cable; -use television::channels::cable::prototypes::CableChannels; +use television::channels::cable::prototypes::{ + CableChannelPrototype, CableChannelPrototypes, +}; use television::utils::clipboard::CLIPBOARD; use tracing::{debug, error, info}; @@ -81,7 +83,8 @@ async fn main() -> Result<()> { args.no_help, config.application.tick_rate, ); - let mut app = App::new(channel, config, args.input, options); + let mut app = + App::new(channel, config, args.input, options, cable_channels); stdout().flush()?; debug!("Running application..."); let output = app.run(stdout().is_terminal(), false).await?; @@ -157,8 +160,8 @@ pub fn determine_channel( args: PostProcessedCli, config: &Config, readable_stdin: bool, - cable_channels: &CableChannels, -) -> Result { + cable_channels: &CableChannelPrototypes, +) -> Result { if readable_stdin { debug!("Using stdin channel"); Ok(TelevisionChannel::Stdin(StdinChannel::new( @@ -197,9 +200,9 @@ mod tests { config: &Config, readable_stdin: bool, expected_channel: &TelevisionChannel, - cable_channels: Option, + cable_channels: Option, ) { - let channels: CableChannels = cable_channels + let channels: CableChannelPrototypes = cable_channels .unwrap_or_else(|| load_cable_channels().unwrap_or_default()); let channel = determine_channel(args.clone(), config, readable_stdin, &channels) diff --git a/television/television.rs b/television/television.rs index b075f90..9492c77 100644 --- a/television/television.rs +++ b/television/television.rs @@ -1,21 +1,29 @@ -use crate::action::Action; -use crate::cable::load_cable_channels; -use crate::channels::entry::{Entry, ENTRY_PLACEHOLDER}; -use crate::channels::{ - remote_control::RemoteControl, OnAir, TelevisionChannel, +use crate::{ + action::Action, + cable::load_cable_channels, + channels::{ + cable::{prototypes::CableChannelPrototypes, Channel as CableChannel}, + entry::{Entry, ENTRY_PLACEHOLDER}, + remote_control::RemoteControl, + // stdin::Channel as StdinChannel, + OnAir, + TelevisionChannel, + }, + config::{Config, Theme}, + draw::{ChannelState, Ctx, TvState}, + input::convert_action_to_input_request, + picker::Picker, + preview::{previewer::Previewer, Preview, PreviewState}, + render::UiState, + screen::{ + colors::Colorscheme, + layout::InputPosition, + spinner::{Spinner, SpinnerState}, + }, + utils::{ + clipboard::CLIPBOARD, metadata::AppMetadata, strings::EMPTY_STRING, + }, }; -use crate::config::{Config, Theme}; -use crate::draw::{ChannelState, Ctx, TvState}; -use crate::input::convert_action_to_input_request; -use crate::picker::Picker; -use crate::preview::{previewer::Previewer, Preview, PreviewState}; -use crate::render::UiState; -use crate::screen::colors::Colorscheme; -use crate::screen::layout::InputPosition; -use crate::screen::spinner::{Spinner, SpinnerState}; -use crate::utils::clipboard::CLIPBOARD; -use crate::utils::metadata::AppMetadata; -use crate::utils::strings::EMPTY_STRING; use anyhow::Result; use rustc_hash::{FxBuildHasher, FxHashSet}; use serde::{Deserialize, Serialize}; @@ -45,7 +53,7 @@ pub struct Television { pub matching_mode: MatchingMode, pub results_picker: Picker, pub rc_picker: Picker, - pub previewer: Previewer, + pub previewer: Option, pub preview_state: PreviewState, pub spinner: Spinner, pub spinner_state: SpinnerState, @@ -66,14 +74,24 @@ impl Television { no_remote: bool, no_help: bool, exact: bool, + cable_channels: CableChannelPrototypes, ) -> Self { let mut results_picker = Picker::new(input.clone()); if config.ui.input_bar_position == InputPosition::Bottom { results_picker = results_picker.inverted(); } - // FIXME: fix this - let previewer = Previewer::new(); - let cable_channels = load_cable_channels().unwrap_or_default(); + + let previewer = match &channel { + // TelevisionChannel::Stdin(StdinChannel { + // preview_command: command, + // .. + // }) | + TelevisionChannel::Cable(CableChannel { + preview_command: command, + .. + }) => command.clone().map(Previewer::new), + _ => None, + }; let app_metadata = AppMetadata::new( env!("CARGO_PKG_VERSION").to_string(), @@ -369,10 +387,14 @@ impl Television { &mut self, selected_entry: &Entry, ) -> Result<()> { - if self.config.ui.show_preview_panel && self.channel.supports_preview() + if self.config.ui.show_preview_panel + && self.channel.supports_preview() + && self.previewer.is_some() { // preview content - if let Some(preview) = self.previewer.preview(selected_entry) { + if let Some(preview) = + self.previewer.as_mut().unwrap().preview(selected_entry) + { // only update if the preview content has changed if self.preview_state.preview.title != preview.title { self.preview_state.update(