refactor(cable): stream in cable results + better error logging + default delimiter consistency (#257)

This commit is contained in:
Alex Pasmantier 2025-01-09 13:30:31 +01:00 committed by GitHub
parent ea8b955e6d
commit 3b7fb0c6d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 19 deletions

View File

@ -1,4 +1,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::io::{BufRead, BufReader};
use std::process::Stdio;
use color_eyre::Result; use color_eyre::Result;
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -104,19 +106,37 @@ impl Channel {
#[allow(clippy::unused_async)] #[allow(clippy::unused_async)]
async fn load_candidates(command: String, injector: Injector<String>) { async fn load_candidates(command: String, injector: Injector<String>) {
debug!("Loading candidates from command: {:?}", command); debug!("Loading candidates from command: {:?}", command);
let output = shell_command() let mut child = shell_command()
.arg(command) .arg(command)
.output() .stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to execute process"); .expect("failed to execute process");
let decoded_output = String::from_utf8_lossy(&output.stdout); if let Some(out) = child.stdout.take() {
debug!("Decoded output: {:?}", decoded_output); let reader = BufReader::new(out);
let mut produced_output = false;
for line in decoded_output.lines() { for line in reader.lines() {
if !line.trim().is_empty() { let line = line.unwrap();
let () = injector.push(line.to_string(), |e, cols| { if !line.trim().is_empty() {
cols[0] = e.clone().into(); let () = injector.push(line, |e, cols| {
}); cols[0] = e.clone().into();
});
produced_output = true;
}
}
if !produced_output {
let reader = BufReader::new(child.stderr.take().unwrap());
for line in reader.lines() {
let line = line.unwrap();
if !line.trim().is_empty() {
let () = injector.push(line, |e, cols| {
cols[0] = e.clone().into();
});
}
}
} }
} }
} }

View File

@ -1,4 +1,3 @@
/// git log --oneline --date=short --pretty="format:%C(auto)%h %s %Cblue%an %C(green)%cd" "$@" | ~/code/rust/television/target/release/tv --preview 'git show -p --stat --pretty=fuller --color=always {0}' --delimiter ' '
use crate::previewers::cache::PreviewCache; use crate::previewers::cache::PreviewCache;
use crate::previewers::{Preview, PreviewContent}; use crate::previewers::{Preview, PreviewContent};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -27,7 +26,7 @@ pub struct CommandPreviewerConfig {
delimiter: String, delimiter: String,
} }
const DEFAULT_DELIMITER: &str = ":"; const DEFAULT_DELIMITER: &str = " ";
impl Default for CommandPreviewerConfig { impl Default for CommandPreviewerConfig {
fn default() -> Self { fn default() -> Self {
@ -124,19 +123,21 @@ lazy_static! {
/// let entry = Entry::new("a:given:entry:to:preview".to_string(), PreviewType::Command(command.clone())); /// let entry = Entry::new("a:given:entry:to:preview".to_string(), PreviewType::Command(command.clone()));
/// let formatted_command = format_command(&command, &entry); /// let formatted_command = format_command(&command, &entry);
/// ///
/// assert_eq!(formatted_command, "something a:given:entry:to:preview entry a"); /// assert_eq!(formatted_command, "something 'a:given:entry:to:preview' 'entry' 'a'");
/// ``` /// ```
pub fn format_command(command: &PreviewCommand, entry: &Entry) -> String { pub fn format_command(command: &PreviewCommand, entry: &Entry) -> String {
let parts = entry.name.split(&command.delimiter).collect::<Vec<&str>>(); let parts = entry.name.split(&command.delimiter).collect::<Vec<&str>>();
debug!("Parts: {:?}", parts); debug!("Parts: {:?}", parts);
let mut formatted_command = command.command.replace("{}", &entry.name); let mut formatted_command = command
.command
.replace("{}", format!("'{}'", entry.name).as_str());
formatted_command = COMMAND_PLACEHOLDER_REGEX formatted_command = COMMAND_PLACEHOLDER_REGEX
.replace_all(&formatted_command, |caps: &regex::Captures| { .replace_all(&formatted_command, |caps: &regex::Captures| {
let index = let index =
caps.get(1).unwrap().as_str().parse::<usize>().unwrap(); caps.get(1).unwrap().as_str().parse::<usize>().unwrap();
parts[index].to_string() format!("'{}'", parts[index])
}) })
.to_string(); .to_string();
@ -202,7 +203,10 @@ mod tests {
); );
let formatted_command = format_command(&command, &entry); let formatted_command = format_command(&command, &entry);
assert_eq!(formatted_command, "something an:entry:to:preview to an"); assert_eq!(
formatted_command,
"something 'an:entry:to:preview' 'to' 'an'"
);
} }
#[test] #[test]
@ -232,7 +236,7 @@ mod tests {
); );
let formatted_command = format_command(&command, &entry); let formatted_command = format_command(&command, &entry);
assert_eq!(formatted_command, "something an:entry:to:preview"); assert_eq!(formatted_command, "something 'an:entry:to:preview'");
} }
#[test] #[test]
@ -247,6 +251,6 @@ mod tests {
); );
let formatted_command = format_command(&command, &entry); let formatted_command = format_command(&command, &entry);
assert_eq!(formatted_command, "something an -t to"); assert_eq!(formatted_command, "something 'an' -t 'to'");
} }
} }

View File

@ -31,7 +31,7 @@ pub struct Cli {
pub no_preview: bool, pub no_preview: bool,
/// The delimiter used to extract fields from the entry to provide to the preview command /// The delimiter used to extract fields from the entry to provide to the preview command
/// (defaults to ":") /// (defaults to " ")
#[arg(long, value_name = "STRING", default_value = " ", value_parser = delimiter_parser)] #[arg(long, value_name = "STRING", default_value = " ", value_parser = delimiter_parser)]
pub delimiter: String, pub delimiter: String,
@ -283,7 +283,7 @@ pub fn guess_channel_from_prompt(
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn delimiter_parser(s: &str) -> Result<String, String> { fn delimiter_parser(s: &str) -> Result<String, String> {
Ok(match s { Ok(match s {
"" => ":".to_string(), "" => " ".to_string(),
"\\t" => "\t".to_string(), "\\t" => "\t".to_string(),
_ => s.to_string(), _ => s.to_string(),
}) })