Merge branch 'main' into main

This commit is contained in:
Alexandre Pasmantier 2025-04-09 19:03:29 +00:00 committed by GitHub
commit 529802a64b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 97 additions and 33 deletions

4
Cargo.lock generated
View File

@ -2401,9 +2401,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.44.1"
version = "1.44.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
dependencies = [
"backtrace",
"bytes",

View File

@ -37,7 +37,7 @@ anyhow = "1.0"
base64 = "0.22.1"
directories = "6.0"
devicons = "0.6"
tokio = { version = "1.43", features = ["full"] }
tokio = { version = "1.44", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
rustc-hash = "2.1"

View File

@ -2,7 +2,7 @@
[[cable_channel]]
name = "git-diff"
source_command = "git diff --name-only"
preview_command = "git diff --color=always {0}"
preview_command = "git diff --color=always -- {0}"
[[cable_channel]]
name = "git-reflog"

View File

@ -4,7 +4,9 @@ use crate::channels::entry::Entry;
use crate::channels::entry::PreviewType;
use crate::channels::OnAir;
use crate::matcher::{config::Config, injector::Injector, Matcher};
use crate::utils::command::shell_command;
use crate::utils::indices::sep_name_and_value_indices;
use crate::utils::shell::Shell;
use devicons::FileIcon;
use rustc_hash::FxBuildHasher;
use rustc_hash::FxHashSet;
@ -32,19 +34,20 @@ pub struct Channel {
const NUM_THREADS: usize = 1;
const FILE_ICON_STR: &str = "nu";
const SHELL_ENV_VAR: &str = "SHELL";
fn get_current_shell() -> Option<String> {
std::env::var(SHELL_ENV_VAR).ok()
}
fn get_raw_aliases(shell: Shell) -> Vec<String> {
// this needs to be run in an interactive shell in order to get the aliases
let mut command = shell_command(true);
fn get_raw_aliases(shell: &str) -> Vec<String> {
let output = std::process::Command::new(shell)
.arg("-i")
.arg("-c")
.arg("alias")
.output()
.expect("failed to execute process");
let output = match shell {
Shell::PowerShell => {
command.arg("Get-Alias | Format-List -Property Name, Definition")
}
Shell::Cmd => command.arg("doskey /macros"),
_ => command.arg("-i").arg("alias").arg("2>/dev/null"),
}
.output()
.expect("failed to execute process");
let aliases = String::from_utf8_lossy(&output.stdout);
aliases.lines().map(ToString::to_string).collect()
@ -151,8 +154,7 @@ impl OnAir for Channel {
#[allow(clippy::unused_async)]
async fn load_aliases(injector: Injector<Alias>) {
let raw_shell = get_current_shell().unwrap_or("bash".to_string());
let shell = raw_shell.split('/').last().unwrap();
let shell = Shell::from_env().unwrap_or_default();
debug!("Current shell: {}", shell);
let raw_aliases = get_raw_aliases(shell);
@ -167,6 +169,8 @@ async fn load_aliases(injector: Injector<Alias>) {
value.to_string(),
));
}
} else {
debug!("Invalid alias format: {}", alias);
}
None
})

View File

@ -110,7 +110,7 @@ impl Channel {
#[allow(clippy::unused_async)]
async fn load_candidates(command: String, injector: Injector<String>) {
debug!("Loading candidates from command: {:?}", command);
let mut child = shell_command()
let mut child = shell_command(false)
.arg(command)
.stdout(Stdio::piped())
.stderr(Stdio::piped())

View File

@ -174,7 +174,7 @@ pub fn try_preview(
let command = format_command(command, entry, command_re);
debug!("Formatted preview command: {:?}", command);
let child = shell_command()
let child = shell_command(false)
.arg(&command)
.output()
.expect("failed to execute process");

View File

@ -1,19 +1,21 @@
use std::process::Command;
#[cfg(not(windows))]
pub fn shell_command() -> Command {
let mut cmd = Command::new("sh");
use super::shell::Shell;
cmd.arg("-c");
cmd
}
#[cfg(windows)]
pub fn shell_command() -> Command {
let mut cmd = Command::new("cmd");
cmd.arg("/c");
pub fn shell_command(interactive: bool) -> Command {
let shell = Shell::from_env().unwrap_or_default();
let mut cmd = Command::new(shell.executable());
cmd.arg(match shell {
Shell::PowerShell => "-Command",
Shell::Cmd => "/C",
_ => "-c",
});
#[cfg(unix)]
if interactive {
cmd.arg("-i");
}
cmd
}

View File

@ -1,8 +1,10 @@
use crate::cli::args::Shell as CliShell;
use crate::config::shell_integration::ShellIntegrationConfig;
use anyhow::Result;
use strum::Display;
use tracing::debug;
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Display)]
pub enum Shell {
Bash,
Zsh,
@ -11,6 +13,62 @@ pub enum Shell {
Cmd,
}
impl Default for Shell {
#[cfg(unix)]
fn default() -> Self {
Shell::Bash
}
#[cfg(windows)]
fn default() -> Self {
Shell::PowerShell
}
}
const SHELL_ENV_VAR: &str = "SHELL";
impl TryFrom<&str> for Shell {
type Error = anyhow::Error;
fn try_from(value: &str) -> Result<Self> {
if value.contains("bash") {
Ok(Shell::Bash)
} else if value.contains("zsh") {
Ok(Shell::Zsh)
} else if value.contains("fish") {
Ok(Shell::Fish)
} else if value.contains("powershell") {
Ok(Shell::PowerShell)
} else if value.contains("cmd") {
Ok(Shell::Cmd)
} else {
Err(anyhow::anyhow!("Unsupported shell: {}", value))
}
}
}
impl Shell {
#[allow(clippy::borrow_interior_mutable_const)]
pub fn from_env() -> Result<Self> {
if let Ok(shell) = std::env::var(SHELL_ENV_VAR) {
Shell::try_from(shell.as_str())
} else {
debug!("Environment variable {} not set", SHELL_ENV_VAR);
Ok(Shell::default())
}
}
pub fn executable(&self) -> &'static str {
match self {
Shell::Bash => "bash",
Shell::Zsh => "zsh",
Shell::Fish => "fish",
Shell::PowerShell => "powershell",
Shell::Cmd => "cmd",
}
}
}
impl From<CliShell> for Shell {
fn from(val: CliShell) -> Self {
match val {