add changelog style to command line template.
authorVadim Gelfer <vadim.gelfer@gmail.com>
Tue, 21 Mar 2006 23:29:21 -0800
changeset 1987 04c17fc39c84
parent 1985 c577689006fa
child 1988 18a3e6369600
add changelog style to command line template. to use, "hg log --style=changelog". makes different output with no flags, -q, -v, --debug. templater module has new template filters for this. email - committer email address fill68 - refill text to 68 colums fill76 - refill text to 76 colums tabindent - prefix every not empty line with tab shortdate - iso 8631 date, no time zone stringify - turn template iterator into string
mercurial/templater.py
mercurial/util.py
templates/map-cmdline.changelog
--- a/mercurial/templater.py	Tue Mar 21 15:33:29 2006 +0100
+++ b/mercurial/templater.py	Tue Mar 21 23:29:21 2006 -0800
@@ -8,7 +8,7 @@
 import re
 from demandload import demandload
 from i18n import gettext as _
-demandload(globals(), "cStringIO cgi sys os time urllib util")
+demandload(globals(), "cStringIO cgi re sys os time urllib util textwrap")
 
 esctable = {
     '\\': '\\',
@@ -181,8 +181,43 @@
         if n >= 2 or s == 1:
             return fmt(t, n)
 
+def stringify(thing):
+    '''turn nested template iterator into string.'''
+    cs = cStringIO.StringIO()
+    def walk(things):
+        for t in things:
+            if hasattr(t, '__iter__'):
+                walk(t)
+            else:
+                cs.write(t)
+    walk(thing)
+    return cs.getvalue()
+
+para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
+space_re = re.compile(r'  +')
+
+def fill(text, width):
+    '''fill many paragraphs.'''
+    def findparas():
+        start = 0
+        while True:
+            m = para_re.search(text, start)
+            if not m:
+                w = len(text)
+                while w > start and text[w-1].isspace(): w -= 1
+                yield text[start:w], text[w:]
+                break
+            yield text[start:m.start(0)], m.group(1)
+            start = m.end(1)
+            
+    fp = cStringIO.StringIO()
+    for para, rest in findparas():
+        fp.write(space_re.sub(' ', textwrap.fill(para, width)))
+        fp.write(rest)
+    return fp.getvalue()
+
 def isodate(date):
-    '''turn a (timestamp, tzoff) tuple into an iso 8631 date.'''
+    '''turn a (timestamp, tzoff) tuple into an iso 8631 date and time.'''
     return util.datestr(date, format='%Y-%m-%d %H:%M')
 
 def nl2br(text):
@@ -201,25 +236,54 @@
     if f >= 0: author = author[:f]
     return author
 
+def email(author):
+    '''get email of author.'''
+    r = author.find('>')
+    if r == -1: r = None
+    return author[author.find('<')+1:r]
+    
 def person(author):
     '''get name of author, or else username.'''
     f = author.find('<')
     if f == -1: return util.shortuser(author)
     return author[:f].rstrip()
 
+def shortdate(date):
+    '''turn (timestamp, tzoff) tuple into iso 8631 date.'''
+    return util.datestr(date, format='%Y-%m-%d', timezone=False)
+
+def indent(text, prefix):
+    '''indent each non-empty line of text after first with prefix.'''
+    fp = cStringIO.StringIO()
+    lines = text.splitlines()
+    num_lines = len(lines)
+    for i in xrange(num_lines):
+        l = lines[i]
+        if i and l.strip(): fp.write(prefix)
+        fp.write(l)
+        if i < num_lines - 1 or text.endswith('\n'):
+            fp.write('\n')
+    return fp.getvalue()
+
 common_filters = {
     "addbreaks": nl2br,
     "age": age,
     "date": lambda x: util.datestr(x),
     "domain": domain,
+    "email": email,
     "escape": lambda x: cgi.escape(x, True),
+    "fill68": lambda x: fill(x, width=68),
+    "fill76": lambda x: fill(x, width=76),
     "firstline": lambda x: x.splitlines(1)[0].rstrip('\r\n'),
+    "tabindent": lambda x: indent(x, '\t'),
     "isodate": isodate,
     "obfuscate": obfuscate,
     "permissions": lambda x: x and "-rwxr-xr-x" or "-rw-r--r--",
     "person": person,
     "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
     "short": lambda x: x[:12],
+    "shortdate": shortdate,
+    "stringify": stringify,
     "strip": lambda x: x.strip(),
     "urlescape": lambda x: urllib.quote(x),
     "user": lambda x: util.shortuser(x),
--- a/mercurial/util.py	Tue Mar 21 15:33:29 2006 +0100
+++ b/mercurial/util.py	Tue Mar 21 23:29:21 2006 -0800
@@ -744,15 +744,16 @@
         tz = time.timezone
     return time.mktime(lt), tz
 
-def datestr(date=None, format='%a %b %d %H:%M:%S %Y'):
+def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
     """represent a (unixtime, offset) tuple as a localized time.
     unixtime is seconds since the epoch, and offset is the time zone's
-    number of seconds away from UTC."""
+    number of seconds away from UTC. if timezone is false, do not
+    append time zone to string."""
     t, tz = date or makedate()
-    return ("%s %+03d%02d" %
-            (time.strftime(format, time.gmtime(float(t) - tz)),
-             -tz / 3600,
-             ((-tz % 3600) / 60)))
+    s = time.strftime(format, time.gmtime(float(t) - tz))
+    if timezone:
+        s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
+    return s
 
 def shortuser(user):
     """Return a short representation of a user name or email address."""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/map-cmdline.changelog	Tue Mar 21 23:29:21 2006 -0800
@@ -0,0 +1,15 @@
+changeset = '{date|shortdate}  {author|person}  <{author|email}>  ({node|short}{tags})\n\n\t* {files|stringify|fill68|tabindent}{desc|fill68|tabindent|strip}\n\n'
+changeset_quiet = '{date|shortdate}  {author|person}  <{author|email}>\n\n\t* {desc|firstline|fill68|tabindent|strip}\n\n'
+changeset_verbose = '{date|isodate}  {author|person}  <{author|email}>  ({node|short}{tags})\n\n\t* {file_adds|stringify|fill68|tabindent}{file_dels|stringify|fill68|tabindent}{files|stringify|fill68|tabindent}{desc|fill68|tabindent|strip}\n\n'
+start_tags = ' ['
+tag = '{tag}, '
+last_tag = '{tag}]'
+start_files = '('
+file = '{file}, '
+last_file = '{file}):\n\t'
+start_file_adds = '('
+file_add = '{file_add}, '
+last_file_add = '{file_add}): new file.\n* '
+start_file_dels = '('
+file_del = '{file_del}, '
+last_file_del = '{file_del}): deleted file.\n* '