Skip to content

Commit 96fc0e7

Browse files
committed
SedRegex: Split _replacer_process into smaller functions
That each either access global state or apply the user-provided regexp. A future commit will add an alternative implementation of _replacer_process for Windows that calls them differently in order to access global state in the main process and only applies regexps in the child process.
1 parent af6b50d commit 96fc0e7

1 file changed

Lines changed: 78 additions & 50 deletions

File tree

plugins/SedRegex/plugin.py

Lines changed: 78 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,60 @@
5858
class SearchNotFoundError(Exception):
5959
pass
6060

61+
62+
def filter_messages(network, msg, target, messages, ignoreRegex, sedRegex):
63+
"""Applies all filters but the user-provided regexp, so it is safe to
64+
run in the main process."""
65+
for m in messages:
66+
if m.command in ('PRIVMSG', 'NOTICE') and \
67+
ircutils.strEqual(m.args[0], msg.args[0]) and \
68+
m.tagged('receivedBy') is not None and \
69+
m.tagged('receivedBy').network == network :
70+
if target and m.nick != target:
71+
continue
72+
# Don't snarf ignored users' messages unless specifically
73+
# told to.
74+
if ircdb.checkIgnored(m.prefix) and not target:
75+
continue
76+
77+
# Test messages sent before SedRegex was activated. Mark them all as seen
78+
# so we only need to do this check once per message.
79+
if not m.tagged(TAG_SEEN):
80+
m.tag(TAG_SEEN)
81+
if sedRegex.match(m.args[1]):
82+
m.tag(TAG_IS_REGEX)
83+
# Ignore messages containing a regexp if ignoreRegex is on.
84+
if ignoreRegex and m.tagged(TAG_IS_REGEX):
85+
continue
86+
87+
yield m
88+
89+
def get_first_matching_message(pattern, messages):
90+
for m in messages:
91+
# When running substitutions, ignore the "* nick" part of any actions.
92+
action = ircmsgs.isAction(m)
93+
if action:
94+
text = ircmsgs.unAction(m)
95+
else:
96+
text = m.args[1]
97+
98+
replace_result = pattern.search(text)
99+
if replace_result:
100+
return m
101+
102+
def apply_substitution(pattern, replacement, m, count):
103+
action = ircmsgs.isAction(m)
104+
if action:
105+
text = ircmsgs.unAction(m)
106+
else:
107+
text = m.args[1]
108+
109+
subst = pattern.sub(replacement, text, count)
110+
if action: # If the message was an ACTION, prepend the nick back.
111+
subst = '* %s %s' % (m.nick, subst)
112+
113+
return axe_spaces(subst)
114+
61115
class SedRegex(callbacks.Plugin):
62116
"""
63117
Enable SedRegex on the desired channels:
@@ -175,6 +229,8 @@ def doPrivmsg(self, irc, msg):
175229
return
176230

177231
regex_timeout = self.registryValue('processTimeout')
232+
if self.registryValue('boldReplacementText', msg.channel, irc.network):
233+
replacement = ircutils.bold(replacement)
178234
try:
179235
message = process(self._replacer_process, irc, msg,
180236
target, pattern, replacement, count, iterable, sedRegex,
@@ -192,63 +248,35 @@ def doPrivmsg(self, irc, msg):
192248
else:
193249
irc.reply(message, prefixNick=False)
194250

195-
def _replacer_process(self, irc, msg, target, pattern, replacement, count, messages, sedRegex):
196-
for m in messages:
197-
if m.command in ('PRIVMSG', 'NOTICE') and \
198-
ircutils.strEqual(m.args[0], msg.args[0]) and m.tagged('receivedBy') == irc:
199-
if target and m.nick != target:
200-
continue
201-
# Don't snarf ignored users' messages unless specifically
202-
# told to.
203-
if ircdb.checkIgnored(m.prefix) and not target:
204-
continue
205-
206-
# When running substitutions, ignore the "* nick" part of any actions.
207-
action = ircmsgs.isAction(m)
208-
if action:
209-
text = ircmsgs.unAction(m)
210-
else:
211-
text = m.args[1]
212-
213-
# Test messages sent before SedRegex was activated. Mark them all as seen
214-
# so we only need to do this check once per message.
215-
if not m.tagged(TAG_SEEN):
216-
m.tag(TAG_SEEN)
217-
if sedRegex.match(m.args[1]):
218-
m.tag(TAG_IS_REGEX)
219-
# Ignore messages containing a regexp if ignoreRegex is on.
220-
if self.registryValue('ignoreRegex', msg.channel, irc.network) and m.tagged(TAG_IS_REGEX):
221-
self.log.debug("Skipping message %s because it is tagged as isRegex", m.args[1])
222-
continue
223-
224-
try:
225-
replace_result = pattern.search(text)
226-
if replace_result:
227-
if self.registryValue('boldReplacementText',
228-
msg.channel, irc.network):
229-
replacement = ircutils.bold(replacement)
230-
subst = pattern.sub(replacement, text, count)
231-
if action: # If the message was an ACTION, prepend the nick back.
232-
subst = '* %s %s' % (m.nick, subst)
233-
234-
subst = axe_spaces(subst)
251+
def _format_result(self, irc, msg, m, subst):
252+
if m.nick == msg.nick:
253+
fmt = self.registryValue('format', msg.channel, irc.network)
254+
env = {'replacement': subst}
255+
else:
256+
fmt = self.registryValue('format.other', msg.channel, irc.network)
257+
env = {'otherNick': msg.nick, 'replacement': subst}
235258

236-
if m.nick == msg.nick:
237-
fmt = self.registryValue('format', msg.channel, irc.network)
238-
env = {'replacement': subst}
239-
else:
240-
fmt = self.registryValue('format.other', msg.channel, irc.network)
241-
env = {'otherNick': msg.nick, 'replacement': subst}
259+
return ircutils.standardSubstitute(irc, m, fmt, env)
242260

243-
return ircutils.standardSubstitute(irc, m, fmt, env)
261+
def _replacer_process(self, irc, msg, target, pattern, replacement, count,
262+
messages, sedRegex):
263+
ignoreRegex = self.registryValue('ignoreRegex', msg.channel, irc.network)
264+
messages = filter_messages(irc.network, msg, target, messages,
265+
ignoreRegex, sedRegex)
244266

245-
except Exception as e:
246-
self.log.warning(_("SedRegex error: %s"), e, exc_info=True)
247-
raise
267+
try:
268+
m = get_first_matching_message(pattern, messages)
269+
if m:
270+
subst = apply_substitution(pattern, replacement, m, count)
271+
return self._format_result(irc, msg, m, subst)
272+
except Exception as e:
273+
self.log.warning(_("SedRegex error: %s"), e, exc_info=True)
274+
raise
248275

249276
self.log.debug(_("SedRegex: Search %r not found in the last %i messages of %s."),
250277
msg.args[1], len(irc.state.history), msg.args[0])
251278
raise SearchNotFoundError()
279+
252280
doNotice = doPrivmsg
253281

254282
Class = SedRegex

0 commit comments

Comments
 (0)