Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
15 changes: 5 additions & 10 deletions cmd2/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,23 +250,18 @@ 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
Copy Markdown
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
except ValueError:
# the terminator is not in the tokens
pass

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
Copy Markdown
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 == 'has | inside'
assert statement.argv == ['multiline', 'has', '|', '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