diff options
-rw-r--r-- | SHLEX_TODO.txt | 1 | ||||
-rwxr-xr-x | cmd2/cmd2.py | 6 | ||||
-rw-r--r-- | cmd2/parsing.py | 18 | ||||
-rw-r--r-- | tests/test_parsing.py | 16 |
4 files changed, 21 insertions, 20 deletions
diff --git a/SHLEX_TODO.txt b/SHLEX_TODO.txt index b9ffe70d..b8526afa 100644 --- a/SHLEX_TODO.txt +++ b/SHLEX_TODO.txt @@ -12,6 +12,7 @@ Changelog Items: - if self.default_to_shell is true, then redirection and piping are now properly passed to the shell, previously it was truncated - object passed to do_* methods has changed. It no longer is the pyparsing object, it's a new Statement object. A side effect of this is that we now have a clean interface between the parsing logic and the rest of cmd2. If we need to change the parser in the future, we can do it without breaking anything. The parser is now self.statement_parser instead of self.command_parser. - input redirection no longer supported. Use the load command instead. +- multilineCommand attribute is no multiline_command - submenus now call all hooks, it used to just call precmd and postcmd - cmd2 ignores identchars. The standardlibrary cmd uses those characters to split the first "word" of the input, but cmd2 hasn't used those for a while, and the new parsing logic parses on whitespace, which has the added benefit of full unicode support, unlike cmd or prior versions of cmd2. - set_posix_shlex function and POSIX_SHLEX variable have been removed. Parsing behavior is now always posix=false. diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 626769fe..136d86b2 100755 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -595,7 +595,7 @@ class Cmd(cmd.Cmd): """ # Attributes used to configure the StatementParser, best not to change these at runtime blankLinesAllowed = False - multilineCommands = [] + multiline_commands = [] redirector = '>' # for sending output to file shortcuts = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'} aliases = dict() @@ -689,7 +689,7 @@ class Cmd(cmd.Cmd): self.statement_parser = StatementParser( allow_redirection=self.allow_redirection, terminators=self.terminators, - multilineCommands=self.multilineCommands, + multiline_commands=self.multiline_commands, aliases=self.aliases, shortcuts=self.shortcuts, ) @@ -2077,7 +2077,7 @@ class Cmd(cmd.Cmd): backwards compatibility with the standard library version of cmd. """ statement = self.statement_parser.parse(line) - while statement.multilineCommand and not statement.terminator: + while statement.multiline_command and not statement.terminator: if not self.quit_on_sigint: try: newline = self.pseudo_raw_input(self.continuation_prompt) diff --git a/cmd2/parsing.py b/cmd2/parsing.py index b4f0e9c1..03937856 100644 --- a/cmd2/parsing.py +++ b/cmd2/parsing.py @@ -33,7 +33,7 @@ class Statement(str): super().__init__() self.raw = str(obj) self.command = None - self.multilineCommand = None + self.multiline_command = None # has to be an empty string for compatibility with standard library cmd self.args = '' self.terminator = None @@ -56,7 +56,7 @@ class StatementParser(): self, allow_redirection=True, terminators=None, - multilineCommands = None, + multiline_commands = None, aliases = None, shortcuts = [], ): @@ -65,10 +65,10 @@ class StatementParser(): self.terminators = [';'] else: self.terminators = terminators - if multilineCommands is None: + if multiline_commands is None: self.multilineCommands = [] else: - self.multilineCommands = multilineCommands + self.multiline_commands = multiline_commands if aliases is None: self.aliases = {} else: @@ -167,7 +167,7 @@ class StatementParser(): tokens = tokens[terminator_pos+1:] else: (testcommand, testargs) = self._command_and_args(tokens) - if testcommand in self.multilineCommands: + if testcommand in self.multiline_commands: # no terminator on this line but we have a multiline command # everything else on the line is part of the args # because redirectors can only be after a terminator @@ -228,10 +228,10 @@ class StatementParser(): (command, args) = self._command_and_args(tokens) # set multiline - if command in self.multilineCommands: - multilineCommand = command + if command in self.multiline_commands: + multiline_command = command else: - multilineCommand = None + multiline_command = None # build Statement object result = Statement(args) @@ -244,7 +244,7 @@ class StatementParser(): result.outputTo = outputTo result.pipeTo = pipeTo result.suffix = suffix - result.multilineCommand = multilineCommand + result.multiline_command = multiline_command return result def parse_command_only(self, rawinput: str) -> Statement: diff --git a/tests/test_parsing.py b/tests/test_parsing.py index b920b440..3fc7c171 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -16,7 +16,7 @@ def parser(): parser = StatementParser( allow_redirection=True, terminators = [';'], - multilineCommands = ['multiline'], + multiline_commands = ['multiline'], aliases = {'helpalias': 'help', '42': 'theanswer', 'anothermultiline': 'multiline', 'fake': 'pyscript'}, shortcuts = [('?', 'help'), ('!', 'shell')] ) @@ -192,7 +192,7 @@ def test_has_redirect_inside_terminator(parser): def test_parse_unfinished_multiliine_command(parser): line = 'multiline has > inside an unfinished command' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.command == 'multiline' assert statement.args == 'has > inside an unfinished command' assert not statement.terminator @@ -200,7 +200,7 @@ def test_parse_unfinished_multiliine_command(parser): def test_parse_multiline_command_ignores_redirectors_within_it(parser): line = 'multiline has > inside;' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.args == 'has > inside' assert statement.terminator == ';' @@ -209,28 +209,28 @@ def test_parse_multiline_with_incomplete_comment(parser): Un-closed comments effectively comment out everything after the start.""" line = 'multiline command /* with comment in progress;' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.args == 'command' assert not statement.terminator def test_parse_multiline_with_complete_comment(parser): line = 'multiline command /* with comment complete */ is done;' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.args == 'command is done' assert statement.terminator == ';' def test_parse_multiline_termninated_by_empty_line(parser): line = 'multiline command ends\n\n' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.args == 'command ends' assert statement.terminator == '\n' def test_parse_multiline_ignores_terminators_in_comments(parser): line = 'multiline command "with term; ends" now\n\n' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.args == 'command "with term; ends" now' assert statement.terminator == '\n' @@ -283,7 +283,7 @@ def test_alias_and_shortcut_expansion(parser, line, command, args): def test_alias_on_multiline_command(parser): line = 'anothermultiline has > inside an unfinished command' statement = parser.parse(line) - assert statement.multilineCommand == 'multiline' + assert statement.multiline_command == 'multiline' assert statement.command == 'multiline' assert statement.args == 'has > inside an unfinished command' assert not statement.terminator |