mercurial/templater.py
changeset 2189 e3eba577a0ae
parent 2001 a439b7b51530
child 2191 c2e43535d4d1
equal deleted inserted replaced
2188:62ae3d140185 2189:e3eba577a0ae
     6 # of the GNU General Public License, incorporated herein by reference.
     6 # of the GNU General Public License, incorporated herein by reference.
     7 
     7 
     8 import re
     8 import re
     9 from demandload import demandload
     9 from demandload import demandload
    10 from i18n import gettext as _
    10 from i18n import gettext as _
       
    11 from node import *
    11 demandload(globals(), "cStringIO cgi re sys os time urllib util textwrap")
    12 demandload(globals(), "cStringIO cgi re sys os time urllib util textwrap")
    12 
    13 
    13 esctable = {
    14 esctable = {
    14     '\\': '\\',
    15     '\\': '\\',
    15     'r': '\r',
    16     'r': '\r',
   207                 while w > start and text[w-1].isspace(): w -= 1
   208                 while w > start and text[w-1].isspace(): w -= 1
   208                 yield text[start:w], text[w:]
   209                 yield text[start:w], text[w:]
   209                 break
   210                 break
   210             yield text[start:m.start(0)], m.group(1)
   211             yield text[start:m.start(0)], m.group(1)
   211             start = m.end(1)
   212             start = m.end(1)
   212             
   213 
   213     fp = cStringIO.StringIO()
   214     fp = cStringIO.StringIO()
   214     for para, rest in findparas():
   215     for para, rest in findparas():
   215         fp.write(space_re.sub(' ', textwrap.fill(para, width)))
   216         fp.write(space_re.sub(' ', textwrap.fill(para, width)))
   216         fp.write(rest)
   217         fp.write(rest)
   217     return fp.getvalue()
   218     return fp.getvalue()
   239 def email(author):
   240 def email(author):
   240     '''get email of author.'''
   241     '''get email of author.'''
   241     r = author.find('>')
   242     r = author.find('>')
   242     if r == -1: r = None
   243     if r == -1: r = None
   243     return author[author.find('<')+1:r]
   244     return author[author.find('<')+1:r]
   244     
   245 
   245 def person(author):
   246 def person(author):
   246     '''get name of author, or else username.'''
   247     '''get name of author, or else username.'''
   247     f = author.find('<')
   248     f = author.find('<')
   248     if f == -1: return util.shortuser(author)
   249     if f == -1: return util.shortuser(author)
   249     return author[:f].rstrip()
   250     return author[:f].rstrip()
   290     }
   291     }
   291 
   292 
   292 def templatepath(name=None):
   293 def templatepath(name=None):
   293     '''return location of template file or directory (if no name).
   294     '''return location of template file or directory (if no name).
   294     returns None if not found.'''
   295     returns None if not found.'''
       
   296 
   295     # executable version (py2exe) doesn't support __file__
   297     # executable version (py2exe) doesn't support __file__
   296     if hasattr(sys, 'frozen'):
   298     if hasattr(sys, 'frozen'):
   297         module = sys.executable
   299         module = sys.executable
   298     else:
   300     else:
   299         module = __file__
   301         module = __file__
   301         fl = f.split('/')
   303         fl = f.split('/')
   302         if name: fl.append(name)
   304         if name: fl.append(name)
   303         p = os.path.join(os.path.dirname(module), *fl)
   305         p = os.path.join(os.path.dirname(module), *fl)
   304         if (name and os.path.exists(p)) or os.path.isdir(p):
   306         if (name and os.path.exists(p)) or os.path.isdir(p):
   305             return os.path.normpath(p)
   307             return os.path.normpath(p)
       
   308 
       
   309 class changeset_templater(object):
       
   310     '''format changeset information.'''
       
   311 
       
   312     def __init__(self, ui, repo, mapfile, dest=None):
       
   313         self.t = templater(mapfile, common_filters,
       
   314                            cache={'parent': '{rev}:{node|short} ',
       
   315                                   'manifest': '{rev}:{node|short}'})
       
   316         self.ui = ui
       
   317         self.dest = dest
       
   318         self.repo = repo
       
   319 
       
   320     def use_template(self, t):
       
   321         '''set template string to use'''
       
   322         self.t.cache['changeset'] = t
       
   323 
       
   324     def write(self, thing, header=False):
       
   325         '''write expanded template.
       
   326         uses in-order recursive traverse of iterators.'''
       
   327         dest = self.dest or self.ui
       
   328         for t in thing:
       
   329             if hasattr(t, '__iter__'):
       
   330                 self.write(t, header=header)
       
   331             elif header:
       
   332                 dest.write_header(t)
       
   333             else:
       
   334                 dest.write(t)
       
   335 
       
   336     def write_header(self, thing):
       
   337         self.write(thing, header=True)
       
   338 
       
   339     def show(self, rev=0, changenode=None, brinfo=None):
       
   340         '''show a single changeset or file revision'''
       
   341         log = self.repo.changelog
       
   342         if changenode is None:
       
   343             changenode = log.node(rev)
       
   344         elif not rev:
       
   345             rev = log.rev(changenode)
       
   346 
       
   347         changes = log.read(changenode)
       
   348 
       
   349         def showlist(name, values, plural=None, **args):
       
   350             '''expand set of values.
       
   351             name is name of key in template map.
       
   352             values is list of strings or dicts.
       
   353             plural is plural of name, if not simply name + 's'.
       
   354 
       
   355             expansion works like this, given name 'foo'.
       
   356 
       
   357             if values is empty, expand 'no_foos'.
       
   358 
       
   359             if 'foo' not in template map, return values as a string,
       
   360             joined by space.
       
   361 
       
   362             expand 'start_foos'.
       
   363 
       
   364             for each value, expand 'foo'. if 'last_foo' in template
       
   365             map, expand it instead of 'foo' for last key.
       
   366 
       
   367             expand 'end_foos'.
       
   368             '''
       
   369             if plural: names = plural
       
   370             else: names = name + 's'
       
   371             if not values:
       
   372                 noname = 'no_' + names
       
   373                 if noname in self.t:
       
   374                     yield self.t(noname, **args)
       
   375                 return
       
   376             if name not in self.t:
       
   377                 if isinstance(values[0], str):
       
   378                     yield ' '.join(values)
       
   379                 else:
       
   380                     for v in values:
       
   381                         yield dict(v, **args)
       
   382                 return
       
   383             startname = 'start_' + names
       
   384             if startname in self.t:
       
   385                 yield self.t(startname, **args)
       
   386             vargs = args.copy()
       
   387             def one(v, tag=name):
       
   388                 try:
       
   389                     vargs.update(v)
       
   390                 except (AttributeError, ValueError):
       
   391                     try:
       
   392                         for a, b in v:
       
   393                             vargs[a] = b
       
   394                     except ValueError:
       
   395                         vargs[name] = v
       
   396                 return self.t(tag, **vargs)
       
   397             lastname = 'last_' + name
       
   398             if lastname in self.t:
       
   399                 last = values.pop()
       
   400             else:
       
   401                 last = None
       
   402             for v in values:
       
   403                 yield one(v)
       
   404             if last is not None:
       
   405                 yield one(last, tag=lastname)
       
   406             endname = 'end_' + names
       
   407             if endname in self.t:
       
   408                 yield self.t(endname, **args)
       
   409 
       
   410         if brinfo:
       
   411             def showbranches(**args):
       
   412                 if changenode in brinfo:
       
   413                     for x in showlist('branch', brinfo[changenode],
       
   414                                       plural='branches', **args):
       
   415                         yield x
       
   416         else:
       
   417             showbranches = ''
       
   418 
       
   419         if self.ui.debugflag:
       
   420             def showmanifest(**args):
       
   421                 args = args.copy()
       
   422                 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
       
   423                                  node=hex(changes[0])))
       
   424                 yield self.t('manifest', **args)
       
   425         else:
       
   426             showmanifest = ''
       
   427 
       
   428         def showparents(**args):
       
   429             parents = [[('rev', log.rev(p)), ('node', hex(p))]
       
   430                        for p in log.parents(changenode)
       
   431                        if self.ui.debugflag or p != nullid]
       
   432             if (not self.ui.debugflag and len(parents) == 1 and
       
   433                 parents[0][0][1] == rev - 1):
       
   434                 return
       
   435             for x in showlist('parent', parents, **args):
       
   436                 yield x
       
   437 
       
   438         def showtags(**args):
       
   439             for x in showlist('tag', self.repo.nodetags(changenode), **args):
       
   440                 yield x
       
   441 
       
   442         if self.ui.debugflag:
       
   443             files = self.repo.changes(log.parents(changenode)[0], changenode)
       
   444             def showfiles(**args):
       
   445                 for x in showlist('file', files[0], **args): yield x
       
   446             def showadds(**args):
       
   447                 for x in showlist('file_add', files[1], **args): yield x
       
   448             def showdels(**args):
       
   449                 for x in showlist('file_del', files[2], **args): yield x
       
   450         else:
       
   451             def showfiles(**args):
       
   452                 for x in showlist('file', changes[3], **args): yield x
       
   453             showadds = ''
       
   454             showdels = ''
       
   455 
       
   456         props = {
       
   457             'author': changes[1],
       
   458             'branches': showbranches,
       
   459             'date': changes[2],
       
   460             'desc': changes[4],
       
   461             'file_adds': showadds,
       
   462             'file_dels': showdels,
       
   463             'files': showfiles,
       
   464             'manifest': showmanifest,
       
   465             'node': hex(changenode),
       
   466             'parents': showparents,
       
   467             'rev': rev,
       
   468             'tags': showtags,
       
   469             }
       
   470 
       
   471         try:
       
   472             if self.ui.debugflag and 'header_debug' in self.t:
       
   473                 key = 'header_debug'
       
   474             elif self.ui.quiet and 'header_quiet' in self.t:
       
   475                 key = 'header_quiet'
       
   476             elif self.ui.verbose and 'header_verbose' in self.t:
       
   477                 key = 'header_verbose'
       
   478             elif 'header' in self.t:
       
   479                 key = 'header'
       
   480             else:
       
   481                 key = ''
       
   482             if key:
       
   483                 self.write_header(self.t(key, **props))
       
   484             if self.ui.debugflag and 'changeset_debug' in self.t:
       
   485                 key = 'changeset_debug'
       
   486             elif self.ui.quiet and 'changeset_quiet' in self.t:
       
   487                 key = 'changeset_quiet'
       
   488             elif self.ui.verbose and 'changeset_verbose' in self.t:
       
   489                 key = 'changeset_verbose'
       
   490             else:
       
   491                 key = 'changeset'
       
   492             self.write(self.t(key, **props))
       
   493         except KeyError, inst:
       
   494             raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
       
   495                                                            inst.args[0]))
       
   496         except SyntaxError, inst:
       
   497             raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))