Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions cmd2/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,23 +250,27 @@ def parse(self, rawinput: str) -> Statement:
tokens = self.tokenize(rawinput)

# of the valid terminators, find the first one to occur in the input
terminator_pos = len(tokens)+1
for test_terminator in self.terminators:
try:
pos = tokens.index(test_terminator)
if pos < terminator_pos:
terminator_pos = len(tokens) + 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok to me

for pos, cur_token in enumerate(tokens):
for test_terminator in self.terminators:
if cur_token.startswith(test_terminator):
terminator_pos = pos
terminator = test_terminator
# break the inner loop, and we want to break the
# outer loop too
break
except ValueError:
# the terminator is not in the tokens
pass
else:
# this else clause is only run if the inner loop
# didn't execute a break. If it didn't, then
# continue to the next iteration of the outer loop
continue
# inner loop was broken, break the outer
break

if terminator:
if terminator == LINE_FEED:
terminator_pos = len(tokens)+1
else:
terminator_pos = tokens.index(terminator)

# everything before the first terminator is the command and the args
argv = tokens[:terminator_pos]
(command, args) = self._command_and_args(argv)
Expand Down
38 changes: 36 additions & 2 deletions tests/test_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,23 @@ def test_parse_redirect_inside_terminator(parser):
assert statement.argv == ['has', '>', 'inside']
assert statement.terminator == ';'

@pytest.mark.parametrize('line,terminator',[
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding lots of unit tests to cover this functionality

('multiline with | inside;', ';'),
('multiline with | inside ;', ';'),
('multiline with | inside;;;', ';'),
('multiline with | inside;; ;;', ';'),
('multiline with | inside&', '&'),
('multiline with | inside &;', '&'),
('multiline with | inside&&;', '&'),
('multiline with | inside &; &;', '&'),
])
def test_parse_multiple_terminators(parser, line, terminator):
statement = parser.parse(line)
assert statement.multiline_command == 'multiline'
assert statement.args == 'with | inside'
assert statement.argv == ['multiline', 'with', '|', 'inside']
assert statement.terminator == terminator

def test_parse_unfinished_multiliine_command(parser):
line = 'multiline has > inside an unfinished command'
statement = parser.parse(line)
Expand All @@ -261,7 +278,10 @@ def test_parse_unfinished_multiliine_command(parser):

@pytest.mark.parametrize('line,terminator',[
('multiline has > inside;', ';'),
('multiline has > inside;;;', ';'),
('multiline has > inside;; ;;', ';'),
('multiline has > inside &', '&'),
('multiline has > inside & &', '&'),
])
def test_parse_multiline_command_ignores_redirectors_within_it(parser, line, terminator):
statement = parser.parse(line)
Expand Down Expand Up @@ -388,8 +408,15 @@ def test_parse_alias_pipe(parser, line):
assert not statement.args
assert statement.pipe_to == ['less']

def test_parse_alias_terminator_no_whitespace(parser):
line = 'helpalias;'
@pytest.mark.parametrize('line', [
'helpalias;',
'helpalias;;',
'helpalias;; ;',
'helpalias ;',
'helpalias ; ;',
'helpalias ;; ;',
])
def test_parse_alias_terminator_no_whitespace(parser, line):
statement = parser.parse(line)
assert statement.command == 'help'
assert not statement.args
Expand Down Expand Up @@ -448,13 +475,20 @@ def test_parse_command_only_quoted_args(parser):
'helpalias>>out.txt',
'help|less',
'helpalias;',
'help ;;',
'help; ;;',
])
def test_parse_command_only_specialchars(parser, line):
statement = parser.parse_command_only(line)
assert statement.command == 'help'

@pytest.mark.parametrize('line', [
';',
';;',
';; ;',
'&',
'& &',
' && &',
'>',
"'",
'"',
Expand Down