mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 03:25:23 +00:00
refactor: avoid multiple cable channel parsing passes
This commit is contained in:
parent
ba1c3fe8ee
commit
9b56e6687b
@ -15,8 +15,9 @@
|
|||||||
|
|
||||||
# General settings
|
# General settings
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
frame_rate = 60 # DEPRECATED: this option is no longer used
|
frame_rate = 60 # DEPRECATED: this option is no longer used
|
||||||
tick_rate = 50
|
tick_rate = 50
|
||||||
|
default_channel = "files"
|
||||||
|
|
||||||
[ui]
|
[ui]
|
||||||
# Whether to use nerd font icons in the UI
|
# Whether to use nerd font icons in the UI
|
||||||
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -11,6 +11,8 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
name: Test Suite
|
name: Test Suite
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -18,7 +20,7 @@ jobs:
|
|||||||
uses: dtolnay/rust-toolchain@nightly
|
uses: dtolnay/rust-toolchain@nightly
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: Install fd
|
- name: Install fd
|
||||||
run: sudo apt-get install -y fd-find
|
run: sudo apt install -y fd-find && sudo ln -s $(which fdfind) /usr/bin/fd
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --locked --all-features --workspace -- --nocapture
|
run: cargo test --locked --all-features --workspace -- --nocapture
|
||||||
|
|
||||||
|
@ -4,6 +4,13 @@ name = "files"
|
|||||||
source_command = "fd -t f"
|
source_command = "fd -t f"
|
||||||
preview_command = ":files:"
|
preview_command = ":files:"
|
||||||
|
|
||||||
|
# Text
|
||||||
|
[[cable_channel]]
|
||||||
|
name = "text"
|
||||||
|
source_command = "rg . --no-heading --line-number"
|
||||||
|
preview_command = "bat -n --color=always {0} -H {1}"
|
||||||
|
preview_delimiter = ":"
|
||||||
|
|
||||||
# Directories
|
# Directories
|
||||||
[[cable_channel]]
|
[[cable_channel]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
|
@ -10,9 +10,9 @@ use crate::config::get_config_dir;
|
|||||||
|
|
||||||
/// Just a proxy struct to deserialize prototypes
|
/// Just a proxy struct to deserialize prototypes
|
||||||
#[derive(Debug, serde::Deserialize, Default)]
|
#[derive(Debug, serde::Deserialize, Default)]
|
||||||
struct ChannelPrototypes {
|
pub struct ChannelPrototypes {
|
||||||
#[serde(rename = "cable_channel")]
|
#[serde(rename = "cable_channel")]
|
||||||
prototypes: Vec<CableChannelPrototype>,
|
pub prototypes: Vec<CableChannelPrototype>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CABLE_FILE_NAME_SUFFIX: &str = "channels";
|
const CABLE_FILE_NAME_SUFFIX: &str = "channels";
|
||||||
@ -85,6 +85,10 @@ pub fn load_cable_channels() -> Result<CableChannels> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
debug!("Loaded cable channels: {:?}", prototypes);
|
debug!("Loaded cable channels: {:?}", prototypes);
|
||||||
|
if prototypes.is_empty() {
|
||||||
|
error!("No cable channels found");
|
||||||
|
return Err(anyhow::anyhow!("No cable channels found"));
|
||||||
|
}
|
||||||
|
|
||||||
let mut cable_channels = FxHashMap::default();
|
let mut cable_channels = FxHashMap::default();
|
||||||
for prototype in prototypes {
|
for prototype in prototypes {
|
||||||
|
@ -13,11 +13,14 @@ use regex::Regex;
|
|||||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::channels::entry::{Entry, PreviewCommand, PreviewType};
|
|
||||||
use crate::channels::OnAir;
|
use crate::channels::OnAir;
|
||||||
use crate::matcher::Matcher;
|
use crate::matcher::Matcher;
|
||||||
use crate::matcher::{config::Config, injector::Injector};
|
use crate::matcher::{config::Config, injector::Injector};
|
||||||
use crate::utils::command::shell_command;
|
use crate::utils::command::shell_command;
|
||||||
|
use crate::{
|
||||||
|
cable::ChannelPrototypes,
|
||||||
|
channels::entry::{Entry, PreviewCommand, PreviewType},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum PreviewKind {
|
pub enum PreviewKind {
|
||||||
@ -39,10 +42,10 @@ pub struct Channel {
|
|||||||
impl Default for Channel {
|
impl Default for Channel {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
"Files",
|
"files",
|
||||||
"find . -type f",
|
"find . -type f",
|
||||||
false,
|
false,
|
||||||
Some(PreviewCommand::new("bat -n --color=always {}", ":")),
|
Some(PreviewCommand::new("cat {}", ":")),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,7 +293,7 @@ impl Display for CableChannelPrototype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, Default)]
|
#[derive(Debug, serde::Deserialize)]
|
||||||
pub struct CableChannels(pub FxHashMap<String, CableChannelPrototype>);
|
pub struct CableChannels(pub FxHashMap<String, CableChannelPrototype>);
|
||||||
|
|
||||||
impl Deref for CableChannels {
|
impl Deref for CableChannels {
|
||||||
@ -300,3 +303,25 @@ impl Deref for CableChannels {
|
|||||||
&self.0
|
&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::<ChannelPrototypes>(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,13 +9,8 @@ pub struct Cli {
|
|||||||
/// A list of the available channels can be displayed using the
|
/// A list of the available channels can be displayed using the
|
||||||
/// `list-channels` command. The channel can also be changed from within
|
/// `list-channels` command. The channel can also be changed from within
|
||||||
/// the application.
|
/// the application.
|
||||||
#[arg(
|
#[arg(value_enum, index = 1, verbatim_doc_comment)]
|
||||||
value_enum,
|
pub channel: Option<String>,
|
||||||
default_value = "files",
|
|
||||||
index = 1,
|
|
||||||
verbatim_doc_comment
|
|
||||||
)]
|
|
||||||
pub channel: String,
|
|
||||||
|
|
||||||
/// A preview command to use with the stdin channel.
|
/// A preview command to use with the stdin channel.
|
||||||
///
|
///
|
||||||
|
@ -4,10 +4,10 @@ use std::path::Path;
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::channels::cable::{parse_preview_kind, PreviewKind};
|
use crate::channels::cable::{parse_preview_kind, CableChannels, PreviewKind};
|
||||||
use crate::channels::{cable::CableChannelPrototype, entry::PreviewCommand};
|
use crate::channels::{cable::CableChannelPrototype, entry::PreviewCommand};
|
||||||
use crate::cli::args::{Cli, Command};
|
use crate::cli::args::{Cli, Command};
|
||||||
use crate::config::KeyBindings;
|
use crate::config::{KeyBindings, DEFAULT_CHANNEL};
|
||||||
use crate::{
|
use crate::{
|
||||||
cable,
|
cable,
|
||||||
config::{get_config_dir, get_data_dir},
|
config::{get_config_dir, get_data_dir},
|
||||||
@ -86,22 +86,37 @@ impl From<Cli> for PostProcessedCli {
|
|||||||
let channel: CableChannelPrototype;
|
let channel: CableChannelPrototype;
|
||||||
let working_directory: Option<String>;
|
let working_directory: Option<String>;
|
||||||
|
|
||||||
match parse_channel(&cli.channel) {
|
let cable_channels = cable::load_cable_channels().unwrap_or_default();
|
||||||
Ok(p) => {
|
if cli.channel.is_none() {
|
||||||
channel = p;
|
channel = cable_channels
|
||||||
working_directory = cli.working_directory;
|
.get(DEFAULT_CHANNEL)
|
||||||
}
|
.expect("Default channel not found in cable channels")
|
||||||
Err(_) => {
|
.clone();
|
||||||
// if the path is provided as first argument and it exists, use it as the working
|
working_directory = cli.working_directory;
|
||||||
// directory and default to the files channel
|
} else {
|
||||||
if cli.working_directory.is_none()
|
let cli_channel = cli.channel.as_ref().unwrap().to_owned();
|
||||||
&& Path::new(&cli.channel).exists()
|
match parse_channel(&cli_channel, &cable_channels) {
|
||||||
{
|
Ok(p) => {
|
||||||
channel = CableChannelPrototype::default();
|
channel = p;
|
||||||
working_directory = Some(cli.channel.clone());
|
working_directory = cli.working_directory;
|
||||||
} else {
|
}
|
||||||
unknown_channel_exit(&cli.channel);
|
Err(_) => {
|
||||||
unreachable!();
|
// if the path is provided as first argument and it exists, use it as the working
|
||||||
|
// directory and default to the files channel
|
||||||
|
if cli.working_directory.is_none()
|
||||||
|
&& Path::new(&cli_channel).exists()
|
||||||
|
{
|
||||||
|
channel = cable_channels
|
||||||
|
.get(DEFAULT_CHANNEL)
|
||||||
|
.expect(
|
||||||
|
"Default channel not found in cable channels",
|
||||||
|
)
|
||||||
|
.clone();
|
||||||
|
working_directory = Some(cli.channel.unwrap().clone());
|
||||||
|
} else {
|
||||||
|
unknown_channel_exit(&cli.channel.unwrap());
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,15 +172,17 @@ fn parse_keybindings_literal(
|
|||||||
toml::from_str(&toml_definition).map_err(|e| anyhow!(e))
|
toml::from_str(&toml_definition).map_err(|e| anyhow!(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_channel(channel: &str) -> Result<CableChannelPrototype> {
|
pub fn parse_channel(
|
||||||
let cable_channels = cable::load_cable_channels().unwrap_or_default();
|
channel: &str,
|
||||||
|
cable_channels: &CableChannels,
|
||||||
|
) -> Result<CableChannelPrototype> {
|
||||||
// try to parse the channel as a cable channel
|
// try to parse the channel as a cable channel
|
||||||
match cable_channels
|
match cable_channels
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(k, _)| k.to_lowercase() == channel)
|
.find(|(k, _)| k.to_lowercase() == channel)
|
||||||
{
|
{
|
||||||
Some((_, v)) => Ok(v.clone()),
|
Some((_, v)) => Ok(v.clone()),
|
||||||
None => Err(anyhow!("Unknown channel: {channel}")),
|
None => Err(anyhow!("The following channel wasn't found among cable channels: {channel}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,13 +218,18 @@ pub fn list_channels() {
|
|||||||
pub fn guess_channel_from_prompt(
|
pub fn guess_channel_from_prompt(
|
||||||
prompt: &str,
|
prompt: &str,
|
||||||
command_mapping: &FxHashMap<String, String>,
|
command_mapping: &FxHashMap<String, String>,
|
||||||
fallback_channel: CableChannelPrototype,
|
fallback_channel: &str,
|
||||||
|
cable_channels: &CableChannels,
|
||||||
) -> Result<CableChannelPrototype> {
|
) -> Result<CableChannelPrototype> {
|
||||||
debug!("Guessing channel from prompt: {}", prompt);
|
debug!("Guessing channel from prompt: {}", prompt);
|
||||||
// git checkout -qf
|
// git checkout -qf
|
||||||
// --- -------- --- <---------
|
// --- -------- --- <---------
|
||||||
|
let fallback = cable_channels
|
||||||
|
.get(fallback_channel)
|
||||||
|
.expect("Fallback channel not found in cable channels")
|
||||||
|
.clone();
|
||||||
if prompt.trim().is_empty() {
|
if prompt.trim().is_empty() {
|
||||||
return Ok(fallback_channel);
|
return Ok(fallback);
|
||||||
}
|
}
|
||||||
let rev_prompt_words = prompt.split_whitespace().rev();
|
let rev_prompt_words = prompt.split_whitespace().rev();
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
@ -221,7 +243,7 @@ pub fn guess_channel_from_prompt(
|
|||||||
for word in rev_prompt_words.clone() {
|
for word in rev_prompt_words.clone() {
|
||||||
// if the stack is empty, we have a match
|
// if the stack is empty, we have a match
|
||||||
if stack.is_empty() {
|
if stack.is_empty() {
|
||||||
return parse_channel(channel);
|
return parse_channel(channel, cable_channels);
|
||||||
}
|
}
|
||||||
// if the word matches the top of the stack, pop it
|
// if the word matches the top of the stack, pop it
|
||||||
if stack.last() == Some(&word) {
|
if stack.last() == Some(&word) {
|
||||||
@ -230,14 +252,14 @@ pub fn guess_channel_from_prompt(
|
|||||||
}
|
}
|
||||||
// if the stack is empty, we have a match
|
// if the stack is empty, we have a match
|
||||||
if stack.is_empty() {
|
if stack.is_empty() {
|
||||||
return parse_channel(channel);
|
return parse_channel(channel, cable_channels);
|
||||||
}
|
}
|
||||||
// reset the stack
|
// reset the stack
|
||||||
stack.clear();
|
stack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("No match found, falling back to default channel");
|
debug!("No match found, falling back to default channel");
|
||||||
Ok(fallback_channel)
|
Ok(fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION_MESSAGE: &str = env!("CARGO_PKG_VERSION");
|
const VERSION_MESSAGE: &str = env!("CARGO_PKG_VERSION");
|
||||||
@ -285,7 +307,7 @@ mod tests {
|
|||||||
#[allow(clippy::float_cmp)]
|
#[allow(clippy::float_cmp)]
|
||||||
fn test_from_cli() {
|
fn test_from_cli() {
|
||||||
let cli = Cli {
|
let cli = Cli {
|
||||||
channel: "files".to_string(),
|
channel: Some("files".to_string()),
|
||||||
preview: Some("bat -n --color=always {}".to_string()),
|
preview: Some("bat -n --color=always {}".to_string()),
|
||||||
delimiter: ":".to_string(),
|
delimiter: ":".to_string(),
|
||||||
working_directory: Some("/home/user".to_string()),
|
working_directory: Some("/home/user".to_string()),
|
||||||
@ -317,7 +339,7 @@ mod tests {
|
|||||||
#[allow(clippy::float_cmp)]
|
#[allow(clippy::float_cmp)]
|
||||||
fn test_from_cli_no_args() {
|
fn test_from_cli_no_args() {
|
||||||
let cli = Cli {
|
let cli = Cli {
|
||||||
channel: ".".to_string(),
|
channel: Some(".".to_string()),
|
||||||
delimiter: ":".to_string(),
|
delimiter: ":".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -338,7 +360,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_builtin_previewer_files() {
|
fn test_builtin_previewer_files() {
|
||||||
let cli = Cli {
|
let cli = Cli {
|
||||||
channel: "files".to_string(),
|
channel: Some("files".to_string()),
|
||||||
preview: Some(":files:".to_string()),
|
preview: Some(":files:".to_string()),
|
||||||
delimiter: ":".to_string(),
|
delimiter: ":".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -355,7 +377,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_builtin_previewer_env() {
|
fn test_builtin_previewer_env() {
|
||||||
let cli = Cli {
|
let cli = Cli {
|
||||||
channel: "files".to_string(),
|
channel: Some("files".to_string()),
|
||||||
preview: Some(":env_var:".to_string()),
|
preview: Some(":env_var:".to_string()),
|
||||||
delimiter: ":".to_string(),
|
delimiter: ":".to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -372,7 +394,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_custom_keybindings() {
|
fn test_custom_keybindings() {
|
||||||
let cli = Cli {
|
let cli = Cli {
|
||||||
channel: "files".to_string(),
|
channel: Some("files".to_string()),
|
||||||
preview: Some(":env_var:".to_string()),
|
preview: Some(":env_var:".to_string()),
|
||||||
delimiter: ":".to_string(),
|
delimiter: ":".to_string(),
|
||||||
keybindings: Some(
|
keybindings: Some(
|
||||||
@ -395,15 +417,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a tuple containing a command mapping and a fallback channel.
|
/// Returns a tuple containing a command mapping and a fallback channel.
|
||||||
fn guess_channel_from_prompt_setup(
|
fn guess_channel_from_prompt_setup<'a>(
|
||||||
) -> (FxHashMap<String, String>, CableChannelPrototype) {
|
) -> (FxHashMap<String, String>, &'a str, CableChannels) {
|
||||||
let mut command_mapping = FxHashMap::default();
|
let mut command_mapping = FxHashMap::default();
|
||||||
command_mapping.insert("vim".to_string(), "files".to_string());
|
command_mapping.insert("vim".to_string(), "files".to_string());
|
||||||
command_mapping.insert("export".to_string(), "env".to_string());
|
command_mapping.insert("export".to_string(), "env".to_string());
|
||||||
|
|
||||||
(
|
(
|
||||||
command_mapping,
|
command_mapping,
|
||||||
CableChannelPrototype::new("env", "", false, None, None),
|
"env",
|
||||||
|
cable::load_cable_channels().unwrap_or_default(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,11 +434,16 @@ mod tests {
|
|||||||
fn test_guess_channel_from_prompt_present() {
|
fn test_guess_channel_from_prompt_present() {
|
||||||
let prompt = "vim -d file1";
|
let prompt = "vim -d file1";
|
||||||
|
|
||||||
let (command_mapping, fallback) = guess_channel_from_prompt_setup();
|
let (command_mapping, fallback, channels) =
|
||||||
|
guess_channel_from_prompt_setup();
|
||||||
|
|
||||||
let channel =
|
let channel = guess_channel_from_prompt(
|
||||||
guess_channel_from_prompt(prompt, &command_mapping, fallback)
|
prompt,
|
||||||
.unwrap();
|
&command_mapping,
|
||||||
|
fallback,
|
||||||
|
&channels,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(channel.name, "files");
|
assert_eq!(channel.name, "files");
|
||||||
}
|
}
|
||||||
@ -424,31 +452,35 @@ mod tests {
|
|||||||
fn test_guess_channel_from_prompt_fallback() {
|
fn test_guess_channel_from_prompt_fallback() {
|
||||||
let prompt = "git checkout ";
|
let prompt = "git checkout ";
|
||||||
|
|
||||||
let (command_mapping, fallback) = guess_channel_from_prompt_setup();
|
let (command_mapping, fallback, channels) =
|
||||||
|
guess_channel_from_prompt_setup();
|
||||||
|
|
||||||
let channel = guess_channel_from_prompt(
|
let channel = guess_channel_from_prompt(
|
||||||
prompt,
|
prompt,
|
||||||
&command_mapping,
|
&command_mapping,
|
||||||
fallback.clone(),
|
fallback,
|
||||||
|
&channels,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(channel, fallback);
|
assert_eq!(channel.name, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_guess_channel_from_prompt_empty() {
|
fn test_guess_channel_from_prompt_empty() {
|
||||||
let prompt = "";
|
let prompt = "";
|
||||||
|
|
||||||
let (command_mapping, fallback) = guess_channel_from_prompt_setup();
|
let (command_mapping, fallback, channels) =
|
||||||
|
guess_channel_from_prompt_setup();
|
||||||
|
|
||||||
let channel = guess_channel_from_prompt(
|
let channel = guess_channel_from_prompt(
|
||||||
prompt,
|
prompt,
|
||||||
&command_mapping,
|
&command_mapping,
|
||||||
fallback.clone(),
|
fallback,
|
||||||
|
&channels,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(channel, fallback);
|
assert_eq!(channel.name, fallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,15 @@ pub struct AppConfig {
|
|||||||
pub frame_rate: f64,
|
pub frame_rate: f64,
|
||||||
#[serde(default = "default_tick_rate")]
|
#[serde(default = "default_tick_rate")]
|
||||||
pub tick_rate: f64,
|
pub tick_rate: f64,
|
||||||
|
/// The default channel to use when no channel is specified
|
||||||
|
#[serde(default = "default_channel")]
|
||||||
|
pub default_channel: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DEFAULT_CHANNEL: &str = "files";
|
||||||
|
|
||||||
|
fn default_channel() -> String {
|
||||||
|
DEFAULT_CHANNEL.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for AppConfig {
|
impl Hash for AppConfig {
|
||||||
|
@ -5,8 +5,8 @@ use std::process::exit;
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use television::channels::cable::PreviewKind;
|
use television::cable;
|
||||||
use television::cli::parse_channel;
|
use television::channels::cable::{CableChannels, PreviewKind};
|
||||||
use television::utils::clipboard::CLIPBOARD;
|
use television::utils::clipboard::CLIPBOARD;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
@ -43,6 +43,9 @@ async fn main() -> Result<()> {
|
|||||||
debug!("Loading configuration...");
|
debug!("Loading configuration...");
|
||||||
let mut config = Config::new(&ConfigEnv::init()?)?;
|
let mut config = Config::new(&ConfigEnv::init()?)?;
|
||||||
|
|
||||||
|
debug!("Loading cable channels...");
|
||||||
|
let cable_channels = cable::load_cable_channels().unwrap_or_default();
|
||||||
|
|
||||||
// optionally handle subcommands
|
// optionally handle subcommands
|
||||||
debug!("Handling subcommands...");
|
debug!("Handling subcommands...");
|
||||||
args.command
|
args.command
|
||||||
@ -58,8 +61,12 @@ async fn main() -> Result<()> {
|
|||||||
|
|
||||||
// determine the channel to use based on the CLI arguments and configuration
|
// determine the channel to use based on the CLI arguments and configuration
|
||||||
debug!("Determining channel...");
|
debug!("Determining channel...");
|
||||||
let channel =
|
let channel = determine_channel(
|
||||||
determine_channel(args.clone(), &config, is_readable_stdin())?;
|
args.clone(),
|
||||||
|
&config,
|
||||||
|
is_readable_stdin(),
|
||||||
|
&cable_channels,
|
||||||
|
)?;
|
||||||
|
|
||||||
CLIPBOARD.with(<_>::default);
|
CLIPBOARD.with(<_>::default);
|
||||||
|
|
||||||
@ -146,6 +153,7 @@ pub fn determine_channel(
|
|||||||
args: PostProcessedCli,
|
args: PostProcessedCli,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
readable_stdin: bool,
|
readable_stdin: bool,
|
||||||
|
cable_channels: &CableChannels,
|
||||||
) -> Result<TelevisionChannel> {
|
) -> Result<TelevisionChannel> {
|
||||||
if readable_stdin {
|
if readable_stdin {
|
||||||
debug!("Using stdin channel");
|
debug!("Using stdin channel");
|
||||||
@ -163,7 +171,8 @@ pub fn determine_channel(
|
|||||||
let channel = guess_channel_from_prompt(
|
let channel = guess_channel_from_prompt(
|
||||||
&prompt,
|
&prompt,
|
||||||
&config.shell_integration.commands,
|
&config.shell_integration.commands,
|
||||||
parse_channel(&config.shell_integration.fallback_channel)?,
|
&config.shell_integration.fallback_channel,
|
||||||
|
cable_channels,
|
||||||
)?;
|
)?;
|
||||||
debug!("Using guessed channel: {:?}", channel);
|
debug!("Using guessed channel: {:?}", channel);
|
||||||
Ok(TelevisionChannel::Cable(channel.into()))
|
Ok(TelevisionChannel::Cable(channel.into()))
|
||||||
@ -176,7 +185,9 @@ pub fn determine_channel(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use television::channels::cable::CableChannelPrototype;
|
use television::{
|
||||||
|
cable::load_cable_channels, channels::cable::CableChannelPrototype,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -185,9 +196,13 @@ mod tests {
|
|||||||
config: &Config,
|
config: &Config,
|
||||||
readable_stdin: bool,
|
readable_stdin: bool,
|
||||||
expected_channel: &TelevisionChannel,
|
expected_channel: &TelevisionChannel,
|
||||||
|
cable_channels: Option<CableChannels>,
|
||||||
) {
|
) {
|
||||||
|
let channels: CableChannels = cable_channels
|
||||||
|
.unwrap_or_else(|| load_cable_channels().unwrap_or_default());
|
||||||
let channel =
|
let channel =
|
||||||
determine_channel(args.clone(), config, readable_stdin).unwrap();
|
determine_channel(args.clone(), config, readable_stdin, &channels)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
channel.name(),
|
channel.name(),
|
||||||
@ -212,6 +227,7 @@ mod tests {
|
|||||||
&config,
|
&config,
|
||||||
true,
|
true,
|
||||||
&TelevisionChannel::Stdin(StdinChannel::new(PreviewType::None)),
|
&TelevisionChannel::Stdin(StdinChannel::new(PreviewType::None)),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +258,13 @@ mod tests {
|
|||||||
};
|
};
|
||||||
config.shell_integration.merge_triggers();
|
config.shell_integration.merge_triggers();
|
||||||
|
|
||||||
assert_is_correct_channel(&args, &config, false, &expected_channel);
|
assert_is_correct_channel(
|
||||||
|
&args,
|
||||||
|
&config,
|
||||||
|
false,
|
||||||
|
&expected_channel,
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -262,6 +284,7 @@ mod tests {
|
|||||||
CableChannelPrototype::new("dirs", "", false, None, None)
|
CableChannelPrototype::new("dirs", "", false, None, None)
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user