diff --git a/plugins/Topic.py b/plugins/Topic.py index af04fcb69..ea9ec1fec 100644 --- a/plugins/Topic.py +++ b/plugins/Topic.py @@ -73,10 +73,15 @@ conf.registerChannelValue(conf.supybot.plugins.Topic, 'recognizeTopiclen', TOPICLEN value sent to it by the server and thus refuse to send TOPICs longer than the TOPICLEN. These topics are likely to be truncated by the server anyway, so this defaults to True.""")) +conf.registerGroup(conf.supybot.plugins.Topic, 'undo') +conf.registerChannelValue(conf.supybot.plugins.Topic.undo, 'max', + registry.NonNegativeInteger(10, """Determines the number of previous + topics to keep around in case the undo command is called.""")) class Topic(callbacks.Privmsg): def __init__(self): callbacks.Privmsg.__init__(self) + self.undos = ircutils.IrcDict() self.lastTopics = ircutils.IrcDict() def _splitTopic(self, topic, channel): @@ -92,6 +97,23 @@ class Topic(callbacks.Privmsg): env = {'topic': topic} return plugins.standardSubstitute(irc, msg, formatter, env) + def _addUndo(self, channel, topics): + try: + stack = self.undos[channel] + except KeyError: + stack = [] + self.undos[channel] = stack + stack.append(topics) + maxLen = self.registryValue('undo.max', channel) + while len(stack) > maxLen: + del stack[0] + + def _getUndo(self, channel): + try: + return self.undos[channel].pop() + except (KeyError, IndexError): + return None + def _sendTopics(self, irc, channel, topics): topics = [s for s in topics if s and not s.isspace()] self.lastTopics[channel] = topics @@ -104,6 +126,7 @@ class Topic(callbacks.Privmsg): '(maximum length: %s).' % maxLen, Raise=True) except KeyError: pass + self._addUndo(channel, topics) irc.queueMsg(ircmsgs.topic(channel, newTopic)) def _canChangeTopic(self, irc, channel): @@ -343,6 +366,20 @@ class Topic(callbacks.Privmsg): self._sendTopics(irc, channel, topics) restore = privmsgs.channel(restore) + def undo(self, irc, msg, args, channel): + """[] + + Restores the topic to the one previous to the last topic command that + set it. + """ + topics = self._getUndo(channel) # This is the last topic sent. + topics = self._getUndo(channel) # This is the topic list we want. + if topics is not None: + self._sendTopics(irc, channel, topics) + else: + irc.error('There are no more undos for %s.' % channel) + undo = privmsgs.channel(undo) + Class = Topic diff --git a/test/test_Topic.py b/test/test_Topic.py index e683c13a6..f057c1c14 100644 --- a/test/test_Topic.py +++ b/test/test_Topic.py @@ -77,13 +77,13 @@ class TopicTestCase(ChannelPluginTestCase, PluginDocumentation): def testConfig(self): try: + original = conf.supybot.plugins.Topic.separator() conf.supybot.plugins.Topic.separator.setValue(' <==> ') _ = self.getMsg('topic add foo') m = self.getMsg('topic add bar') self.failUnless('<==>' in m.args[1]) finally: - default = conf.supybot.plugins.Topic.separator.default() - conf.supybot.plugins.Topic.separator.setValue(default) + conf.supybot.plugins.Topic.separator.setValue(original) def testReorder(self): _ = self.getMsg('topic add foo') @@ -116,6 +116,24 @@ class TopicTestCase(ChannelPluginTestCase, PluginDocumentation): self.assertRegexp('topic set -1 bar', 'bar') self.assertNotRegexp('topic set -1 baz', 'bar') + def testTopic(self): + self.assertResponse('topic foo bar baz', 'foo bar baz') + + def testUndo(self): + try: + original = conf.supybot.plugins.Topic.format() + conf.supybot.plugins.Topic.format.setValue('$topic') + self.assertResponse('topic ""', '') + self.assertResponse('topic add foo', 'foo') + self.assertResponse('topic add bar', 'foo || bar') + self.assertResponse('topic add baz', 'foo || bar || baz') + self.assertResponse('topic undo', 'foo || bar') + self.assertResponse('topic undo', 'foo') + self.assertResponse('topic undo', '') + finally: + conf.supybot.plugins.Topic.format.setValue(original) + + # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: