Tue Oct 28 13:44:36 ARST 2008  Alberto Bertogli <albertito@blitiri.com.ar>
  tagged 1.1
Tue Oct 28 13:43:41 ARST 2008  Alberto Bertogli <albertito@gmail.com>
  * Update my email address
Tue Aug 12 06:50:07 ART 2008  Alexandre Rossi <alexandre.rossi@gmail.com>
  * fix pygments disaligned linenos and code when using windows fonts (pygments>0.7 only)
Tue Oct 14 18:18:42 ART 2008  Alberto Bertogli <albertito@gmail.com>
  tagged 1.1-rc1
Tue Oct 14 18:18:29 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Update HTML version number
Sun Oct  5 12:53:16 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Import pygments only when needed
  
  Otherwise, we pay for the pygments import (which is noticeable) on every
  darcsweb page view.
  
  This follows the lazy module loading that is already being done for other
  costly modules (i.e. 're').
  
Sun Oct  5 12:48:31 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Ignore broken multidir directories
  
  When a multidir directory is not really a directory or a valid symlink to one,
  we want to skip it instead of exploding.
  
  This patch fixes that by doing a simple sanity check while processing the
  configured multidirs.
  
  Thanks to Ralph Giles <giles@ghostscript.com> for the report and the patch.
  
Thu Aug  7 02:31:41 ART 2008  Alexandre Rossi <alexandre.rossi@gmail.com>
  * optional source headblob syntax highlighting using python-pygments
Thu Aug  7 01:41:45 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Handle old date formats
  
  Very old darcs commits use a different time format, that leaks out in some
  operations like annotate. This patch makes darcsweb able to handle it.
  
  Thanks to Simon Michael <simon@joyful.com> for the report and the help.
  
Sun Aug  3 12:04:07 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Fix typo in annotate output
Sun Aug  3 12:03:41 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Simplify annotate code
  
  A very simple change, makes the code more straightforward.
  
Sun Aug  3 12:02:56 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Fix annotate so it works with darcs 2
  
  darcs 2 doesn't like files beginning with / as parameters for annotate. Since
  darcs 1 doesn't care, remove the '/' before running darcs.
  
Sun Aug  3 12:00:34 ART 2008  Alberto Bertogli <albertito@gmail.com>
  * Use _darcs/patches instead of _darcs/inventory
  
  In darcs 2, there is no _darcs/inventory, so use the patches directory to find
  out the last modification time of the repository.
  
  Thanks to Patrick Waugh (ptwaugh@gmail.com) for providing (and testing) this
  fix.
  
Mon Apr  7 21:11:05 ART 2008  Alberto Bertogli <albertito@gmail.com>
  tagged 1.0
diff -rN -u old-darcsweb/darcsweb.cgi new-darcsweb/darcsweb.cgi
--- old-darcsweb/darcsweb.cgi	2008-10-28 13:45:37.000000000 -0200
+++ new-darcsweb/darcsweb.cgi	2008-10-28 13:45:37.000000000 -0200
@@ -2,7 +2,7 @@
 
 """
 darcsweb - A web interface for darcs
-Alberto Bertogli (albertito@gmail.com)
+Alberto Bertogli (albertito@blitiri.com.ar)
 
 Inspired on gitweb (as of 28/Jun/2005), which is written by Kay Sievers
 <kay.sievers@vrfy.org> and Christian Gierke <ch@gierke.de>
@@ -292,6 +292,21 @@
 	lf.close()
 
 
+def parse_darcs_time(s):
+	"Try to convert a darcs' time string into a Python time tuple."
+	try:
+		return time.strptime(s, "%Y%m%d%H%M%S")
+	except ValueError:
+		# very old darcs commits use a different format, for example:
+		# "Wed May 21 19:39:10 CEST 2003"
+		# we can't parse the "CEST" part reliably, so we leave it out
+		fmt = "%a %b %d %H:%M:%S %Y"
+		parts = s.split()
+		ns = ' '.join(parts[0:4]) + ' ' + parts[5]
+		return time.strptime(ns, fmt)
+
+
+
 #
 # generic html functions
 #
@@ -303,8 +318,8 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<!-- darcsweb 1.0
-     Alberto Bertogli (albertito@gmail.com).
+<!-- darcsweb 1.1
+     Alberto Bertogli (albertito@blitiri.com.ar).
 
      Based on gitweb, which is written by Kay Sievers <kay.sievers@vrfy.org>
      and Christian Gierke <ch@gierke.de>
@@ -543,7 +558,7 @@
 			sys.stdout = self
 			return 0
 
-		inv = config.repodir + '/_darcs/inventory'
+		inv = config.repodir + '/_darcs/patches'
 		cache_lastmod = os.stat(fname).st_mtime
 		repo_lastmod = os.stat(inv).st_mtime
 		dw_lastmod = os.stat(sys.argv[0]).st_mtime
@@ -733,8 +748,7 @@
 				au = au[:au.find('<')].strip()
 			p.shortauthor = fixu8(escape(au))
 
-			td = time.strptime(attrs.get('date', None),
-					"%Y%m%d%H%M%S")
+			td = parse_darcs_time(attrs.get('date', None))
 			p.date = time.mktime(td)
 			p.date_str = time.strftime("%a, %d %b %Y %H:%M:%S", td)
 
@@ -994,8 +1008,7 @@
 	lastname = lastname.childNodes[0].wholeText
 	annotate.lastchange_name = fixu8(lastname)
 
-	lastdate = lastpatch.getAttribute("date")
-	lastdate = time.strptime(lastdate, "%Y%m%d%H%M%S")
+	lastdate = parse_darcs_time(lastpatch.getAttribute("date"))
 	annotate.lastchange_date = lastdate
 
 	annotate.patches[annotate.lastchange_hash] = annotate.lastchange_date
@@ -1017,7 +1030,7 @@
 			phash = patch.getAttribute("hash")
 			pauthor = patch.getAttribute("author")
 			pdate = patch.getAttribute("date")
-			pdate = time.strptime(pdate, "%Y%m%d%H%M%S")
+			pdate = parse_darcs_time(pdate)
 		else:
 			# added lines inherit the creation from the annotate
 			# patch
@@ -1050,15 +1063,20 @@
 	return annotate
 
 def get_annotate(fname, hash = None):
+	if config.disable_annotate:
+		return None
+
 	cmd = 'annotate --xml-output'
 	if hash:
 		cmd += ' --match="hash %s"' % hash
+
+	if fname.startswith('/'):
+		# darcs 2 doesn't like files starting with /, and darcs 1
+		# doesn't really care
+		fname = fname[1:]
 	cmd += ' "%s"' % fname
-	if not config.disable_annotate:
-		out = run_darcs(cmd)
-	else:
-		return None
-	return parse_annotate(out)
+
+	return parse_annotate(run_darcs(cmd))
 
 
 
@@ -1244,14 +1262,37 @@
 
 def print_blob(fname):
 	print '<div class="page_path"><b>%s</b></div>' % escape(fname)
-	print '<div class="page_body">'
 	if isbinary(fname):
 		print """
