@@ -109,7 +109,7 @@ function complete_keyword(s::ByteString)
109109 sorted_keywords[r]
110110end
111111
112- function complete_path (path:: AbstractString , pos)
112+ function complete_path (path:: AbstractString , pos; use_envpath = false )
113113 if Base. is_unix (OS_NAME) && ismatch (r" ^~(?:/|$)" , path)
114114 # if the path is just "~", don't consider the expanded username as a prefix
115115 if path == " ~"
@@ -141,6 +141,38 @@ function complete_path(path::AbstractString, pos)
141141 push! (matches, id ? file * (@windows ? " \\\\ " : " /" ) : file)
142142 end
143143 end
144+
145+ if use_envpath && length (dir) == 0
146+ # Look for files in PATH as well
147+ local pathdirs = split (ENV [" PATH" ], @unix ? " :" : " ;" )
148+
149+ for pathdir in pathdirs
150+ local actualpath
151+ try
152+ actualpath = realpath (pathdir)
153+ catch
154+ # Bash doesn't expect every folder in PATH to exist, so neither shall we
155+ continue
156+ end
157+
158+ if actualpath != pathdir && in (actualpath,pathdirs)
159+ # Remove paths which (after resolving links) are in the env path twice.
160+ # Many distros eg. point /bin to /usr/bin but have both in the env path.
161+ continue
162+ end
163+
164+ local filesinpath = readdir (pathdir)
165+
166+ for file in filesinpath
167+ # In a perfect world, we would filter on whether the file is executable
168+ # here, or even on whether the current user can execute the file in question.
169+ if startswith (file, prefix) && isfile (joinpath (pathdir, file))
170+ push! (matches, file)
171+ end
172+ end
173+ end
174+ end
175+
144176 matches = UTF8String[replace (s, r" \s " , " \\ " ) for s in matches]
145177 startpos = pos - endof (prefix) + 1 - length (matchall (r" " , prefix))
146178 # The pos - endof(prefix) + 1 is correct due to `endof(prefix)-endof(prefix)==0`,
@@ -440,8 +472,9 @@ function shell_completions(string, pos)
440472 isempty (args. args[end ]. args) && return UTF8String[], 0 : - 1 , false
441473 arg = args. args[end ]. args[end ]
442474 if all (s -> isa (s, AbstractString), args. args[end ]. args)
443- # Treat this as a path (perhaps give a list of commands in the future as well?)
444- return complete_path (join (args. args[end ]. args), pos)
475+ # Treat this as a path
476+ # Also try looking into the env path if the user wants to complete the first argument
477+ return complete_path (join (args. args[end ]. args), pos, use_envpath= length (args. args) < 2 )
445478 elseif isexpr (arg, :escape ) && (isexpr (arg. args[1 ], :incomplete ) || isexpr (arg. args[1 ], :error ))
446479 r = first (last_parse): prevind (last_parse, last (last_parse))
447480 partial = scs[r]
0 commit comments