fix(cable): don't panic when unable to format user template with entry (#516)

This commit is contained in:
Alex Pasmantier 2025-05-20 22:59:41 +02:00 committed by GitHub
parent 9127e419fb
commit 6b3c4ee773
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 7 deletions

View File

@ -152,6 +152,7 @@ async fn load_candidates(
if let Ok(l) = line { if let Ok(l) = line {
if !l.trim().is_empty() { if !l.trim().is_empty() {
let () = injector.push(l, |e, cols| { let () = injector.push(l, |e, cols| {
// PERF: maybe we can avoid cloning here by using &Utf32Str
cols[0] = e.clone().into(); cols[0] = e.clone().into();
}); });
produced_output = true; produced_output = true;

View File

@ -95,6 +95,19 @@ impl Display for ChannelPrototype {
pub static CMD_RE: &Lazy<Regex> = regex!(r"\{(\d+)\}"); pub static CMD_RE: &Lazy<Regex> = regex!(r"\{(\d+)\}");
/// Formats a prototype string with the given template and source strings.
///
/// # Example
/// ```
/// use television::channels::prototypes::format_prototype_string;
///
/// let template = "cat {} {1}";
/// let source = "foo:bar:baz";
/// let delimiter = ":";
///
/// let formatted = format_prototype_string(template, source, delimiter);
/// assert_eq!(formatted, "cat 'foo:bar:baz' 'bar'");
/// ```
pub fn format_prototype_string( pub fn format_prototype_string(
template: &str, template: &str,
source: &str, source: &str,
@ -108,8 +121,9 @@ pub fn format_prototype_string(
formatted_string = CMD_RE formatted_string = CMD_RE
.replace_all(&formatted_string, |caps: &regex::Captures| { .replace_all(&formatted_string, |caps: &regex::Captures| {
let index = let index =
// these unwraps are safe because of the regex pattern
caps.get(1).unwrap().as_str().parse::<usize>().unwrap(); caps.get(1).unwrap().as_str().parse::<usize>().unwrap();
format!("'{}'", parts[index]) format!("'{}'", parts.get(index).unwrap_or(&""))
}) })
.to_string(); .to_string();

View File

@ -131,10 +131,11 @@ impl Preview {
pub struct Previewer { pub struct Previewer {
config: Config, config: Config,
// FIXME: maybe use a bounded channel here with a single slot
requests: UnboundedReceiver<Request>, requests: UnboundedReceiver<Request>,
last_job_entry: Option<Entry>, last_job_entry: Option<Entry>,
preview_command: PreviewCommand, preview_command: PreviewCommand,
previews: UnboundedSender<Preview>, results: UnboundedSender<Preview>,
} }
impl Previewer { impl Previewer {
@ -149,7 +150,7 @@ impl Previewer {
requests: receiver, requests: receiver,
last_job_entry: None, last_job_entry: None,
preview_command, preview_command,
previews: sender, results: sender,
} }
} }
@ -166,7 +167,7 @@ impl Previewer {
debug!("Preview request is stale, skipping"); debug!("Preview request is stale, skipping");
continue; continue;
} }
let notify = self.previews.clone(); let results_handle = self.results.clone();
let command = let command =
self.preview_command.format_with(&ticket.entry); self.preview_command.format_with(&ticket.entry);
self.last_job_entry = Some(ticket.entry.clone()); self.last_job_entry = Some(ticket.entry.clone());
@ -174,7 +175,11 @@ impl Previewer {
match timeout( match timeout(
self.config.job_timeout, self.config.job_timeout,
tokio::spawn(async move { tokio::spawn(async move {
try_preview(&command, &ticket.entry, &notify); try_preview(
&command,
&ticket.entry,
&results_handle,
);
}), }),
) )
.await .await
@ -203,7 +208,7 @@ impl Previewer {
pub fn try_preview( pub fn try_preview(
command: &str, command: &str,
entry: &Entry, entry: &Entry,
notify: &UnboundedSender<Preview>, results_handle: &UnboundedSender<Preview>,
) { ) {
debug!("Preview command: {}", command); debug!("Preview command: {}", command);
@ -241,7 +246,7 @@ pub fn try_preview(
) )
} }
}; };
notify results_handle
.send(preview) .send(preview)
.expect("Unable to send preview result to main thread."); .expect("Unable to send preview result to main thread.");
} }