1818
1919function shell_parse (str:: AbstractString , interpolate:: Bool = true ;
2020 special:: AbstractString = " " , filename= " none" )
21- s = SubString (str, firstindex (str))
21+ last_arg = firstindex (str) # N.B.: This is used by REPLCompletions
22+ s = SubString (str, last_arg)
2223 s = rstrip_shell (lstrip (s))
2324
24- # N.B.: This is used by REPLCompletions
25- last_parse = 0 : - 1
26- isempty (s) && return interpolate ? (Expr (:tuple ,:()),last_parse) : ([],last_parse)
25+ isempty (s) && return interpolate ? (Expr (:tuple ,:()), last_arg) : ([], last_arg)
2726
2827 in_single_quotes = false
2928 in_double_quotes = false
@@ -32,6 +31,7 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
3231 arg = []
3332 i = firstindex (s)
3433 st = Iterators. Stateful (pairs (s))
34+ update_last_arg = false # true after spaces or interpolate
3535
3636 function push_nonempty! (list, x)
3737 if ! isa (x,AbstractString) || ! isempty (x)
@@ -54,6 +54,7 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
5454 for (j, c) in st
5555 j, c = j:: Int , c:: C
5656 if ! in_single_quotes && ! in_double_quotes && isspace (c)
57+ update_last_arg = true
5758 i = consume_upto! (arg, s, i, j)
5859 append_2to1! (args, arg)
5960 while ! isempty (st)
@@ -77,12 +78,17 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
7778 # use parseatom instead of parse to respect filename (#28188)
7879 ex, j = Meta. parseatom (s, stpos, filename= filename)
7980 end
80- last_parse = (stpos: prevind (s, j)) .+ s. offset
81- push_nonempty! (arg, ex)
81+ last_arg = stpos + s. offset
82+ update_last_arg = true
83+ push! (arg, ex)
8284 s = SubString (s, j)
8385 Iterators. reset! (st, pairs (s))
8486 i = firstindex (s)
8587 else
88+ if update_last_arg
89+ last_arg = i + s. offset
90+ update_last_arg = false
91+ end
8692 if ! in_double_quotes && c == ' \' '
8793 in_single_quotes = ! in_single_quotes
8894 i = consume_upto! (arg, s, i, j)
@@ -124,14 +130,14 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
124130 push_nonempty! (arg, s[i: end ])
125131 append_2to1! (args, arg)
126132
127- interpolate || return args, last_parse
133+ interpolate || return args, last_arg
128134
129135 # construct an expression
130136 ex = Expr (:tuple )
131137 for arg in args
132138 push! (ex. args, Expr (:tuple , arg... ))
133139 end
134- return ex, last_parse
140+ return ex, last_arg
135141end
136142
137143function shell_split (s:: AbstractString )
@@ -216,7 +222,7 @@ function print_shell_escaped_posixly(io::IO, args::AbstractString...)
216222 function isword (c:: AbstractChar )
217223 if ' 0' <= c <= ' 9' || ' a' <= c <= ' z' || ' A' <= c <= ' Z'
218224 # word characters
219- elseif c == ' _' || c == ' /' || c == ' +' || c == ' -'
225+ elseif c == ' _' || c == ' /' || c == ' +' || c == ' -' || c == ' . '
220226 # other common characters
221227 elseif c == ' \' '
222228 have_single = true
0 commit comments