summaryrefslogtreecommitdiff
path: root/cmd2
diff options
context:
space:
mode:
authorkotfu <kotfu@kotfu.net>2018-04-21 17:04:04 -0600
committerkotfu <kotfu@kotfu.net>2018-04-21 17:04:04 -0600
commitece08c33108a04cdeeb49af090c56e45edf46ee7 (patch)
tree5b06418087d3d5259b2546709b94cf906c8c2531 /cmd2
parent78339014ba78d07f9388997ba707984eb225c758 (diff)
downloadcmd2-git-ece08c33108a04cdeeb49af090c56e45edf46ee7.tar.gz
new shlex based parser grafted into cmd2.py
Miles to go, but the new parser is partially grafted in to cmd2, and the mumble command from example.py works.
Diffstat (limited to 'cmd2')
-rwxr-xr-xcmd2/cmd2.py80
1 files changed, 45 insertions, 35 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 60d1dbf8..3dc0cb5f 100755
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -52,6 +52,8 @@ import pyperclip
# Set up readline
from .rl_utils import rl_force_redisplay, readline, rl_type, RlType
+from cmd2.parsing import CommandParser
+
if rl_type == RlType.PYREADLINE:
# Save the original pyreadline display completion function since we need to override it and restore it
@@ -703,11 +705,11 @@ class Cmd(cmd.Cmd):
"""
# Attributes used to configure the ParserManager (all are not dynamically settable at runtime)
blankLinesAllowed = False
- commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment])
- commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/')
- legalChars = u'!#$%.:?@_-' + pyparsing.alphanums + pyparsing.alphas8bit
+ commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment]) # deleteme
+ commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/') # deleteme
+ legalChars = u'!#$%.:?@_-' + pyparsing.alphanums + pyparsing.alphas8bit # deleteme
multilineCommands = []
- prefixParser = pyparsing.Empty()
+ prefixParser = pyparsing.Empty() #deleteme
redirector = '>' # for sending output to file
shortcuts = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'}
aliases = dict()
@@ -798,13 +800,20 @@ class Cmd(cmd.Cmd):
self.history = History()
self.pystate = {}
self.keywords = self.reserved_words + [fname[3:] for fname in dir(self) if fname.startswith('do_')]
- self.parser_manager = ParserManager(redirector=self.redirector, terminators=self.terminators,
- multilineCommands=self.multilineCommands,
- legalChars=self.legalChars, commentGrammars=self.commentGrammars,
- commentInProgress=self.commentInProgress,
- blankLinesAllowed=self.blankLinesAllowed, prefixParser=self.prefixParser,
- preparse=self.preparse, postparse=self.postparse, aliases=self.aliases,
- shortcuts=self.shortcuts)
+ self.command_parser = CommandParser(
+ quotes=QUOTES,
+ allow_redirection=self.allow_redirection,
+ redirection_chars=REDIRECTION_CHARS,
+ terminators=self.terminators,
+ multilineCommands=self.multilineCommands,
+ )
+ # self.parser_manager = ParserManager(redirector=self.redirector, terminators=self.terminators,
+ # multilineCommands=self.multilineCommands,
+ # legalChars=self.legalChars, commentGrammars=self.commentGrammars,
+ # commentInProgress=self.commentInProgress,
+ # blankLinesAllowed=self.blankLinesAllowed, prefixParser=self.prefixParser,
+ # preparse=self.preparse, postparse=self.postparse, aliases=self.aliases,
+ # shortcuts=self.shortcuts)
self._transcript_files = transcript_files
# Used to enable the ability for a Python script to quit the application
@@ -2205,14 +2214,15 @@ class Cmd(cmd.Cmd):
def _complete_statement(self, line):
"""Keep accepting lines of input until the command is complete."""
- if not line or (not pyparsing.Or(self.commentGrammars).setParseAction(lambda x: '').transformString(line)):
- raise EmptyStatement()
- statement = self.parser_manager.parsed(line)
- while statement.parsed.multilineCommand and (statement.parsed.terminator == ''):
- statement = '%s\n%s' % (statement.parsed.raw,
- self.pseudo_raw_input(self.continuation_prompt))
- statement = self.parser_manager.parsed(statement)
- if not statement.parsed.command:
+ #if not line or (not pyparsing.Or(self.commentGrammars).setParseAction(lambda x: '').transformString(line)):
+ # raise EmptyStatement()
+ # statement = self.parser_manager.parsed(line) # deleteme
+ statement = self.command_parser.parseString(line)
+ #while statement.parsed.multilineCommand and (statement.parsed.terminator == ''):
+ # statement = '%s\n%s' % (statement.parsed.raw,
+ # self.pseudo_raw_input(self.continuation_prompt))
+ # statement = self.parser_manager.parsed(statement)
+ if not statement.command:
raise EmptyStatement()
return statement
@@ -2221,7 +2231,7 @@ class Cmd(cmd.Cmd):
:param statement: ParsedString - subclass of str which also contains pyparsing ParseResults instance
"""
- if statement.parsed.pipeTo:
+ if statement.pipeTo:
self.kept_state = Statekeeper(self, ('stdout',))
# Create a pipe with read and write sides
@@ -2236,7 +2246,7 @@ class Cmd(cmd.Cmd):
# We want Popen to raise an exception if it fails to open the process. Thus we don't set shell to True.
try:
- self.pipe_proc = subprocess.Popen(shlex.split(statement.parsed.pipeTo), stdin=subproc_stdin)
+ self.pipe_proc = subprocess.Popen(shlex.split(statement.pipeTo), stdin=subproc_stdin)
except Exception as ex:
# Restore stdout to what it was and close the pipe
self.stdout.close()
@@ -2248,20 +2258,20 @@ class Cmd(cmd.Cmd):
# Re-raise the exception
raise ex
- elif statement.parsed.output:
- if (not statement.parsed.outputTo) and (not can_clip):
+ elif statement.output:
+ if (not statement.outputTo) and (not can_clip):
raise EnvironmentError('Cannot redirect to paste buffer; install ``xclip`` and re-run to enable')
self.kept_state = Statekeeper(self, ('stdout',))
self.kept_sys = Statekeeper(sys, ('stdout',))
self.redirecting = True
- if statement.parsed.outputTo:
+ if statement.outputTo:
mode = 'w'
- if statement.parsed.output == 2 * self.redirector:
+ if statement.output == 2 * self.redirector:
mode = 'a'
- sys.stdout = self.stdout = open(os.path.expanduser(statement.parsed.outputTo), mode)
+ sys.stdout = self.stdout = open(os.path.expanduser(statement.outputTo), mode)
else:
sys.stdout = self.stdout = tempfile.TemporaryFile(mode="w+")
- if statement.parsed.output == '>>':
+ if statement.output == '>>':
self.poutput(get_paste_buffer())
def _restore_output(self, statement):
@@ -2272,7 +2282,7 @@ class Cmd(cmd.Cmd):
# If we have redirected output to a file or the clipboard or piped it to a shell command, then restore state
if self.kept_state is not None:
# If we redirected output to the clipboard
- if statement.parsed.output and not statement.parsed.outputTo:
+ if statement.output and not statement.outputTo:
self.stdout.seek(0)
write_to_paste_buffer(self.stdout.read())
@@ -2310,29 +2320,29 @@ class Cmd(cmd.Cmd):
result = target
return result
- def onecmd(self, line):
+ def onecmd(self, statement):
""" This executes the actual do_* method for a command.
If the command provided doesn't exist, then it executes _default() instead.
- :param line: ParsedString - subclass of string including the pyparsing ParseResults
+ :param line: 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)
- funcname = self._func_named(statement.parsed.command)
+ #statement = self.parser_manager.parsed(line) # deleteme
+ funcname = self._func_named(statement.command)
if not funcname:
return self.default(statement)
# Since we have a valid command store it in the history
- if statement.parsed.command not in self.exclude_from_history:
- self.history.append(statement.parsed.raw)
+ if statement.command not in self.exclude_from_history:
+ self.history.append(statement.raw)
try:
func = getattr(self, funcname)
except AttributeError:
return self.default(statement)
- stop = func(statement)
+ stop = func("{} {}".format(statement.command, statement.args))
return stop
def default(self, statement):