-
Notifications
You must be signed in to change notification settings - Fork 0
OverlayParser
This is a demonstration plugin for constructing a wiki language parser based on the default parser which doesn't need permanent updates (but maybe from time to time).
Until now it was only possible to create a copy of the default parser plugin and modify it in the desired way. This meaned that each change in the default parser had to be done to the copied parser as well.
For simple changes (like double brackets for links as this plugin demonstrates) it can be done more comfortable now by giving some redefinitions of definitions in default parser which are used instead of the original ones. If other parts of the default parser change an overlay parser automatically uses these changes without a manual update.
The OverlayParser works by executing the default parser code in some sort of "guarded" environment. When one of the overlaid identifiers should be set as global variable, the OverlayParser evaluates the definition from its PAYLOAD and sets this result instead. This allows to redefine e.g. the URL patterns to support more URL protocols.
The plugin works for recent 2.2 and 2.1 versions. For final 2.0 it should work but wasn't tested yet.
This plugin is mainly intended for demonstration purposes. If you want your own, you should rename it and modify WIKI_LANGUAGE_NAME (internal name of new wiki language) and WIKI_HR_LANGUAGE_NAME (human readable name) and of course PAYLOAD.
import re, traceback
WIKIDPAD_PLUGIN = (("WikiParser", 1),)
WIKI_LANGUAGE_NAME = "wikidpad_overlaid_2_0"
WIKI_HR_LANGUAGE_NAME = u"WikidPad overlaid 2.0"
def describeWikiLanguage(ver, app):
"""
API function for "WikiParser" plugins
Returns a sequence of tuples describing the supported
insertion keys. Each tuple has the form (intLanguageName, hrLanguageName,
parserFactory, parserIsThreadsafe, editHelperFactory,
editHelperIsThreadsafe)
Where the items mean:
intLanguageName -- internal unique name (should be ascii only) to
identify wiki language processed by parser
hrLanguageName -- human readable language name, unistring
(TODO: localization)
parserFactory -- factory function to create parser object(s) fulfilling
parserIsThreadsafe -- boolean if parser is threadsafe. If not this
will currently lead to a very inefficient operation
processHelperFactory -- factory for helper object containing further
functions needed for editing, tree presentation and so on.
editHelperIsThreadsafe -- boolean if edit helper functions are
threadsafe.
Parameters:
ver -- API version (can only be 1 currently)
app -- wxApp object
"""
return ((WIKI_LANGUAGE_NAME, WIKI_HR_LANGUAGE_NAME, parserFactory,
True, languageHelperFactory, True),)
# The PAYLOAD looks like Python code but has to use a much simpler syntax:
#
# <identifier to overlay> = <Python expression>
#
# If the expression spans multiple lines each except the last one has to end
# with backslash '\'
#
# Comments are not allowed
PAYLOAD = """
BracketStart = u"[["
BracketStartPAT = ur"\[\["
BracketEnd = u"]]"
BracketEndPAT = ur"\]\]"
BracketStartRevPAT = ur"\[\["
BracketEndRevPAT = ur"\]\]"
"""
# ---------- Modifications below this line are not recommended ----------
_LINECONT_RE = re.compile(r"(?:\r\n?|\n)\\", re.UNICODE)
_LINEEND_SPLIT_RE = re.compile(r"\r\n?|\n", re.UNICODE)
def _joinLineConts(text):
return _LINECONT_RE.sub("", text)
def _splitLines(text):
return _LINEEND_SPLIT_RE.split(text)
class _ReplacementDictWrapper(dict):
def __init__(self, realDict, replaceExprDict):
self.realDict = realDict
dict.update(self, realDict)
self.replaceExprDict = replaceExprDict
def __setitem__(self, key, value):
if self.replaceExprDict.has_key(key):
value = eval(self.replaceExprDict[key][0], self)
self.realDict[key] = value
dict.__setitem__(self, key, value)
def __delitem__(self, key):
del self.realDict[key]
dict.__delitem__(self, key)
@staticmethod
def overlayToReplaceExprDict(overlay):
overlay = _joinLineConts(overlay)
result = {}
for line in _splitLines(overlay):
sp = line.split("=", 1)
if len(sp) != 2:
continue
result[sp[0].strip()] = (sp[1].strip(),)
return result
_realParserFactory = None
_realLanguageHelperFactory = None
def _loadWorkerModule():
global _realParserFactory, _realLanguageHelperFactory
from os.path import join
from imp import new_module
from pwiki.StringOps import loadEntireTxtFile
# Find original "WikidPadParser.py" file
try:
# Should work with 2.2beta03 and later
import wikidpadSystemPlugins
targetPath = join(wikidpadSystemPlugins.__path__[0],
"wikidPadParser/WikidPadParser.py")
except ImportError:
# Fallback method
import sys
targetPath = join(sys.modules[__name__.split(".", 1)[0]].__path__[0],
"../extensions/wikidPadParser/WikidPadParser.py")
original = loadEntireTxtFile(targetPath)
module = new_module("")
glSpace = _ReplacementDictWrapper(module.__dict__,
_ReplacementDictWrapper.overlayToReplaceExprDict(PAYLOAD))
exec original in glSpace
_realParserFactory = module.parserFactory
_realLanguageHelperFactory = module.languageHelperFactory
def parserFactory(intLanguageName, debugMode):
"""
Builds up a parser object. If the parser is threadsafe this function is
allowed to return the same object multiple times (currently it should do
so for efficiency).
For seldom needed parsers it is recommended to put the actual parser
construction as singleton in this function to reduce startup time of WikidPad.
For non-threadsafe parsers it is required to create one inside this
function at each call.
intLanguageName -- internal unique name (should be ascii only) to
identify wiki language to process by parser
"""
global _realParserFactory
if _realParserFactory is None:
_loadWorkerModule()
return _realParserFactory(intLanguageName, debugMode)
def languageHelperFactory(intLanguageName, debugMode):
"""
Builds up a language helper object. If the object is threadsafe this function is
allowed to return the same object multiple times (currently it should do
so for efficiency).
intLanguageName -- internal unique name (should be ascii only) to
identify wiki language to process by helper
"""
global _realLanguageHelperFactory
if _realLanguageHelperFactory is None:
_loadWorkerModule()
return _realLanguageHelperFactory(intLanguageName, debugMode)
Source: http://trac.wikidpad2.webfactional.com/wiki/OverlayParser