It's Bach. He's back. With more hearing than ever!
This commit is contained in:
parent
cb20e0e8de
commit
b83e72fc37
|
@ -1,3 +1,5 @@
|
||||||
# happybot 2.0
|
# happybot <s>2.0</s> 1.0
|
||||||
|
|
||||||
You've heard the rumors, you know it's been a long time in the making, and it's finally here! Happybot 2.0: Vaporware Edition.
|
<s>You've heard the rumors, you know it's been a long time in the making, and it's finally here! Happybot 2.0: Vaporware Edition.</s>
|
||||||
|
|
||||||
|
Oh no. The old edition came back. And now it's _partially open source_! **The horror!!!**
|
||||||
|
|
230
xed.py
230
xed.py
|
@ -1,230 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from lark import Lark, Transformer, ParseError, Tree
|
|
||||||
|
|
||||||
parser = Lark(r'''
|
|
||||||
DIGIT : /[0-9]/
|
|
||||||
DIGITS : DIGIT+
|
|
||||||
NUMBER : "-"? DIGITS
|
|
||||||
|
|
||||||
?bracketliteral : "\\" /./
|
|
||||||
| /[^\]\-]/
|
|
||||||
?range : bracketliteral -> char
|
|
||||||
| bracketliteral "-" bracketliteral
|
|
||||||
brackets : "[" range+ "]" -> either
|
|
||||||
|
|
||||||
char : /[^\\\[\]\{\}\(\)\|\^~\?!]/
|
|
||||||
| "\\" /\D/
|
|
||||||
| //
|
|
||||||
|
|
||||||
numrange : DIGITS
|
|
||||||
| DIGITS "-" DIGITS
|
|
||||||
|
|
||||||
?unit : parens | brackets | char
|
|
||||||
?concat_func : unit
|
|
||||||
| concat_func "{" DIGITS "}" -> concat_repeat
|
|
||||||
| concat_func "?" -> zero_or_one
|
|
||||||
| concat_func "~" -> reverse
|
|
||||||
| concat_func "~" NUMBER -> roll
|
|
||||||
| concat_func "~{" NUMBER ["," DIGITS] "}" -> roll
|
|
||||||
| concat_func "!" -> collapse
|
|
||||||
| concat_func "!" DIGIT+ -> collapse
|
|
||||||
| concat_func "!{" numrange ("," numrange)* "}" -> collapse_ranges
|
|
||||||
| concat_func "\\" DIGIT+ -> index
|
|
||||||
| concat_func "\\{" numrange ("," numrange)* "}" -> index_ranges
|
|
||||||
|
|
||||||
?concat : concat_func+
|
|
||||||
|
|
||||||
?choice_func : concat
|
|
||||||
| choice_func "^{" DIGITS "}" -> weave_repeat
|
|
||||||
| choice_func "|{" DIGITS "}" -> either_repeat
|
|
||||||
|
|
||||||
?choice : choice_func
|
|
||||||
| choice ("^" choice_func)+ -> weave
|
|
||||||
| choice ("|" choice_func)+ -> either
|
|
||||||
|
|
||||||
?parens : "(" choice ")"
|
|
||||||
''', start='choice', ambiguity='resolve__antiscore_sum')
|
|
||||||
|
|
||||||
class Expand(Transformer):
|
|
||||||
def __init__(self, amp=None):
|
|
||||||
self.amp = amp
|
|
||||||
|
|
||||||
def char(self, args):
|
|
||||||
if args:
|
|
||||||
c = args[0].value
|
|
||||||
else:
|
|
||||||
c = ''
|
|
||||||
if self.amp and c == '&':
|
|
||||||
return self.amp
|
|
||||||
return [c]
|
|
||||||
|
|
||||||
def range(self, args):
|
|
||||||
result = []
|
|
||||||
a, b = map(ord, args)
|
|
||||||
while a < b:
|
|
||||||
result.append(chr(a))
|
|
||||||
a += 1
|
|
||||||
while a > b:
|
|
||||||
result.append(chr(a))
|
|
||||||
a -= 1
|
|
||||||
result.append(chr(a))
|
|
||||||
return result
|
|
||||||
|
|
||||||
def zero_or_one(self, args):
|
|
||||||
return self.either([[''], args[0]])
|
|
||||||
|
|
||||||
def either(self, args):
|
|
||||||
result = []
|
|
||||||
for x in args:
|
|
||||||
result.extend(x)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def concat(self, args):
|
|
||||||
result = ['']
|
|
||||||
for arg in args:
|
|
||||||
replace = []
|
|
||||||
for a in result:
|
|
||||||
for b in arg:
|
|
||||||
replace.append(a + b)
|
|
||||||
result = replace
|
|
||||||
return result
|
|
||||||
|
|
||||||
def weave(self, args):
|
|
||||||
result = []
|
|
||||||
for i in range(max(map(len, args))):
|
|
||||||
for arg in args:
|
|
||||||
if i < len(arg):
|
|
||||||
result.append(arg[i])
|
|
||||||
return result
|
|
||||||
|
|
||||||
def roll(self, args):
|
|
||||||
if len(args) == 3:
|
|
||||||
g = int(args[2].value)
|
|
||||||
else:
|
|
||||||
g = len(args[0])
|
|
||||||
r = int(args[1].value)
|
|
||||||
groups = [[]]
|
|
||||||
for i, elem in enumerate(args[0]):
|
|
||||||
if i % g == 0:
|
|
||||||
groups.append([])
|
|
||||||
groups[-1].append(elem)
|
|
||||||
result = []
|
|
||||||
for group in groups:
|
|
||||||
for i in range(len(group)):
|
|
||||||
result.append(group[(i + r) % len(group)])
|
|
||||||
return result
|
|
||||||
|
|
||||||
def reverse(self, args):
|
|
||||||
return args[0][::-1]
|
|
||||||
|
|
||||||
def numrange(self, args):
|
|
||||||
result = []
|
|
||||||
a = int(args[0].value)
|
|
||||||
if len(args) == 1:
|
|
||||||
b = a
|
|
||||||
else:
|
|
||||||
b = int(args[1].value)
|
|
||||||
while a < b:
|
|
||||||
result.append(a)
|
|
||||||
a += 1
|
|
||||||
while a > b:
|
|
||||||
result.append(a)
|
|
||||||
a -= 1
|
|
||||||
result.append(a)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def index(self, args):
|
|
||||||
result, x = [], args[0]
|
|
||||||
for i in args[1:]:
|
|
||||||
result.append(x[int(i.value) % len(x)])
|
|
||||||
return result
|
|
||||||
|
|
||||||
def index_ranges(self, args):
|
|
||||||
result, x = [], args[0]
|
|
||||||
for arg in args[1:]:
|
|
||||||
for i in arg:
|
|
||||||
result.append(x[i % len(x)])
|
|
||||||
return result
|
|
||||||
|
|
||||||
def collapse(self, args):
|
|
||||||
result, x = '', args[0]
|
|
||||||
if len(args) > 1:
|
|
||||||
for i in args[1:]:
|
|
||||||
result += x[int(i.value) % len(x)]
|
|
||||||
else:
|
|
||||||
result = ''.join(args[0])
|
|
||||||
return [result]
|
|
||||||
|
|
||||||
def collapse_ranges(self, args):
|
|
||||||
result, x = '', args[0]
|
|
||||||
for arg in args[1:]:
|
|
||||||
for i in arg:
|
|
||||||
result += x[i % len(x)]
|
|
||||||
return [result]
|
|
||||||
|
|
||||||
|
|
||||||
def concat_repeat(self, args):
|
|
||||||
return self.concat([args[0]] * int(args[1].value))
|
|
||||||
def either_repeat(self, args):
|
|
||||||
return self.either([args[0]] * int(args[1].value))
|
|
||||||
def weave_repeat(self, args):
|
|
||||||
return self.weave([args[0]] * int(args[1].value))
|
|
||||||
|
|
||||||
def lookup(choices):
|
|
||||||
lookup = dict()
|
|
||||||
for n, choice in enumerate(choices):
|
|
||||||
curr = lookup
|
|
||||||
for c in choice:
|
|
||||||
if c not in curr:
|
|
||||||
curr[c] = dict()
|
|
||||||
curr = curr[c]
|
|
||||||
curr[None] = n
|
|
||||||
return lookup
|
|
||||||
|
|
||||||
def findall(lookup, string):
|
|
||||||
i, result = 0, []
|
|
||||||
while i < len(string):
|
|
||||||
c = string[i]
|
|
||||||
if c in lookup:
|
|
||||||
j = i + 1
|
|
||||||
curr = lookup[c]
|
|
||||||
while j < len(string) and string[j] in curr:
|
|
||||||
curr = curr[string[j]]
|
|
||||||
j += 1
|
|
||||||
if None in curr:
|
|
||||||
result.append((curr[None], i, j))
|
|
||||||
i = j
|
|
||||||
else:
|
|
||||||
i += 1
|
|
||||||
elif None in lookup:
|
|
||||||
result.append((lookup[None], i, i))
|
|
||||||
i += 1
|
|
||||||
else:
|
|
||||||
i += 1
|
|
||||||
if None in lookup:
|
|
||||||
i = len(string)
|
|
||||||
result.append((lookup[None], i, i))
|
|
||||||
return result
|
|
||||||
|
|
||||||
def replace(a, b, s):
|
|
||||||
try:
|
|
||||||
a = parser.parse(a)
|
|
||||||
b = parser.parse(b)
|
|
||||||
except ParseError:
|
|
||||||
return '<Parse error.>'
|
|
||||||
a = Expand().transform(a)
|
|
||||||
look = lookup(a)
|
|
||||||
locs = findall(look, s)
|
|
||||||
if not locs:
|
|
||||||
return '<No change.>'
|
|
||||||
b = Expand(amp=a).transform(b)
|
|
||||||
for n, i, j in reversed(locs):
|
|
||||||
r = b[n % len(b)]
|
|
||||||
s = s[:i] + r + s[j:]
|
|
||||||
return s
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
from sys import argv
|
|
||||||
p = parser.parse(argv[1])
|
|
||||||
print(p.pretty())
|
|
||||||
print(Expand().transform(p))
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from lark import Lark, Transformer, ParseError, Tree
|
||||||
|
|
||||||
|
parser = Lark(r'''
|
||||||
|
DIGIT : /[0-9]/
|
||||||
|
DIGITS : DIGIT+
|
||||||
|
NUMBER : "-"? DIGITS
|
||||||
|
|
||||||
|
?bracketliteral : "\\" /./
|
||||||
|
| /[^\]\-]/
|
||||||
|
?range : bracketliteral -> char
|
||||||
|
| bracketliteral "-" bracketliteral
|
||||||
|
brackets : "[" range+ "]" -> either
|
||||||
|
|
||||||
|
char : /[^\\\[\]\{\}\(\)\|\^~\?!]/
|
||||||
|
| "\\" /\D/
|
||||||
|
| //
|
||||||
|
|
||||||
|
numrange : DIGITS
|
||||||
|
| DIGITS "-" DIGITS
|
||||||
|
|
||||||
|
?unit : parens | brackets | char
|
||||||
|
?concat_func : unit
|
||||||
|
| concat_func "{" DIGITS "}" -> concat_repeat
|
||||||
|
| concat_func "?" -> zero_or_one
|
||||||
|
| concat_func "~" -> reverse
|
||||||
|
| concat_func "~" NUMBER -> roll
|
||||||
|
| concat_func "~{" NUMBER ["," DIGITS] "}" -> roll
|
||||||
|
| concat_func "!" -> collapse
|
||||||
|
| concat_func "!" DIGIT+ -> collapse
|
||||||
|
| concat_func "!{" numrange ("," numrange)* "}" -> collapse_ranges
|
||||||
|
| concat_func "\\" DIGIT+ -> index
|
||||||
|
| concat_func "\\{" numrange ("," numrange)* "}" -> index_ranges
|
||||||
|
|
||||||
|
?concat : concat_func+
|
||||||
|
|
||||||
|
?choice_func : concat
|
||||||
|
| choice_func "^{" DIGITS "}" -> weave_repeat
|
||||||
|
| choice_func "|{" DIGITS "}" -> either_repeat
|
||||||
|
|
||||||
|
?choice : choice_func
|
||||||
|
| choice ("^" choice_func)+ -> weave
|
||||||
|
| choice ("|" choice_func)+ -> either
|
||||||
|
|
||||||
|
?parens : "(" choice ")"
|
||||||
|
''', start='choice', ambiguity='resolve__antiscore_sum')
|
||||||
|
|
||||||
|
class Expand(Transformer):
|
||||||
|
def __init__(self, amp=None):
|
||||||
|
self.amp = amp
|
||||||
|
|
||||||
|
def char(self, args):
|
||||||
|
if args:
|
||||||
|
c = args[0].value
|
||||||
|
else:
|
||||||
|
c = ''
|
||||||
|
if self.amp and c == '&':
|
||||||
|
return self.amp
|
||||||
|
return [c]
|
||||||
|
|
||||||
|
def range(self, args):
|
||||||
|
result = []
|
||||||
|
a, b = map(ord, args)
|
||||||
|
while a < b:
|
||||||
|
result.append(chr(a))
|
||||||
|
a += 1
|
||||||
|
while a > b:
|
||||||
|
result.append(chr(a))
|
||||||
|
a -= 1
|
||||||
|
result.append(chr(a))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def zero_or_one(self, args):
|
||||||
|
return self.either([[''], args[0]])
|
||||||
|
|
||||||
|
def either(self, args):
|
||||||
|
result = []
|
||||||
|
for x in args:
|
||||||
|
result.extend(x)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def concat(self, args):
|
||||||
|
result = ['']
|
||||||
|
for arg in args:
|
||||||
|
replace = []
|
||||||
|
for a in result:
|
||||||
|
for b in arg:
|
||||||
|
replace.append(a + b)
|
||||||
|
result = replace
|
||||||
|
return result
|
||||||
|
|
||||||
|
def weave(self, args):
|
||||||
|
result = []
|
||||||
|
for i in range(max(map(len, args))):
|
||||||
|
for arg in args:
|
||||||
|
if i < len(arg):
|
||||||
|
result.append(arg[i])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def roll(self, args):
|
||||||
|
if len(args) == 3:
|
||||||
|
g = int(args[2].value)
|
||||||
|
else:
|
||||||
|
g = len(args[0])
|
||||||
|
r = int(args[1].value)
|
||||||
|
groups = [[]]
|
||||||
|
for i, elem in enumerate(args[0]):
|
||||||
|
if i % g == 0:
|
||||||
|
groups.append([])
|
||||||
|
groups[-1].append(elem)
|
||||||
|
result = []
|
||||||
|
for group in groups:
|
||||||
|
for i in range(len(group)):
|
||||||
|
result.append(group[(i + r) % len(group)])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def reverse(self, args):
|
||||||
|
return args[0][::-1]
|
||||||
|
|
||||||
|
def numrange(self, args):
|
||||||
|
result = []
|
||||||
|
a = int(args[0].value)
|
||||||
|
if len(args) == 1:
|
||||||
|
b = a
|
||||||
|
else:
|
||||||
|
b = int(args[1].value)
|
||||||
|
while a < b:
|
||||||
|
result.append(a)
|
||||||
|
a += 1
|
||||||
|
while a > b:
|
||||||
|
result.append(a)
|
||||||
|
a -= 1
|
||||||
|
result.append(a)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def index(self, args):
|
||||||
|
result, x = [], args[0]
|
||||||
|
for i in args[1:]:
|
||||||
|
result.append(x[int(i.value) % len(x)])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def index_ranges(self, args):
|
||||||
|
result, x = [], args[0]
|
||||||
|
for arg in args[1:]:
|
||||||
|
for i in arg:
|
||||||
|
result.append(x[i % len(x)])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def collapse(self, args):
|
||||||
|
result, x = '', args[0]
|
||||||
|
if len(args) > 1:
|
||||||
|
for i in args[1:]:
|
||||||
|
result += x[int(i.value) % len(x)]
|
||||||
|
else:
|
||||||
|
result = ''.join(args[0])
|
||||||
|
return [result]
|
||||||
|
|
||||||
|
def collapse_ranges(self, args):
|
||||||
|
result, x = '', args[0]
|
||||||
|
for arg in args[1:]:
|
||||||
|
for i in arg:
|
||||||
|
result += x[i % len(x)]
|
||||||
|
return [result]
|
||||||
|
|
||||||
|
|
||||||
|
def concat_repeat(self, args):
|
||||||
|
return self.concat([args[0]] * int(args[1].value))
|
||||||
|
def either_repeat(self, args):
|
||||||
|
return self.either([args[0]] * int(args[1].value))
|
||||||
|
def weave_repeat(self, args):
|
||||||
|
return self.weave([args[0]] * int(args[1].value))
|
||||||
|
|
||||||
|
def lookup(choices):
|
||||||
|
lookup = dict()
|
||||||
|
for n, choice in enumerate(choices):
|
||||||
|
curr = lookup
|
||||||
|
for c in choice:
|
||||||
|
if c not in curr:
|
||||||
|
curr[c] = dict()
|
||||||
|
curr = curr[c]
|
||||||
|
curr[None] = n
|
||||||
|
return lookup
|
||||||
|
|
||||||
|
def findall(lookup, string):
|
||||||
|
i, result = 0, []
|
||||||
|
while i < len(string):
|
||||||
|
c = string[i]
|
||||||
|
if c in lookup:
|
||||||
|
j = i + 1
|
||||||
|
curr = lookup[c]
|
||||||
|
while j < len(string) and string[j] in curr:
|
||||||
|
curr = curr[string[j]]
|
||||||
|
j += 1
|
||||||
|
if None in curr:
|
||||||
|
result.append((curr[None], i, j))
|
||||||
|
i = j
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
elif None in lookup:
|
||||||
|
result.append((lookup[None], i, i))
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
if None in lookup:
|
||||||
|
i = len(string)
|
||||||
|
result.append((lookup[None], i, i))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def replace(a, b, s):
|
||||||
|
try:
|
||||||
|
a = parser.parse(a)
|
||||||
|
b = parser.parse(b)
|
||||||
|
except ParseError:
|
||||||
|
return '<Parse error.>'
|
||||||
|
a = Expand().transform(a)
|
||||||
|
look = lookup(a)
|
||||||
|
locs = findall(look, s)
|
||||||
|
if not locs:
|
||||||
|
return '<No change.>'
|
||||||
|
b = Expand(amp=a).transform(b)
|
||||||
|
for n, i, j in reversed(locs):
|
||||||
|
r = b[n % len(b)]
|
||||||
|
s = s[:i] + r + s[j:]
|
||||||
|
return s
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from sys import argv
|
||||||
|
p = parser.parse(argv[1])
|
||||||
|
print(p.pretty())
|
||||||
|
print(Expand().transform(p))
|
|
@ -0,0 +1,262 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# How to read a line.
|
||||||
|
|
||||||
|
def deirc(nick, line):
|
||||||
|
action = False
|
||||||
|
if len(line) <= 3:
|
||||||
|
return action, nick, line
|
||||||
|
if line[0] == '\u200b':
|
||||||
|
if line[1] == '<':
|
||||||
|
try:
|
||||||
|
close = line.index('>')
|
||||||
|
assert(line[close+1] == ' ')
|
||||||
|
assert(not any(map(lambda x: x.isspace(), line[2:close])))
|
||||||
|
nick = line[2:close]
|
||||||
|
line = line[close+2:]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
elif line[1:3] == '* ':
|
||||||
|
try:
|
||||||
|
close = line[3:].index(' ') + 3
|
||||||
|
assert(not any(map(lambda x: x.isspace(), line[3:close])))
|
||||||
|
nick = line[3:close]
|
||||||
|
line = line[close+1:]
|
||||||
|
action = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
elif line[:8] == '\x01ACTION ' and line[-1] == '\x01':
|
||||||
|
action = True
|
||||||
|
line = line[8:-1]
|
||||||
|
|
||||||
|
# Redact the nologs.
|
||||||
|
if line.startswith('[nolog]') or line.startswith('nolog:'):
|
||||||
|
line = '[REDACTED]'
|
||||||
|
|
||||||
|
return action, nick, line
|
||||||
|
|
||||||
|
# Set flags and funcs.
|
||||||
|
|
||||||
|
from sys import argv
|
||||||
|
if len(argv) != 3:
|
||||||
|
print('Usage: in out')
|
||||||
|
exit(1)
|
||||||
|
_, fin, fout = argv
|
||||||
|
|
||||||
|
# Read the outfile.
|
||||||
|
|
||||||
|
class ReadOut:
|
||||||
|
def __init__(self, fout=fout):
|
||||||
|
self.file = open(fout, 'rb')
|
||||||
|
self.first = True
|
||||||
|
def cat(self):
|
||||||
|
self.first = False
|
||||||
|
for line in self.file:
|
||||||
|
yield str(line[:-1], 'utf-8', 'ignore')
|
||||||
|
def tac(self):
|
||||||
|
if self.first:
|
||||||
|
self.first = False
|
||||||
|
self.file.seek(0, 2)
|
||||||
|
buffer = b''
|
||||||
|
if self.file.tell():
|
||||||
|
self.file.seek(self.file.tell() - 1)
|
||||||
|
if self.file.read(1) == b'\n':
|
||||||
|
self.file.seek(self.file.tell() - 1)
|
||||||
|
while self.file.tell():
|
||||||
|
self.file.seek(self.file.tell() - 1)
|
||||||
|
char = self.file.read(1)
|
||||||
|
if char == b'\n':
|
||||||
|
yield str(buffer[::-1], 'utf-8', 'ignore')
|
||||||
|
buffer = b''
|
||||||
|
else:
|
||||||
|
buffer += char
|
||||||
|
self.file.seek(self.file.tell() - 1)
|
||||||
|
if buffer:
|
||||||
|
yield str(buffer[::-1], 'utf-8', 'ignore')
|
||||||
|
def close(self):
|
||||||
|
self.file.close()
|
||||||
|
|
||||||
|
from re import compile as regex
|
||||||
|
|
||||||
|
xed_match = regex(r'x/((?:\\.|[^/])*)/((?:\\.|[^/])*)/([^\s~]*)(?:~(\d+))?')
|
||||||
|
xed_verbose_match = regex(r'xv/((?:\\.|[^/])*)/(?:((?:\\.|[^/])*)/)?')
|
||||||
|
sed_match = regex(r's/((?:\\.|[^/])*)/((?:\\.|[^/])*)/([^\s~]*)(?:~(\d+))?')
|
||||||
|
find_match = regex(r'p([\+-]\d+)?/((?:\\.|[^/])*)/([^\s~]*)(?:~(\d+))?')
|
||||||
|
tr_match = regex(r'y/((?:\\.|[^/])*)/((?:\\.|[^/])*)/([^\s~]*)(?:~(\d+))?')
|
||||||
|
|
||||||
|
matchers = [xed_match, sed_match, find_match, tr_match, xed_verbose_match]
|
||||||
|
|
||||||
|
def xed_test(nick, line):
|
||||||
|
# Is it a command?
|
||||||
|
match = xed_match.match(line)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
search, replace, who, back = match.groups()
|
||||||
|
return search, replace, nick, who, back
|
||||||
|
|
||||||
|
import x as xed
|
||||||
|
|
||||||
|
def xed_method(search, replace, nick, who, back):
|
||||||
|
# Some things to fix.
|
||||||
|
if not back:
|
||||||
|
back = 0
|
||||||
|
else:
|
||||||
|
back = int(back)
|
||||||
|
|
||||||
|
fuzzy = True
|
||||||
|
if not who:
|
||||||
|
fuzzy = False
|
||||||
|
who = nick
|
||||||
|
elif who == 'g':
|
||||||
|
who = ''
|
||||||
|
who = who.lower()
|
||||||
|
|
||||||
|
# Turn it into a possibility space.
|
||||||
|
try:
|
||||||
|
search = xed.parser.parse(search)
|
||||||
|
replace = xed.parser.parse(replace)
|
||||||
|
except e:
|
||||||
|
print('| Parsing error:', e)
|
||||||
|
return None
|
||||||
|
search = xed.Expand().transform(search)
|
||||||
|
lookup = xed.lookup(search)
|
||||||
|
|
||||||
|
output = None
|
||||||
|
|
||||||
|
# Now it is time to try to xed.
|
||||||
|
log = ReadOut()
|
||||||
|
for nline, line in enumerate(log.tac()):
|
||||||
|
if nline > 500:
|
||||||
|
log.close()
|
||||||
|
break
|
||||||
|
|
||||||
|
_, _, nick, line = line.split(' ', 3)
|
||||||
|
nick = nick[1:-1]
|
||||||
|
|
||||||
|
skip = False
|
||||||
|
for test in matchers:
|
||||||
|
if test.match(line):
|
||||||
|
skip = True
|
||||||
|
break
|
||||||
|
if skip:
|
||||||
|
continue
|
||||||
|
|
||||||
|
action, nick, line = deirc(nick, line)
|
||||||
|
|
||||||
|
match_nick = nick.lower().replace('*', '')
|
||||||
|
if fuzzy and not match_nick.startswith(who):
|
||||||
|
continue
|
||||||
|
elif not fuzzy and match_nick != who:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if action:
|
||||||
|
action = False
|
||||||
|
line = '\x01ACTION ' + line + '\x01'
|
||||||
|
|
||||||
|
output = xed.findall(lookup, line)
|
||||||
|
if not output:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if back != 0:
|
||||||
|
back -= 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
log.close()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
log.close()
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not output:
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = line
|
||||||
|
replace = xed.Expand(amp=search).transform(replace)
|
||||||
|
for n, i, j in reversed(output):
|
||||||
|
rep = replace[n % len(replace)]
|
||||||
|
result = result[:i] + rep + result[j:]
|
||||||
|
|
||||||
|
if result[:8] == '\x01ACTION ' and result[-1] == '\x01':
|
||||||
|
action = True
|
||||||
|
result = result[8:-1]
|
||||||
|
|
||||||
|
log.close()
|
||||||
|
return action, nick + '*', result
|
||||||
|
|
||||||
|
# Execute a command.
|
||||||
|
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
def cmd(args):
|
||||||
|
proc = Popen(args, stdout=PIPE)
|
||||||
|
while True:
|
||||||
|
line = proc.stdout.readline()
|
||||||
|
if line:
|
||||||
|
try:
|
||||||
|
yield str(line[:-1], 'utf-8', 'ignore')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Do the thing!
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
def begin():
|
||||||
|
for line in cmd(['tail', '-n', '0', '-f', fout]):
|
||||||
|
_, _, nick, line = line.split(' ', 3)
|
||||||
|
nick = nick[1:-1]
|
||||||
|
|
||||||
|
# Ignore actions.
|
||||||
|
if line[:8] == '\x01ACTION ' and line[-1] == '\x01':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Ignore bots and nologs.
|
||||||
|
if line[0] == '\u200b':
|
||||||
|
continue
|
||||||
|
if line.startswith('[nolog]') or line.startswith('nolog:'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try it out.
|
||||||
|
print('Testing xed.')
|
||||||
|
result = xed_test(nick, line)
|
||||||
|
if not result:
|
||||||
|
print('| Test complete, yet invalid.')
|
||||||
|
m = xed_verbose_match.match(line)
|
||||||
|
if m:
|
||||||
|
n = m.group(2)
|
||||||
|
try:
|
||||||
|
m = xed.parser.parse(m.group(1))
|
||||||
|
if n:
|
||||||
|
n = xed.parser.parse(n)
|
||||||
|
except:
|
||||||
|
with open(fin, 'w') as fh:
|
||||||
|
fh.write('\u200b' + nick + ': Parsing error.\n')
|
||||||
|
m = xed.Expand().transform(m)
|
||||||
|
if n:
|
||||||
|
n = xed.Expand(amp=m).transform(n)
|
||||||
|
with open(fin, 'w') as fh:
|
||||||
|
if n:
|
||||||
|
fh.write('\u200b' + nick + ': ' + repr(m) + ' -> ' + repr(n) + '\n')
|
||||||
|
else:
|
||||||
|
fh.write('\u200b' + nick + ': ' + repr(m) + '\n')
|
||||||
|
continue
|
||||||
|
print('| Test complete and valid.\nProceeding with xed.')
|
||||||
|
result = xed_method(*result)
|
||||||
|
print('| Method complete.')
|
||||||
|
if not result:
|
||||||
|
continue
|
||||||
|
action, nick, line = result
|
||||||
|
if action:
|
||||||
|
reply = '* ' + nick + ' ' + line
|
||||||
|
else:
|
||||||
|
reply = '<' + nick + '> ' + line
|
||||||
|
print('| It is valid! Sending:', reply)
|
||||||
|
with open(fin, 'w') as fh:
|
||||||
|
fh.write('\u200b' + reply + '\n')
|
||||||
|
except:
|
||||||
|
with open(fin, 'w') as fh:
|
||||||
|
fh.write('\u200b' + nick + ': This would have crashed me.\n')
|
||||||
|
|
||||||
|
begin()
|
Loading…
Reference in New Issue