@@ -185,12 +185,16 @@ def flag_based_complete(text, line, begidx, endidx, flag_dict, default_completer
185185
186186 # Get all tokens prior to text being completed
187187 try :
188- prev_space_index = line .rfind (' ' , 0 , begidx )
188+ prev_space_index = max ( line .rfind (' ' , 0 , begidx ), 0 )
189189 tokens = shlex .split (line [:prev_space_index ], posix = POSIX_SHLEX )
190190 except ValueError :
191191 # Invalid syntax for shlex (Probably due to missing closing quote)
192192 return []
193193
194+ # Nothing to do
195+ if len (tokens ) == 0 :
196+ return []
197+
194198 completions = []
195199 flag_processed = False
196200
@@ -247,7 +251,7 @@ def index_based_complete(text, line, begidx, endidx, index_dict, default_complet
247251
248252 # Get all tokens prior to text being completed
249253 try :
250- prev_space_index = line .rfind (' ' , 0 , begidx )
254+ prev_space_index = max ( line .rfind (' ' , 0 , begidx ), 0 )
251255 tokens = shlex .split (line [:prev_space_index ], posix = POSIX_SHLEX )
252256 except ValueError :
253257 # Invalid syntax for shlex (Probably due to missing closing quote)
@@ -1348,7 +1352,7 @@ def complete_help(self, text, line, begidx, endidx):
13481352
13491353 # Get all tokens prior to text being completed
13501354 try :
1351- prev_space_index = line .rfind (' ' , 0 , begidx )
1355+ prev_space_index = max ( line .rfind (' ' , 0 , begidx ), 0 )
13521356 tokens = shlex .split (line [:prev_space_index ], posix = POSIX_SHLEX )
13531357 except ValueError :
13541358 # Invalid syntax for shlex (Probably due to missing closing quote)
@@ -1464,7 +1468,7 @@ def parseline(self, line):
14641468 if line .startswith (shortcut ):
14651469 # If the next character after the shortcut isn't a space, then insert one
14661470 shortcut_len = len (shortcut )
1467- if len (line ) > shortcut_len and line [shortcut_len ] != ' ' :
1471+ if len (line ) == shortcut_len or line [shortcut_len ] != ' ' :
14681472 expansion += ' '
14691473
14701474 # Expand the shortcut
@@ -2066,21 +2070,26 @@ def _shell_command_complete(text, line, begidx, endidx):
20662070 # Get a list of every directory in the PATH environment variable and ignore symbolic links
20672071 paths = [p for p in os .getenv ('PATH' ).split (os .path .pathsep ) if not os .path .islink (p )]
20682072
2073+ # Use a set to store exe names since there can be duplicates
2074+ exes = set ()
2075+
20692076 # Find every executable file in the PATH that matches the pattern
2070- exes = []
20712077 for path in paths :
20722078 full_path = os .path .join (path , text )
20732079 matches = [f for f in glob .glob (full_path + '*' ) if os .path .isfile (f ) and os .access (f , os .X_OK )]
20742080
20752081 for match in matches :
2076- exes .append (os .path .basename (match ))
2082+ exes .add (os .path .basename (match ))
2083+
2084+ # Sort the exes alphabetically
2085+ results = list (exes )
2086+ results .sort ()
20772087
20782088 # If there is a single completion and we are at end of the line, then add a space at the end for convenience
2079- if len (exes ) == 1 and endidx == len (line ):
2080- exes [0 ] += ' '
2089+ if len (results ) == 1 and endidx == len (line ):
2090+ results [0 ] += ' '
20812091
2082- exes .sort ()
2083- return exes
2092+ return results
20842093
20852094 def complete_shell (self , text , line , begidx , endidx ):
20862095 """Handles tab completion of executable commands and local file system paths.
@@ -2092,26 +2101,31 @@ def complete_shell(self, text, line, begidx, endidx):
20922101 :return: List[str] - a list of possible tab completions
20932102 """
20942103
2095- # Get all tokens through the text being completed
2104+ # Get all tokens prior to text being completed
20962105 try :
2097- tokens = shlex .split (line [:endidx ], posix = POSIX_SHLEX )
2106+ prev_space_index = max (line .rfind (' ' , 0 , begidx ), 0 )
2107+ tokens = shlex .split (line [:prev_space_index ], posix = POSIX_SHLEX )
20982108 except ValueError :
20992109 # Invalid syntax for shlex (Probably due to missing closing quote)
21002110 return []
21012111
2102- if len ( tokens ) == 1 :
2103- # Don't tab complete anything if user only typed shell
2112+ # Nothing to do
2113+ if len ( tokens ) == 0 :
21042114 return []
21052115
21062116 # Check if we are still completing the shell command
2107- elif len (tokens ) == 2 and not line . endswith ( ' ' ) :
2117+ elif len (tokens ) == 1 :
21082118
21092119 # Readline places begidx after ~ and path separators (/) so we need to get the whole token
21102120 # and see if it begins with a possible path in case we need to do path completion
21112121 # to find the shell command executables
2112- cur_token = tokens [- 1 ]
2122+ cmd_token = line [prev_space_index + 1 :begidx + 1 ]
2123+
2124+ # Don't tab complete anything if no shell command has been started
2125+ if len (cmd_token ) == 0 :
2126+ return []
21132127
2114- if not (cur_token .startswith ('~' ) or os .path .sep in cur_token ):
2128+ if not (cmd_token .startswith ('~' ) or os .path .sep in cmd_token ):
21152129 # No path characters are in this token, it is OK to try shell command completion.
21162130 command_completions = self ._shell_command_complete (text , line , begidx , endidx )
21172131
0 commit comments