9595function complete_keyword (s:: ByteString )
9696 const sorted_keywords = [
9797 " abstract" , " baremodule" , " begin" , " bitstype" , " break" , " catch" , " ccall" ,
98- " const" , " continue" , " do" , " else" , " elseif" , " end" , " export" , " finally " ,
99- " for" , " function" , " global" , " if" , " immutable" , " import" , " importall " ,
100- " let" , " local" , " macro" , " module" , " quote" , " return" , " try " , " type " ,
101- " typealias" , " using" , " while" ]
98+ " const" , " continue" , " do" , " else" , " elseif" , " end" , " export" , " false " ,
99+ " finally " , " for" , " function" , " global" , " if" , " immutable" , " import" ,
100+ " importall " , " let" , " local" , " macro" , " module" , " quote" , " return" ,
101+ " true " , " try " , " type " , " typealias" , " using" , " while" ]
102102 r = searchsorted (sorted_keywords, s)
103103 i = first (r)
104104 n = length (sorted_keywords)
@@ -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,49 @@ 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
165+ try
166+ filesinpath = readdir (pathdir)
167+ catch e
168+ # Bash allows dirs in PATH that can't be read, so we should as well.
169+ if isa (e, SystemError)
170+ continue
171+ else
172+ # We only handle SystemErrors here
173+ rethrow (e)
174+ end
175+ end
176+
177+ for file in filesinpath
178+ # In a perfect world, we would filter on whether the file is executable
179+ # here, or even on whether the current user can execute the file in question.
180+ if startswith (file, prefix) && isfile (joinpath (pathdir, file))
181+ push! (matches, file)
182+ end
183+ end
184+ end
185+ end
186+
144187 matches = UTF8String[replace (s, r" \s " , " \\ " ) for s in matches]
145188 startpos = pos - endof (prefix) + 1 - length (matchall (r" " , prefix))
146189 # The pos - endof(prefix) + 1 is correct due to `endof(prefix)-endof(prefix)==0`,
@@ -222,14 +265,64 @@ get_value(sym::Symbol, fn) = isdefined(fn, sym) ? (fn.(sym), true) : (nothing, f
222265get_value (sym:: QuoteNode , fn) = isdefined (fn, sym. value) ? (fn .(sym. value), true ) : (nothing , false )
223266get_value (sym, fn) = sym, true
224267
268+ # Return the value of a getfield call expression
269+ function get_value_getfield (ex:: Expr , fn)
270+ # Example :((top(getfield))(Base,:max))
271+ val, found = get_value_getfield (ex. args[2 ],fn) # Look up Base in Main and returns the module
272+ found || return (nothing , false )
273+ get_value_getfield (ex. args[3 ],val) # Look up max in Base and returns the function if found.
274+ end
275+ get_value_getfield (sym, fn) = get_value (sym, fn)
276+ # Determines the return type with Base.return_types of a function call using the type information of the arguments.
277+ function get_type_call (expr:: Expr )
278+ f_name = expr. args[1 ]
279+ # The if statement should find the f function. How f is found depends on how f is referenced
280+ if isa (f_name, TopNode)
281+ f = Base .(f_name. name)
282+ found = true
283+ elseif isa (f_name, Expr) && f_name. args[1 ] === TopNode (:getfield )
284+ f, found = get_value_getfield (f_name, Main)
285+ else
286+ f, found = get_value (f_name, Main)
287+ end
288+ found || return (Any, false ) # If the function f is not found return Any.
289+ args = Any[]
290+ for ex in expr. args[2 : end ] # Find the type of the function arguments
291+ typ, found = get_type (ex, Main)
292+ found ? push! (args, typ) : push! (args, Any)
293+ end
294+ return_types = Base. return_types (f,Tuple{args... })
295+ length (return_types) == 1 || return (Any, false )
296+ return (return_types[1 ], true )
297+ end
298+ # Returns the return type. example: get_type(:(Base.strip("",' ')),Main) returns (ASCIIString,true)
299+ function get_type (sym:: Expr , fn)
300+ sym= expand (sym)
301+ val, found = get_value (sym, fn)
302+ found && return Base. typesof (val). parameters[1 ], found
303+ if sym. head === :call
304+ # getfield call is special cased as the evaluation of getfield provides good type information,
305+ # is inexpensive and it is also performed in the complete_symbol function.
306+ if sym. args[1 ] === TopNode (:getfield )
307+ val, found = get_value_getfield (sym, Main)
308+ return found ? Base. typesof (val). parameters[1 ] : Any, found
309+ end
310+ return get_type_call (sym)
311+ end
312+ (Any, false )
313+ end
314+ function get_type (sym, fn)
315+ val, found = get_value (sym, fn)
316+ return found ? Base. typesof (val). parameters[1 ] : Any, found
317+ end
225318# Method completion on function call expression that look like :(max(1))
226319function complete_methods (ex_org:: Expr )
227320 args_ex = DataType[]
228321 func, found = get_value (ex_org. args[1 ], Main)
229322 (! found || (found && ! isgeneric (func))) && return UTF8String[]
230323 for ex in ex_org. args[2 : end ]
231- val, found = get_value (ex, Main)
232- found ? push! (args_ex, Base . typesof ( val) . parameters[ 1 ]) : push! (args_ex, Any )
324+ val, found = get_type (ex, Main)
325+ push! (args_ex, val)
233326 end
234327 out = UTF8String[]
235328 t_in = Tuple{args_ex... } # Input types
@@ -390,8 +483,18 @@ function shell_completions(string, pos)
390483 isempty (args. args[end ]. args) && return UTF8String[], 0 : - 1 , false
391484 arg = args. args[end ]. args[end ]
392485 if all (s -> isa (s, AbstractString), args. args[end ]. args)
393- # Treat this as a path (perhaps give a list of commands in the future as well?)
394- return complete_path (join (args. args[end ]. args), pos)
486+ # Treat this as a path
487+
488+ # As Base.shell_parse throws away trailing spaces (unless they are escaped),
489+ # we need to special case here.
490+ # If the last char was a space, but shell_parse ignored it search on "".
491+ ignore_last_word = arg != " " && scs[end ] == ' '
492+ prefix = ignore_last_word ? " " : join (args. args[end ]. args)
493+
494+ # Also try looking into the env path if the user wants to complete the first argument
495+ use_envpath = ! ignore_last_word && length (args. args) < 2
496+
497+ return complete_path (prefix, pos, use_envpath= use_envpath)
395498 elseif isexpr (arg, :escape ) && (isexpr (arg. args[1 ], :incomplete ) || isexpr (arg. args[1 ], :error ))
396499 r = first (last_parse): prevind (last_parse, last (last_parse))
397500 partial = scs[r]
0 commit comments