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 Nov 10, 2015
1 parent dce9d18 commit 5b12348
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 3 deletions.
39 changes: 36 additions & 3 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=false)
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,38 @@ 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"], @unix? ":" : ";")

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
# In a perfect world, we would filter on whether the file is executable
# here, or even on whether the current user can execute the file in question.
if startswith(file, prefix) && isfile(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 @@ -392,8 +424,9 @@ function shell_completions(string, pos)
isempty(args.args[end].args) && return UTF8String[], 0:-1, false
arg = args.args[end].args[end]
if all(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 user wants to complete the first argument
return complete_path(join(args.args[end].args), pos, use_envpath=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
18 changes: 18 additions & 0 deletions test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,24 @@ 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"]
path = tempdir()
ENV["PATH"] = path
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 5b12348

Please sign in to comment.