Skip to content

Windows shell support in REPL #58526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

MilesCranmer
Copy link
Member

@MilesCranmer MilesCranmer commented May 25, 2025

This PR is a rewrite of @stevengj's #31490 on top of the cleaned-up repl_cmd in #58525. It should only be merged after that PR.

This PR also extends #31490 to handle cd for the various windows shells, which has become simpler and more maintainable after the cleanup. Note that these functions do not allow passing flags at the moment; however, it is much easier for a power user to extend this behaviour if they so desire in their startup.jl.

The specific diff of this PR is as follows:

diff --git a/base/client.jl b/base/client.jl
index 027f4bbb4c..c319e75302 100644
--- a/base/client.jl
+++ b/base/client.jl
@@ -65,6 +65,19 @@ end
 function prepare_shell_command(::ShellSpecification{false,:nu}, raw_string)
     return `nu -c $raw_string`
 end
+function prepare_shell_command(::ShellSpecification{true,:cmd}, cmd)
+    return Cmd(`cmd /s /c $(string('"', cmd, '"'))`; windows_verbatim=true)
+end
+function prepare_shell_command(::ShellSpecification{true,:powershell}, cmd)
+    return `powershell -Command $cmd`
+end
+function prepare_shell_command(::ShellSpecification{true,:pwsh}, cmd)
+    return `pwsh -Command $cmd`
+end
+function prepare_shell_command(::ShellSpecification{true,:busybox}, cmd)
+    return `busybox sh -c $(shell_escape_posixly(cmd))`
+end
+
 
 """
     needs_cmd(::ShellSpecification) -> Bool
@@ -83,13 +96,19 @@ Determines if a command is a `cd` command. Overload this for
 shells that have a different syntax for `cd`.
 """
 is_cd_cmd(::ShellSpecification, cmd::Cmd) = cmd.exec[1] == "cd"
-is_cd_cmd(::ShellSpecification, cmd::String) = false
+is_cd_cmd(::ShellSpecification{true,:cmd}, cmd::Cmd) = cmd.exec[1] in ("cd", "chdir")
+is_cd_cmd(::ShellSpecification{true,:powershell}, cmd::Cmd) = cmd.exec[1] ∈ ("Set-Location", "cd", "sl", "chdir")
+is_cd_cmd(::ShellSpecification{true,:pwsh}, cmd::Cmd) = cmd.exec[1] ∈ ("Set-Location", "cd", "sl", "chdir")
+is_cd_cmd(::ShellSpecification{true,:busybox}, cmd::Cmd) = cmd.exec[1] == "cd"
+is_cd_cmd(::ShellSpecification, cmd::String) = false  # Safe default
 is_cd_cmd(::ShellSpecification{false,:nu}, raw_string::String) = startswith(strip(raw_string), "cd")
 
 function pre_repl_cmd(raw_string, parsed, out)
-    shell = shell_split(get(ENV, "JULIA_SHELL", get(ENV, "SHELL", "/bin/sh")))
-    shell_name = Base.basename(shell[1])
-    shell_spec = ShellSpecification{@static(Sys.iswindows() ? true : false),Symbol(shell_name)}()
+    is_windows = Sys.iswindows()
+    shell_path = shell_split(get(ENV, "JULIA_SHELL", is_windows ? "cmd" : get(ENV, "SHELL", "/bin/sh")))
+    shell_name = Base.basename(shell_path[1])
+    normalized_shell_name = is_windows ? lowercase(splitext(shell_name)[1]) : shell_name
+    shell_spec = ShellSpecification{is_windows,Symbol(normalized_shell_name)}()
     if needs_cmd(shell_spec)
         cmd = Base.cmd_gen(parsed)
         return repl_cmd(shell_spec, cmd, parsed, out)

For example, the line

is_cd_cmd(::ShellSpecification{true,:powershell}, cmd::Cmd) = cmd.exec[1]  ("Set-Location", "cd", "sl", "chdir")

is equivalent to saying "if we are on Windows (true) and using powershell, then a 'cd' command should be performed if the first word is either Set-Location, cd, sl, or chdir."


You can try this PR out in your local julia by pasting the following code into your startup.jl: https://gist.github.com/MilesCranmer/0b530cf4602905d548acdfb3bb54ded0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants