mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-12 13:19:49 +01:00
Changed the whole handling of nonCommands and ambiguousCommands and whatnot. Now plugins can define an 'invalidCommand' method to be called on invalid commands.
This commit is contained in:
parent
114909f702
commit
e03c65f753
55
src/Misc.py
55
src/Misc.py
@ -43,6 +43,7 @@ from itertools import ifilter
|
|||||||
import conf
|
import conf
|
||||||
import debug
|
import debug
|
||||||
import utils
|
import utils
|
||||||
|
import irclib
|
||||||
import ircmsgs
|
import ircmsgs
|
||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
@ -73,56 +74,12 @@ def reload(x=None):
|
|||||||
replyWhenNotCommand = x
|
replyWhenNotCommand = x
|
||||||
|
|
||||||
class Misc(callbacks.Privmsg):
|
class Misc(callbacks.Privmsg):
|
||||||
def doPrivmsg(self, irc, msg):
|
def invalidCommand(self, irc, msg, tokens):
|
||||||
# This exists to be able to respond to attempts to command the bot
|
if conf.replyWhenNotCommand:
|
||||||
# with a "That's not a command!" if the proper conf.variable is set.
|
irc.error(msg, '%r is not a valid command.' % tokens[0])
|
||||||
callbacks.Privmsg.doPrivmsg(self, irc, msg)
|
|
||||||
notCommands = []
|
|
||||||
ambiguousCommands = {}
|
|
||||||
s = callbacks.addressed(irc.nick, msg)
|
|
||||||
if s:
|
|
||||||
tokens = callbacks.tokenize(s)
|
|
||||||
commands = callbacks.getCommands(tokens)
|
|
||||||
for command in commands:
|
|
||||||
command = callbacks.canonicalName(command)
|
|
||||||
cbs = callbacks.findCallbackForCommand(irc, command)
|
|
||||||
if not cbs:
|
|
||||||
notCommands.append(command)
|
|
||||||
elif len(cbs) > 1:
|
|
||||||
ambiguousCommands[command] = [cb.name() for cb in cbs]
|
|
||||||
if ambiguousCommands:
|
|
||||||
if len(ambiguousCommands) == 1: # Common case.
|
|
||||||
(command, names) = ambiguousCommands.popitem()
|
|
||||||
names.sort()
|
|
||||||
s = 'The command %r is available in the %s plugins. '\
|
|
||||||
'Please specify the plugin whose command you ' \
|
|
||||||
'wish to call by using its name as a command ' \
|
|
||||||
'before calling it.' % \
|
|
||||||
(command, utils.commaAndify(names))
|
|
||||||
else:
|
else:
|
||||||
L = []
|
if not isinstance(irc.irc, irclib.Irc):
|
||||||
while ambiguousCommands:
|
irc.reply(msg, '[%s]' % ' '.join(tokens))
|
||||||
(command, names) = ambiguousCommands.popitem()
|
|
||||||
names.sort()
|
|
||||||
L.append('The command %r is available in the %s '
|
|
||||||
'plugins' %(command,utils.commaAndify(names)))
|
|
||||||
s = '%s; please specify from which plugins to ' \
|
|
||||||
'call these commands.' % '; '.join(L)
|
|
||||||
irc.queueMsg(callbacks.reply(msg, 'Error: ' + s))
|
|
||||||
return
|
|
||||||
if conf.replyWhenNotCommand and msg.nick!=irc.nick and notCommands:
|
|
||||||
for cb in irc.callbacks:
|
|
||||||
if isinstance(cb, callbacks.PrivmsgRegexp) or \
|
|
||||||
isinstance(cb, callbacks.PrivmsgCommandAndRegexp):
|
|
||||||
for (r, _) in cb.res:
|
|
||||||
if r.search(msg.args[1]):
|
|
||||||
return
|
|
||||||
if hasattr(cb, 'addressedRes'):
|
|
||||||
for (r, _) in cb.addressedRes:
|
|
||||||
if r.search(s):
|
|
||||||
return
|
|
||||||
irc = callbacks.IrcObjectProxyRegexp(irc)
|
|
||||||
replyWhenNotCommand(irc, msg, notCommands)
|
|
||||||
|
|
||||||
def list(self, irc, msg, args):
|
def list(self, irc, msg, args):
|
||||||
"""[--private] [<module name>]
|
"""[--private] [<module name>]
|
||||||
|
@ -88,7 +88,11 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
|
|
||||||
def doPrivmsg(self, irc, msg):
|
def doPrivmsg(self, irc, msg):
|
||||||
callbacks.Privmsg.handled = False
|
callbacks.Privmsg.handled = False
|
||||||
super(self.__class__, self).doPrivmsg(irc, msg)
|
notCommands = []
|
||||||
|
ambiguousCommands = {}
|
||||||
|
s = callbacks.addressed(irc.nick, msg)
|
||||||
|
if s:
|
||||||
|
callbacks.IrcObjectProxy(irc, msg, callbacks.tokenize(s))
|
||||||
|
|
||||||
def eval(self, irc, msg, args):
|
def eval(self, irc, msg, args):
|
||||||
"""<expression>
|
"""<expression>
|
||||||
|
104
src/callbacks.py
104
src/callbacks.py
@ -344,6 +344,35 @@ class IrcObjectProxy:
|
|||||||
if not args:
|
if not args:
|
||||||
irc.reply(msg, '[]')
|
irc.reply(msg, '[]')
|
||||||
else:
|
else:
|
||||||
|
if isinstance(irc, irclib.Irc):
|
||||||
|
# Let's check for {ambiguous,non}Commands.
|
||||||
|
ambiguousCommands = {}
|
||||||
|
commands = getCommands(args)
|
||||||
|
for command in commands:
|
||||||
|
command = canonicalName(command)
|
||||||
|
cbs = findCallbackForCommand(irc, command)
|
||||||
|
if len(cbs) > 1:
|
||||||
|
ambiguousCommands[command] = [cb.name() for cb in cbs]
|
||||||
|
if ambiguousCommands:
|
||||||
|
if len(ambiguousCommands) == 1: # Common case.
|
||||||
|
(command, names) = ambiguousCommands.popitem()
|
||||||
|
names.sort()
|
||||||
|
s = 'The command %r is available in the %s plugins. '\
|
||||||
|
'Please specify the plugin whose command you ' \
|
||||||
|
'wish to call by using its name as a command ' \
|
||||||
|
'before calling it.' % \
|
||||||
|
(command, utils.commaAndify(names))
|
||||||
|
else:
|
||||||
|
L = []
|
||||||
|
for (command, names) in ambiguousCommands.iteritems():
|
||||||
|
names.sort()
|
||||||
|
L.append('The command %r is available in the %s '
|
||||||
|
'plugins' %
|
||||||
|
(command, utils.commaAndify(names)))
|
||||||
|
s = '%s; please specify from which plugins to ' \
|
||||||
|
'call these commands.' % '; '.join(L)
|
||||||
|
irc.queueMsg(error(msg, s))
|
||||||
|
return
|
||||||
self.irc = irc
|
self.irc = irc
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.args = args
|
self.args = args
|
||||||
@ -367,23 +396,31 @@ class IrcObjectProxy:
|
|||||||
self.finalEval()
|
self.finalEval()
|
||||||
|
|
||||||
def finalEval(self):
|
def finalEval(self):
|
||||||
if self.finalEvaled:
|
assert not self.finalEvaled, 'finalEval called twice.'
|
||||||
raise ValueError, 'finalEval called twice. Odd.'
|
|
||||||
self.finalEvaled = True
|
self.finalEvaled = True
|
||||||
originalName = self.args.pop(0)
|
name = canonicalName(self.args[0])
|
||||||
name = canonicalName(originalName)
|
|
||||||
cbs = findCallbackForCommand(self, name)
|
cbs = findCallbackForCommand(self, name)
|
||||||
if len(cbs) == 0:
|
if len(cbs) == 0:
|
||||||
self.args.insert(0, originalName)
|
for cb in self.irc.callbacks:
|
||||||
if not isinstance(self.irc, irclib.Irc):
|
if isinstance(cb, PrivmsgRegexp):
|
||||||
# If self.irc is an actual irclib.Irc, then this is the
|
for (r, _) in cb.res:
|
||||||
# first command given, and should be ignored as usual.
|
if r.search(msg.args[1]):
|
||||||
self.reply(self.msg, '[%s]' % ' '.join(self.args))
|
|
||||||
return
|
return
|
||||||
elif len(cbs) > 1:
|
if isinstance(cb, PrivmsgCommandAndRegexp):
|
||||||
return # Misc.doPrivmsg will handle this.
|
for (r, _) in cb.res:
|
||||||
|
if r.search(msg.args[1]):
|
||||||
|
return
|
||||||
|
for (r, _) in cb.addressedRes:
|
||||||
|
if r.search(msg.args[1]):
|
||||||
|
return
|
||||||
|
# Ok, no regexp-based things matched.
|
||||||
|
for cb in self.irc.callbacks:
|
||||||
|
if hasattr(cb, 'invalidCommand'):
|
||||||
|
cb.invalidCommand(self, self.msg, self.args)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
assert len(cbs) == 1
|
||||||
|
del self.args[0]
|
||||||
cb = cbs[0]
|
cb = cbs[0]
|
||||||
anticap = ircdb.makeAntiCapability(name)
|
anticap = ircdb.makeAntiCapability(name)
|
||||||
#debug.printf('Checking for %s' % anticap)
|
#debug.printf('Checking for %s' % anticap)
|
||||||
@ -454,22 +491,6 @@ class IrcObjectProxy:
|
|||||||
elif self.action:
|
elif self.action:
|
||||||
self.irc.queueMsg(ircmsgs.action(msg.args[0], s))
|
self.irc.queueMsg(ircmsgs.action(msg.args[0], s))
|
||||||
else:
|
else:
|
||||||
# The size of a PRIVMSG is:
|
|
||||||
# 1 for the colon
|
|
||||||
# len(prefix)
|
|
||||||
# 1 for the space
|
|
||||||
# 7 for the PRIVMSG
|
|
||||||
# 1 for the space
|
|
||||||
# len(target)
|
|
||||||
# 1 for the space
|
|
||||||
# 1 for the colon
|
|
||||||
# len(payload)
|
|
||||||
# 2 for the \r\n
|
|
||||||
# So non-variable stuff it's 1+1+7+1+1+1+2, or 14
|
|
||||||
# We'll estimate the channel length at 30, and we'll know the
|
|
||||||
# prefix length exactly. We also might append the string
|
|
||||||
# " (more)" to the end, so that's 7 more characters.
|
|
||||||
# 512 - 51 == 461.
|
|
||||||
s = ircutils.safeArgument(s)
|
s = ircutils.safeArgument(s)
|
||||||
allowedLength = 450 - len(self.irc.prefix)
|
allowedLength = 450 - len(self.irc.prefix)
|
||||||
msgs = textwrap.wrap(s, allowedLength-30) # -30 is for "nick:"
|
msgs = textwrap.wrap(s, allowedLength-30) # -30 is for "nick:"
|
||||||
@ -689,33 +710,7 @@ class Privmsg(irclib.IrcCallback):
|
|||||||
debug.msg('%s took %s seconds' % (funcname, elapsed), 'verbose')
|
debug.msg('%s took %s seconds' % (funcname, elapsed), 'verbose')
|
||||||
|
|
||||||
def doPrivmsg(self, irc, msg, rateLimit=True):
|
def doPrivmsg(self, irc, msg, rateLimit=True):
|
||||||
s = addressed(irc.nick, msg)
|
pass
|
||||||
#debug.printf('Privmsg.doPrivmsg: s == %r' % s)
|
|
||||||
if s:
|
|
||||||
recipient = msg.args[0]
|
|
||||||
if ircdb.checkIgnored(msg.prefix, recipient):
|
|
||||||
debug.msg('Privmsg.doPrivmsg: ignoring %s.' % msg.prefix)
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
args = tokenize(s)
|
|
||||||
except SyntaxError, e:
|
|
||||||
irc.queueMsg(reply(msg, debug.exnToString(e)))
|
|
||||||
return
|
|
||||||
if args and isinstance(args[0], str):
|
|
||||||
args[0] = canonicalName(args[0])
|
|
||||||
if self.isCommand(args[0]):
|
|
||||||
if self.handled and args[0] not in self.alwaysCall:
|
|
||||||
return
|
|
||||||
if rateLimit:
|
|
||||||
self.rateLimiter.put(msg)
|
|
||||||
msg = self.rateLimiter.get()
|
|
||||||
if msg:
|
|
||||||
if conf.replyWhenNotCommand:
|
|
||||||
for command in getCommands(args):
|
|
||||||
command = canonicalName(command)
|
|
||||||
if not findCallbackForCommand(irc, command):
|
|
||||||
return
|
|
||||||
self.Proxy(irc, msg, args)
|
|
||||||
|
|
||||||
|
|
||||||
class IrcObjectProxyRegexp:
|
class IrcObjectProxyRegexp:
|
||||||
@ -871,7 +866,6 @@ class PrivmsgCommandAndRegexp(Privmsg):
|
|||||||
if msg:
|
if msg:
|
||||||
proxy = IrcObjectProxyRegexp(irc)
|
proxy = IrcObjectProxyRegexp(irc)
|
||||||
self.callCommand(method,proxy,msg,m,catchErrors=True)
|
self.callCommand(method,proxy,msg,m,catchErrors=True)
|
||||||
Privmsg.doPrivmsg(self, irc, msg, rateLimit=(not fed))
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -38,7 +38,11 @@ class MiscTestCase(ChannelPluginTestCase, PluginDocumentation):
|
|||||||
conf.replyWhenNotCommand = True
|
conf.replyWhenNotCommand = True
|
||||||
self.prefix = 'somethingElse!user@host.domain.tld'
|
self.prefix = 'somethingElse!user@host.domain.tld'
|
||||||
self.assertRegexp('foo bar baz', 'not.*command')
|
self.assertRegexp('foo bar baz', 'not.*command')
|
||||||
|
try:
|
||||||
|
conf.enablePipeSyntax = True
|
||||||
self.assertRegexp('foo | bar | baz', 'not.*commands')
|
self.assertRegexp('foo | bar | baz', 'not.*commands')
|
||||||
|
finally:
|
||||||
|
conf.enablePipeSyntax = False
|
||||||
self.assertRegexp('baz [foo] [bar]', 'not.*commands')
|
self.assertRegexp('baz [foo] [bar]', 'not.*commands')
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotCommand = False
|
conf.replyWhenNotCommand = False
|
||||||
|
@ -84,19 +84,19 @@ class OwnerTestCase(PluginTestCase, PluginDocumentation):
|
|||||||
def testLoad(self):
|
def testLoad(self):
|
||||||
self.assertError('load Owner')
|
self.assertError('load Owner')
|
||||||
self.assertError('load owner')
|
self.assertError('load owner')
|
||||||
self.assertNotError('load Misc')
|
self.assertNotError('load Admin')
|
||||||
self.assertNotError('list Owner')
|
self.assertNotError('list Owner')
|
||||||
|
|
||||||
def testReload(self):
|
def testReload(self):
|
||||||
self.assertError('reload Misc')
|
self.assertError('reload Admin')
|
||||||
self.assertNotError('load Misc')
|
self.assertNotError('load Admin')
|
||||||
self.assertNotError('reload Misc')
|
self.assertNotError('reload Admin')
|
||||||
|
|
||||||
def testUnload(self):
|
def testUnload(self):
|
||||||
self.assertError('unload Misc')
|
self.assertError('unload Admin')
|
||||||
self.assertNotError('load Misc')
|
self.assertNotError('load Admin')
|
||||||
self.assertNotError('unload Misc')
|
self.assertNotError('unload Admin')
|
||||||
self.assertError('unload Misc')
|
self.assertError('unload Admin')
|
||||||
|
|
||||||
def testSetconf(self):
|
def testSetconf(self):
|
||||||
self.assertRegexp('setconf', 'confDir')
|
self.assertRegexp('setconf', 'confDir')
|
||||||
|
Loading…
Reference in New Issue
Block a user