Skip to content

Commit 66eb856

Browse files
committed
Merge pull request #13032 from omus/edit_backslash
edit command breaks for EDITOR path containing spaces
2 parents 64d0cc9 + 53fcec2 commit 66eb856

File tree

3 files changed

+90
-23
lines changed

3 files changed

+90
-23
lines changed

base/interactiveutil.jl

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,52 @@
22

33
# editing files
44

5-
function edit(file::AbstractString, line::Integer)
5+
doc"""
6+
editor()
7+
8+
Determines the editor to use when running functions like `edit`. Returns an Array compatible
9+
for use within backticks. You can change the editor by setting JULIA_EDITOR, VISUAL, or
10+
EDITOR as an environmental variable.
11+
"""
12+
function editor()
613
if OS_NAME == :Windows || OS_NAME == :Darwin
714
default_editor = "open"
815
elseif isreadable("/etc/alternatives/editor")
916
default_editor = "/etc/alternatives/editor"
1017
else
1118
default_editor = "emacs"
1219
end
13-
editor = get(ENV,"JULIA_EDITOR", get(ENV,"VISUAL", get(ENV,"EDITOR", default_editor)))
14-
if ispath(editor)
15-
if isreadable(editor)
16-
edpath = realpath(editor)
17-
edname = basename(edpath)
18-
else
19-
error("can't find \"$editor\"")
20-
end
21-
else
22-
edpath = edname = editor
23-
end
20+
# Note: the editor path can include spaces (if escaped) and flags.
21+
command = shell_split(get(ENV,"JULIA_EDITOR", get(ENV,"VISUAL", get(ENV,"EDITOR", default_editor))))
22+
isempty(command) && error("editor is empty")
23+
return command
24+
end
25+
26+
function edit(file::AbstractString, line::Integer)
27+
command = editor()
28+
name = basename(first(command))
2429
issrc = length(file)>2 && file[end-2:end] == ".jl"
2530
if issrc
2631
f = find_source_file(file)
2732
f !== nothing && (file = f)
2833
end
2934
const no_line_msg = "Unknown editor: no line number information passed.\nThe method is defined at line $line."
30-
if startswith(edname, "emacs") || edname == "gedit"
31-
spawn(`$edpath +$line $file`)
32-
elseif edname == "vi" || edname == "vim" || edname == "nvim" || edname == "mvim" || edname == "nano"
33-
run(`$edpath +$line $file`)
34-
elseif edname == "textmate" || edname == "mate" || edname == "kate"
35-
spawn(`$edpath $file -l $line`)
36-
elseif startswith(edname, "subl") || edname == "atom"
37-
spawn(`$(shell_split(edpath)) $file:$line`)
38-
elseif OS_NAME == :Windows && (edname == "start" || edname == "open")
35+
if startswith(name, "emacs") || name == "gedit"
36+
spawn(`$command +$line $file`)
37+
elseif name == "vi" || name == "vim" || name == "nvim" || name == "mvim" || name == "nano"
38+
run(`$command +$line $file`)
39+
elseif name == "textmate" || name == "mate" || name == "kate"
40+
spawn(`$command $file -l $line`)
41+
elseif startswith(name, "subl") || name == "atom"
42+
spawn(`$command $file:$line`)
43+
elseif OS_NAME == :Windows && (name == "start" || name == "open")
3944
spawn(`cmd /c start /b $file`)
4045
println(no_line_msg)
41-
elseif OS_NAME == :Darwin && (edname == "start" || edname == "open")
46+
elseif OS_NAME == :Darwin && (name == "start" || name == "open")
4247
spawn(`open -t $file`)
4348
println(no_line_msg)
4449
else
45-
run(`$(shell_split(edpath)) $file`)
50+
run(`$command $file`)
4651
println(no_line_msg)
4752
end
4853
nothing

test/replutil.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,43 @@ let
132132
showerror(buff, MethodError(convert, Tuple{Type, Float64}))
133133
showerror(buff, MethodError(convert, Tuple{DataType, Float64}))
134134
end
135+
136+
# Issue #13032
137+
withenv("JULIA_EDITOR" => nothing, "VISUAL" => nothing, "EDITOR" => nothing) do
138+
139+
# Make sure editor doesn't error when no ENV editor is set.
140+
@test isa(Base.editor(), Array)
141+
142+
# Invalid editor
143+
ENV["JULIA_EDITOR"] = ""
144+
@test_throws ErrorException Base.editor()
145+
146+
# Note: The following testcases should work regardless of whether these editors are
147+
# installed or not.
148+
149+
# Editor on the path.
150+
ENV["JULIA_EDITOR"] = "vim"
151+
@test Base.editor() == ["vim"]
152+
153+
# Absolute path to editor.
154+
ENV["JULIA_EDITOR"] = "/usr/bin/vim"
155+
@test Base.editor() == ["/usr/bin/vim"]
156+
157+
# Editor on the path using arguments.
158+
ENV["JULIA_EDITOR"] = "subl -w"
159+
@test Base.editor() == ["subl", "-w"]
160+
161+
# Absolute path to editor with spaces.
162+
ENV["JULIA_EDITOR"] = "/Applications/Sublime\\ Text.app/Contents/SharedSupport/bin/subl"
163+
@test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl"]
164+
165+
# Paths with spaces and arguments (#13032).
166+
ENV["JULIA_EDITOR"] = "/Applications/Sublime\\ Text.app/Contents/SharedSupport/bin/subl -w"
167+
@test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "-w"]
168+
169+
ENV["JULIA_EDITOR"] = "'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl' -w"
170+
@test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "-w"]
171+
172+
ENV["JULIA_EDITOR"] = "\"/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl\" -w"
173+
@test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "-w"]
174+
end

test/spawn.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,25 @@ let fname = tempname()
307307
@test success(pipeline(`cat $fname`, `$exename -e $code`))
308308
rm(fname)
309309
end
310+
311+
let cmd = AbstractString[]
312+
# Ensure that quoting works
313+
@test Base.shell_split("foo bar baz") == ["foo", "bar", "baz"]
314+
@test Base.shell_split("foo\\ bar baz") == ["foo bar", "baz"]
315+
@test Base.shell_split("'foo bar' baz") == ["foo bar", "baz"]
316+
@test Base.shell_split("\"foo bar\" baz") == ["foo bar", "baz"]
317+
318+
# "Over quoted"
319+
@test Base.shell_split("'foo\\ bar' baz") == ["foo\\ bar", "baz"]
320+
@test Base.shell_split("\"foo\\ bar\" baz") == ["foo\\ bar", "baz"]
321+
322+
# Ensure that shell_split handles quoted spaces
323+
cmd = ["/Volumes/External HD/program", "-a"]
324+
@test Base.shell_split("/Volumes/External\\ HD/program -a") == cmd
325+
@test Base.shell_split("'/Volumes/External HD/program' -a") == cmd
326+
@test Base.shell_split("\"/Volumes/External HD/program\" -a") == cmd
327+
328+
# Backticks should automatically quote where necessary
329+
cmd = ["foo bar", "baz"]
330+
@test string(`$cmd`) == "`'foo bar' baz`"
331+
end

0 commit comments

Comments
 (0)