Skip to content

Commit

Permalink
Also complete commands (files in the env path) in REPL shell mode
Browse files Browse the repository at this point in the history
Tested on Fedora only.
  • Loading branch information
mariushoch committed Jul 25, 2015
1 parent bbd3745 commit ae02a91
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 4 deletions.
39 changes: 35 additions & 4 deletions base/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function complete_keyword(s::ByteString)
sorted_keywords[r]
end

function complete_path(path::AbstractString, pos)
function complete_path(path::AbstractString, pos, use_envpath)
if Base.is_unix(OS_NAME) && ismatch(r"^~(?:/|$)", path)
# if the path is just "~", don't consider the expanded username as a prefix
if path == "~"
Expand Down Expand Up @@ -141,6 +141,36 @@ function complete_path(path::AbstractString, pos)
push!(matches, id ? file * (@windows? "\\\\" : "/") : file)
end
end

if use_envpath && length(dir) == 0
# Look for files in PATH as well
local pathdirs = split(ENV["PATH"],":")

for pathdir in pathdirs
local actualpath
try
actualpath = realpath(pathdir)
catch
# Bash doesn't expect every folder in PATH to exist, so neither shall we
continue
end

if actualpath != pathdir && in(actualpath,pathdirs)
# Remove paths which (after resolving links) are in the env path twice.
# Many distros eg. point /bin to /usr/bin but have both in the env path.
continue
end

local filesinpath = readdir(pathdir)

for file in filesinpath
if startswith(file, prefix) && isexecutable(joinpath(pathdir, file))
push!(matches, file)
end
end
end
end

matches = UTF8String[replace(s, r"\s", "\\ ") for s in matches]
startpos = pos - endof(prefix) + 1 - length(matchall(r" ", prefix))
# The pos - endof(prefix) + 1 is correct due to `endof(prefix)-endof(prefix)==0`,
Expand Down Expand Up @@ -299,7 +329,7 @@ function completions(string, pos)
m = match(r"[\t\n\r\"'`@\$><=;|&\{]| (?!\\)", reverse(partial))
startpos = nextind(partial, reverseind(partial, m.offset))
r = startpos:pos
paths, r, success = complete_path(replace(string[r], r"\\ ", " "), pos)
paths, r, success = complete_path(replace(string[r], r"\\ ", " "), pos, false)
if inc_tag == :string &&
length(paths) == 1 && # Only close if there's a single choice,
!isdir(expanduser(replace(string[startpos:start(r)-1] * paths[1], r"\\ ", " "))) && # except if it's a directory
Expand Down Expand Up @@ -392,8 +422,9 @@ function shell_completions(string, pos)
isempty(args.args[end].args) && return UTF8String[], 0:-1, false
arg = args.args[end].args[end]
if all(map(s -> isa(s, AbstractString), args.args[end].args))
# Treat this as a path (perhaps give a list of commands in the future as well?)
return complete_path(join(args.args[end].args), pos)
# Treat this as a path
# Also try looking into the env path if the use wants to complete the first argument
return complete_path(join(args.args[end].args), pos, length(args.args) < 2)
elseif isexpr(arg, :escape) && (isexpr(arg.args[1], :incomplete) || isexpr(arg.args[1], :error))
r = first(last_parse):prevind(last_parse, last(last_parse))
partial = scs[r]
Expand Down
17 changes: 17 additions & 0 deletions test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,23 @@ c, r, res = test_scomplete(s)
@test s[r] == "tmpfoob"
rm(dir)
end

# Tests detecting of files in the env path (in shell mode)
let
oldpath = ENV["PATH"]
ENV["PATH"] = homedir()
file = joinpath(path, "tmp-executable")
touch(file)
chmod(file, 0o755)
s = "tmp-execu"
c,r = test_scomplete(s)
@test "tmp-executable" in c
@test r == 1:9
@test s[r] == "tmp-execu"
rm(file)
ENV["PATH"] = oldpath
end

end

let #test that it can auto complete with spaces in file/path
Expand Down

0 comments on commit ae02a91

Please sign in to comment.