summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd2/cmd2.py46
-rw-r--r--cmd2/parsing.py67
-rw-r--r--tests/test_shlexparsing.py2
3 files changed, 71 insertions, 44 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 3dc0cb5f..4e2c053f 100755
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -386,20 +386,21 @@ def write_to_paste_buffer(txt: str) -> None:
pyperclip.copy(txt)
-class ParsedString(str):
- """Subclass of str which also stores a pyparsing.ParseResults object containing structured parse results."""
- # pyarsing.ParseResults - structured parse results, to provide multiple means of access to the parsed data
- parsed = None
+# deleteme
+# class ParsedString(str):
+# """Subclass of str which also stores a pyparsing.ParseResults object containing structured parse results."""
+# # pyarsing.ParseResults - structured parse results, to provide multiple means of access to the parsed data
+# parsed = None
- # Function which did the parsing
- parser = None
+# # Function which did the parsing
+# parser = None
- def full_parsed_statement(self):
- """Used to reconstruct the full parsed statement when a command isn't recognized."""
- new = ParsedString('%s %s' % (self.parsed.command, self.parsed.args))
- new.parsed = self.parsed
- new.parser = self.parser
- return new
+# def full_parsed_statement(self):
+# """Used to reconstruct the full parsed statement when a command isn't recognized."""
+# new = ParsedString('%s %s' % (self.parsed.command, self.parsed.args))
+# new.parsed = self.parsed
+# new.parser = self.parser
+# return new
def replace_with_file_contents(fname: str) -> str:
@@ -2010,8 +2011,8 @@ class Cmd(cmd.Cmd):
def precmd(self, statement):
"""Hook method executed just before the command is processed by ``onecmd()`` and after adding it to the history.
- :param statement: ParsedString - subclass of str which also contains pyparsing ParseResults instance
- :return: ParsedString - a potentially modified version of the input ParsedString statement
+ :param statement: Statement - subclass of str which also contains the parsed input
+ :return: Statement - a potentially modified version of the input Statement object
"""
return statement
@@ -2027,11 +2028,11 @@ class Cmd(cmd.Cmd):
return raw
# noinspection PyMethodMayBeStatic
- def postparse(self, parse_result):
- """Hook that runs immediately after parsing the command-line but before ``parsed()`` returns a ParsedString.
+ def postparse(self, statement):
+ """Hook that runs immediately after parsing the user input.
- :param parse_result: pyparsing.ParseResults - parsing results output by the pyparsing parser
- :return: pyparsing.ParseResults - potentially modified ParseResults object
+ :param statement: Statement object populated by parsing
+ :return: Statement - potentially modified Statement object
"""
return parse_result
@@ -2048,8 +2049,8 @@ class Cmd(cmd.Cmd):
- raise EmptyStatement - will silently fail and do nothing
- raise <AnyOtherException> - will fail and print an error message
- :param statement: - the parsed command-line statement
- :return: (bool, statement) - (stop, statement) containing a potentially modified version of the statement
+ :param statement: - the parsed command-line statement as a Statement object
+ :return: (bool, statement) - (stop, statement) containing a potentially modified version of the statement object
"""
stop = False
return stop, statement
@@ -2325,10 +2326,9 @@ class Cmd(cmd.Cmd):
If the command provided doesn't exist, then it executes _default() instead.
- :param line: Command - a parsed command from the input stream
+ :param statement: Command - a parsed command from the input stream
:return: bool - a flag indicating whether the interpretation of commands should stop
"""
- #statement = self.parser_manager.parsed(line) # deleteme
funcname = self._func_named(statement.command)
if not funcname:
return self.default(statement)
@@ -2342,7 +2342,7 @@ class Cmd(cmd.Cmd):
except AttributeError:
return self.default(statement)
- stop = func("{} {}".format(statement.command, statement.args))
+ stop = func(statement)
return stop
def default(self, statement):
diff --git a/cmd2/parsing.py b/cmd2/parsing.py
index 41ce5743..164c7735 100644
--- a/cmd2/parsing.py
+++ b/cmd2/parsing.py
@@ -7,10 +7,19 @@ import shlex
import cmd2
-class Command():
- """Store the results of a parsed command."""
- def __init__(self, rawinput):
- self.raw = rawinput
+class Statement(str):
+ """String subclass with additional attributes to store the results of parsing.
+
+ The cmd module in the standard library passes commands around as a
+ string. To retain backwards compatibility, cmd2 does the same. However, we
+ need a place to capture the additional output of the command parsing, so we add
+ our own attributes to this subclass.
+
+ The string portion of the class contains the arguments, but not the command, nor
+ the output redirection clauses.
+ """
+ def __init__(self, object):
+ self.raw = str(object)
self.command = None
self.multilineCommand = None
self.args = None
@@ -37,7 +46,7 @@ class CommandParser():
self.multilineCommands = multilineCommands
def parseString(self, rawinput):
- result = Command(rawinput)
+ #result = Statement(rawinput)
# strip C-style and C++-style comments
# shlex will handle the python/shell style comments for us
@@ -67,6 +76,7 @@ class CommandParser():
if pos < terminator_pos:
terminator_pos = pos
terminator = test_terminator
+ break
except ValueError:
# the terminator is not in the tokens
pass
@@ -74,35 +84,37 @@ class CommandParser():
if terminator:
terminator_pos = tokens.index(terminator)
# everything before the first terminator is the command and the args
- (result.command, result.args) = self._command_and_args(tokens[:terminator_pos])
- result.terminator = tokens[terminator_pos]
+ (command, args) = self._command_and_args(tokens[:terminator_pos])
+ #terminator = tokens[terminator_pos]
# we will set the suffix later
# remove all the tokens before and including the terminator
tokens = tokens[terminator_pos+1:]
# check for input from file
+ inputFrom = None
try:
if tokens[0] == '<':
- result.inputFrom = ' '.join(tokens[1:])
+ inputFrom = ' '.join(tokens[1:])
tokens = []
except IndexError:
- # no input from file
pass
+
# check for output redirect
try:
output_pos = tokens.index('>')
- result.output = '>'
- result.outputTo = ' '.join(tokens[output_pos+1:])
+ output = '>'
+ outputTo = ' '.join(tokens[output_pos+1:])
# remove all the tokens after the output redirect
tokens = tokens[:output_pos]
except ValueError:
- pass
+ output = None
+ outputTo = None
# check for paste buffer
try:
output_pos = tokens.index('>>')
- result.output = '>>'
+ output = '>>'
# remove all tokens after the output redirect
tokens = tokens[:output_pos]
except ValueError:
@@ -113,23 +125,36 @@ class CommandParser():
# find the first pipe if it exists
pipe_pos = tokens.index('|')
# set everything after the first pipe to result.pipeTo
- result.pipeTo = ' '.join(tokens[pipe_pos+1:])
+ pipeTo = ' '.join(tokens[pipe_pos+1:])
# remove all the tokens after the pipe
tokens = tokens[:pipe_pos]
except ValueError:
# no pipe in the tokens
- pass
+ pipeTo = None
- if result.terminator:
+ if terminator:
# whatever is left is the suffix
- result.suffix = ' '.join(tokens)
+ suffix = ' '.join(tokens)
else:
# no terminator, so whatever is left is the command and the args
- (result.command, result.args) = self._command_and_args(tokens)
-
- if result.command in self.multilineCommands:
- result.multilineCommand = result.command
+ suffix = None
+ (command, args) = self._command_and_args(tokens)
+ if command in self.multilineCommands:
+ multilineCommand = command
+ else:
+ multilineCommand = None
+
+ result = Statement(args)
+ result.command = command
+ result.args = args
+ result.terminator = terminator
+ result.inputFrom = inputFrom
+ result.output = output
+ result.outputTo = outputTo
+ result.pipeTo = pipeTo
+ result.suffix = suffix
+ result.multilineCommand = multilineCommand
return result
def _command_and_args(self, tokens):
diff --git a/tests/test_shlexparsing.py b/tests/test_shlexparsing.py
index 5d3c9546..9142e178 100644
--- a/tests/test_shlexparsing.py
+++ b/tests/test_shlexparsing.py
@@ -5,6 +5,8 @@ Unit/functional testing for ply based parsing in cmd2
Todo List
- multiline
- case sensitive flag
+- checkout Cmd2.parseline() function which parses and expands shortcuts and such
+ this code should probably be included in CommandParser
Notes: