acp_thread: If available, use git bash over powershell in terminal tool (#39466)
Release Notes: - When git bash is installed, agents will now use that over powershell when invoking terminal commands
This commit is contained in:
Generated
+1
@@ -20340,6 +20340,7 @@ dependencies = [
|
||||
"tendril",
|
||||
"unicase",
|
||||
"walkdir",
|
||||
"which 6.0.3",
|
||||
"workspace-hack",
|
||||
"zed-collections",
|
||||
"zed-util-macros",
|
||||
|
||||
@@ -12,7 +12,7 @@ use language::language_settings::FormatOnSave;
|
||||
pub use mention::*;
|
||||
use project::lsp_store::{FormatTrigger, LspFormatTarget};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::Settings as _;
|
||||
use settings::{Settings as _, SettingsLocation};
|
||||
use task::{Shell, ShellBuilder};
|
||||
pub use terminal::*;
|
||||
|
||||
@@ -35,7 +35,7 @@ use std::rc::Rc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{fmt::Display, mem, path::PathBuf, sync::Arc};
|
||||
use ui::App;
|
||||
use util::{ResultExt, get_default_system_shell};
|
||||
use util::{ResultExt, get_default_system_shell_preferring_bash};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -2086,7 +2086,16 @@ impl AcpThread {
|
||||
) -> Task<Result<Entity<Terminal>>> {
|
||||
let env = match &cwd {
|
||||
Some(dir) => self.project.update(cx, |project, cx| {
|
||||
let shell = TerminalSettings::get_global(cx).shell.clone();
|
||||
let worktree = project.find_worktree(dir.as_path(), cx);
|
||||
let shell = TerminalSettings::get(
|
||||
worktree.as_ref().map(|(worktree, path)| SettingsLocation {
|
||||
worktree_id: worktree.read(cx).id(),
|
||||
path: &path,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
.shell
|
||||
.clone();
|
||||
project.directory_environment(&shell, dir.as_path().into(), cx)
|
||||
}),
|
||||
None => Task::ready(None).shared(),
|
||||
@@ -2115,7 +2124,7 @@ impl AcpThread {
|
||||
.remote_client()
|
||||
.and_then(|r| r.read(cx).default_system_shell())
|
||||
})?
|
||||
.unwrap_or_else(|| get_default_system_shell());
|
||||
.unwrap_or_else(|| get_default_system_shell_preferring_bash());
|
||||
let (task_command, task_args) = ShellBuilder::new(&Shell::Program(shell))
|
||||
.redirect_stdin_to_dev_null()
|
||||
.build(Some(command.clone()), &args);
|
||||
|
||||
@@ -18,7 +18,7 @@ use portable_pty::{CommandBuilder, PtySize, native_pty_system};
|
||||
use project::Project;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::Settings;
|
||||
use settings::{Settings, SettingsLocation};
|
||||
use std::{
|
||||
env,
|
||||
path::{Path, PathBuf},
|
||||
@@ -32,8 +32,8 @@ use terminal_view::TerminalView;
|
||||
use theme::ThemeSettings;
|
||||
use ui::{CommonAnimationExt, Disclosure, Tooltip, prelude::*};
|
||||
use util::{
|
||||
ResultExt, get_default_system_shell, markdown::MarkdownInlineCode, size::format_file_size,
|
||||
time::duration_alt_display,
|
||||
ResultExt, get_default_system_shell_preferring_bash, markdown::MarkdownInlineCode,
|
||||
size::format_file_size, time::duration_alt_display,
|
||||
};
|
||||
use workspace::Workspace;
|
||||
|
||||
@@ -122,7 +122,16 @@ impl Tool for TerminalTool {
|
||||
let cwd = working_dir.clone();
|
||||
let env = match &cwd {
|
||||
Some(dir) => project.update(cx, |project, cx| {
|
||||
let shell = TerminalSettings::get_global(cx).shell.clone();
|
||||
let worktree = project.find_worktree(dir.as_path(), cx);
|
||||
let shell = TerminalSettings::get(
|
||||
worktree.as_ref().map(|(worktree, path)| SettingsLocation {
|
||||
worktree_id: worktree.read(cx).id(),
|
||||
path: &path,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
.shell
|
||||
.clone();
|
||||
project.directory_environment(&shell, dir.as_path().into(), cx)
|
||||
}),
|
||||
None => Task::ready(None).shared(),
|
||||
@@ -133,7 +142,7 @@ impl Tool for TerminalTool {
|
||||
.remote_client()
|
||||
.and_then(|r| r.read(cx).default_system_shell())
|
||||
})
|
||||
.unwrap_or_else(|| get_default_system_shell());
|
||||
.unwrap_or_else(|| get_default_system_shell_preferring_bash());
|
||||
|
||||
let env = cx.spawn(async move |_| {
|
||||
let mut env = env.await.unwrap_or_default();
|
||||
|
||||
@@ -14,7 +14,9 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
use text::LineEnding;
|
||||
use util::{ResultExt, get_default_system_shell, rel_path::RelPath};
|
||||
use util::{
|
||||
ResultExt, get_default_system_shell_preferring_bash, rel_path::RelPath, shell::ShellKind,
|
||||
};
|
||||
|
||||
use crate::UserPromptId;
|
||||
|
||||
@@ -43,7 +45,7 @@ impl ProjectContext {
|
||||
user_rules: default_user_rules,
|
||||
os: std::env::consts::OS.to_string(),
|
||||
arch: std::env::consts::ARCH.to_string(),
|
||||
shell: get_default_system_shell(),
|
||||
shell: ShellKind::new(&get_default_system_shell_preferring_bash()).to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ tempfile.workspace = true
|
||||
unicase.workspace = true
|
||||
util_macros = { workspace = true, optional = true }
|
||||
walkdir.workspace = true
|
||||
which.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
|
||||
@@ -29,6 +29,30 @@ pub fn get_default_system_shell() -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default system shell, preferring git-bash on Windows.
|
||||
pub fn get_default_system_shell_preferring_bash() -> String {
|
||||
if cfg!(windows) {
|
||||
get_windows_git_bash().unwrap_or_else(|| get_windows_system_shell())
|
||||
} else {
|
||||
"/bin/sh".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_windows_git_bash() -> Option<String> {
|
||||
static GIT_BASH: LazyLock<Option<String>> = LazyLock::new(|| {
|
||||
// /path/to/git/cmd/git.exe/../../bin/bash.exe
|
||||
let git = which::which("git").ok()?;
|
||||
let git_bash = git.parent()?.parent()?.join("bin").join("bash.exe");
|
||||
if git_bash.is_file() {
|
||||
Some(git_bash.to_string_lossy().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
(*GIT_BASH).clone()
|
||||
}
|
||||
|
||||
pub fn get_windows_system_shell() -> String {
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -152,20 +176,16 @@ impl ShellKind {
|
||||
|
||||
pub fn new(program: impl AsRef<Path>) -> Self {
|
||||
let program = program.as_ref();
|
||||
let Some(program) = program.file_name().and_then(|s| s.to_str()) else {
|
||||
let Some(program) = program.file_stem().and_then(|s| s.to_str()) else {
|
||||
return if cfg!(windows) {
|
||||
ShellKind::PowerShell
|
||||
} else {
|
||||
ShellKind::Posix
|
||||
};
|
||||
};
|
||||
if program == "powershell"
|
||||
|| program.ends_with("powershell.exe")
|
||||
|| program == "pwsh"
|
||||
|| program.ends_with("pwsh.exe")
|
||||
{
|
||||
if program == "powershell" || program == "pwsh" {
|
||||
ShellKind::PowerShell
|
||||
} else if program == "cmd" || program.ends_with("cmd.exe") {
|
||||
} else if program == "cmd" {
|
||||
ShellKind::Cmd
|
||||
} else if program == "nu" {
|
||||
ShellKind::Nushell
|
||||
@@ -177,6 +197,8 @@ impl ShellKind {
|
||||
ShellKind::Tcsh
|
||||
} else if program == "rc" {
|
||||
ShellKind::Rc
|
||||
} else if program == "sh" || program == "bash" {
|
||||
ShellKind::Posix
|
||||
} else {
|
||||
if cfg!(windows) {
|
||||
ShellKind::PowerShell
|
||||
|
||||
@@ -999,7 +999,9 @@ pub fn default<D: Default>() -> D {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub use self::shell::{get_default_system_shell, get_system_shell};
|
||||
pub use self::shell::{
|
||||
get_default_system_shell, get_default_system_shell_preferring_bash, get_system_shell,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConnectionResult<O> {
|
||||
|
||||
Reference in New Issue
Block a user