2 # A topic plugin to allow for multi-item topics.
3 # Complete rip-off of supybot.
6 class Topic < PluginBase
11 @topics = YAML.load_file(file_name('topics.db'))
17 open_file('topics.db', 'w') do |f|
18 f.puts '# CyBot topic plugin: Topic database.'
25 @brief_help = 'Manipulates channel topic.'
29 :help => 'Makes the topic plugin save topic on exit and restore it on join. If not set, the current channel topic is read on join.',
33 :help => 'Makes the topic plugin automatically follow all topic changes.',
37 :help => "Allows user to use the 'topic' command to change the channel topic.",
45 'topic-preserve' => tp,
56 'topic-preserve' => tp,
83 :help => 'Settings for the topic plugin.',
85 'separator' => "Topic item separator. Defaults to '|'",
87 :help => 'The maximum length of the topic line.',
97 # On-join hook. Read topic, if enabled, or set our own.
98 def hook_init_chan(irc)
100 t = @topics[cn = c.name] || (@topics[cn] = [nil, nil])
101 if setting_cs(irc, 'topic-preserve') { $config['plugins/topic/preserve'] }
110 # On topic change. Read if enabled.
111 def hook_topic_chan(irc, topic)
112 return if !irc.from or irc.from.nick == irc.server.nick
113 if setting_cs(irc, 'topic-follow') { $config['plugins/topic/follow'] }
114 t = @topics[cn = irc.channel.name] || (@topics[cn] = [nil, nil])
115 sep = $config['plugins/topic/separator', '|']
116 t[0] = t[1] = topic.split(" #{sep} ")
120 # Internal helper to avoid repetition.
121 def topic(chan, topic)
122 sep = $config['plugins/topic/separator', '|']
123 chan.server.cmd('TOPIC', chan.name, topic.join(" #{sep} "))
126 # Split into an integer list. Raises ArgumentError.
128 raise ArgumentError unless data
129 data.split.map do |e|
130 raise ArgumentError if e.nil?
135 # Check if list is a permutation of the numbers 1...n. Raises RuntimeError.
136 def check_permute(list, n)
137 raise ArgumentError unless list.length == n
140 raise ArgumentError if e < 1 or e > n or a[e-1]
143 raise ArgumentError if a.any? { |e| e.nil? }
146 # Perform topic reorder.
147 def reorder(chan, topics, list)
149 topics[1] = (u = c.dup)
150 list.length.times { |i| c[i] = u[list[i] - 1] }
154 # Silly test command.
155 def chan_list(irc, chan, line)
156 irc.reply "Da topic list!!!"
159 # Read topic from channel.
161 sep = $config['plugins/topic/separator', '|']
162 (topic = chan.topic) ? topic.split(" #{sep} ") : []
166 def common(irc, chan, line)
167 if !$user.caps(irc, 'topic', 'op', 'owner').any?
168 irc.reply "I'm afraid you're not allowed to do that!"
172 irc.reply 'For now, I must be operator to manipulate the topic.'
175 t = @topics[chan.name] || (@topics[chan.name] = [[], []])
177 line = nil if line and line.empty?
178 [line, t, current, undo]
181 def chan_set(irc, chan, line)
182 stuff = common(irc, chan, line) or return
183 data, t, current, undo = stuff
185 t[1], t[0] = current, (c = [data])
187 else irc.reply 'USAGE: topic set <topic string>' end
189 help :set, 'Sets the channel topic to the line provided.'
191 def chan_add(irc, chan, line)
192 stuff = common(irc, chan, line) or return
193 data, t, current, undo = stuff
198 else irc.reply 'USAGE: topic add <topic item>' end
200 help :add, 'Adds the given item to the list of topics in the channel.'
202 def chan_del(irc, chan, line)
203 stuff = common(irc, chan, line) or return
204 data, t, current, undo = stuff
206 raise ArgumentError unless data
208 if i <= (l = current.length) and i >= 1
210 current.delete_at(i - 1)
213 irc.reply "Item number is out of range. There are #{l} items in the topic."
216 irc.reply 'USAGE: topic del <item number>'
219 help :del, 'Deletes the item number (1-base) from the channel topic list.'
221 def chan_reorder(irc, chan, line)
222 stuff = common(irc, chan, line) or return
223 data, t, current, undo = stuff
226 check_permute(l, current.length)
229 irc.reply 'USAGE: topic reorder <position 1> ... <position n>'
232 help :reorder, 'Reorders the channel topic list. You must provide a permutation of the numbers 1-n (both included), where n is the number of topic items. Example: topic reorder 2 4 1 3, if there are four items.'
234 def chan_swap(irc, chan, line)
235 stuff = common(irc, chan, line) or return
236 data, t, current, undo = stuff
239 raise ArgumentError unless l.length == 2
242 if i >= 1 and i <= l and j >= 1 and j <= l
243 if i == j: irc.reply "That seems rather silly, doesn't it?"
246 current[i-1], current[j-1] = current[j-1], current[i-1]
250 irc.reply "Item numbers are out of range. There are #{l} items in the topic."
253 irc.reply 'USAGE: topic swap <item number 1> <item number 2>'
256 help :swap, 'Swaps the two topic items (numbered from 1) in the channel topic list.'
258 def chan_shuffle(irc, chan, line)
259 stuff = common(irc, chan, line) or return
260 data, t, current, undo = stuff
264 l.times { |i| b << a.delete_at(rand(l - i)) }
267 help :shuffle, 'Randomly permutes the channel topic list.'
269 def chan_undo(irc, chan, line)
270 stuff = common(irc, chan, line) or return
271 data, t, current, undo = stuff
272 t[1], t[0] = current, undo
275 help :undo, 'Undoes the last channel topic change (if caused by one of the topic commands).'
277 def chan_restore(irc, chan, line)
278 stuff = common(irc, chan, line) or return
279 data, t, current, undo = stuff
280 list = read_topic(chan)
286 help :restore, 'Restores the last channel topic set with one of the topic commands.'
288 def chan_read(irc, chan, line)
289 stuff = common(irc, chan, line) or return
290 data, t, current, undo = stuff
291 list = read_topic(chan)
292 t[0], t[1] = list, t[0]
293 irc.reply "Ok. Found #{list.length} topic items."
295 help :read, 'Reads and parses the currently set channel topic line. Use this if someone else changes the topic and you want the bot to grab it.'
297 def chan_replace(irc, chan, line)
298 stuff = common(irc, chan, line) or return
299 data, t, current, undo = stuff
301 raise ArgumentError unless data
302 i, txt = data.split(' ', 2)
303 raise ArgumentError unless txt
305 if i <= (l = current.length) and i >= 1
309 irc.reply "Item number is out of range. There are #{l} items in the topic."
312 irc.reply 'USAGE: topic replace <item number> <new topic item>'
315 help :replace, 'Replaces the given topic item (numbered from 1) in the channel topic list.'