📄 template.py
字号:
"""simple, elegant templating(part of web.py)"""import re, glob, os, os.pathfrom types import FunctionType as functionfrom utils import storage, group, utf8from net import websafe# differences from python:# - for: has an optional else: that gets called if the loop never runs# differences to add:# - you can use the expression inside if, while blocks# - special for loop attributes, like django?# - you can check to see if a variable is defined (perhaps w/ get func?)# all these are probably good ideas for python...# todo:# inline tuple# relax constraints on spacing# continue, break, etc.# tracebacksglobal_globals = {'None':None, 'False':False, 'True': True}MAX_ITERS = 100000WHAT = 0ARGS = 4KWARGS = 6NAME = 2BODY = 4CLAUSE = 2ELIF = 6ELSE = 8IN = 6NAME = 2EXPR = 4FILTER = 4THING = 2ATTR = 4ITEM = 4NEGATE = 4X = 2OP = 4Y = 6LINENO = -1# http://docs.python.org/ref/identifiers.htmlr_var = '[a-zA-Z_][a-zA-Z0-9_]*'class ParseError(Exception): passclass Parser: def __init__(self, text, name=""): self.t = text self.p = 0 self._lock = [False] self.name = name def lock(self): self._lock[-1] = True def curline(self): return self.t[:self.p].count('\n')+1 def csome(self): return repr(self.t[self.p:self.p+5]+'...') def Error(self, x, y=None): if y is None: y = self.csome() raise ParseError, "%s: expected %s, got %s (line %s)" % (self.name, x, y, self.curline()) def q(self, f): def internal(*a, **kw): checkp = self.p self._lock.append(False) try: q = f(*a, **kw) except ParseError: if self._lock[-1]: raise self.p = checkp self._lock.pop() return False self._lock.pop() return q or True return internal def tokr(self, t): text = self.c(len(t)) if text != t: self.Error(repr(t), repr(text)) return t def ltokr(self, *l): for x in l: o = self.tokq(x) if o: return o self.Error('one of '+repr(l)) def rer(self, r): x = re.match(r, self.t[self.p:]) #@@re_compile if not x: self.Error('r'+repr(r)) return self.tokr(x.group()) def endr(self): if self.p != len(self.t): self.Error('EOF') def c(self, n=1): out = self.t[self.p:self.p+n] if out == '' and n != 0: self.Error('character', 'EOF') self.p += n return out def lookbehind(self, t): return self.t[self.p-len(t):self.p] == t def __getattr__(self, a): if a.endswith('q'): return self.q(getattr(self, a[:-1]+'r')) raise AttributeError, aclass TemplateParser(Parser): def __init__(self, *a, **kw): Parser.__init__(self, *a, **kw) self.curws = '' self.curind = '' def o(self, *a): return a+('lineno', self.curline()) def go(self): # maybe try to do some traceback parsing/hacking return self.gor() def gor(self): header = self.defwithq() results = self.lines(start=True) self.endr() return header, results def ws(self): n = 0 while self.tokq(" "): n += 1 return " " * n def defwithr(self): self.tokr('$def with ') self.lock() self.tokr('(') args = [] kw = [] x = self.req(r_var) while x: if self.tokq('='): v = self.exprr() kw.append((x, v)) else: args.append(x) x = self.tokq(', ') and self.req(r_var) self.tokr(')\n') return self.o('defwith', 'null', None, 'args', args, 'kwargs', kw) def literalr(self): o = ( self.req('"[^"]*"') or #@@ no support for escapes self.req("'[^']*'") ) if o is False: o = self.req('\-?[0-9]+(\.[0-9]*)?') if o is not False: if '.' in o: o = float(o) else: o = int(o) if o is False: self.Error('literal') return self.o('literal', 'thing', o) def listr(self): self.tokr('[') self.lock() x = [] if not self.tokq(']'): while True: t = self.exprr() x.append(t) if not self.tokq(', '): break self.tokr(']') return self.o('list', 'thing', x) def dictr(self): self.tokr('{') self.lock() x = {} if not self.tokq('}'): while True: k = self.exprr() self.tokr(': ') v = self.exprr() x[k] = v if not self.tokq(', '): break self.tokr('}') return self.o('dict', 'thing', x) def parenr(self): self.tokr('(') self.lock() o = self.exprr() # todo: allow list self.tokr(')') return self.o('paren', 'thing', o) def atomr(self): """returns var, literal, paren, dict, or list""" o = ( self.varq() or self.parenq() or self.dictq() or self.listq() or self.literalq() ) if o is False: self.Error('atom') return o def primaryr(self): """returns getattr, call, or getitem""" n = self.atomr() while 1: if self.tokq('.'): v = self.req(r_var) if not v: self.p -= 1 # get rid of the '.' break else: n = self.o('getattr', 'thing', n, 'attr', v) elif self.tokq('('): args = [] kw = [] while 1: # need to see if we're doing a keyword argument checkp = self.p k = self.req(r_var) if k and self.tokq('='): # yup v = self.exprr() kw.append((k, v)) else: self.p = checkp x = self.exprq() if x: # at least it's something args.append(x) else: break if not self.tokq(', '): break self.tokr(')') n = self.o('call', 'thing', n, 'args', args, 'kwargs', kw) elif self.tokq('['): v = self.exprr() self.tokr(']') n = self.o('getitem', 'thing', n, 'item', v) else: break return n def exprr(self): negate = self.tokq('not ') x = self.primaryr() if self.tokq(' '): operator = self.ltokr('not in', 'in', 'is not', 'is', '==', '!=', '>=', '<=', '<', '>', 'and', 'or', '*', '+', '-', '/', '%') self.tokr(' ') y = self.exprr() x = self.o('test', 'x', x, 'op', operator, 'y', y) return self.o('expr', 'thing', x, 'negate', negate) def varr(self): return self.o('var', 'name', self.rer(r_var)) def liner(self): out = [] o = self.curws while 1: c = self.c() self.lock() if c == '\n': self.p -= 1 break if c == '$': if self.lookbehind('\\$'): o = o[:-1] + c else: filter = not bool(self.tokq(':')) if self.tokq('{'): out.append(o) out.append(self.o('itpl', 'name', self.exprr(), 'filter', filter)) self.tokr('}') o = '' else: g = self.primaryq() if g: out.append(o) out.append(self.o('itpl', 'name', g, 'filter', filter)) o = '' else: o += c else: o += c self.tokr('\n') if not self.lookbehind('\\\n'): o += '\n' else: o = o[:-1] out.append(o) return self.o('line', 'thing', out) def varsetr(self): self.tokr('$var ') self.lock() what = self.rer(r_var) self.tokr(':') body = self.lines() return self.o('varset', 'name', what, 'body', body) def ifr(self): self.tokr("$if ") self.lock() expr = self.exprr() self.tokr(":") ifc = self.lines() elifs = [] while self.tokq(self.curws + self.curind + '$elif '): v = self.exprr() self.tokr(':') c = self.lines() elifs.append(self.o('elif', 'clause', v, 'body', c)) if self.tokq(self.curws + self.curind + "$else:"): elsec = self.lines() else: elsec = None return self.o('if', 'clause', expr, 'then', ifc, 'elif', elifs, 'else', elsec) def forr(self): self.tokr("$for ") self.lock() v = self.setabler() self.tokr(" in ") g = self.exprr() self.tokr(":") l = self.lines() if self.tokq(self.curws + self.curind + '$else:'): elsec = self.lines() else: elsec = None return self.o('for', 'name', v, 'body', l, 'in', g, 'else', elsec) def whiler(self): self.tokr('$while ') self.lock() v = self.exprr() self.tokr(":") l = self.lines() if self.tokq(self.curws + self.curind + '$else:'): elsec = self.lines() else: elsec = None return self.o('while', 'clause', v, 'body', l, 'null', None, 'else', elsec) def assignr(self): self.tokr('$ ') assign = self.rer(r_var) # NOTE: setable self.tokr(' = ') expr = self.exprr() self.tokr('\n') return self.o('assign', 'name', assign, 'expr', expr) def commentr(self): self.tokr('$#') self.lock() while self.c() != '\n': pass return self.o('comment') def setabler(self): out = [self.varr()] #@@ not quite right while self.tokq(', '): out.append(self.varr()) return out def lines(self, start=False): """ This function gets called from two places: 1. at the start, where it's matching the document itself 2. after any command, where it matches one line or an indented block """ o = [] if not start: # try to match just one line singleline = self.tokq(' ') and self.lineq() if singleline: return [singleline] else: self.rer(' *') #@@slurp space? self.tokr('\n') oldind = self.curind self.curind += ' ' while 1: oldws = self.curws t = self.tokq(oldws + self.curind) if not t: break self.curws += self.ws() x = t and ( self.varsetq() or self.ifq() or self.forq() or self.whileq() or self.assignq() or self.commentq() or self.lineq()) self.curws = oldws if not x: break elif x[WHAT] == 'comment': pass else: o.append(x) if not start: self.curind = oldind return o
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -