diff --git a/plugins/Alias.py b/plugins/Alias.py index 091ecd95e..d78fb24ab 100644 --- a/plugins/Alias.py +++ b/plugins/Alias.py @@ -85,32 +85,64 @@ def findBiggestAt(alias): return 0 def makeNewAlias(name, alias): + original = alias if findAliasCommand(name, alias): raise RecursiveAlias - biggestDollar = findBiggestDollar(alias) - biggestAt = findBiggestAt(alias) - wildcard = '$*' in alias + biggestDollar = findBiggestDollar(original) + biggestAt = findBiggestAt(original) + wildcard = '$*' in original if biggestAt and wildcard: - raise AliasError, 'Can\'t use $* and optional args (@1, etc.)' + raise AliasError, 'Can\'t mix $* and optional args (@1, etc.)' + if original.count('$*') > 1: + raise AliasError, 'There can be only one $* in an alias.' def f(self, irc, msg, args): - alias_ = alias.replace('$nick', msg.nick) - if '$channel' in alias: + alias = original.replace('$nick', msg.nick) + if '$channel' in original: channel = privmsgs.getChannel(msg, args) - alias_ = alias_.replace('$channel', channel) + alias = alias.replace('$channel', channel) + tokens = callbacks.tokenize(alias) if not wildcard and biggestDollar or biggestAt: - args = privmsgs.getArgs(args, needed=biggestDollar, + args = privmsgs.getArgs(args, + needed=biggestDollar, optional=biggestAt) - # Gotta have a tuple. - if biggestDollar + biggestAt == 1 and not wildcard: - args = (args,) - def replace(m): + # Gotta have a mutable sequence (for replace). + if biggestDollar + biggestAt == 1: # We got a string, no tuple. + args = [args] + def regexpReplace(m): idx = int(m.group(1)) - return utils.dqrepr(args[idx-1]) - alias_ = dollarRe.sub(replace, alias_) - args = args[biggestDollar:] - alias_ = atRe.sub(replace, alias_) - alias_ = alias_.replace('$*', ' '.join(map(utils.dqrepr, args))) - self.Proxy(irc.irc, msg, callbacks.tokenize(alias_)) + return args[idx-1] + def replace(tokens, replacer): + for (i, token) in enumerate(tokens): + if isinstance(token, list): + replace(token, replacer) + else: + tokens[i] = replacer(token) + replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) + if biggestAt: + assert not wildcard + args = args[biggestDollar:] + replace(tokens, lambda s: atRe.sub(regexpReplace, s)) + if wildcard: + assert not biggestAt + # Gotta remove the things that have already been subbed in. + i = biggestDollar + while i: + args.pop(0) + i -= 1 + def everythingReplace(tokens): + for (i, token) in enumerate(tokens): + if isinstance(token, list): + if everythingReplace(token): + return + if token == '$*': + tokens[i:i+1] = args + return True + elif '$*' in token: + tokens[i] = token.replace('$*', ' '.join(args)) + return True + return False + everythingReplace(tokens) + self.Proxy(irc.irc, msg, tokens) f = types.FunctionType(f.func_code, f.func_globals, name, closure=f.func_closure) f.__doc__ ='\n\nAlias for %r' % \ diff --git a/test/test_Alias.py b/test/test_Alias.py index f27f2b070..1c0424452 100644 --- a/test/test_Alias.py +++ b/test/test_Alias.py @@ -133,6 +133,14 @@ class AliasTestCase(ChannelPluginTestCase, PluginDocumentation): self.assertNotError('alias add myrepr "repr @1"') self.assertResponse('myrepr foo', '"foo"') self.assertResponse('myrepr ""', '""') + + def testNoExtraSpaces(self): + self.assertNotError('alias add foo "action takes $1\'s money"') + self.assertResponse('foo bar', '\x01ACTION takes bar\'s money\x01') + + def testNoExtraQuotes(self): + self.assertNotError('alias add myre "echo s/$1/$2/g"') + self.assertResponse('myre foo bar', 's/foo/bar/g')