diff --git a/base/REPLCompletions.jl b/base/REPLCompletions.jl index 3789fa0efb729..490bb41178adf 100644 --- a/base/REPLCompletions.jl +++ b/base/REPLCompletions.jl @@ -130,7 +130,8 @@ function complete_path(path::AbstractString, pos) push!(matches, id ? file * (@windows? "\\\\" : "/") : file) end end - matches, (nextind(path, pos-sizeof(prefix))):pos, length(matches) > 0 + matches = UTF8String[replace(s, r"\s", "\\ ") for s in matches] + return matches, nextind(path, pos - sizeof(prefix) - length(matchall(r" ", prefix))):pos, length(matches) > 0 end function complete_methods(input::AbstractString) @@ -148,7 +149,6 @@ end include("latex_symbols.jl") const non_identifier_chars = [" \t\n\r\"\\'`\$><=:;|&{}()[],+-*/?%^~"...] -const non_filename_chars = [(" \t\n\r\"'`@\$><=;|&{(" * (@unix?"\\" : "")) ...] const whitespace_chars = [" \t\n\r"...] # Aux function to detect whether we're right after a @@ -187,12 +187,13 @@ function completions(string, pos) partial = string[1:pos] inc_tag = Base.incomplete_tag(parse(partial , raise=false)) if inc_tag in [:cmd, :string] - startpos = nextind(partial, rsearch(partial, non_filename_chars, pos)) + m = match(r"[\t\n\r\"'`@\$><=;|&\{]| (?!\\)",reverse(partial)) + startpos = length(partial)-(m == nothing ? 1 : m.offset) + 2 r = startpos:pos - paths, r, success = complete_path(string[r], pos) + paths, r, success = complete_path(unescape_string(string[r]), pos) if inc_tag == :string && length(paths) == 1 && # Only close if there's a single choice, - !isdir(string[startpos:start(r)-1] * paths[1]) && # except if it's a directory + !isdir(unescape_string(string[startpos:start(r)-1] * paths[1])) && # except if it's a directory (length(string) <= pos || string[pos+1] != '"') # or there's already a " at the cursor. paths[1] *= "\"" end diff --git a/base/string.jl b/base/string.jl index 71231e0951c7e..9c81e20102066 100644 --- a/base/string.jl +++ b/base/string.jl @@ -1075,7 +1075,24 @@ macro mstr(s...); triplequoted(s...); end ## shell-like command parsing ## function shell_parse(raw::AbstractString, interp::Bool) - s = strip(raw) + s = lstrip(raw) + #Strips the end but respects the space when the string endswith "\\ " + r = RevString(s) + i = start(r) + c_old = nothing + while !done(r,i) + c, j = next(r,i) + if c == '\\' && c_old == ' ' + i -= 1 + break + elseif !(c in _default_delims) + break + end + i = j + c_old = c + end + s = s[1:end-i+1] + last_parse = 0:-1 isempty(s) && return interp ? (Expr(:tuple,:()),last_parse) : ([],last_parse) diff --git a/test/replcompletions.jl b/test/replcompletions.jl index cc8e47fce1c7f..e70c5828f2e49 100644 --- a/test/replcompletions.jl +++ b/test/replcompletions.jl @@ -164,6 +164,28 @@ c,r = test_scomplete("\$a") @test s[r] == "Pk" end +let #test that it can auto complete with spaces in file/path + path = tempdir() + space_folder = randstring() * " r" + dir = joinpath(path, space_folder) + dir_space = replace(space_folder, " ", "\\ ") + mkdir(dir) + cd(path) do + open(joinpath(space_folder, "space .file"),"w") do f + s = @windows? "rm $dir_space\\\\space" : "cd $dir_space/space" + c,r = test_scomplete(s) + @test r == endof(s)-4:endof(s) + @test "space\\ .file" in c + + s = @windows? "cd(\"$dir_space\\\\space" : "cd(\"$dir_space/space" + c,r = test_complete(s) + @test r == endof(s)-4:endof(s) + @test "space\\ .file\"" in c + end + end + rm(dir, recursive=true) +end + @windows_only begin tmp = tempname() path = dirname(tmp)