Skip to content

Commit a53b76a

Browse files
authored
Merge pull request #749 from python-cmd2/termination
Added terminators to completion delimiters
2 parents 54e3014 + f1c87a9 commit a53b76a

File tree

3 files changed

+14
-60
lines changed

3 files changed

+14
-60
lines changed

cmd2/cmd2.py

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -824,56 +824,8 @@ def tokens_for_completion(self, line: str, begidx: int, endidx: int) -> Tuple[Li
824824
# Return empty lists since this means the line is malformed.
825825
return [], []
826826

827-
# We need to treat redirection characters (|, <, >) as word breaks when they are in unquoted strings.
828-
# Go through each token and further split them on these characters. Each run of redirect characters
829-
# is treated as a single token.
830-
raw_tokens = []
831-
832-
for cur_initial_token in initial_tokens:
833-
834-
# Save tokens up to 1 character in length or quoted tokens. No need to parse these.
835-
if len(cur_initial_token) <= 1 or cur_initial_token[0] in constants.QUOTES:
836-
raw_tokens.append(cur_initial_token)
837-
continue
838-
839-
# Iterate over each character in this token
840-
cur_index = 0
841-
cur_char = cur_initial_token[cur_index]
842-
843-
# Keep track of the token we are building
844-
cur_raw_token = ''
845-
846-
while True:
847-
if cur_char not in constants.REDIRECTION_CHARS:
848-
849-
# Keep appending to cur_raw_token until we hit a redirect char
850-
while cur_char not in constants.REDIRECTION_CHARS:
851-
cur_raw_token += cur_char
852-
cur_index += 1
853-
if cur_index < len(cur_initial_token):
854-
cur_char = cur_initial_token[cur_index]
855-
else:
856-
break
857-
858-
else:
859-
redirect_char = cur_char
860-
861-
# Keep appending to cur_raw_token until we hit something other than redirect_char
862-
while cur_char == redirect_char:
863-
cur_raw_token += cur_char
864-
cur_index += 1
865-
if cur_index < len(cur_initial_token):
866-
cur_char = cur_initial_token[cur_index]
867-
else:
868-
break
869-
870-
# Save the current token
871-
raw_tokens.append(cur_raw_token)
872-
cur_raw_token = ''
873-
874-
# Check if we've viewed all characters
875-
if cur_index >= len(cur_initial_token):
876-
break
827+
# Further split tokens on punctuation characters
828+
raw_tokens = self.statement_parser.split_on_punctuation(initial_tokens)
877829

878830
# Save the unquoted tokens
879831
tokens = [utils.strip_quotes(cur_token) for cur_token in raw_tokens]
@@ -2299,10 +2251,11 @@ def _set_up_cmd2_readline(self) -> _SavedReadlineSettings:
22992251
readline_settings.completer = readline.get_completer()
23002252
readline.set_completer(self.complete)
23012253

2302-
# Break words on whitespace, quotes, and redirectors when tab completing
2254+
# Set the readline word delimiters for completion
23032255
completer_delims = " \t\n"
23042256
completer_delims += ''.join(constants.QUOTES)
23052257
completer_delims += ''.join(constants.REDIRECTION_CHARS)
2258+
completer_delims += ''.join(self.statement_parser.terminators)
23062259

23072260
readline_settings.delims = readline.get_completer_delims()
23082261
readline.set_completer_delims(completer_delims)

cmd2/parsing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ def tokenize(self, line: str, *, expand: bool = True) -> List[str]:
379379
tokens = shlex_split(line)
380380

381381
# custom lexing
382-
tokens = self._split_on_punctuation(tokens)
382+
tokens = self.split_on_punctuation(tokens)
383383
return tokens
384384

385385
def parse(self, line: str, *, expand: bool = True) -> Statement:
@@ -675,7 +675,7 @@ def _command_and_args(tokens: List[str]) -> Tuple[str, str]:
675675

676676
return command, args
677677

678-
def _split_on_punctuation(self, tokens: List[str]) -> List[str]:
678+
def split_on_punctuation(self, tokens: List[str]) -> List[str]:
679679
"""Further splits tokens from a command line using punctuation characters
680680
681681
Punctuation characters are treated as word breaks when they are in

tests/test_completion.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -689,26 +689,27 @@ def test_tokens_for_completion_unclosed_quote(cmd2_app):
689689
assert expected_tokens == tokens
690690
assert expected_raw_tokens == raw_tokens
691691

692-
def test_tokens_for_completion_redirect(cmd2_app):
693-
text = '>>file'
694-
line = 'command | < {}'.format(text)
692+
def test_tokens_for_completion_punctuation(cmd2_app):
693+
"""Test that redirectors and terminators are word delimiters"""
694+
text = 'file'
695+
line = 'command | < ;>>{}'.format(text)
695696
endidx = len(line)
696697
begidx = endidx - len(text)
697698

698-
expected_tokens = ['command', '|', '<', '>>', 'file']
699-
expected_raw_tokens = ['command', '|', '<', '>>', 'file']
699+
expected_tokens = ['command', '|', '<', ';', '>>', 'file']
700+
expected_raw_tokens = ['command', '|', '<', ';', '>>', 'file']
700701

701702
tokens, raw_tokens = cmd2_app.tokens_for_completion(line, begidx, endidx)
702703
assert expected_tokens == tokens
703704
assert expected_raw_tokens == raw_tokens
704705

705-
def test_tokens_for_completion_quoted_redirect(cmd2_app):
706+
def test_tokens_for_completion_quoted_punctuation(cmd2_app):
707+
"""Test that quoted punctuation characters are not word delimiters"""
706708
text = '>file'
707709
line = 'command "{}'.format(text)
708710
endidx = len(line)
709711
begidx = endidx - len(text)
710712

711-
cmd2_app.statement_parser.redirection = True
712713
expected_tokens = ['command', '>file']
713714
expected_raw_tokens = ['command', '">file']
714715

0 commit comments

Comments
 (0)