Skip to content
Closed
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
16 changes: 16 additions & 0 deletions src/utils/__tests__/shell.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// npx jest src/utils/__tests__/shell.test.ts

import * as vscode from "vscode"
import { userInfo } from "os"
import { getShell } from "../shell"
Expand Down Expand Up @@ -90,6 +92,20 @@ describe("Shell Detection Tests", () => {
expect(getShell()).toBe("/bin/bash")
})

it("uses Git Bash when profile indicates Git Bash source", () => {
mockVsCodeConfig("windows", "Git Bash", {
"Git Bash": { source: "Git Bash" },
})
expect(getShell()).toBe("/usr/bin/bash")
})

it("uses Git Bash when profile name includes 'git bash'", () => {
mockVsCodeConfig("windows", "MinGW Git Bash", {
"MinGW Git Bash": {},
})
expect(getShell()).toBe("/usr/bin/bash")
})

it("defaults to cmd.exe if no special profile is matched", () => {
mockVsCodeConfig("windows", "CommandPrompt", {
CommandPrompt: {},
Expand Down
88 changes: 42 additions & 46 deletions src/utils/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const SHELL_PATHS = {
POWERSHELL_LEGACY: "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
CMD: "C:\\Windows\\System32\\cmd.exe",
WSL_BASH: "/bin/bash",
GIT_BASH: "/usr/bin/bash",
// Unix paths
MAC_DEFAULT: "/bin/zsh",
LINUX_DEFAULT: "/bin/bash",
Expand All @@ -28,7 +29,7 @@ type MacTerminalProfiles = Record<string, MacTerminalProfile>

interface WindowsTerminalProfile {
path?: string
source?: "PowerShell" | "WSL"
source?: "PowerShell" | "WSL" | "Git Bash"
}

type WindowsTerminalProfiles = Record<string, WindowsTerminalProfile>
Expand Down Expand Up @@ -114,6 +115,10 @@ function getWindowsShellFromVSCode(): string | null {
return SHELL_PATHS.WSL_BASH
}

if (profile?.source === "Git Bash" || defaultProfileName.toLowerCase().includes("git bash")) {
return SHELL_PATHS.GIT_BASH
}

// If nothing special detected, we assume cmd
return SHELL_PATHS.CMD
}
Expand Down Expand Up @@ -162,66 +167,57 @@ function getShellFromEnv(): string | null {
const { env } = process

if (process.platform === "win32") {
// On Windows, COMSPEC typically holds cmd.exe
return env.COMSPEC || "C:\\Windows\\System32\\cmd.exe"
// On Windows, COMSPEC typically holds cmd.exe.
return env.SHELL || env.COMSPEC || "C:\\Windows\\System32\\cmd.exe"
}

if (process.platform === "darwin") {
// On macOS/Linux, SHELL is commonly the environment variable
// On macOS/Linux, SHELL is commonly the environment variable.
return env.SHELL || "/bin/zsh"
}

if (process.platform === "linux") {
// On Linux, SHELL is commonly the environment variable
// On Linux, SHELL is commonly the environment variable.
return env.SHELL || "/bin/bash"
}

return null
}

// -----------------------------------------------------
// 4) Publicly Exposed Shell Getter
// -----------------------------------------------------

export function getShell(): string {
// 1. Check VS Code config first.
function fallbackShell() {
// On Windows, if we got here, we have no config, no COMSPEC, and one
// very messed up operating system. Use CMD as a last resort.
if (process.platform === "win32") {
// Special logic for Windows
const windowsShell = getWindowsShellFromVSCode()
if (windowsShell) {
return windowsShell
}
} else if (process.platform === "darwin") {
// macOS from VS Code
const macShell = getMacShellFromVSCode()
if (macShell) {
return macShell
}
} else if (process.platform === "linux") {
// Linux from VS Code
const linuxShell = getLinuxShellFromVSCode()
if (linuxShell) {
return linuxShell
}
return SHELL_PATHS.CMD
}

// 2. If no shell from VS Code, try userInfo()
const userInfoShell = getShellFromUserInfo()
if (userInfoShell) {
return userInfoShell
}
// On macOS/Linux, fallback to a POSIX shell - This is the behavior of our
// old shell detection method.
return SHELL_PATHS.FALLBACK
}

// 3. If still nothing, try environment variable
const envShell = getShellFromEnv()
if (envShell) {
return envShell
}
// -----------------------------------------------------
// 4) Publicly Exposed Shell Getter
// -----------------------------------------------------

// 4. Finally, fall back to a default
if (process.platform === "win32") {
// On Windows, if we got here, we have no config, no COMSPEC, and one very messed up operating system.
// Use CMD as a last resort
return SHELL_PATHS.CMD
}
// On macOS/Linux, fallback to a POSIX shell - This is the behavior of our old shell detection method.
return SHELL_PATHS.FALLBACK
export function getShell() {
// 1. Check VS Code config first.
// 2. If no shell from VS Code, try userInfo().
// 3. If still nothing, try environment variable.
// 4. Finally, fall back to a default.
let vsCodeShell: string | null = null

switch (process.platform) {
case "win32":
vsCodeShell = getWindowsShellFromVSCode()
break
case "darwin":
vsCodeShell = getMacShellFromVSCode()
break
case "linux":
vsCodeShell = getLinuxShellFromVSCode()
break
}

return vsCodeShell || getShellFromUserInfo() || getShellFromEnv() || fallbackShell()
}