Show More
@@ -338,15 +338,20 b' def trimuser(ui, name, rev, revcache):' | |||
|
338 | 338 | return user |
|
339 | 339 | |
|
340 | 340 | class changeset_templater(object): |
|
341 | '''use templater module to format changeset information.''' | |
|
342 | ||
|
341 | 343 | def __init__(self, ui, repo, mapfile): |
|
342 | 344 | self.t = templater.templater(mapfile, templater.common_filters) |
|
343 | 345 | self.ui = ui |
|
344 | 346 | self.repo = repo |
|
345 | 347 | |
|
346 | 348 | def use_template(self, t): |
|
349 | '''set template string to use''' | |
|
347 | 350 | self.t.cache['template'] = t |
|
348 | 351 | |
|
349 | 352 | def write(self, thing): |
|
353 | '''write expanded template. | |
|
354 | uses in-order recursive traverse of iterators.''' | |
|
350 | 355 | for t in thing: |
|
351 | 356 | if hasattr(t, '__iter__'): |
|
352 | 357 | self.write(t) |
@@ -354,7 +359,7 b' class changeset_templater(object):' | |||
|
354 | 359 | self.ui.write(t) |
|
355 | 360 | |
|
356 | 361 | def show(self, rev=0, changenode=None, brinfo=None): |
|
357 |
|
|
|
362 | '''show a single changeset or file revision''' | |
|
358 | 363 | log = self.repo.changelog |
|
359 | 364 | if changenode is None: |
|
360 | 365 | changenode = log.node(rev) |
@@ -364,6 +369,25 b' class changeset_templater(object):' | |||
|
364 | 369 | changes = log.read(changenode) |
|
365 | 370 | |
|
366 | 371 | def showlist(name, values, plural=None, **args): |
|
372 | '''expand set of values. | |
|
373 | name is name of key in template map. | |
|
374 | values is list of strings or dicts. | |
|
375 | plural is plural of name, if not simply name + 's'. | |
|
376 | ||
|
377 | expansion works like this, given name 'foo'. | |
|
378 | ||
|
379 | if values is empty, expand 'no_foos'. | |
|
380 | ||
|
381 | if 'foo' not in template map, return values as a string, | |
|
382 | joined by space. | |
|
383 | ||
|
384 | expand 'start_foos'. | |
|
385 | ||
|
386 | for each value, expand 'foo'. if 'last_foo' in template | |
|
387 | map, expand it instead of 'foo' for last key. | |
|
388 | ||
|
389 | expand 'end_foos'. | |
|
390 | ''' | |
|
367 | 391 | if plural: names = plural |
|
368 | 392 | else: names = name + 's' |
|
369 | 393 | if not values: |
@@ -371,13 +395,13 b' class changeset_templater(object):' | |||
|
371 | 395 | if noname in self.t: |
|
372 | 396 | yield self.t(noname, **args) |
|
373 | 397 | return |
|
374 | vargs = args.copy() | |
|
375 | 398 | if name not in self.t: |
|
376 | 399 | yield ' '.join(values) |
|
377 | 400 | return |
|
378 | 401 | startname = 'start_' + names |
|
379 | 402 | if startname in self.t: |
|
380 | 403 | yield self.t(startname, **args) |
|
404 | vargs = args.copy() | |
|
381 | 405 | def one(v, tag=name): |
|
382 | 406 | try: |
|
383 | 407 | vargs.update(v) |
@@ -464,12 +488,14 b' class changeset_templater(object):' | |||
|
464 | 488 | raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0])) |
|
465 | 489 | |
|
466 | 490 | class changeset_printer(object): |
|
491 | '''show changeset information when templating not requested.''' | |
|
492 | ||
|
467 | 493 | def __init__(self, ui, repo): |
|
468 | 494 | self.ui = ui |
|
469 | 495 | self.repo = repo |
|
470 | 496 | |
|
471 | 497 | def show(self, rev=0, changenode=None, brinfo=None): |
|
472 |
|
|
|
498 | '''show a single changeset or file revision''' | |
|
473 | 499 | log = self.repo.changelog |
|
474 | 500 | if changenode is None: |
|
475 | 501 | changenode = log.node(rev) |
@@ -530,6 +556,9 b' class changeset_printer(object):' | |||
|
530 | 556 | self.ui.status("\n") |
|
531 | 557 | |
|
532 | 558 | def show_changeset(ui, repo, opts): |
|
559 | '''show one changeset. uses template or regular display. caller | |
|
560 | can pass in 'map_file' and 'template' options in opts.''' | |
|
561 | ||
|
533 | 562 | tmpl = opts.get('template') |
|
534 | 563 | if tmpl: |
|
535 | 564 | tmpl = templater.parsestring(tmpl, quoted=False) |
@@ -1,3 +1,10 b'' | |||
|
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 | |
|
6 | # of the GNU General Public License, incorporated herein by reference. | |
|
7 | ||
|
1 | 8 | import re |
|
2 | 9 | from demandload import demandload |
|
3 | 10 | from i18n import gettext as _ |
@@ -12,6 +19,8 b' esctable = {' | |||
|
12 | 19 | } |
|
13 | 20 | |
|
14 | 21 | def parsestring(s, quoted=True): |
|
22 | '''parse a string using simple c-like syntax. | |
|
23 | string must be in quotes if quoted is True.''' | |
|
15 | 24 | fp = cStringIO.StringIO() |
|
16 | 25 | if quoted: |
|
17 | 26 | first = s[0] |
@@ -31,7 +40,30 b' def parsestring(s, quoted=True):' | |||
|
31 | 40 | return fp.getvalue() |
|
32 | 41 | |
|
33 | 42 | class templater(object): |
|
43 | '''template expansion engine. | |
|
44 | ||
|
45 | template expansion works like this. a map file contains key=value | |
|
46 | pairs. if value is quoted, it is treated as string. otherwise, it | |
|
47 | is treated as name of template file. | |
|
48 | ||
|
49 | templater is asked to expand a key in map. it looks up key, and | |
|
50 | looks for atrings like this: {foo}. it expands {foo} by looking up | |
|
51 | foo in map, and substituting it. expansion is recursive: it stops | |
|
52 | when there is no more {foo} to replace. | |
|
53 | ||
|
54 | expansion also allows formatting and filtering. | |
|
55 | ||
|
56 | format uses key to expand each item in list. syntax is | |
|
57 | {key%format}. | |
|
58 | ||
|
59 | filter uses function to transform value. syntax is | |
|
60 | {key|filter1|filter2|...}.''' | |
|
61 | ||
|
34 | 62 | def __init__(self, mapfile, filters={}, defaults={}): |
|
63 | '''set up template engine. | |
|
64 | mapfile is name of file to read map definitions from. | |
|
65 | filters is dict of functions. each transforms a value into another. | |
|
66 | defaults is dict of default map definitions.''' | |
|
35 | 67 | self.mapfile = mapfile or 'template' |
|
36 | 68 | self.cache = {} |
|
37 | 69 | self.map = {} |
@@ -64,6 +96,9 b' class templater(object):' | |||
|
64 | 96 | return key in self.cache |
|
65 | 97 | |
|
66 | 98 | def __call__(self, t, **map): |
|
99 | '''perform expansion. | |
|
100 | t is name of map element to expand. | |
|
101 | map is added elements to use during expansion.''' | |
|
67 | 102 | m = self.defaults.copy() |
|
68 | 103 | m.update(map) |
|
69 | 104 | try: |
@@ -127,7 +162,9 b' agescales = [("second", 1),' | |||
|
127 | 162 | |
|
128 | 163 | agescales.reverse() |
|
129 | 164 | |
|
130 |
def age( |
|
|
165 | def age(date): | |
|
166 | '''turn a (timestamp, tzoff) tuple into an age string.''' | |
|
167 | ||
|
131 | 168 | def plural(t, c): |
|
132 | 169 | if c == 1: |
|
133 | 170 | return t |
@@ -136,7 +173,7 b' def age(x):' | |||
|
136 | 173 | return "%d %s" % (c, plural(t, c)) |
|
137 | 174 | |
|
138 | 175 | now = time.time() |
|
139 |
then = |
|
|
176 | then = date[0] | |
|
140 | 177 | delta = max(1, int(now - then)) |
|
141 | 178 | |
|
142 | 179 | for t, s in agescales: |
@@ -145,15 +182,18 b' def age(x):' | |||
|
145 | 182 | return fmt(t, n) |
|
146 | 183 | |
|
147 | 184 | def isodate(date): |
|
185 | '''turn a (timestamp, tzoff) tuple into an iso 8631 date.''' | |
|
148 | 186 | return util.datestr(date, format='%Y-%m-%d %H:%M') |
|
149 | 187 | |
|
150 | 188 | def nl2br(text): |
|
189 | '''replace raw newlines with xhtml line breaks.''' | |
|
151 | 190 | return text.replace('\n', '<br/>\n') |
|
152 | 191 | |
|
153 | 192 | def obfuscate(text): |
|
154 | 193 | return ''.join(['&#%d;' % ord(c) for c in text]) |
|
155 | 194 | |
|
156 | 195 | def domain(author): |
|
196 | '''get domain of author, or empty string if none.''' | |
|
157 | 197 | f = author.find('@') |
|
158 | 198 | if f == -1: return '' |
|
159 | 199 | author = author[f+1:] |
@@ -162,6 +202,7 b' def domain(author):' | |||
|
162 | 202 | return author |
|
163 | 203 | |
|
164 | 204 | def person(author): |
|
205 | '''get name of author, or else username.''' | |
|
165 | 206 | f = author.find('<') |
|
166 | 207 | if f == -1: return util.shortuser(author) |
|
167 | 208 | return author[:f].rstrip() |
@@ -185,6 +226,8 b' common_filters = {' | |||
|
185 | 226 | } |
|
186 | 227 | |
|
187 | 228 | def templatepath(name=None): |
|
229 | '''return location of template file or directory (if no name). | |
|
230 | returns None if not found.''' | |
|
188 | 231 | for f in 'templates', '../templates': |
|
189 | 232 | fl = f.split('/') |
|
190 | 233 | if name: fl.append(name) |
General Comments 0
You need to be logged in to leave comments.
Login now