Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 13 additions & 4 deletions crates/acp_thread/src/acp_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand All @@ -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)]
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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);
Expand Down
19 changes: 14 additions & 5 deletions crates/assistant_tools/src/terminal_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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;

Expand Down Expand Up @@ -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(),
Expand All @@ -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();
Expand Down
6 changes: 4 additions & 2 deletions crates/prompt_store/src/prompts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes it so we name the shell by name only in the prompt, not by path. That is:

  • /bin/sh becomes just sh
  • /bin/bash becomes just sh
  • C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe becomes just powershell
  • C:\Program Files\Git\bin\bash.exe becomes just sh

This feels more correct to me, the concrete path is not relevant for the agent as far as I can tell. Just the type of the shell

}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
36 changes: 29 additions & 7 deletions crates/util/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion crates/util/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
Loading