98 lines
4 KiB
Python
Executable file
98 lines
4 KiB
Python
Executable file
#!/usr/bin/env python3
|
||
|
||
import os, sys, random
|
||
from os.path import dirname, realpath, exists
|
||
import argparse, textwrap
|
||
try:
|
||
import re2 as re
|
||
except:
|
||
import re
|
||
|
||
balloonstyles={'cowsay': ('<\\|/ _ >\\|/ - \\/', '(((( _ )))) - \\/')}
|
||
|
||
ponypath = realpath(dirname(__file__)+'/../share/ponies')
|
||
if not exists(ponypath):
|
||
ponypath=realpath(dirname(__file__)+'/ponies')
|
||
termwidth = 80
|
||
try:
|
||
termwidth = os.get_terminal_size()[0]
|
||
except:
|
||
pass
|
||
|
||
def list_ponies(markQuotes=False):
|
||
quotes = lambda n: ' (q)' if markQuotes and exists(ponypath+'/'+n+'.quotes') else ''
|
||
return [ f[:-5]+quotes(f[:-5]) for f in os.listdir(ponypath) if not f.endswith('quotes') ]
|
||
|
||
def list_ponies_with_quotes(markQuotes=False):
|
||
return [ f[:-7] for f in os.listdir(ponypath) if f.endswith('quotes') ]
|
||
|
||
def load_pony(name):
|
||
return open(ponypath+'/'+name+'.pony').readlines()
|
||
|
||
def random_quote(name):
|
||
quotepath=ponypath+'/'+name+'.quotes'
|
||
if exists(quotepath):
|
||
return random.choice(open(quotepath).read().split('\n\n'))
|
||
else:
|
||
return None
|
||
|
||
def render_balloon(text, balloonstyle, minwidth=0, maxwidth=40, pad=str.center):
|
||
if text is None:
|
||
return []
|
||
[ls, lb, lm, lt, tl, t, tr, rs, rt, rm, rb, br, b, bl, _, _] = balloonstyle
|
||
lines = [ wrapline for textline in text.split('\n') for wrapline in textwrap.wrap(textline, maxwidth) ]
|
||
width = max([ len(line) for line in lines ]+[minwidth])
|
||
lines = [ pad(line, width) for line in lines ]
|
||
sides = [(lt, rt)] + [(lm, rm)]*(len(lines)-2) + [(lb, rb)] if len(lines) > 1 else [(ls, rs)]
|
||
return [tl+t*(width+2)+tr+'\n']+\
|
||
[sides[i][0]+' '+line+' '+sides[i][1]+'\n' for i,line in enumerate(lines)]+\
|
||
[bl+b*(width+2)+br+'\n']
|
||
|
||
def render_pony(name, text=None, balloonstyle=balloonstyles['cowsay'][0], width=80, center=False, centertext=False):
|
||
pony = load_pony(name) #CAUTION: these lines already end with '\n'
|
||
balloon = link_l = link_r = ''
|
||
if text:
|
||
[link_l, link_r] = balloonstyle[-2:]
|
||
for i,line in enumerate(pony):
|
||
match = re.search('\$balloon([0-9]*)\$', line)
|
||
if match:
|
||
minwidth = int(match.group(1) or '0')
|
||
pony[i:i+1] = render_balloon(text, balloonstyle, minwidth=minwidth, maxwidth=int(width/2), pad=str.center if centertext else str.ljust)
|
||
break
|
||
#FIXME I have no idea what these three-dollar-sign-pairs thingys are for. Can they occur more than once per pony?
|
||
try:
|
||
first = pony.index('$$$\n')
|
||
second = pony[first+1:].index('$$$\n')
|
||
pony[first:] = pony[first+1+second+1:]
|
||
except:
|
||
pass
|
||
pony = [ line.replace('$\\$', link_l).replace('$/$', link_r) for line in pony ]
|
||
indent = ''
|
||
if center:
|
||
ponywidth = max([ len(re.sub(r'\x1B\[[0-9;]+m|\$.*\$', '', line)) for line in pony ])
|
||
indent = ' '*int((width-ponywidth)/2)
|
||
wre = re.compile('((\x1B\[[0-9;]+m)?.){0,%s}' % width)
|
||
return ''.join([ indent+wre.search(line).group()+'\n[49m' for line in pony ])
|
||
|
||
parser = argparse.ArgumentParser(description='Cowsay with ponies')
|
||
parser.add_argument('-p', '--pony', type=str, default='random', help='The name of the pony to be used. Use "-p list" to list all ponies, "-p random" (default) to use a random pony.')
|
||
parser.add_argument('-q', '--quote', action='store_true', help='Use a random quote of the pony being displayed as text')
|
||
parser.add_argument('-c', '--center', action='store_true', help='Use a random quote of the pony being displayed as text')
|
||
parser.add_argument('-t', '--center-text', action='store_true', help='Center the text in the bubble')
|
||
parser.add_argument('-w', '--width', type=int, default=termwidth, help='Terminal width. Use 0 for unlimited width. Default: autodetect')
|
||
parser.add_argument('text', type=str, nargs='*', help='The text to be placed in the speech bubble')
|
||
args = parser.parse_args()
|
||
|
||
if args.pony == "list":
|
||
print('\n'.join(sorted(list_ponies(True))))
|
||
sys.exit()
|
||
pony = args.pony
|
||
if pony == "random":
|
||
pony = random.choice(list_ponies() if not args.quote else list_ponies_with_quotes())
|
||
text = ' '.join(args.text) or None
|
||
if text == '-':
|
||
text = '\n'.join(sys.stdin.readlines())
|
||
if args.quote:
|
||
text = random_quote(pony)
|
||
|
||
print(render_pony(pony, text, width=args.width or sys.maxint, center=args.center, centertext=args.center_text))
|