+# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+#
+# This file is part of Hooke.
+#
+# Hooke is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# Hooke is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+# Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Hooke. If not, see
+# <http://www.gnu.org/licenses/>.
+
"""Defines :class:`CommandLine` for driving Hooke from the command
line.
"""
+import codecs
import cmd
import optparse
import readline # including readline makes cmd.Cmd.cmdloop() smarter
from ..command import CommandExit, Exit, Command, Argument, StoreValue
from ..interaction import Request, BooleanRequest, ReloadUserInterfaceConfig
from ..ui import UserInterface, CommandMessage
+from ..util.convert import from_string
+from ..util.encoding import get_input_encoding, get_output_encoding
# Define a few helper classes.
continue # 'help' is a default OptionParser option
if a.optional == True:
name = name_fn(a.name)
+ type = a.type
+ if type == 'bool':
+ if a.default == True:
+ self.add_option(
+ '--disable-%s' % name, dest=name, default=Default,
+ action='store_false')
+ self.command_opts.append(a)
+ continue
+ elif a.default == False:
+ self.add_option(
+ '--enable-%s' % name, dest=name, default=Default,
+ action='store_true')
+ self.command_opts.append(a)
+ continue
+ else:
+ type = 'string'
+ elif type not in ['string', 'int', 'long', 'choice', 'float',
+ 'complex']:
+ type = 'string'
self.add_option(
- '--%s' % name, dest=name, default=Default)
+ '--%s' % name, dest=name, type=type, default=Default)
self.command_opts.append(a)
else:
self.command_args.append(a)
self.cmd.stdout.write(str(e).lstrip()+'\n')
self.cmd.stdout.write('Failure\n')
return
+ print args
self.cmd.inqueue.put(CommandMessage(self.command, args))
while True:
msg = self.cmd.outqueue.get()
self.cmd.stdout.write(str(msg).rstrip()+'\n')
def _parse_args(self, args):
- argv = shlex.split(args, comments=True, posix=True)
- options,args = self.parser.parse_args(argv)
+ options,args = self.parser.parse_args(args)
self._check_argument_length_bounds(args)
params = {}
for argument in self.parser.command_opts:
arg_index = 0
for argument in self.parser.command_args:
if argument.count == 1:
- params[argument.name] = args[arg_index]
+ params[argument.name] = from_string(args[arg_index],
+ argument.type)
elif argument.count > 1:
- params[argument.name] = \
- args[arg_index:arg_index+argument.count]
+ params[argument.name] = [
+ from_string(a, argument.type)
+ for a in args[arg_index:arg_index+argument.count]]
else: # argument.count == -1:
- params[argument.name] = args[arg_index:]
+ params[argument.name] = [
+ from_string(a, argument.type) for a in args[arg_index:]]
arg_index += argument.count
return params
If not, raise optparse.OptParseError().
"""
min_args = 0
- max_args = -1
+ max_args = 0
for argument in self.parser.command_args:
if argument.optional == False and argument.count > 0:
min_args += argument.count
return msg.msg + d
def _string_request_parser(self, msg, response):
+ response = response.strip()
+ if response == '':
+ return msg.default
return response.strip()
def _float_request_prompt(self, msg):
return self._string_request_prompt(msg)
def _float_request_parser(self, msg, resposne):
+ if response.strip() == '':
+ return msg.default
return float(response)
def _selection_request_prompt(self, msg):
prompt = '? '
else:
prompt = '? [%d] ' % msg.default
- return '\n'.join([msg,options,prompt])
+ return '\n'.join([msg.msg,options,prompt])
def _selection_request_parser(self, msg, response):
+ if response.strip() == '':
+ return msg.default
+ return int(response)
+
+ def _point_request_prompt(self, msg):
+ block = msg.curve.data[msg.block]
+ block_info = ('(curve: %s, block: %s, %d points)'
+ % (msg.curve.name,
+ block.info['name'],
+ block.shape[0]))
+
+ if msg.default == None:
+ prompt = '? '
+ else:
+ prompt = '? [%d] ' % msg.default
+ return ' '.join([msg.msg,block_info,prompt])
+
+ def _point_request_parser(self, msg, response):
+ if response.strip() == '':
+ return msg.default
return int(response)
default = True
if len(not_saved) > 0:
msg = 'Unsaved playlists (%s). %s' \
- % (', '.join(not_saved), msg)
+ % (', '.join([str(p) for p in not_saved]), msg)
default = False
outqueue.put(BooleanRequest(msg, default))
result = inqueue.get()
setattr(self.__class__, 'complete_%s' % name,
CompleteCommand(self, command, self._name_fn))
+ def parseline(self, line):
+ """Override Cmd.parseline to use shlex.split.
+
+ Notes
+ -----
+ This allows us to handle comments cleanly. With the default
+ Cmd implementation, a pure comment line will call the .default
+ error message.
+
+ Since we use shlex to strip comments, we return a list of
+ split arguments rather than the raw argument string.
+ """
+ line = line.strip()
+ argv = shlex.split(line, comments=True, posix=True)
+ if len(argv) == 0:
+ return None, None, '' # return an empty line
+ cmd = argv[0]
+ args = argv[1:]
+ if cmd == '?':
+ cmd = 'help'
+ elif cmd == '!':
+ cmd = 'system'
+ return cmd, args, line
+
+ def do_help(self, arg):
+ """Wrap Cmd.do_help to handle our .parseline argument list.
+ """
+ if len(arg) == 0:
+ return cmd.Cmd.do_help(self, '')
+ return cmd.Cmd.do_help(self, arg[0])
+
+ def emptyline(self):
+ """Override Cmd.emptyline to not do anything.
+
+ Repeating the last non-empty command seems unwise. Explicit
+ is better than implicit.
+ """
+ pass
+
class CommandLine (UserInterface):
"""Command line interface. Simple and powerful.
def __init__(self):
super(CommandLine, self).__init__(name='command line')
- def run(self, commands, ui_to_command_queue, command_to_ui_queue):
+ def _cmd(self, commands, ui_to_command_queue, command_to_ui_queue):
cmd = HookeCmd(self, commands,
inqueue=ui_to_command_queue,
outqueue=command_to_ui_queue)
- cmd.cmdloop(self._splash_text())
+ #cmd.stdin = codecs.getreader(get_input_encoding())(cmd.stdin)
+ cmd.stdout = codecs.getwriter(get_output_encoding())(cmd.stdout)
+ return cmd
+
+ def run(self, commands, ui_to_command_queue, command_to_ui_queue):
+ cmd = self._cmd(commands, ui_to_command_queue, command_to_ui_queue)
+ cmd.cmdloop(self._splash_text(extra_info={
+ 'get-details':'run `license`',
+ }))
+
+ def run_lines(self, commands, ui_to_command_queue, command_to_ui_queue,
+ lines):
+ cmd = self._cmd(commands, ui_to_command_queue, command_to_ui_queue)
+ for line in lines:
+ cmd.onecmd(line)