import sys, re
from bazbase.wiki import (macros,environment,illegal,divided,
WikiException, NoContentException,
safesplit, parse_macro_args, recurse,
baz_eval, full_eval, leafprop, render_propval,
render_allow_override, get_format,
get_element, get_current_element, get_propname,
atom, eoverride, moverride, poverride)
from bazbase.flavors import FORMATS
from bazbase import config
from redbeans.tokens import *
from . import custom
def moverride_thunk(ename, pname, form):
with moverride(dict(form=form)):
for t in recurse(ename, pname):
yield t
def get_headfoot(form, ename):
return (moverride_thunk(ename, u'topleft', form),
moverride_thunk(ename, u'topright', form),
moverride_thunk(ename, u'bottomleft', form),
moverride_thunk(ename, u'bottomright', form))
def html_div_headers(headfoot):
yield Literal('
')
yield Literal('')
yield Literal('')
yield Literal('')
def html_table_header(headfoot):
yield Literal('| ')
for t in headfoot[0]:
yield t
yield Literal(' | ')
for t in headfoot[1]:
yield t
yield Literal(' | | |
')
def html_table_footer(headfoot):
yield Literal('')
def latex_cmd_headers(headfoot):
yield Literal('\\lhead{')
for t in headfoot[0]:
yield t
yield Literal('}\\rhead{')
for t in headfoot[1]:
yield t
yield Literal('}\\lfoot{')
for t in headfoot[2]:
yield t
yield Literal('}\\rfoot{')
for t in headfoot[3]:
yield t
yield Literal('}\n')
def latex_arg_headers(headfoot):
for hf in headfoot:
for t in hf:
yield t
yield Literal('}{')
def form(argstr):
"""Placeholder that evaluates to 'sheet' or 'card' or 'badge' when
evaluating headers and footers."""
return ""
macros.form = form
def sheet(argstr, content):
"""Render content as a sheet. Takes an element to get headers and
footers from, and optionally a 'color' parameter for paper color."""
args = parse_macro_args(argstr)
color = ""
headfoot = [(),(),(),()]
for key,val in args.items():
if key == 'color':
color = baz_eval(val).strip()
elif key == 1:
headfoot = get_headfoot('sheet', val)
else:
raise WikiException("Unknown arg '%s' in sheet!"
% (key))
if not color.strip():
color = "white"
if get_format() == FORMATS['html']:
yield Literal('' % color)
for t in html_div_headers(headfoot):
yield t
for t in content:
yield t
yield Literal('
')
elif get_format() == FORMATS['tex']:
yield Literal('\\begin{sheet}\n')
for t in latex_cmd_headers(headfoot):
yield t
for t in content:
yield t
yield Literal('\n\\end{sheet}')
else:
for t in content:
yield t
macros.sheet = sheet
flippat = re.compile(r'<>')
def card(argstr, content):
"""Render content as a card. Takes an element to get headers and
footers from, and optionally a 'color' parameter for paper color
and a 'size' parameter."""
parts = safesplit(content,flippat)
args = parse_macro_args(argstr)
color = ""
size = ""
headfoot = [(),(),(),()]
for key,val in args.items():
if key == 'color':
color = baz_eval(val).strip()
elif key == 'size':
size = " "+baz_eval(val).strip()
elif key == 1:
headfoot = get_headfoot('card', val)
else:
raise WikiException("Unknown arg '%s' in card!"
% (key))
if not color.strip():
color = "white"
if len(parts) > 2:
raise WikiException("More than one ##flip## in a ##card##!")
else:
if len(parts) < 2:
front = parts[0]
back = ""
else:
front,back = parts
if get_format() == FORMATS['html']:
yield Literal('\n' % (color, size))
for t in html_table_header(headfoot):
yield t
yield Literal('\n| \n')
for t in front:
yield t
yield Literal('\n | \n')
yield Literal('\n')
for t in back:
yield t
yield Literal('\n | \n
\n')
for t in html_table_footer(headfoot):
yield t
yield Literal('
\n')
elif get_format() == FORMATS['tex']:
yield Literal('\\begin{card}%s\n'
% ("[%s]" % size.strip() if size.strip() else ""))
yield Literal('\\front{')
for t in latex_cmd_headers(headfoot):
yield t
for t in front:
yield t
yield Literal('}\n\\back{')
for t in back:
yield t
yield Literal('}\n\\end{card}\n')
else:
for t in front:
yield t
yield Entity(ENV_BREAK)
for t in back:
yield t
macros.card = card
macros.flip = illegal('flip','card')
def packet(argstr,content):
"""Render content as a packet. Takes a label for the outside and
an element to get headers and footers from, and optionally a
'color' parameter for paper color and a 'style' parameter ("envelope"
or "folding")."""
args = parse_macro_args(argstr)
label = ""
color = ""
style = "Envelope"
headfoot = [(), (), (), ()]
for key,val in args.items():
if key == 'color':
color = baz_eval(val).strip()
elif key == 1:
label = baz_eval(val).strip()
elif key == 2:
headfoot = get_headfoot('packet', val)
elif key == 'style':
style = baz_eval(val).strip().capitalize()
if style not in ("Envelope","Folding"):
raise WikiException('The only valid packet styles are "envelope" and "folding"!')
else:
raise WikiException("Unknown arg '%s' in packet!"
% (key))
if not color.strip():
color = "white"
if get_format() == FORMATS['html']:
yield Literal('\n' % (style.lower(),
color))
for t in html_table_header(headfoot):
yield t
yield Literal('\n| \n')
for t in label:
yield t
yield Literal('\n | \n')
yield Literal('\n')
for t in content:
yield t
yield Literal('\n | \n
\n')
for t in html_table_footer(headfoot):
yield t
yield Literal('
\n')
elif get_format() == FORMATS['tex']:
yield Literal('\\%sPacket{' % (style,))
for t in latex_arg_headers(headfoot):
yield t
for t in label:
yield t
yield Literal('}{')
for t in content:
yield t
yield Literal('}')
else:
yield Text("Packet: ")
for t in label:
yield t
macros.packet = packet
def notebook(argstr,content):
args = parse_macro_args(argstr)
front = ""
color = ""
headfoot = [(), (), (), ()]
for key,val in args.items():
if key == 'color':
color = baz_eval(val).strip()
elif key == 1:
front = full_eval(val)
elif key == 2:
headfoot = get_headfoot('notebook', val)
else:
raise WikiException("Unknown arg '%s' in notebook!"
% (key))
if not color.strip():
color = "white"
if get_format() == FORMATS['html']:
yield Literal('\n' % (color))
yield Literal('
')
for t in html_div_headers(headfoot):
yield t
for t in front:
yield t
yield Literal('
')
for t in content:
yield t
yield Literal('
\n')
elif get_format() == FORMATS['tex']:
yield Literal('\\startnotebook{')
for t in latex_arg_headers(headfoot):
yield t
for t in front:
yield t
yield Literal('}{')
for t in content:
yield t
yield Literal('\n\\endnotebook\n')
else:
yield Text("Notebook: ")
for t in front:
yield t
macros.notebook = notebook
def page(argstr,content):
"""Dummy page for previewing outside a notebook."""
args = parse_macro_args(argstr)
if 1 in args:
title = baz_eval(argstr).strip()
else:
title = getattr(get_format(), 'gknextpage', 1)
get_format().gknextpage = title+1
title = unicode(title)
if get_format() == FORMATS['html']:
yield Literal('')
yield Text(title)
yield Literal('
\n')
for t in content:
yield t
yield Literal('')
elif get_format() == FORMATS['tex']:
yield Literal(r"\begin{nbpage}{")
yield Text(title)
yield Literal('}\n')
for t in content:
yield t
yield Literal('\n\\end{nbpage}\n')
else:
yield Start(HEADING, 2)
yield Text(Title)
yield End(HEADING, 2)
for t in content:
yield t
macros.page = page
def badge(argstr,content):
args = parse_macro_args(argstr)
color = ""
style = "light"
headfoot = [(), (), (), ()]
for key,val in args.items():
if key == 'color':
color = baz_eval(val).strip()
elif key == 1:
headfoot = get_headfoot('badge', val)
elif key == 'style':
style = baz_eval(val).strip()
if style not in ("light","dark"):
raise WikiException('The only valid badge styles are "light" and "dark"!')
else:
raise WikiException("Unknown arg '%s' in badge!"
% (key))
if not color.strip():
color = "white"
if get_format() == FORMATS['html']:
yield Literal('\n' % (style.lower(), color))
for t in html_div_headers(headfoot):
yield t
for t in content:
yield t
yield Literal('
\n')
elif get_format() == FORMATS['tex']:
yield Literal('\\NameBadge[%s]{' % (style,))
for t in latex_arg_headers(headfoot):
yield t
for t in content:
yield t
yield Literal('}')
else:
yield Text("Badge: ")
for t in content:
yield t
macros.badge = badge
def sign(argstr,content):
args = parse_macro_args(argstr)
name = ""
color = ""
size = "Big"
location = ""
blurb = ""
headfoot = [(), (), (), ()]
for key,val in args.items():
if key == 'color':
color = baz_eval(val).strip()
elif key == 'blurb':
blurb = baz_eval(val).strip()
elif key == 'location':
location = baz_eval(val).strip()
elif key == 'size':
size = baz_eval(val).strip().capitalize()
if size not in ("Big","Medium","Small"):
raise WikiException("Sign size must be big, medium, or small!")
elif key == 1:
name = baz_eval(val).strip()
elif key == 2:
headfoot = get_headfoot('sign', val)
else:
raise WikiException("Unknown arg '%s' in packet!"
% (key))
if not color.strip():
color = "white"
if get_format() == FORMATS['html']:
yield Literal('\n' % (size.lower(), color))
for t in html_div_headers(headfoot):
yield t
yield Literal('
')
yield Text(name)
yield Literal('
')
yield Literal('
\n')
for t in content:
yield t
yield Literal('
\n')
yield Literal('
')
yield Text(blurb)
yield Literal('
\n')
yield Literal('
\n')
elif get_format() == FORMATS['tex']:
yield Literal('\\%sSign{' % (size,))
for t in latex_arg_headers(headfoot):
yield t
yield Text(name)
yield Literal('}{')
yield Text(location)
yield Literal('}{')
for t in content:
yield t
yield Literal('}{')
yield Text(blurb)
yield Literal('}')
else:
yield Text('Sign: ')
for t in content:
yield t
macros.sign = sign
#macros.header = divided('header','gap','left','right')
#macros.footer = divided('footer','gap','left','right')
#macros.gap = illegal('gap','header','footer')
def imageheader(argstr, content=None):
args = parse_macro_args(argstr)
if 1 not in args or 2 not in args or 3 not in args or len(args) != 3:
raise WikiException(
"##imageheader## takes exactly 3 parameters!")
if content is None:
raise NoContentException("##imageheader## needs content!")
width = baz_eval(args[2]).strip()
height = baz_eval(args[3]).strip()
img = Entity(IMAGE, "%s^d%sx%s" % (args[1], width, height))
if get_format() == FORMATS['html']:
yield Literal('\n')
elif get_format() == FORMATS['tex']:
yield Literal('\\imageheader{')
yield img
yield Literal('}{%spx}{%spx}{' % (width, height))
for t in content:
yield t
yield Literal('}')
else:
yield Start(HEADER, 1)
for t in content:
yield t
yield End(HEADER, 1)
macros.imageheader = imageheader
macros.secret = environment(
'secret', doc="""Mark this content as secret, for printing.""")
def current_run():
return '1'
def runtime(argstr):
ename, propname = argstr.split('.', 1)
element = get_element(ename)
propname = get_propname(propname)
propval = element[propname]
run = current_run()
if propval.has_overlay(run):
yield Start(STRIKE)
yield Entity(MACRO, ('%s.%s' % (ename, propname), None))
yield End(STRIKE)
yield Text(' ')
yield Start(BOLD)
yield Text(propval.get_overlay(run))
yield End(BOLD)
else:
for t in recurse(ename, propname): yield t
macros.runtime = runtime
def contexteval(argstr):
"""Call as {{{<>}}} in an element's
substitution to allow that element to serve as a context for
name/pronoun/prop evaluation."""
args = parse_macro_args(argstr)
if 1 not in args or 2 not in args or 3 not in args or len(args) != 3:
raise WikiException(
"##contexteval## takes exactly 3 parameters!")
ename = args[1]
current = get_element(ename)
carg = render_allow_override(current, args[2])
ccontent = render_allow_override(current, args[3])
with eoverride({u'current': current}):
if ccontent is not None:
for t in ccontent(None, None): yield t
elif carg:
yield Entity(MACRO, (carg, None))
else:
for t in recurse(ename, u'name'): yield t
macros.contexteval = contexteval
GENDER_CONV_MAP = {'?': 'A'}
def pronoun(**mfna):
def pn(argstr):
e = get_current_element()
genderp = u'gender'
gen = render_allow_override(e, genderp, '?')[0:1].upper()
if gen in GENDER_CONV_MAP:
gen = GENDER_CONV_MAP[gen]
if gen in mfna:
yield Text(mfna[gen])
else:
yield Text(mfna['A'])
return pn
# Helpers
def _pron(mac, M, F, **mfna):
mfna['M'] = M
mfna['F'] = F
if 'A' not in mfna:
mfna['A'] = u'%s/%s' % (mfna['M'], mfna['F'])
if 'S' not in mfna and mac.startswith('th'):
mfna['S'] = mac[2:]
for a in [mac] + mfna.keys():
if not hasattr(macros, a):
pn = pronoun(**mfna)
if a == mac:
pn.hidden = 'pronoun'
else:
pn.hidden = 'pronounvariation'
setattr(macros, a, pn)
upper = dict((k, mfna[k][0].upper() + mfna[k][1:]) for k in mfna)
mac = mac[0].upper()+mac[1:]
for a in [mac] + upper.keys():
if not hasattr(macros, a):
pn = pronoun(**upper)
pn.hidden = 'pronounupper'
setattr(macros, a, pn)
# First in the list wins
_pron('they', 'he', 'she', N='it')
_pron('them', 'him', 'her', N='it')
_pron('their', 'his', 'her', N='its')
_pron('theirs', 'his', 'hers', N='its')
_pron('themself', 'himself', 'herself', N='itself')
_pron('spouse', 'husband', 'wife', N='spouse', A='spouse')
_pron('offspring', 'son', 'daughter', N='child', A='child')
_pron('kid', 'boy', 'girl', N='kid', A='kid')
_pron('sibling', 'brother', 'sister', N='sibling', A='sibling')
_pron('parent', 'father', 'mother', N='parent', A='parent')
_pron('uncle', 'uncle', 'aunt')
_pron('nephew', 'nephew', 'niece')
_pron('human', 'man', 'woman', N='human', A='human')
_pron('gender', 'male', 'female', N='neuter', A='uncertain', S='other')
PRE='<<>>'
SUF='<<>>'
def parsename(name):
gd = dict((k, '') for k in ('first', 'middle', 'last',
'prefix', 'suffix'))
gd['full'] = name
if SUF in name:
name, gd['suffix'] = name.split(SUF, 1)
gd['full'] = gd['full'].replace(SUF, ' ')
elif ", " in name:
name, gd['suffix'] = name.split(", ", 1)
if PRE in name:
gd['prefix'], name = name.split(PRE, 1)
gd['full'] = gd['full'].replace(PRE, ' ')
bits = name.split()
assert len(bits) >= 1
if len(bits) == 1:
gd['first'] = bits[0]
elif not gd['prefix'] and bits[0].endswith('.'):
gd['prefix'] = bits[0]
if len(bits) == 2:
gd['last'] = bits[1]
elif len(bits) == 3:
gd['first'], gd['last'] = bits[1:]
else:
gd['first'] = bits[1]
gd['last'] = bits[-1]
gd['middle'] = ' '.join(bits[2:-1])
else:
if len(bits) == 2:
gd['first'], gd['last'] = bits
else:
gd['first'] = bits[0]
gd['last'] = bits[-1]
gd['middle'] = ' '.join(bits[1:-1])
gd['informal'] = gd['first'] or gd['last']
gd['formal'] = gd['last'] or gd['first']
if gd['prefix']:
gd['formal'] = "%s %s" % (gd['prefix'], gd['formal'])
return gd
def namepart(part, nameprop=u'name'):
def np(argstr):
if argstr.strip():
namep = argstr.strip()
else:
namep = nameprop
e = get_current_element()
name = render_allow_override(e, namep,
moverrides=dict(pre=PRE, suf=SUF))
if name is None:
raise WikiException("%s.%s is not defined for name parsing!"
% (e.ename,namep))
#print >>sys.stderr, repr(name)
namedict = parsename(name)
yield Text(namedict[part])
np.hidden = 'namepart'
return np
macros.pre = atom(
default=" ",
doc="Marks the end of a title or prefix for name parsing.")
macros.suf = atom(
default=" ",
doc="Marks the start of an end title or suffix for name parsing.")
macros.first = namepart('first')
macros.middle = namepart('middle')
macros.last = namepart('last')
macros.full = namepart('full')
macros.formal = namepart('formal')
macros.informal = namepart('informal')
macros.player = leafprop(u'player')
macros.contact = leafprop(u'contact')