Permalink
Browse files

Merge branch 'tmpl_plugins'

  • Loading branch information...
2 parents 8aa6757 + aa42188 commit fbbb8701be30ed8f5d869fc0e30857a6b59824b3 @tsufeki committed Jul 18, 2013
Showing with 70 additions and 38 deletions.
  1. +16 −0 qygmy/dialogs.py
  2. +1 −1 qygmy/formatter.py
  3. +53 −37 qygmy/templates/template.py
View
@@ -1,5 +1,7 @@
import os
+import glob
+import importlib.machinery
import configparser
from PySide.QtCore import *
@@ -40,10 +42,12 @@ class Settings(QDialog):
PATH = os.path.expanduser(os.path.join(os.environ.get('XDG_CONFIG_HOME', '~/.config'), 'qygmy'))
FILENAME = 'qygmy.conf'
+ PLUGINS = 'tmplplugin_*.py'
def __init__(self, main):
super().__init__(main)
self.main = main
+
self.ui = Ui_settings()
self.ui.setupUi(self)
self.retranslate()
@@ -58,6 +62,7 @@ def __init__(self, main):
self.conf._join_multiline_values()
self.validate(self)
self.conf_to_ui()
+ self.load_tmplplugins()
def retranslate(self):
self.defaults = {
@@ -117,6 +122,17 @@ def environ_conf(self):
return {'connection': c}
return {}
+ def load_tmplplugins(self):
+ self.tmplplugins = []
+ for plugin in sorted(glob.glob(os.path.join(self.PATH, self.PLUGINS))):
+ try:
+ name = os.path.split(plugin)[1][:-3]
+ mod = importlib.machinery.SourceFileLoader(name, plugin).load_module()
+ if mod:
+ self.tmplplugins.append(mod)
+ except Exception as e:
+ logger.error('{}: {}'.format(e.__class__.__name__, e))
+
def __getitem__(self, section):
return self.conf[section]
View
@@ -122,7 +122,7 @@ def _compile(self, template):
pref = '$if(%bold%,<span style="font-weight: bold">,)'
suff = '$if(%bold%,</span>,)'
if isinstance(template, str):
- return Template(pref + template + suff)
+ return Template(pref + template + suff, self.settings.tmplplugins)
r = []
for a, b in template:
a = self._compile(a)
@@ -32,13 +32,14 @@ def __repr__(self):
class Element(Renderable):
- def __init__(self, src, start, end):
+ def __init__(self, tmpl, src, start, end):
+ self.template = tmpl
self.src = src
self.start = start
self.end = end
@classmethod
- def parse_first(cls, src, pos=0):
+ def parse_first(cls, tmpl, src, pos=0):
return None
def parse_rest(self):
@@ -50,20 +51,20 @@ class RegexElement(Element):
regex = None
@classmethod
- def parse_first(cls, src, pos=0):
+ def parse_first(cls, tmpl, src, pos=0):
m = cls.regex.search(src, pos)
if m is None:
return None
- return cls(src, m.start(), m.end(), *m.groups())
+ return cls(tmpl, src, m.start(), m.end(), *m.groups())
class Backslash(RegexElement):
newlines = ('\n', '\r\n', '\r')
regex = re.compile(r'\\({}|.)'.format('|'.join(newlines)))
- def __init__(self, src, start, end, char):
- super().__init__(src, start, end)
+ def __init__(self, tmpl, src, start, end, char):
+ super().__init__(tmpl, src, start, end)
self.char = char
if char in self.newlines:
self.char = ''
@@ -79,8 +80,8 @@ class Variable(RegexElement):
regex = re.compile(r'%' + IDENTIFIER + r'%')
- def __init__(self, src, start, end, name):
- super().__init__(src, start, end)
+ def __init__(self, tmpl, src, start, end, name):
+ super().__init__(tmpl, src, start, end)
self.name = name.lower()
def render(self, context):
@@ -95,21 +96,21 @@ class Sequence(Element):
class End(RegexElement):
regex = re.compile(r'$')
- def __init__(self, src, start, end, delims=[], types=None):
- super().__init__(src, start, end)
+ def __init__(self, tmpl, src, start, end, delims=[], types=None):
+ super().__init__(tmpl, src, start, end)
if types is None:
types = [Backslash, Variable, Function]
self.delims = delims + [self.End]
self.types = types + self.delims
self.elems = []
@classmethod
- def parse_first(cls, src, pos=0, delims=[], types=None):
- return cls(src, pos, pos, delims, types)
+ def parse_first(cls, tmpl, src, pos=0, delims=[], types=None):
+ return cls(tmpl, src, pos, pos, delims, types)
def parse_rest(self):
while True:
- matches = [t.parse_first(self.src, self.end) for t in self.types]
+ matches = [t.parse_first(self.template, self.src, self.end) for t in self.types]
minimum = None
for m in matches:
if m is not None and (minimum is None or m.start < minimum.start):
@@ -143,8 +144,8 @@ class ClosingParen(RegexElement):
regex = re.compile(r'\)')
- def __init__(self, src, start, end, name):
- super().__init__(src, start, end)
+ def __init__(self, tmpl, src, start, end, name):
+ super().__init__(tmpl, src, start, end)
self.name = name.lower()
self.args = []
@@ -156,50 +157,64 @@ def __init__(self, src, start, end, name):
),
}
- f = getattr(functions, 'lazy_' + self.name, None)
- if f is not None:
- self.function = f
- self.call = self.call_lazy
- return
- f = getattr(functions, 'f_' + self.name, None)
- if f is not None:
- self.function = f
- self.call = self.call_f
- return
- f = getattr(functions, 'context_' + self.name, None)
- if f is not None:
- self.function = f
- self.call = self.call_context
+ self.call = None
+ for module in reversed(self.template.functions):
+ f = getattr(module, 'lazycontext_' + self.name, None)
+ if f is not None:
+ self.function = f
+ self.call = self.call_lazycontext
+ return
+ f = getattr(module, 'context_' + self.name, None)
+ if f is not None:
+ self.function = f
+ self.call = self.call_context
+ return
+ f = getattr(module, 'lazy_' + self.name, None)
+ if f is not None:
+ self.function = f
+ self.call = self.call_lazy
+ return
+ f = getattr(module, 'f_' + self.name, None)
+ if f is not None:
+ self.function = f
+ self.call = self.call_f
+ return
def parse_rest(self):
while True:
- seq = Sequence.parse_first(self.src, self.end,
+ seq = Sequence.parse_first(self.template, self.src, self.end,
delims=[self.Comma, self.ClosingParen])
seq.parse_rest()
self.end = seq.end
self.args.append(seq)
if type(seq.last) != self.Comma:
return
- def call_lazy(self, context):
- args = [(lambda a=a: a.render(context)) for a in self.args]
- return self.function(*args)
-
def call_f(self, context):
args = [a.render(context) for a in self.args]
return self.function(*args)
+ def call_lazy(self, context):
+ args = [(lambda a=a: a.render(context)) for a in self.args]
+ return self.function(*args)
+
def call_context(self, context):
context.update(self._ctx_additions)
args = [a.render(context) for a in self.args]
return self.function(context, *args)
+ def call_lazycontext(self, context):
+ context.update(self._ctx_additions)
+ args = [(lambda a=a: a.render(context)) for a in self.args]
+ return self.function(context, *args)
+
def render(self, context):
+ if self.call is None:
+ raise TemplateError("function '${}' is not defined".format(self.name))
try:
return self.call(context)
except Exception as e:
raise TemplateError(str(e)) from e
- raise TemplateError('no such function: {!r}'.format(self.name))
def __repr__(self):
s = 'Function('
@@ -208,8 +223,9 @@ def __repr__(self):
class Template:
- def __init__(self, source):
- self.compiled = Sequence.parse_first(source)
+ def __init__(self, source, function_modules=[]):
+ self.functions = [functions] + function_modules
+ self.compiled = Sequence.parse_first(self, source)
self.compiled.parse_rest()
def render(self, context):

0 comments on commit fbbb870

Please sign in to comment.