Prettify the web interface

Add header, footer templates
Add null parent handling
Combine files and directories
Add parity flag for alternating line colors
Add line numbers to filerevision
This commit is contained in:
mpm@selenic.com 2005-05-23 20:57:48 -08:00
parent 12c3bda8c3
commit e4397937b5
14 changed files with 223 additions and 137 deletions

2
hg
View File

@ -463,7 +463,7 @@ elif cmd == "verify":
except Exception, inst:
ui.warn("unpacking manifest %s: %s\n" % (hg.short(n), inst))
errors += 1
ff = [ l.split('\0') for l in delta.splitlines() ]
for f, fn in ff:
filenodes.setdefault(f, {})[hg.bin(fn)] = 1

View File

@ -122,6 +122,10 @@ class hgweb:
if len(files) > self.maxfiles:
yield self.t("fileellipses")
def parent(self, t1, node, rev):
if node != hex(nullid):
yield self.t(t1, node = node, rev = rev)
def diff(self, node1, node2, files):
def filterfiles(list, files):
l = [ x for x in list if x in files ]
@ -169,6 +173,12 @@ class hgweb:
tn = ""
yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
def header(self):
yield self.t("header", repo = self.reponame)
def footer(self):
yield self.t("footer", repo = self.reponame)
def changelog(self, pos=None):
def changenav():
def seq(factor = 1):
@ -191,6 +201,7 @@ class hgweb:
yield self.t("naventry", rev = count - 1)
def changelist():
parity = (start - end) & 1
cl = self.repo.changelog
l = [] # build a list in forward order for efficiency
for i in range(start, end + 1):
@ -202,9 +213,14 @@ class hgweb:
l.insert(0, self.t(
'changelogentry',
parity = parity,
author = obfuscate(changes[1]),
shortdesc = cgi.escape(changes[4].splitlines()[0]),
age = age(t),
parent1 = self.parent("changelogparent",
hex(p1), cl.rev(p1)),
parent2 = self.parent("changelogparent",
hex(p2), cl.rev(p2)),
p1 = hex(p1), p2 = hex(p2),
p1rev = cl.rev(p1), p2rev = cl.rev(p2),
manifest = hex(changes[0]),
@ -213,6 +229,7 @@ class hgweb:
files = self.listfilediffs(changes[3], n),
rev = i,
node = hn))
parity = 1 - parity
yield l
@ -222,8 +239,12 @@ class hgweb:
start = max(0, pos - self.maxchanges)
end = min(count - 1, start + self.maxchanges)
yield self.t('changelog', repo = self.reponame, changenav = changenav,
rev = pos, changesets = count, changelist = changelist)
yield self.t('changelog',
header = self.header(),
footer = self.footer(),
repo = self.reponame,
changenav = changenav,
rev = pos, changesets = count, entries = changelist)
def changeset(self, nodeid):
n = bin(nodeid)
@ -243,10 +264,17 @@ class hgweb:
yield self.diff(p1, n, changes[3])
yield self.t('changeset',
header = self.header(),
footer = self.footer(),
repo = self.reponame,
diff = diff,
rev = cl.rev(n),
node = nodeid,
shortdesc = cgi.escape(changes[4].splitlines()[0]),
parent1 = self.parent("changesetparent",
hex(p1), cl.rev(p1)),
parent2 = self.parent("changesetparent",
hex(p2), cl.rev(p2)),
p1 = hex(p1), p2 = hex(p2),
p1rev = cl.rev(p1), p2rev = cl.rev(p2),
manifest = hex(changes[0]),
@ -262,6 +290,8 @@ class hgweb:
def entries():
l = []
parity = (count - 1) & 1
for i in range(count):
n = fl.node(i)
@ -272,6 +302,7 @@ class hgweb:
t = float(cs[2].split(' ')[0])
l.insert(0, self.t("filelogentry",
parity = parity,
filenode = hex(n),
filerev = i,
file = f,
@ -282,10 +313,14 @@ class hgweb:
shortdesc = cgi.escape(cs[4].splitlines()[0]),
p1 = hex(p1), p2 = hex(p2),
p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
parity = 1 - parity
yield l
yield self.t("filelog",
header = self.header(),
footer = self.footer(),
repo = self.reponame,
file = f,
filenode = filenode,
entries = entries)
@ -301,11 +336,21 @@ class hgweb:
p1, p2 = fl.parents(n)
t = float(cs[2].split(' ')[0])
mfn = cs[0]
def lines():
for l, t in enumerate(text.splitlines(1)):
yield self.t("fileline",
line = t,
linenumber = "% 6d" % (l + 1),
parity = l & 1)
yield self.t("filerevision", file = f,
header = self.header(),
footer = self.footer(),
repo = self.reponame,
filenode = node,
path = up(f),
text = text,
text = lines(),
rev = changerev,
node = hex(cn),
manifest = hex(mfn),
@ -313,6 +358,10 @@ class hgweb:
age = age(t),
date = time.asctime(time.gmtime(t)),
shortdesc = cgi.escape(cs[4].splitlines()[0]),
parent1 = self.parent("filerevparent",
hex(p1), fl.rev(p1)),
parent2 = self.parent("filerevparent",
hex(p2), fl.rev(p2)),
p1 = hex(p1), p2 = hex(p2),
p1rev = fl.rev(p1), p2rev = fl.rev(p2))
@ -332,6 +381,8 @@ class hgweb:
mfn = cs[0]
def annotate():
parity = 1
last = None
for r, l in fl.annotate(n):
try:
cnode = ncache[r]
@ -348,7 +399,12 @@ class hgweb:
name = name[:f]
bcache[r] = name
if last != cnode:
parity = 1 - parity
last = cnode
yield self.t("annotateline",
parity = parity,
node = hex(cnode),
rev = r,
author = name,
@ -356,6 +412,9 @@ class hgweb:
line = cgi.escape(l))
yield self.t("fileannotate",
header = self.header(),
footer = self.footer(),
repo = self.reponame,
file = f,
filenode = node,
annotate = annotate,
@ -367,6 +426,10 @@ class hgweb:
age = age(t),
date = time.asctime(time.gmtime(t)),
shortdesc = cgi.escape(cs[4].splitlines()[0]),
parent1 = self.parent("filerevparent",
hex(p1), fl.rev(p1)),
parent2 = self.parent("filerevparent",
hex(p2), fl.rev(p2)),
p1 = hex(p1), p2 = hex(p2),
p1rev = fl.rev(p1), p2rev = fl.rev(p2))
@ -375,10 +438,8 @@ class hgweb:
rev = self.repo.manifest.rev(bin(mnode))
node = self.repo.changelog.node(rev)
dirs = {}
files = {}
short = {}
p = path[1:]
l = len(p)
@ -388,37 +449,41 @@ class hgweb:
remain = f[l:]
if "/" in remain:
short = remain[:remain.find("/") + 1] # bleah
dirs[short] = 1
files[short] = (f, None)
else:
short = os.path.basename(remain)
files[short] = (f, n)
def dirlist():
dl = dirs.keys()
dl.sort()
for d in dl:
yield self.t("manifestdirentry",
path = os.path.join(path, d),
manifest = mnode, basename = d[:-1])
def filelist():
parity = 0
fl = files.keys()
fl.sort()
for f in fl:
full, fnode = files[f]
yield self.t("manifestfileentry",
file = full, manifest = mnode, filenode = hex(fnode),
basename = f)
if fnode:
yield self.t("manifestfileentry",
file = full,
manifest = mnode,
filenode = hex(fnode),
parity = parity,
basename = f)
else:
yield self.t("manifestdirentry",
parity = parity,
path = os.path.join(path, f),
manifest = mnode, basename = f[:-1])
parity = 1 - parity
yield self.t("manifest",
header = self.header(),
footer = self.footer(),
repo = self.reponame,
manifest = mnode,
rev = rev,
node = hex(node),
path = path,
up = up(path),
dirs = dirlist,
files = filelist)
entries = filelist)
def filediff(self, file, changeset):
n = bin(changeset)
@ -431,6 +496,9 @@ class hgweb:
yield self.diff(p1, n, file)
yield self.t("filediff",
header = self.header(),
footer = self.footer(),
repo = self.reponame,
file = file,
filenode = hex(mf[file]),
node = changeset,
@ -439,12 +507,7 @@ class hgweb:
p1rev = self.repo.changelog.rev(p1),
diff = diff)
# header and footer, css
# add tags to things
# show parents
# diff between rev and parent in changeset and file
# manifest links
# browse at top
# tags -> list of changesets corresponding to tags
# find tag, changeset, file

View File

@ -1,16 +1,13 @@
Content-Type: text/html
<html>
#header#
<title>#repo#: changelog</title>
</head>
<body>
<h2>changelog for #repo#</h2>
navigate: #changenav#<br>
<table>
#changelist#
</table>
#entries#
navigate: #changenav#<br>
</body>
</html>
#footer#

View File

@ -1,26 +1,25 @@
<div class=parity#parity#>
<table width=100% cellpadding=0 cellspacing=0>
<tr>
<td align=right width="15%"><b>#age# ago:</b></td>
<td align=right width="15%"><b>#age# ago:&nbsp;</b></td>
<td><b>#shortdesc#</b></td</tr>
<tr>
<td align=right>revision:</td>
<td align=right>revision:&nbsp;</td>
<td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>
#parent1#
#parent2#
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=changeset;node=#p1#">#p1rev#:#p1#</a></td></tr>
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=changeset;node=#p2#">#p2rev#:#p2#</a></td></tr>
<tr>
<td align=right>manifest:</td>
<td align=right>manifest:&nbsp;</td>
<td><a href="?cmd=manifest;manifest=#manifest#;path=/">#rev#:#manifest#</a></td></tr>
<tr>
<td align=right>author:</td>
<td align=right>author:&nbsp;</td>
<td>#author#</td></tr>
<tr>
<td align=right>date:</td>
<td align=right>date:&nbsp;</td>
<td>#date#</td></tr>
<tr>
<td align=right valign=top>files:</td>
<td align=right valign=top>files:&nbsp;</td>
<td>#files#</td></tr>
</table>
</div>

View File

@ -1,42 +1,39 @@
Content-type: text/html
<html>
#header#
<title>#repo#: changeset #node#</title>
</head>
<body>
<div class=buttons>
<a href="?cmd=changelog&pos=#rev#">changelog</a>
<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
</div>
<h2>changeset: #shortdesc#</h2>
<table>
<tr>
<td align=right>revision:</td>
<td class=metatag>revision:</td>
<td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>
#parent1#
#parent2#
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=changeset;node=#p1#">#p1rev#:#p1#</a></td></tr>
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=changeset;node=#p2#">#p2rev#:#p2#</a></td></tr>
<tr>
<td align=right>manifest:</td>
<td class=metatag>manifest:</td>
<td><a href="?cmd=manifest;manifest=#manifest#;path=/">#rev#:#manifest#</a></td></tr>
<tr>
<td align=right>author:</td>
<td class=metatag>author:</td>
<td>#author#</td></tr>
<tr>
<td align=right>date:</td>
<td class=metatag>date:</td>
<td>#date#</td></tr>
<tr>
<td align=right valign=top>files:</td>
<td class=metatag valign=top>files:</td>
<td>#files#</td></tr>
<tr>
<td align=right valign=top>description:</td>
<td class=metatag valign=top>description:</td>
<td>#desc#</td></tr>
</table>
<hr />
<pre>
<pre class=parity0>
#diff#
</pre>

View File

@ -1,42 +1,39 @@
Content-type: text/html
<html>
#header#
<title>#repo#: #file# annotate</title>
</head>
<body>
<div class=buttons>
<a href="?cmd=changelog&rev=#rev#">changelog</a>
<a href="?cmd=changeset&node=#node#">changeset</a>
<a href="?cmd=manifest&manifest=#manifest#;path=#path#">manifest</a>
<a href="?cmd=file&file=#file#&filenode=#filenode#">file</a>
<a href="?cmd=filelog&file=#file#;filenode=#filenode#">revisions</a>
</div>
<h2>Annotate #file# (#filenode#)</h2>
<table>
<tr>
<td align=right>changeset:</td>
<td class=metatag>changeset:</td>
<td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>
#parent1#
#parent2#
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=file;file=#file#;node=#p1#">#p1rev#:#p1#</a></td></tr>
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=file;file=#file#;node=#p2#">#p2rev#:#p2#</a></td></tr>
<tr>
<td align=right>manifest:</td>
<td class=metatag>manifest:</td>
<td><a href="?cmd=manifest;manifest=#manifest#;path=/">#rev#:#manifest#</a></td></tr>
<tr>
<td align=right>author:</td>
<td class=metatag>author:</td>
<td>#author#</td></tr>
<tr>
<td align=right>date:</td>
<td class=metatag>date:</td>
<td>#date#</td></tr>
</table>
<hr />
<br/>
<table>
<table cellspacing=0 cellpadding=0>
#annotate#
</table>
</body>
</html>
#footer#

View File

@ -1,30 +1,31 @@
Content-type: text/html
<html>
#header#
<title>#repo#: #file# diff</title>
</head>
<body>
<div class=buttons>
<a href="?cmd=changelog&rev=#rev#">changelog</a>
<a href="?cmd=changeset&node=#node#">changeset</a>
<a href="?cmd=file&file=#file#&filenode=#filenode#">file</a>
<a href="?cmd=filelog&file=#file#&filenode=#filenode#">revisions</a>
<a href="?cmd=annotate&file=#file#&filenode=#filenode#">annotate</a>
</div>
<h2>#file#</h2>
<table>
<tr>
<td align=right>revision:</td>
<td class=metatag>revision:</td>
<td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>
<tr>
<td align=right>parent:</td>
<td class=metatag>parent:</td>
<td><a href="?cmd=changeset;node=#p1#">#p1rev#:#p1#</a></td></tr>
</table>
<hr />
<pre>
<pre class=parity0>
#diff#
</pre>
</body>
</html
#footer#

View File

@ -1,17 +1,16 @@
Content-type: text/html
<html>
#header#
<title>#repo#: #file# history</title>
</head>
<body>
<div class=buttons>
<a href="?cmd=changelog">changelog</a>
<a href="?cmd=file&file=#file#&filenode=#filenode#">file</a>
<a href="?cmd=annotate&file=#file#&filenode=#filenode#">annotate</a>
</div>
<h2>#file# revision history</h2>
<table>
#entries#
</table>
</body>
</html>
#footer#

View File

@ -1,18 +1,19 @@
<table class=parity#parity# width=100% cellspacing=0 cellpadding=0>
<tr>
<td align=right width="15%"><b>#age# ago:</b></td>
<td><b><a href="?cmd=changeset;node=#changeset#">#shortdesc#</a></b></td</tr>
<td align=right width="15%"><b>#age# ago:&nbsp;</b></td>
<td><b><a href="?cmd=changeset;node=#node#">#shortdesc#</a></b></td</tr>
<tr>
<td align=right>revision:</td>
<td align=right>revision:&nbsp;</td>
<td><a href="?cmd=file;file=#file#;filenode=#filenode#">#filerev#:#filenode#</a>
<a href="?cmd=filediff;file=#file#;node=#node#">(diff)</a>
<a href="?cmd=annotate;file=#file#;filenode=#filenode#">(annotate)</a>
</td></tr>
<tr>
<td align=right>author:</td>
<td align=right>author:&nbsp;</td>
<td>#author#</td></tr>
<tr>
<td align=right>date:</td>
<td align=right>date:&nbsp;</td>
<td>#date#</td></tr>
</table>

View File

@ -1,42 +1,37 @@
Content-type: text/html
<html>
#header#
<title>#repo#:#file#</title>
</head>
<body>
<div class=buttons>
<a href="?cmd=changelog&rev=#rev#">changelog</a>
<a href="?cmd=changeset&node=#node#">changeset</a>
<a href="?cmd=manifest&manifest=#manifest#;path=#path#">manifest</a>
<a href="?cmd=filelog&file=#file#;filenode=#filenode#">revisions</a>
<a href="?cmd=annotate&file=#file#&filenode=#filenode#">annotate</a>
</div>
<h2>#file# (revision #filenode#)</h2>
<table>
<tr>
<td align=right>changeset:</td>
<td class=metatag>changeset:</td>
<td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>
#parent1#
#parent2#
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=file;file=#file#;node=#p1#">#p1rev#:#p1#</a></td></tr>
<tr>
<td align=right>parent:</td>
<td><a href="?cmd=file;file=#file#;node=#p2#">#p2rev#:#p2#</a></td></tr>
<tr>
<td align=right>manifest:</td>
<td class=metatag>manifest:</td>
<td><a href="?cmd=manifest;manifest=#manifest#;path=/">#rev#:#manifest#</a></td></tr>
<tr>
<td align=right>author:</td>
<td class=metatag>author:</td>
<td>#author#</td></tr>
<tr>
<td align=right>date:</td>
<td class=metatag>date:</td>
<td>#date#</td></tr>
</table>
<hr />
<pre>
#text#
</pre>
</body>
</html>
#footer#

2
templates/footer.tmpl Normal file
View File

@ -0,0 +1,2 @@
</body>
</html>

31
templates/header.tmpl Normal file
View File

@ -0,0 +1,31 @@
Content-type: text/html
<html>
<head>
</head>
<style type="text/css">
a { text-decoration:none; }
.parity0 { background-color: #eeeeee; }
.parity1 { background-color: #ffffff; }
.lineno { width: 60px; color: #cccccc; font-size: smaller; }
.plusline { color: green; }
.minusline { color: red; }
.atline { color: purple; }
.annotate { font-size: smaller; text-align: right; padding-right: 1em; }
.buttons a {
background-color: #666666;
padding: 2pt;
color: white;
font-family: sans;
font-weight: bold;
}
.metatag {
background-color: #888888;
color: white;
text-align: right;
}
</style>
</head>
<body>

View File

@ -1,19 +1,16 @@
Content-Type: text/html
<html>
#header#
<title>#repo#: manifest #manifest#</title>
</head>
<body>
<div class=buttons>
<a href="?cmd=changelog&rev=#rev#">changelog</a>
<a href="?cmd=changeset&node=#node#">changeset</a>
</div>
<h2>manifest: #path#</h2>
<p>(#rev#:#manifest#)</p>
<p>
<a href="?cmd=manifest;manifest=#manifest#;path=#up#">[up]</a><br />
#dirs#</p>
<div class=parity1><a href="?cmd=manifest;manifest=#manifest#;path=#up#">[up]</a><br /></div>
#entries#
<p>#files#</p>
</body>
</html>
#footer#

View File

@ -1,3 +1,5 @@
header = header.tmpl
footer = footer.tmpl
changelog = changelog.tmpl
naventry = "<a href="?cmd=changelog;pos=#rev#">#rev#</a> "
filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#">#file#</a> "
@ -6,15 +8,20 @@ fileellipses = "..."
changelogentry = changelogentry.tmpl
changeset = changeset.tmpl
manifest = manifest.tmpl
manifestdirentry = "<a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a><br />"
manifestfileentry = "<a href="?cmd=file;filenode=#filenode#;file=#file#">#basename#</a><br /> "
manifestdirentry = "<div class=parity#parity#><a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a><br /></div>"
manifestfileentry = "<div class=parity#parity#><a href="?cmd=file;filenode=#filenode#;file=#file#">#basename#</a><br /></div>"
filerevision = filerevision.tmpl
fileannotate = fileannotate.tmpl
filediff = filediff.tmpl
filelog = filelog.tmpl
fileline = "<div class=parity#parity#><span class=lineno>#linenumber# </span>#line#</div>"
filelogentry = filelogentry.tmpl
annotateline = "<tr><td align = right><a href="?cmd=changeset;node=#node#">#author#@#rev#</a>:</td><td><pre>#line#</pre></td></tr>"
annotateline = "<tr class=parity#parity#><td class=annotate><a href="?cmd=changeset;node=#node#">#author#@#rev#</a></td><td><pre>#line#</pre></td></tr>"
difflineplus = "<span class=plusline>#line#</span>"
difflineminus = "<span class=minusline>#line#</span>"
difflineat = "<span class=atline>#line#</span>"
diffline = "#line#"
diffline = "#line#"
changelogparent = "<tr><td align=right>parent:&nbsp;</td><td><a href="?cmd=changeset;node=#node">#rev#:#node#</a></td></tr>"
changesetparent = "<tr><td class=metatag>parent:</td><td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>"
filerevparent = "<tr><td class=metatag>parent:</td><td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>"
fileannotateparent = "<tr><td class=metatag>parent:</td><td><a href="?cmd=changeset;node=#node#">#rev#:#node#</a></td></tr>"