From ee71e4788f8ee3f6fd3891e6c0316a4a4df7b369 Mon Sep 17 00:00:00 2001 From: Alex Pasmantier <47638216+alexpasmantier@users.noreply.github.com> Date: Sat, 28 Dec 2024 19:35:21 +0100 Subject: [PATCH] feat(cable): using builtin previewers inside cable channel prototypes (#156) --- Cargo.lock | 1 + cable/unix-channels.toml | 4 +- crates/television-channels/Cargo.toml | 1 + .../television-channels/src/channels/cable.rs | 56 +++++++++++++++---- crates/television-channels/src/entry.rs | 7 ++- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71b8662..ebd1f33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3027,6 +3027,7 @@ dependencies = [ "eyre", "ignore", "lazy_static", + "regex", "serde", "strum", "television-derive", diff --git a/cable/unix-channels.toml b/cable/unix-channels.toml index 9b1fad7..cc6b27d 100644 --- a/cable/unix-channels.toml +++ b/cable/unix-channels.toml @@ -30,15 +30,13 @@ preview_command = "aws s3 ls s3://{0}" [[cable_channel]] name = "my-dotfiles" source_command = "fd -t f . $HOME/.config" -preview_command = "bat -n --color=always {0}" +preview_command = ":files:" # Shell history [[cable_channel]] name = "zsh-history" source_command = "tac $HOME/.zsh_history | cut -d\";\" -f 2-" -preview_command = "echo '{}'" [[cable_channel]] name = "bash-history" source_command = "tac $HOME/.bash_history" -preview_command = "echo '{}'" diff --git a/crates/television-channels/Cargo.toml b/crates/television-channels/Cargo.toml index b6aac52..9921afd 100644 --- a/crates/television-channels/Cargo.toml +++ b/crates/television-channels/Cargo.toml @@ -28,4 +28,5 @@ serde = "1.0.214" strum = { version = "0.26.3", features = ["derive"] } lazy_static = "1.5.0" toml = "0.8.19" +regex = "1.11.1" diff --git a/crates/television-channels/src/channels/cable.rs b/crates/television-channels/src/channels/cable.rs index 0dbed7c..14703e3 100644 --- a/crates/television-channels/src/channels/cable.rs +++ b/crates/television-channels/src/channels/cable.rs @@ -1,4 +1,8 @@ +use color_eyre::Result; +use lazy_static::lazy_static; +use regex::Regex; use std::collections::HashSet; +use tracing::debug; use crate::cable::{CableChannelPrototype, DEFAULT_DELIMITER}; use crate::channels::OnAir; @@ -9,12 +13,19 @@ use television_fuzzy::{ }; use television_utils::command::shell_command; +#[derive(Debug, Clone)] +enum PreviewKind { + Command(PreviewCommand), + Builtin(PreviewType), + None, +} + #[allow(dead_code)] pub struct Channel { name: String, matcher: Matcher, entries_command: String, - preview_command: Option, + preview_kind: PreviewKind, } impl Default for Channel { @@ -45,6 +56,20 @@ impl From for Channel { } } +lazy_static! { + static ref BUILTIN_PREVIEW_RE: Regex = Regex::new(r"^:(\w+):$").unwrap(); +} + +fn parse_preview_kind(command: &PreviewCommand) -> Result { + debug!("Parsing preview kind for command: {:?}", command); + if let Some(captures) = BUILTIN_PREVIEW_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, @@ -54,10 +79,19 @@ impl Channel { let matcher = Matcher::new(Config::default()); let injector = matcher.injector(); tokio::spawn(load_candidates(entries_command.to_string(), injector)); + let preview_kind = match preview_command { + Some(command) => { + parse_preview_kind(&command).unwrap_or_else(|_| { + panic!("Invalid preview command: {command}") + }) + } + None => PreviewKind::None, + }; + debug!("Preview kind: {:?}", preview_kind); Self { matcher, entries_command: entries_command.to_string(), - preview_command, + preview_kind, name: name.to_string(), } } @@ -95,12 +129,14 @@ impl OnAir for Channel { let path = item.matched_string; Entry::new( path.clone(), - match self.preview_command { - Some(ref preview_command) => { - // custom logic to parse builtins + match &self.preview_kind { + PreviewKind::Command(ref preview_command) => { PreviewType::Command(preview_command.clone()) } - None => PreviewType::None, + PreviewKind::Builtin(preview_type) => { + preview_type.clone() + } + PreviewKind::None => PreviewType::None, }, ) .with_name_match_ranges(item.match_indices) @@ -113,12 +149,12 @@ impl OnAir for Channel { let path = item.matched_string; Entry::new( path.clone(), - match self.preview_command { - Some(ref preview_command) => { - // custom logic to parse builtins + match &self.preview_kind { + PreviewKind::Command(ref preview_command) => { PreviewType::Command(preview_command.clone()) } - None => PreviewType::None, + PreviewKind::Builtin(preview_type) => preview_type.clone(), + PreviewKind::None => PreviewType::None, }, ) }) diff --git a/crates/television-channels/src/entry.rs b/crates/television-channels/src/entry.rs index f8f15c2..77c58ee 100644 --- a/crates/television-channels/src/entry.rs +++ b/crates/television-channels/src/entry.rs @@ -1,6 +1,7 @@ use std::{fmt::Display, path::PathBuf}; use devicons::FileIcon; +use strum::EnumString; // NOTE: having an enum for entry types would be nice since it would allow // having a nicer implementation for transitions between channels. This would @@ -136,7 +137,7 @@ pub const ENTRY_PLACEHOLDER: Entry = Entry { preview_type: PreviewType::EnvVar, }; -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] pub struct PreviewCommand { pub command: String, pub delimiter: String, @@ -157,12 +158,14 @@ impl Display for PreviewCommand { } } -#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, EnumString)] +#[strum(serialize_all = "snake_case")] pub enum PreviewType { #[default] Basic, EnvVar, Files, + #[strum(disabled)] Command(PreviewCommand), None, }