Removed the syntax command; changed interface of callbacks.findCallbackForCommand to return a list of the matching callbacks; fix help to handle the prefixing of the plugin name.

This commit is contained in:
Jeremy Fincher 2003-10-20 10:25:13 +00:00
parent 112303af56
commit 55ccb85542
6 changed files with 90 additions and 103 deletions

View File

@ -198,8 +198,8 @@ class Alias(callbacks.Privmsg):
if name != realName:
raise AliasError,'That name isn\'t valid. Try %r instead'%realName
name = realName
cb = callbacks.findCallbackForCommand(irc, name)
if cb is not None and cb != self:
cbs = callbacks.findCallbackForCommand(irc, name)
if [cb for cb in cbs if cb != self]:
raise AliasError, 'A command with the name %r already exists.'%name
if name in self.frozen:
raise AliasError, 'Alias %r is frozen.' % name

View File

@ -124,79 +124,60 @@ class MiscCommands(callbacks.Privmsg):
irc.error(msg, 'There is no plugin named %s, ' \
'or that plugin has no commands.' % name)
def syntax(self, irc, msg, args):
"""<command>
Gives the syntax for a specific command. To find commands,
use the 'list' command to go see the commands offered by a plugin.
The 'list' command by itself will show you what plugins have commands.
"""
command = privmsgs.getArgs(args, needed=0, optional=1)
if not command:
command = 'help'
command = callbacks.canonicalName(command)
cb = callbacks.findCallbackForCommand(irc, command)
if cb:
method = getattr(cb, command)
if hasattr(method, '__doc__') and method.__doc__ is not None:
doclines = method.__doc__.strip().splitlines()
help = doclines.pop(0)
irc.reply(msg, '%s %s' % (command, help))
else:
irc.reply(msg, 'That command exists, '
'but has no syntax description.')
else:
cb = irc.getCallback(command)
if cb:
s = ''
if hasattr(cb, '__doc__') and cb.__doc__ is not None:
s = cb.__doc__
else:
module = sys.modules[cb.__module__]
if hasattr(module, '__doc__') and module.__doc__:
s = module.__doc__
if s:
s = ' '.join(map(str.strip, s.splitlines()))
if not s.endswith('.'):
s += '.'
s += ' Use the list command to see what commands this ' \
'plugin supports.'
else:
s = 'That plugin has no help description.'
irc.reply(msg, s)
else:
irc.error(msg, 'There is no such command or plugin.')
def help(self, irc, msg, args):
"""<command>
"""[<plugin>] <command>
This command gives a much more useful description than the simple
argument list given by the command 'syntax'.
argument list given by the command 'syntax'. <plugin> is only
necessary if the command is in more than one plugin.
"""
def helpFor(method):
doclines = method.__doc__.splitlines()
simplehelp = '(%s %s)' % (method.__name__, doclines.pop(0))
if doclines:
doclines = filter(None, doclines)
doclines = map(str.strip, doclines)
help = ' '.join(doclines)
s = '%s -- %s' % (ircutils.bold(simplehelp), help)
return s
else:
return 'That command has no help. The syntax is: %s' % \
simplehelp[1:-1]
if len(args) > 1:
cb = irc.getCallback(args[0])
if cb is not None:
command = callbacks.canonicalName(privmsgs.getArgs(args[1:]))
if hasattr(cb, 'isCommand') and cb.isCommand(command):
method = getattr(cb, command)
if hasattr(method, '__doc__') and method.__doc__ != None:
irc.reply(msg, helpFor(method))
else:
irc.error(msg, 'That command has no help.')
else:
irc.error(msg, 'There is no such command %s %s.' %
(args[0], command))
else:
irc.error(msg, 'There is no such plugin %s' % args[0])
return
command = callbacks.canonicalName(privmsgs.getArgs(args))
# Users might expect "@help @list" to work.
command = command.lstrip(conf.prefixChars)
cb = callbacks.findCallbackForCommand(irc, command)
if cb:
cbs = callbacks.findCallbackForCommand(irc, command)
if len(cbs) > 1:
irc.error(msg, 'That command exists in the %s %s. Please specify '
'exactly which plugin command you want help with.'%\
(utils.commaAndify([cb.name() for cb in cbs]),
utils.nItems(len(cbs), 'plugin')))
return
elif not cbs:
irc.error(msg, 'There is no such command %s.' % command)
else:
cb = cbs[0]
method = getattr(cb, command)
if hasattr(method, '__doc__') and method.__doc__ is not None:
doclines = method.__doc__.splitlines()
simplehelp = doclines.pop(0)
simplehelp = '(%s %s)' % (command, simplehelp)
if doclines:
doclines = filter(None, doclines)
doclines = map(str.strip, doclines)
help = ' '.join(doclines)
s = '%s %s' % (ircutils.bold(simplehelp),help)
irc.reply(msg, s)
else:
irc.reply(msg, 'That command has no help. '\
'The syntax is this: %s %s' % \
(command, simplehelp))
irc.reply(msg, helpFor(method))
else:
irc.error(msg, '%s has no help or syntax description.'%command)
else:
irc.error(msg, 'There is no such command %s.' % command)
def hostmask(self, irc, msg, args):
"""<nick>
@ -257,9 +238,9 @@ class MiscCommands(callbacks.Privmsg):
Returns the plugin <command> is in.
"""
command = callbacks.canonicalName(privmsgs.getArgs(args))
cb = callbacks.findCallbackForCommand(irc, command)
if cb is not None:
irc.reply(msg, cb.name())
cbs = callbacks.findCallbackForCommand(irc, command)
if cbs:
irc.reply(msg, utils.commaAndify([cb.name() for cb in cbs]))
else:
irc.error(msg, 'There is no such command %s' % command)

View File

@ -297,14 +297,15 @@ def getCommands(tokens):
return L
def findCallbackForCommand(irc, commandName):
"""Given a command name and an Irc object, returns the callback that
command is in. Returns None if there is no callback with that command."""
"""Given a command name and an Irc object, returns a list of callbacks that
commandName is in."""
L = []
for callback in irc.callbacks:
if not isinstance(callback, PrivmsgRegexp):
if hasattr(callback, 'isCommand'):
if callback.isCommand(commandName):
return callback
return None
L.append(callback)
return L
class IrcObjectProxy:
"A proxy object to allow proper nested of commands (even threaded ones)."
@ -341,9 +342,22 @@ class IrcObjectProxy:
self.finalEvaled = True
originalName = self.args.pop(0)
name = canonicalName(originalName)
cb = findCallbackForCommand(self, name)
try:
if cb is not None:
cbs = findCallbackForCommand(self, name)
if len(cbs) == 0:
self.args.insert(0, originalName)
if not isinstance(self.irc, irclib.Irc):
# If self.irc is an actual irclib.Irc, then this is the
# first command given, and should be ignored as usual.
self.reply(self.msg, '[%s]' % ' '.join(self.args))
return
elif len(cbs) > 1:
s = 'The command %s is available in plugins %s. Please specify ' \
'the plugin whose command you wish to call.' % \
(originalName, utils.commaAndify([cb.name() for cb in cbs]))
self.error(self.msg, s)
else:
try:
cb = cbs[0]
anticap = ircdb.makeAntiCapability(name)
#debug.printf('Checking for %s' % anticap)
if ircdb.checkCapability(self.msg.prefix, anticap):
@ -371,26 +385,20 @@ class IrcObjectProxy:
t.start()
else:
cb.callCommand(command, self, self.msg, self.args)
else:
self.args.insert(0, originalName)
except (getopt.GetoptError, ArgumentError):
if hasattr(command, '__doc__'):
s = '%s %s' % (name, command.__doc__.splitlines()[0])
else:
s = 'Invalid arguments for %s.' % name
self.reply(self.msg, s)
except CannotNest, e:
if not isinstance(self.irc, irclib.Irc):
# If self.irc is an actual irclib.Irc, then this is the
# first command given, and should be ignored as usual.
self.reply(self.msg, '[%s]' % ' '.join(self.args))
except (getopt.GetoptError, ArgumentError):
if hasattr(command, '__doc__'):
s = '%s %s' % (name, command.__doc__.splitlines()[0])
else:
s = 'Invalid arguments for %s.' % name
self.reply(self.msg, s)
except CannotNest, e:
if not isinstance(self.irc, irclib.Irc):
self.error(self.msg, 'Command %r cannot be nested.' % name)
except (SyntaxError, Error), e:
self.reply(self.msg, debug.exnToString(e))
except Exception, e:
debug.recoverableException()
self.error(self.msg, debug.exnToString(e))
self.error(self.msg, 'Command %r cannot be nested.' % name)
except (SyntaxError, Error), e:
self.reply(self.msg, debug.exnToString(e))
except Exception, e:
debug.recoverableException()
self.error(self.msg, debug.exnToString(e))
def reply(self, msg, s, noLengthCheck=False, prefixName=True,
action=False, private=False, notice=False):

View File

@ -70,7 +70,6 @@ class AliasTestCase(ChannelPluginTestCase, PluginDocumentation):
plugins = ('Alias', 'Fun', 'Utilities', 'MiscCommands')
def testAliasHelp(self):
self.assertNotError('alias slashdot foo')
self.assertNotRegexp('syntax slashdot', 'None')
self.assertRegexp('help slashdot', "Alias for 'foo'")
def testDollars(self):

View File

@ -61,10 +61,6 @@ class MiscCommandsTestCase(ChannelPluginTestCase, PluginDocumentation):
finally:
conf.repylWhenNotCommand = False
def testSyntax(self):
self.assertNotError('syntax list')
self.assertNotError('syntax help')
def testHelp(self):
self.assertNotError('help list')
try:
@ -73,7 +69,7 @@ class MiscCommandsTestCase(ChannelPluginTestCase, PluginDocumentation):
self.assertNotError('help @list')
finally:
conf.prefixChars = original
self.assertNotError('help syntax')
self.assertNotError('help list')
self.assertRegexp('help help', r'^\x02\(help')
self.assertError('help morehelp')

View File

@ -163,7 +163,7 @@ class FunctionsTestCase(unittest.TestCase):
class PrivmsgTestCase(ChannelPluginTestCase):
plugins = ('Utilities', 'OwnerCommands')
plugins = ('Utilities', 'OwnerCommands', 'MiscCommands')
conf.allowEval = True
timeout = 2
def testEmptySquareBrackets(self):
@ -239,12 +239,15 @@ class PrivmsgTestCase(ChannelPluginTestCase):
self.assertNotRegexp('firstcmd', '(foo.*baz|baz.*foo)')
self.assertResponse('first firstcmd', 'foo')
self.assertResponse('firstrepeat firstcmd', 'baz')
def testHelpDispatching(self):
self.irc.addCallback(self.First())
self.assertNotError('help firstcmd')
self.assertNotError('help first firstcmd')
self.irc.addCallback(self.FirstRepeat())
self.assertError('help firstcmd')
self.assertRegexp('help first firstcmd', 'First', 0) # no re.I flag.
self.assertRegexp('help firstrepeat firstcmd', 'FirstRepeat', 0)
self.assertResponse('syntax first firstcmd', 'firstcmd First')
self.assertResponse('syntax firstrepeat firstcmd',
'firstcmd FirstRepeat')
def testDefaultCommand(self):
self.irc.addCallback(self.First())