-<i>This is a binary file and it's contents will not be displayed.</i>
+<div class="page_body">
+<i>This is a binary file and its contents will not be displayed.</i>
 </div>
 		"""
 		return
 
+	try:
+		import pygments
+	except ImportError:
+		pygments = False
+
+	if not pygments:
+		print_blob_simple(fname)
+		return
+	else:
+		try:
+			print_blob_highlighted(fname)
+		except ValueError:
+			# pygments couldn't guess a lexer to highlight the code, try
+			# another method with sampling the file contents.
+			try:
+				print_blob_highlighted(fname, sample_code=True)
+			except ValueError:
+				# pygments really could not find any lexer for this file.
+				print_blob_simple(fname)
+
+def print_blob_simple(fname):
+	print '<div class="page_body">'
+
 	f = open(realpath(fname), 'r')
 	count = 1
 	for l in f:
@@ -1271,11 +1312,34 @@
 		count += 1
 	print '</div>'
 
+def print_blob_highlighted(fname, sample_code=False):
+	import pygments
+	import pygments.lexers
+	import pygments.formatters
+
+	code = open(realpath(fname), 'r').read()
+	if sample_code:
+		lexer = pygments.lexers.guess_lexer(code[:200],
+				encoding=config.repoencoding[0])
+	else:
+		lexer = pygments.lexers.guess_lexer_for_filename(fname, code[:200],
+				encoding=config.repoencoding[0])
+
+	pygments_version = map(int, pygments.__version__.split('.'))
+	if pygments_version >= [0, 7]:
+		linenos_method = 'inline'
+	else:
+		linenos_method = True
+	formatter = pygments.formatters.HtmlFormatter(linenos=linenos_method,
+				cssclass='page_body')
+
+	print pygments.highlight(code, lexer, formatter)
+
 def print_annotate(ann, style):
 	print '<div class="page_body">'
 	if isbinary(ann.fname):
 		print """
