wip: a checkpoint with stdin as a regular channel which compiles

This commit is contained in:
Alexandre Pasmantier 2025-05-04 01:50:39 +02:00
parent 1bf67b537f
commit 11db510eb3
8 changed files with 81 additions and 92 deletions

View File

@ -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);

View File

@ -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<tokio::task::JoinHandle<Result<()>>>,
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<String>,
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(),

View File

@ -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<TelevisionChannel> {
pub fn zap(&self, channel_name: &str) -> Result<CableChannelPrototype> {
match self {
TelevisionChannel::RemoteControl(remote_control) => {
remote_control.zap(channel_name)

View File

@ -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;
fn try_from(value: &CableChannelPrototype) -> Result<Self, Self::Error> {
let command = value
.preview_command
.as_ref()
.expect("Preview command is not set.");
impl From<&CableChannelPrototype> for Option<PreviewCommand> {
fn from(value: &CableChannelPrototype) -> Self {
if let Some(command) = value.preview_command.as_ref() {
let delimiter = value
.preview_delimiter
.as_ref()
.expect("Preview delimiter is not set");
.map_or(DEFAULT_DELIMITER, |v| v);
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))
Some(PreviewCommand::new(command, delimiter, offset_expr))
} else {
None
}
}
}

View File

@ -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<String>,
@ -38,15 +38,13 @@ impl RemoteControl {
}
}
pub fn zap(&self, channel_name: &str) -> Result<TelevisionChannel> {
pub fn zap(&self, channel_name: &str) -> Result<CableChannelPrototype> {
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

View File

@ -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<CableChannelPrototype> {
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<CableChannelPrototypes>,
) {
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(
let expected_channel = CableChannelPrototype::new(
"dirs", "ls {}", false, None, None, None,
)
.into(),
);
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,
);
}

View File

@ -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<Previewer> {
fn from(value: &CableChannelPrototype) -> Self {
if let Some(preview_command) = value.into() {
Some(Previewer::new(preview_command))
} else {
None
}
}
}

View File

@ -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<Action>,
pub config: Config,
pub channel: TelevisionChannel,
pub channel: CableChannel,
pub remote_control: Option<TelevisionChannel>,
pub mode: Mode,
pub current_pattern: String,
@ -68,7 +71,7 @@ impl Television {
#[must_use]
pub fn new(
action_tx: UnboundedSender<Action>,
mut channel: TelevisionChannel,
channel_prototype: CableChannelPrototype,
mut config: Config,
input: Option<String>,
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<Previewer> = (&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();