@@ -1393,9 +1393,6 @@ def tokens_for_completion(self, line, begidx, endidx):
13931393 def basic_complete (self , text , line , begidx , endidx , match_against ):
13941394 """
13951395 Performs tab completion against a list
1396- This is ultimately called by many completer functions like flag_based_complete and index_based_complete.
1397- It can also be used by custom completer functions and that is the suggested approach since this function
1398- handles things like tab completions with spaces.
13991396
14001397 :param text: str - the string prefix we are attempting to match (all returned matches must begin with it)
14011398 :param line: str - the current input line with leading whitespace removed
@@ -1404,24 +1401,12 @@ def basic_complete(self, text, line, begidx, endidx, match_against):
14041401 :param match_against: Collection - the list being matched against
14051402 :return: List[str] - a sorted list of possible tab completions
14061403 """
1407- # Make sure we were given an Collection with items to match against
1404+ # Make sure we were given a Collection with items to match against
14081405 if not isinstance (match_against , Collection ) or len (match_against ) == 0 :
14091406 return []
14101407
1411- # Get all tokens through the one being completed
1412- tokens , _ = self .tokens_for_completion (line , begidx , endidx )
1413- if tokens is None :
1414- return []
1415-
14161408 # Perform matching and eliminate duplicates
1417- completion_token = tokens [- 1 ]
1418- full_matches = [cur_match for cur_match in set (match_against ) if cur_match .startswith (completion_token )]
1419- if len (full_matches ) == 0 :
1420- return []
1421-
1422- # We will only keep where the text value starts
1423- starting_index = len (completion_token ) - len (text )
1424- completion_matches = [cur_match [starting_index :] for cur_match in full_matches ]
1409+ completion_matches = [cur_match for cur_match in set (match_against ) if cur_match .startswith (text )]
14251410
14261411 completion_matches .sort ()
14271412 return completion_matches
@@ -1443,7 +1428,6 @@ def flag_based_complete(self, text, line, begidx, endidx, flag_dict, all_else=No
14431428 by a flag in flag_dict
14441429 :return: List[str] - a sorted list of possible tab completions
14451430 """
1446-
14471431 # Get all tokens through the one being completed
14481432 tokens , _ = self .tokens_for_completion (line , begidx , endidx )
14491433 if tokens is None :
@@ -1486,7 +1470,6 @@ def index_based_complete(self, text, line, begidx, endidx, index_dict, all_else=
14861470 index in index_dict
14871471 :return: List[str] - a sorted list of possible tab completions
14881472 """
1489-
14901473 # Get all tokens through the one being completed
14911474 tokens , _ = self .tokens_for_completion (line , begidx , endidx )
14921475 if tokens is None :
@@ -1525,19 +1508,11 @@ def path_complete(self, text, line, begidx, endidx, dir_exe_only=False, dir_only
15251508 :param dir_only: bool - only return directories
15261509 :return: List[str] - a sorted list of possible tab completions
15271510 """
1528-
1529- # Get all tokens through the one being completed
1530- tokens , _ = self .tokens_for_completion (line , begidx , endidx )
1531- if tokens is None :
1532- return []
1533-
15341511 # Determine if a trailing separator should be appended to directory completions
15351512 add_trailing_sep_if_dir = False
15361513 if endidx == len (line ) or (endidx < len (line ) and line [endidx ] != os .path .sep ):
15371514 add_trailing_sep_if_dir = True
15381515
1539- completion_token = tokens [- 1 ]
1540-
15411516 # Used to replace cwd in the final results
15421517 cwd = os .getcwd ()
15431518 cwd_added = False
@@ -1546,75 +1521,62 @@ def path_complete(self, text, line, begidx, endidx, dir_exe_only=False, dir_only
15461521 user_path = os .path .expanduser ('~' )
15471522 tilde_expanded = False
15481523
1549- # If the token being completed is blank, then search in the CWD for *
1550- if not completion_token :
1524+ # If the search text is blank, then search in the CWD for *
1525+ if not text :
15511526 search_str = os .path .join (os .getcwd (), '*' )
15521527 cwd_added = True
15531528 else :
15541529 # Purposely don't match any path containing wildcards - what we are doing is complicated enough!
15551530 wildcards = ['*' , '?' ]
15561531 for wildcard in wildcards :
1557- if wildcard in completion_token :
1532+ if wildcard in text :
15581533 return []
15591534
15601535 # Used if we need to prepend a directory to the search string
15611536 dirname = ''
15621537
15631538 # If the user only entered a '~', then complete it with a slash
1564- if completion_token == '~' :
1539+ if text == '~' :
15651540 # This is a directory, so don't add a space or quote
15661541 self .allow_appended_space = False
15671542 self .allow_closing_quote = False
1568- return [completion_token + os .path .sep ]
1543+ return [text + os .path .sep ]
15691544
1570- elif completion_token .startswith ('~' ):
1545+ elif text .startswith ('~' ):
15711546 # Tilde without separator between path is invalid
1572- if not completion_token .startswith ('~' + os .path .sep ):
1547+ if not text .startswith ('~' + os .path .sep ):
15731548 return []
15741549
15751550 # Mark that we are expanding a tilde
15761551 tilde_expanded = True
15771552
1578- # If the token does not have a directory, then use the cwd
1579- elif not os .path .dirname (completion_token ):
1553+ # If the search text does not have a directory, then use the cwd
1554+ elif not os .path .dirname (text ):
15801555 dirname = os .getcwd ()
15811556 cwd_added = True
15821557
15831558 # Build the search string
1584- search_str = os .path .join (dirname , completion_token + '*' )
1559+ search_str = os .path .join (dirname , text + '*' )
15851560
15861561 # Expand "~" to the real user directory
15871562 search_str = os .path .expanduser (search_str )
15881563
1589- # If the text being completed does not appear at the beginning of the token being completed,
1590- # which can happen if there are spaces, save off the index where our search text begins in the
1591- # search string so we can return only that portion of the completed paths to readline
1592- if len (completion_token ) - len (text ) > 0 :
1593- starting_index = search_str .rfind (text + '*' )
1594- else :
1595- starting_index = 0
1596-
15971564 # Find all matching path completions
1598- full_matches = glob .glob (search_str )
1565+ completion_matches = glob .glob (search_str )
15991566
1600- # If we only want directories and executables, filter everything else out first
1567+ # Filter based on type
16011568 if dir_exe_only :
1602- full_matches = [c for c in full_matches if os .path .isdir (c ) or os .access (c , os .X_OK )]
1569+ completion_matches = [c for c in completion_matches if os .path .isdir (c ) or os .access (c , os .X_OK )]
16031570 elif dir_only :
1604- full_matches = [c for c in full_matches if os .path .isdir (c )]
1571+ completion_matches = [c for c in completion_matches if os .path .isdir (c )]
16051572
16061573 # Don't append a space or closing quote to directory
1607- if len (full_matches ) == 1 and not os .path .isfile (full_matches [0 ]):
1574+ if len (completion_matches ) == 1 and not os .path .isfile (completion_matches [0 ]):
16081575 self .allow_appended_space = False
16091576 self .allow_closing_quote = False
16101577
1611- # Build the completion lists
1612- completion_matches = []
1613-
1614- for cur_match in full_matches :
1615-
1616- # Only keep where text started for the tab completion
1617- completion_matches .append (cur_match [starting_index :])
1578+ # Build display_matches and add a slash to directories
1579+ for cur_match in completion_matches :
16181580
16191581 # Display only the basename of this path in the tab-completion suggestions
16201582 self .display_matches .append (os .path .basename (cur_match ))
@@ -1642,7 +1604,6 @@ def get_exes_in_path(starts_with):
16421604 :param starts_with: str - what the exes should start with. leave blank for all exes in path.
16431605 :return: List[str] - a sorted list of matching exe names
16441606 """
1645-
16461607 # Purposely don't match any executable containing wildcards
16471608 wildcards = ['*' , '?' ]
16481609 for wildcard in wildcards :
@@ -1678,31 +1639,13 @@ def shell_cmd_complete(self, text, line, begidx, endidx, complete_blank=False):
16781639 Defaults to False to match Bash shell behavior
16791640 :return: List[str] - a sorted list of possible tab completions
16801641 """
1681-
1682- # Get all tokens through the one being completed
1683- tokens , _ = self .tokens_for_completion (line , begidx , endidx )
1684- if tokens is None :
1685- return []
1686-
1687- completion_token = tokens [- 1 ]
1688-
16891642 # Don't tab complete anything if no shell command has been started
1690- if not complete_blank and len (completion_token ) == 0 :
1643+ if not complete_blank and len (text ) == 0 :
16911644 return []
16921645
1693- # If there are no path characters in this token, then do shell command completion in the user's path
1694- if os .path .sep not in completion_token :
1695- # These matches are already sorted
1696- full_matches = self .get_exes_in_path (completion_token )
1697-
1698- # We will only keep where the text value starts for the tab completions
1699- starting_index = len (completion_token ) - len (text )
1700- completion_matches = [cur_exe [starting_index :] for cur_exe in full_matches ]
1701-
1702- # Use the full name of the executables for the completions that are displayed
1703- self .display_matches = full_matches
1704-
1705- return completion_matches
1646+ # If there are no path characters in the search text, then do shell command completion in the user's path
1647+ if os .path .sep not in text :
1648+ return self .get_exes_in_path (text )
17061649
17071650 # Otherwise look for executables in the given path
17081651 else :
@@ -1722,7 +1665,6 @@ def _redirect_complete(self, text, line, begidx, endidx, compfunc):
17221665 this will be called if we aren't completing for redirection
17231666 :return: List[str] - a sorted list of possible tab completions
17241667 """
1725-
17261668 if self .allow_redirection :
17271669
17281670 # Get all tokens through the one being completed. We want the raw tokens
@@ -1941,7 +1883,6 @@ def complete(self, text, state):
19411883 :param text: str - the current word that user is typing
19421884 :param state: int - non-negative integer
19431885 """
1944-
19451886 if state == 0 :
19461887 unclosed_quote = ''
19471888 self .set_completion_defaults ()
@@ -2011,23 +1952,23 @@ def complete(self, text, state):
20111952 self .completion_matches = []
20121953 return None
20131954
2014- # We may add to the beginning of our search text. Save this text because we
2015- # need to remove it from tab completions later since readline isn't expecting it
2016- text_to_remove = ''
1955+ # readline still performs word breaks in quotes. Therefore quoted search text with
1956+ # a space would have resulted in begidx pointing to the middle of the token we want
1957+ # to complete. Figure out where that token actually begins.
1958+ actual_begidx = line [:endidx ].rfind (tokens [- 1 ])
20171959
2018- if self .allow_redirection :
2019- # Readline may have split a string with an opening quote because of a redirect
2020- # character like <. Therefore the original begidx would be wrong since a redirect
2021- # character in a quoted string should not be a word break. Update begidx to where
2022- # the token being completed actually starts.
2023- actual_begidx = line [:endidx ].rfind (tokens [- 1 ])
1960+ # If actual_begidx is different than what readline gave us, save the beginning portion
1961+ # of the completion token that does not belong in text. We will remove it from the
1962+ # completions later since readline expects our completions to start with the original text.
1963+ text_to_remove = ''
20241964
2025- if actual_begidx != begidx :
2026- text_to_remove = line [actual_begidx :begidx ]
1965+ if actual_begidx != begidx :
1966+ text_to_remove = line [actual_begidx :begidx ]
20271967
2028- # Adjust text and where it begins
2029- text = text_to_remove + text
2030- begidx = actual_begidx
1968+ # Adjust text and where it begins so the completer routines
1969+ # get unbroken search text to complete on.
1970+ text = text_to_remove + text
1971+ begidx = actual_begidx
20311972
20321973 # Get the tokens with preserved quotes
20331974 raw_completion_token = raw_tokens [- 1 ]
0 commit comments