-<i>This is a binary file and it's contents will not be displayed.</i>
+<i>This is a binary file and its contents will not be displayed.</i>
 </div>
 		"""
 		return
@@ -1931,7 +1995,7 @@
 def do_atom():
 	print "Content-type: application/atom+xml; charset=utf-8\n"
 	print '<?xml version="1.0" encoding="utf-8"?>'
-	inv = config.repodir + '/_darcs/inventory'
+	inv = config.repodir + '/_darcs/patches'
 	repo_lastmod = os.stat(inv).st_mtime
 	str_lastmod = time.strftime(iso_datetime,
 			time.localtime(repo_lastmod))
@@ -2220,6 +2284,9 @@
 		if 'multidir' not in dir(c):
 			continue
 
+		if not os.path.isdir(c.multidir):
+			continue
+
 		if 'exclude' not in dir(c):
 			c.exclude = []
 
diff -rN -u old-darcsweb/README new-darcsweb/README
--- old-darcsweb/README	2008-10-28 13:45:37.000000000 -0200
+++ new-darcsweb/README	2008-10-28 13:45:37.000000000 -0200
@@ -1,7 +1,7 @@
 
 darcsweb - A web interface for darcs
-Alberto Bertogli (albertito@gmail.com)
-----------------------------------------
+Alberto Bertogli (albertito@blitiri.com.ar)
+---------------------------------------------
 
 This is a very simple web interface for darcs, inspired in gitweb (written by
 Kay Sievers and Christian Gierke).
diff -rN -u old-darcsweb/style.css new-darcsweb/style.css
--- old-darcsweb/style.css	2008-10-28 13:45:37.000000000 -0200
+++ new-darcsweb/style.css	2008-10-28 13:45:37.000000000 -0200
@@ -1,6 +1,6 @@
 
 /* darcsweb CSS
- * Alberto Bertogli (albertito@gmail.com)
+ * Alberto Bertogli (albertito@blitiri.com.ar)
  *
  * Copied almost entirely from gitweb's, written by Kay Sievers
  * <kay.sievers@vrfy.org> and Christian Gierke <ch@gierke.de>.
@@ -220,7 +220,7 @@
 	right:12px;
 }
 
-a.linenr {
+a.linenr, .linenos {
 	color:#999999;
 	text-decoration:none;
 }
@@ -262,3 +262,70 @@
 	margin-right:5pt;
 }
 
+
+/* Syntax highlighting related styles. This is highly dependent on what
+ * python-pygments generates.
+ * This was generated using the following commands in a python interpreter and
+ * slightly modified after.
+ * >>> import pygments
+ * >>> pygments.formatters.HtmlFormatter().get_style_defs('.page_body')
+ */
+.page_body table { margin: 0; padding: 0;}
+.page_body pre { margin : 0; padding: 0; }
+.page_body .c { color: #008800; font-style: italic } /* Comment */
+.page_body .err { border: 1px solid #FF0000 } /* Error */
+.page_body .k { color: #AA22FF; font-weight: bold } /* Keyword */
+.page_body .o { color: #666666 } /* Operator */
+.page_body .cm { color: #008800; font-style: italic } /* Comment.Multiline */
+.page_body .cp { color: #008800 } /* Comment.Preproc */
+.page_body .c1 { color: #008800; font-style: italic } /* Comment.Single */
+.page_body .gd { color: #A00000 } /* Generic.Deleted */
+.page_body .ge { font-style: italic } /* Generic.Emph */
+.page_body .gr { color: #FF0000 } /* Generic.Error */
+.page_body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.page_body .gi { color: #00A000 } /* Generic.Inserted */
+.page_body .go { color: #808080 } /* Generic.Output */
+.page_body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.page_body .gs { font-weight: bold } /* Generic.Strong */
+.page_body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.page_body .gt { color: #0040D0 } /* Generic.Traceback */
+.page_body .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */
+.page_body .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */
+.page_body .kp { color: #AA22FF } /* Keyword.Pseudo */
+.page_body .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */
+.page_body .kt { color: #AA22FF; font-weight: bold } /* Keyword.Type */
+.page_body .m { color: #666666 } /* Literal.Number */
+.page_body .s { color: #BB4444 } /* Literal.String */
+.page_body .na { color: #BB4444 } /* Name.Attribute */
+.page_body .nb { color: #AA22FF } /* Name.Builtin */
+.page_body .nc { color: #0000FF } /* Name.Class */
+.page_body .no { color: #880000 } /* Name.Constant */
+.page_body .nd { color: #AA22FF } /* Name.Decorator */
+.page_body .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.page_body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.page_body .nf { color: #00A000 } /* Name.Function */
+.page_body .nl { color: #A0A000 } /* Name.Label */
+.page_body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.page_body .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.page_body .nv { color: #B8860B } /* Name.Variable */
+.page_body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.page_body .mf { color: #666666 } /* Literal.Number.Float */
+.page_body .mh { color: #666666 } /* Literal.Number.Hex */
+.page_body .mi { color: #666666 } /* Literal.Number.Integer */
+.page_body .mo { color: #666666 } /* Literal.Number.Oct */
+.page_body .sb { color: #BB4444 } /* Literal.String.Backtick */
+.page_body .sc { color: #BB4444 } /* Literal.String.Char */
+.page_body .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */
+.page_body .s2 { color: #BB4444 } /* Literal.String.Double */
+.page_body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.page_body .sh { color: #BB4444 } /* Literal.String.Heredoc */
+.page_body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.page_body .sx { color: #008000 } /* Literal.String.Other */
+.page_body .sr { color: #BB6688 } /* Literal.String.Regex */
+.page_body .s1 { color: #BB4444 } /* Literal.String.Single */
+.page_body .ss { color: #B8860B } /* Literal.String.Symbol */
+.page_body .bp { color: #AA22FF } /* Name.Builtin.Pseudo */
+.page_body .vc { color: #B8860B } /* Name.Variable.Class */
+.page_body .vg { color: #B8860B } /* Name.Variable.Global */
+.page_body .vi { color: #B8860B } /* Name.Variable.Instance */
+.page_body .il { color: #666666 } /* Literal.Number.Integer.Long */

