Mercurial > traipse_dev
comparison upmana/mercurial/templater.py @ 121:496dbf12a6cb alpha
Traipse Alpha 'OpenRPG' {091030-00}
Traipse is a distribution of OpenRPG that is designed to be easy to setup and go.
Traipse also makes it easy for developers to work on code without fear of
sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the
code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the
productivity of the user.
Update Summary (Cleaning up for Beta):
Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images!
Changes made to the map for increased portability. SnowDog has changes planned in
Core, though.
Added an initial push to the BCG. Not much to see, just shows off how it is
re-writing Main code.
Fix to remote admin commands
Minor fix to texted based server, works in /System/ folder
Some Core changes to gametree to correctly disply Pretty Print, thanks David!
Fix to Splitter Nodes not being created.
Added images to Plugin Control panel for Autostart feature
Fix to massive amounts of images loading; from Core
fix to gsclient so with_statement imports
Added 'boot' command to remote admin
Prep work in Pass tool for remote admin rankings and different passwords, ei,
Server, Admin, Moderator, etc.
Remote Admin Commands more organized, more prep work.
Added Confirmation window for sent nodes.
Minor changes to allow for portability to an OpenSUSE linux OS (hopefully without
breaking)
{091028}
Made changes to gametree to start working with Element Tree, mostly from Core
Minor changes to Map to start working with Element Tree, from Core
Preliminary changes to map efficiency, from FlexiRPG
Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG
Changes to main.py to start working with Element Tree
{091029}
Changes made to server to start working with Element Tree.
Changes made to Meta Server Lib. Prepping test work for a multi meta network
page.
Minor bug fixed with mini to gametree
Zoom Mouse plugin added.
{091030}
Getting ready for Beta. Server needs debugging so Alpha remains bugged.
Plugin UI code cleaned. Auto start works with a graphic, pop-up asks to enable or
disable plugin.
Update Manager now has a partially working Status Bar. Status Bar captures
terminal text, so Merc out put is visible. Manifest.xml file, will be renamed, is
now much cleaner.
Debug Console has a clear button and a Report Bug button. Prep work for a Term2Win
class in Debug Console.
Known: Current Alpha fails in Windows.
author | sirebral |
---|---|
date | Fri, 30 Oct 2009 22:21:40 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
120:d86e762a994f | 121:496dbf12a6cb |
---|---|
1 # templater.py - template expansion for output | |
2 # | |
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 # | |
5 # This software may be used and distributed according to the terms of the | |
6 # GNU General Public License version 2, incorporated herein by reference. | |
7 | |
8 from i18n import _ | |
9 import re, sys, os | |
10 import util, config, templatefilters | |
11 | |
12 path = ['templates', '../templates'] | |
13 stringify = templatefilters.stringify | |
14 | |
15 def parsestring(s, quoted=True): | |
16 '''parse a string using simple c-like syntax. | |
17 string must be in quotes if quoted is True.''' | |
18 if quoted: | |
19 if len(s) < 2 or s[0] != s[-1]: | |
20 raise SyntaxError(_('unmatched quotes')) | |
21 return s[1:-1].decode('string_escape') | |
22 | |
23 return s.decode('string_escape') | |
24 | |
25 class engine(object): | |
26 '''template expansion engine. | |
27 | |
28 template expansion works like this. a map file contains key=value | |
29 pairs. if value is quoted, it is treated as string. otherwise, it | |
30 is treated as name of template file. | |
31 | |
32 templater is asked to expand a key in map. it looks up key, and | |
33 looks for strings like this: {foo}. it expands {foo} by looking up | |
34 foo in map, and substituting it. expansion is recursive: it stops | |
35 when there is no more {foo} to replace. | |
36 | |
37 expansion also allows formatting and filtering. | |
38 | |
39 format uses key to expand each item in list. syntax is | |
40 {key%format}. | |
41 | |
42 filter uses function to transform value. syntax is | |
43 {key|filter1|filter2|...}.''' | |
44 | |
45 template_re = re.compile(r'{([\w\|%]+)}|#([\w\|%]+)#') | |
46 | |
47 def __init__(self, loader, filters={}, defaults={}): | |
48 self.loader = loader | |
49 self.filters = filters | |
50 self.defaults = defaults | |
51 self.cache = {} | |
52 | |
53 def process(self, t, map): | |
54 '''Perform expansion. t is name of map element to expand. map contains | |
55 added elements for use during expansion. Is a generator.''' | |
56 tmpl = self.loader(t) | |
57 iters = [self._process(tmpl, map)] | |
58 while iters: | |
59 try: | |
60 item = iters[0].next() | |
61 except StopIteration: | |
62 iters.pop(0) | |
63 continue | |
64 if isinstance(item, str): | |
65 yield item | |
66 elif item is None: | |
67 yield '' | |
68 elif hasattr(item, '__iter__'): | |
69 iters.insert(0, iter(item)) | |
70 else: | |
71 yield str(item) | |
72 | |
73 def _format(self, expr, get, map): | |
74 key, format = expr.split('%') | |
75 v = get(key) | |
76 if not hasattr(v, '__iter__'): | |
77 raise SyntaxError(_("error expanding '%s%%%s'") % (key, format)) | |
78 lm = map.copy() | |
79 for i in v: | |
80 lm.update(i) | |
81 yield self.process(format, lm) | |
82 | |
83 def _filter(self, expr, get, map): | |
84 if expr not in self.cache: | |
85 parts = expr.split('|') | |
86 val = parts[0] | |
87 try: | |
88 filters = [self.filters[f] for f in parts[1:]] | |
89 except KeyError, i: | |
90 raise SyntaxError(_("unknown filter '%s'") % i[0]) | |
91 def apply(get): | |
92 x = get(val) | |
93 for f in filters: | |
94 x = f(x) | |
95 return x | |
96 self.cache[expr] = apply | |
97 return self.cache[expr](get) | |
98 | |
99 def _process(self, tmpl, map): | |
100 '''Render a template. Returns a generator.''' | |
101 | |
102 def get(key): | |
103 v = map.get(key) | |
104 if v is None: | |
105 v = self.defaults.get(key, '') | |
106 if hasattr(v, '__call__'): | |
107 v = v(**map) | |
108 return v | |
109 | |
110 while tmpl: | |
111 m = self.template_re.search(tmpl) | |
112 if not m: | |
113 yield tmpl | |
114 break | |
115 | |
116 start, end = m.span(0) | |
117 variants = m.groups() | |
118 expr = variants[0] or variants[1] | |
119 | |
120 if start: | |
121 yield tmpl[:start] | |
122 tmpl = tmpl[end:] | |
123 | |
124 if '%' in expr: | |
125 yield self._format(expr, get, map) | |
126 elif '|' in expr: | |
127 yield self._filter(expr, get, map) | |
128 else: | |
129 yield get(expr) | |
130 | |
131 engines = {'default': engine} | |
132 | |
133 class templater(object): | |
134 | |
135 def __init__(self, mapfile, filters={}, defaults={}, cache={}, | |
136 minchunk=1024, maxchunk=65536): | |
137 '''set up template engine. | |
138 mapfile is name of file to read map definitions from. | |
139 filters is dict of functions. each transforms a value into another. | |
140 defaults is dict of default map definitions.''' | |
141 self.mapfile = mapfile or 'template' | |
142 self.cache = cache.copy() | |
143 self.map = {} | |
144 self.base = (mapfile and os.path.dirname(mapfile)) or '' | |
145 self.filters = templatefilters.filters.copy() | |
146 self.filters.update(filters) | |
147 self.defaults = defaults | |
148 self.minchunk, self.maxchunk = minchunk, maxchunk | |
149 self.engines = {} | |
150 | |
151 if not mapfile: | |
152 return | |
153 if not os.path.exists(mapfile): | |
154 raise util.Abort(_('style not found: %s') % mapfile) | |
155 | |
156 conf = config.config() | |
157 conf.read(mapfile) | |
158 | |
159 for key, val in conf[''].items(): | |
160 if val[0] in "'\"": | |
161 try: | |
162 self.cache[key] = parsestring(val) | |
163 except SyntaxError, inst: | |
164 raise SyntaxError('%s: %s' % | |
165 (conf.source('', key), inst.args[0])) | |
166 else: | |
167 val = 'default', val | |
168 if ':' in val[1]: | |
169 val = val[1].split(':', 1) | |
170 self.map[key] = val[0], os.path.join(self.base, val[1]) | |
171 | |
172 def __contains__(self, key): | |
173 return key in self.cache or key in self.map | |
174 | |
175 def load(self, t): | |
176 '''Get the template for the given template name. Use a local cache.''' | |
177 if not t in self.cache: | |
178 try: | |
179 self.cache[t] = open(self.map[t][1]).read() | |
180 except IOError, inst: | |
181 raise IOError(inst.args[0], _('template file %s: %s') % | |
182 (self.map[t][1], inst.args[1])) | |
183 return self.cache[t] | |
184 | |
185 def __call__(self, t, **map): | |
186 ttype = t in self.map and self.map[t][0] or 'default' | |
187 proc = self.engines.get(ttype) | |
188 if proc is None: | |
189 proc = engines[ttype](self.load, self.filters, self.defaults) | |
190 self.engines[ttype] = proc | |
191 | |
192 stream = proc.process(t, map) | |
193 if self.minchunk: | |
194 stream = util.increasingchunks(stream, min=self.minchunk, | |
195 max=self.maxchunk) | |
196 return stream | |
197 | |
198 def templatepath(name=None): | |
199 '''return location of template file or directory (if no name). | |
200 returns None if not found.''' | |
201 normpaths = [] | |
202 | |
203 # executable version (py2exe) doesn't support __file__ | |
204 if hasattr(sys, 'frozen'): | |
205 module = sys.executable | |
206 else: | |
207 module = __file__ | |
208 for f in path: | |
209 if f.startswith('/'): | |
210 p = f | |
211 else: | |
212 fl = f.split('/') | |
213 p = os.path.join(os.path.dirname(module), *fl) | |
214 if name: | |
215 p = os.path.join(p, name) | |
216 if name and os.path.exists(p): | |
217 return os.path.normpath(p) | |
218 elif os.path.isdir(p): | |
219 normpaths.append(os.path.normpath(p)) | |
220 | |
221 return normpaths | |
222 | |
223 def stylemap(style, paths=None): | |
224 """Return path to mapfile for a given style. | |
225 | |
226 Searches mapfile in the following locations: | |
227 1. templatepath/style/map | |
228 2. templatepath/map-style | |
229 3. templatepath/map | |
230 """ | |
231 | |
232 if paths is None: | |
233 paths = templatepath() | |
234 elif isinstance(paths, str): | |
235 paths = [paths] | |
236 | |
237 locations = style and [os.path.join(style, "map"), "map-" + style] or [] | |
238 locations.append("map") | |
239 for path in paths: | |
240 for location in locations: | |
241 mapfile = os.path.join(path, location) | |
242 if os.path.isfile(mapfile): | |
243 return mapfile | |
244 | |
245 raise RuntimeError("No hgweb templates found in %r" % paths) |