mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 19:45:23 +00:00
150 lines
4.6 KiB
Rust
150 lines
4.6 KiB
Rust
use rustc_hash::FxHashMap;
|
|
use std::{
|
|
fmt::{self, Display, Formatter},
|
|
ops::Deref,
|
|
};
|
|
|
|
use crate::{
|
|
cable::CableSpec, channels::preview::PreviewCommand,
|
|
cli::unknown_channel_exit,
|
|
};
|
|
|
|
/// A prototype for cable channels.
|
|
///
|
|
/// This can be seen as a cable channel specification, which is used to
|
|
/// create a cable channel.
|
|
///
|
|
/// The prototype contains the following fields:
|
|
/// - `name`: The name of the channel. This will be used to identify the
|
|
/// channel throughout the application and in UI menus.
|
|
/// - `source_command`: The command to run to get the source for the channel.
|
|
/// This is a shell command that will be run in the background.
|
|
/// - `interactive`: Whether the source command should be run in an interactive
|
|
/// shell. This is useful for commands that need the user's environment e.g.
|
|
/// `alias`.
|
|
/// - `preview_command`: The command to run on each entry to get the preview
|
|
/// for the channel. If this is not `None`, the channel will display a preview
|
|
/// pane with the output of this command.
|
|
/// - `preview_delimiter`: The delimiter to use to split an entry into
|
|
/// multiple parts that can then be referenced in the preview command (e.g.
|
|
/// `{1} + {2}`).
|
|
/// - `preview_offset`: a litteral expression that will be interpreted later on
|
|
/// in order to determine the vertical offset at which the preview should be
|
|
/// displayed.
|
|
///
|
|
/// # Example
|
|
/// The default files channel might look something like this:
|
|
/// ```toml
|
|
/// [[cable_channel]]
|
|
/// name = "files"
|
|
/// source_command = "fd -t f"
|
|
/// preview_command = "cat {}"
|
|
/// ```
|
|
#[derive(Clone, Debug, serde::Deserialize, PartialEq)]
|
|
pub struct ChannelPrototype {
|
|
pub name: String,
|
|
pub source_command: String,
|
|
#[serde(default)]
|
|
pub interactive: bool,
|
|
#[serde(rename = "preview")]
|
|
pub preview_command: Option<PreviewCommand>,
|
|
}
|
|
|
|
const STDIN_CHANNEL_NAME: &str = "stdin";
|
|
const STDIN_SOURCE_COMMAND: &str = "cat";
|
|
|
|
impl ChannelPrototype {
|
|
pub fn new(
|
|
name: &str,
|
|
source_command: &str,
|
|
interactive: bool,
|
|
preview_command: Option<PreviewCommand>,
|
|
) -> Self {
|
|
Self {
|
|
name: name.to_string(),
|
|
source_command: source_command.to_string(),
|
|
interactive,
|
|
preview_command,
|
|
}
|
|
}
|
|
|
|
pub fn stdin(preview: Option<PreviewCommand>) -> Self {
|
|
Self {
|
|
name: STDIN_CHANNEL_NAME.to_string(),
|
|
source_command: STDIN_SOURCE_COMMAND.to_string(),
|
|
interactive: false,
|
|
preview_command: preview,
|
|
}
|
|
}
|
|
|
|
pub fn set_preview(self, preview_command: Option<PreviewCommand>) -> Self {
|
|
Self::new(
|
|
&self.name,
|
|
&self.source_command,
|
|
self.interactive,
|
|
preview_command,
|
|
)
|
|
}
|
|
}
|
|
|
|
pub const DEFAULT_PROTOTYPE_NAME: &str = "files";
|
|
|
|
impl Display for ChannelPrototype {
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
write!(f, "{}", self.name)
|
|
}
|
|
}
|
|
|
|
/// A neat `HashMap` of channel prototypes indexed by their name.
|
|
///
|
|
/// This is used to store cable channel prototypes throughout the application
|
|
/// in a way that facilitates answering questions like "what's the prototype
|
|
/// for `files`?" or "does this channel exist?".
|
|
#[derive(Debug, serde::Deserialize, Clone)]
|
|
pub struct Cable(pub FxHashMap<String, ChannelPrototype>);
|
|
|
|
impl Deref for Cable {
|
|
type Target = FxHashMap<String, ChannelPrototype>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl Cable {
|
|
pub fn get_channel(&self, name: &str) -> ChannelPrototype {
|
|
self.get(name)
|
|
.cloned()
|
|
.unwrap_or_else(|| unknown_channel_exit(name))
|
|
}
|
|
|
|
pub fn has_channel(&self, name: &str) -> bool {
|
|
self.contains_key(name)
|
|
}
|
|
}
|
|
|
|
/// A default cable channels specification that is compiled into the
|
|
/// application.
|
|
#[cfg(unix)]
|
|
const DEFAULT_CABLE_CHANNELS_FILE: &str =
|
|
include_str!("../../cable/unix-channels.toml");
|
|
/// A default cable channels specification that is compiled into the
|
|
/// application.
|
|
#[cfg(not(unix))]
|
|
const DEFAULT_CABLE_CHANNELS_FILE: &str =
|
|
include_str!("../../cable/windows-channels.toml");
|
|
|
|
impl Default for Cable {
|
|
/// Fallback to the default cable channels specification (the template file
|
|
/// included in the repo).
|
|
fn default() -> Self {
|
|
let s = toml::from_str::<CableSpec>(DEFAULT_CABLE_CHANNELS_FILE)
|
|
.expect("Unable to parse default cable channels");
|
|
let mut prototypes = FxHashMap::default();
|
|
for prototype in s.prototypes {
|
|
prototypes.insert(prototype.name.clone(), prototype);
|
|
}
|
|
Cable(prototypes)
|
|
}
|
|
}
|