1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - "text/python" Formatter
Compiles pages to executable python code.
@copyright: 2000-2004 by Juergen Hermann <jh@web.de>
@license: GNU GPL, see COPYING for details.
"""
import time
from MoinMoin import wikiutil
class Formatter:
"""
Inserts '<<<>>>' into the page and adds python code to
self.code_fragments for dynamic parts of the page
(as macros, wikinames...).
Static parts are formatted with an external formatter.
Page must be assembled after the parsing to get working python code.
"""
defaultDependencies = ["time"]
def __init__(self, request, static=[], formatter=None, **kw):
if formatter:
self.formatter = formatter
else:
from MoinMoin.formatter.text_html import Formatter
self.formatter = Formatter(request, store_pagelinks=1)
self.static = static
self.code_fragments = []
self.__formatter = "formatter"
self.__parser = "parser"
self.request = request
self.__lang = request.current_lang
self.__in_p = 0
self.__in_pre = 0
self.text_cmd_begin = '\nrequest.write('
self.text_cmd_end = ')\n'
def assemble_code(self, text):
"""inserts the code into the generated text
"""
# Automatic invalidation due to moin code changes:
# we are called from Page.py, so moincode_timestamp is
# mtime of MoinMoin directory. If we detect, that the
# saved rendering code is older than the MoinMoin directory
# we invalidate it by raising an exception. This avoids
# calling functions that have changed by a code update.
# Hint: we don't check the mtime of the directories within
# MoinMoin, so better do a touch if you only modified stuff
# in a subdirectory.
waspcode_timestamp = int(time.time())
source = ["""
moincode_timestamp = int(os.path.getmtime(os.path.dirname(__file__)))
cfg_mtime = getattr(request.cfg, "cfg_mtime", None)
if moincode_timestamp > %d or cfg_mtime is None or cfg_mtime > %d:
raise Exception("CacheNeedsUpdate")
""" % (waspcode_timestamp, waspcode_timestamp)]
text = text.split('<<<>>>', len(self.code_fragments))
source.extend([self.text_cmd_begin, repr(text[0])])
i = 0
for t in text[1:]:
source.extend([self.text_cmd_end,
self.code_fragments[i],
self.text_cmd_begin,
repr(text[i+1])])
i += 1
source.append(self.text_cmd_end)
source.append(self.__adjust_formatter_state())
self.code_fragments = [] # clear code fragments to make
# this object reusable
return "".join(source)
def __cache_if_no_id(self, name, *args, **kw):
if not 'id' in kw:
return getattr(self.formatter, name)(*args, **kw)
else:
return self.__insert_code('request.write(%s.%s(*%r, **%r))' %
(self.__formatter, name, args, kw))
def __getattr__(self, name):
"""
For every thing we have no method/attribute use the formatter
unless there's an ID in the keywords.
"""
attr = getattr(self.formatter, name)
if callable(attr):
return lambda *args, **kw: self.__cache_if_no_id(name, *args, **kw)
else:
return attr
def __insert_code(self, call):
""" returns the python code
"""
self.code_fragments.append(call)
return '<<<>>>'
def __insert_fmt_call(self, function, *args, **kw):
return self.__insert_code('request.write(%s.%s(*%r, **%r))' % (
self.__formatter, function, args, kw))
def __is_static(self, dependencies):
for dep in dependencies:
if dep not in self.static:
return False
return True
def __adjust_language_state(self):
""" Add current language state changing code to the cache """
if self.__lang != self.request.current_lang:
self.__lang = self.request.current_lang
return 'request.current_lang = %r\n' % self.__lang
return ''
def __adjust_formatter_state(self):
result = self.__adjust_language_state()
if self.__in_p != self.formatter.in_p:
result = "%s%s.in_p = %r\n" % (result, self.__formatter,
self.formatter.in_p)
self.__in_p = self.formatter.in_p
if self.__in_pre != self.formatter.in_pre:
result = "%s%s.in_pre = %r\n" % (result, self.__formatter,
self.formatter.in_pre)
self.__in_pre = self.formatter.in_pre
return result
# Public methods ---------------------------------------------------
def pagelink(self, on, pagename='', page=None, **kw):
if on:
return self.__insert_code('page=Page(request, %r, formatter=%s);'
'request.write(%s.pagelink(%r, page=page, **%r))' %
(pagename, self.__formatter,
self.__formatter, on, kw))
else:
return self.__insert_code('request.write(%s.pagelink(%r, page=page, **%r))' %
(self.__formatter, on, kw))
def attachment_link(self, on, url=None, **kw):
return self.__insert_fmt_call('attachment_link', on, url, **kw)
def attachment_image(self, url, **kw):
return self.__insert_fmt_call('attachment_image', url, **kw)
def attachment_drawing(self, url, text, **kw):
return self.__insert_fmt_call('attachment_drawing', url, text, **kw)
def attachment_inlined(self, url, text, **kw):
return self.__insert_fmt_call('attachment_inlined', url, text, **kw)
def heading(self, on, depth, **kw):
if on:
code = [
self.__adjust_language_state(),
'request.write(%s.heading(%r, %r, **%r))' % (self.__formatter,
on, depth, kw),
]
return self.__insert_code(''.join(code))
else:
return self.formatter.heading(on, depth, **kw)
def icon(self, type):
if self.__is_static(['user']):
return self.formatter.icon(type)
else:
return self.__insert_fmt_call('icon', type)
smiley = icon
def span(self, on, **kw):
if on and 'comment' in kw.get('css_class', '').split():
return self.__insert_fmt_call('span', on, **kw)
else:
return self.formatter.span(on, **kw)
def div(self, on, **kw):
if on and 'comment' in kw.get('css_class', '').split():
return self.__insert_fmt_call('div', on, **kw)
else:
return self.formatter.div(on, **kw)
def macro(self, macro_obj, name, args, markup=None):
if self.__is_static(macro_obj.get_dependencies(name)):
# XXX: why is this necessary??
macro_obj.formatter = self
return macro_obj.execute(name, args)
else:
return self.__insert_code(
'%srequest.write(%s.macro(macro_obj, %r, %r, %r))' %
(self.__adjust_formatter_state(),
self.__formatter, name, args, markup))
def parser(self, parser_name, lines):
""" parser_name MUST be valid!
prints out the result instead of returning it!
"""
try:
Dependencies = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", parser_name, "Dependencies")
except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError):
Dependencies = self.defaultDependencies
if self.__is_static(Dependencies):
return self.formatter.parser(parser_name, lines)
else:
return self.__insert_code('%s%s.parser(%r, %r)' %
(self.__adjust_formatter_state(),
self.__formatter,
parser_name, lines))
def startContent(self, content_id='content', newline=True, **kw):
# we need to tell the request about the start of the content
return self.__insert_fmt_call('startContent', content_id, newline, **kw)
def endContent(self, newline=True):
# we need to tell the request about the end of the content
return self.__insert_fmt_call('endContent', newline)
def anchorlink(self, on, name='', **kw):
# anchorlink depends on state now, namely the include ID in the request.
if on:
return self.__insert_fmt_call('anchorlink', on, name, **kw)
else:
return self.formatter.anchorlink(on, name=name, **kw)
def line_anchorlink(self, on, lineno=0):
# anchorlink depends on state now, namely the include ID in the request.
if on:
return self.__insert_fmt_call('line_anchorlink', on, lineno)
else:
return self.formatter.line_anchorlink(on, lineno)
def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1, msg=None):
if on:
# update state of the HTML formatter
self.formatter._in_code_area = 1
self.formatter._in_code_line = 0
self.formatter._code_area_state = [None, show, start, step, start]
return self.__insert_fmt_call('code_area', on, code_id, code_type, show,
start, step)
else:
return self.formatter.code_area(False, code_id, code_type, show, start, step)
def line_anchordef(self, lineno):
return self.__insert_fmt_call('line_anchordef', lineno)
def anchordef(self, id):
return self.__insert_fmt_call('anchordef', id)
|