Theming

The hgweb interface is completely themable. All output is generated from templates, nothing is hardcoded. Here's how it works:

Note that internally in the code, the term "style" may be used, but for the sake of avoiding confusion with other meanings of this word, the term "theme" is used in this document to describe the resources that change the hgweb interface's appearance.

The Map File

The hgweb engine looks up themes in the templates directory, typically residing within the mercurial package when installed, although some operating system distributions may link mercurial/templates to another location (such as /usr/share/mercurial/templates). A theme may have its own directory with a file named map, or it may place a file in the templates directory with a name of the form map-<theme>, and this map file will look something like this:

default = 'shortlog'
mimetype = 'text/html; charset={encoding}'
header = header.tmpl
footer = footer.tmpl
search = search.tmpl
changelog = changelog.tmpl
shortlog = shortlog.tmpl
shortlogentry = shortlogentry.tmpl
naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
...

This maps a template name to either a file (for example, the content for header is found in the header.tmpl file) or a simple quoted string (such as naventry). The latter is used for small templates where a separate file would be awkward.

A theme is simply a separate map file and possibly some additional template files. Mercurial comes with a few themes already, including the default HTML style (called paper), an XML style for Atom and RSS feeds, and a raw theme that allows getting patches and source files as plain text, as well as a gitweb-lookalike theme. In version 1.5 there are also coal, monoblue and spartan themes.

Templates

Each template is simply a file or string with a number of tags of the form {variable} that get replaced with the appropriate text when the template gets processed. For example, here's the template for the tags page in the former default theme:

{header}
<title>{repo}: tags</title>
</head>
<body>

<div class="buttons">
<a href="?cmd=changelog;rev={rev}">changelog</a>
<a href="?cmd=manifest;manifest={manifest};path=/">manifest</a>
</div>

<h2>tags:</h2>

<ul id="tagEntries">
{entries%tagentry}
</ul>

{footer}

Essential Templates

To have a functioning theme, the following templates appear to be necessary:

Page-Level Templates

These templates provide entire pages:

Template

Information

View Type

branches

named branches

per-repository (introduced in recent versions)

changelog

history

per-repository

changeset

log entry view

error

error page

fileannotate

file editors/contributors

per-file

filediff

file changes

per-file

filerevision

file view

per-file

graph

graphical history

per-repository (introduced in recent versions)

index

list of repositories

manifest

files/browse

per-repository

notfound

resource not found page

search

search results page

shortlog

history

per-repository

summary

summary/dashboard page

per-repository

tags

tag definitions

per-repository

Fragments

These templates are used by the page-level templates to complete displayed pages:

Substitutions

Although the above definition of a template would imply that arbitrary substitutions can be defined, in practice only a selection of variables are defined. In the above example, {repo} causes the predefined variable of that name to yield its value such that it is substituted into the output. Similarly, {header} and {footer} respectively cause the contents of the header and footer definitions to be substituted into the output.

It is not currently possible to define arbitrary substitutions in the map file and then reference them in the unconditional form described above. For example, defining the following in the map file...

logo = '<img src="/images/mercurial.png" alt="Mercurial logo" />'

...and then inserting the reference {logo} in a template will not cause the substitution to occur.

Interpolations

Consider the {entries%tagentry} line in the above example. The entries variable is actually a list of variable mappings, and the % syntax instructs the template engine to apply the tagentry format to each of them.

Note that the tagentry definition is successfully referenced here, and its contents applied to each entry in the entries collection, precisely because an interpolation is being performed. Thus, the limitation described above (where an unconditional {tagentry} reference would fail) does not apply here.

Filters

There is also a set of filters that can be applied to replacements, for example:

<title>{repo|escape}: changeset {node|short}</title>

This applies the escape filter to the repo variable and the short filter to the node variable. Multiple filters can be applied to a single variable:

<h2>changeset: {repo|escape|firstline}</h2>

The available filters include:

Creating Your Own Theme

Now that you know how the templates work, creating your own theme is simply a matter of copying the stock map file to map-mytheme, modifying it, and copying any template files you modify.

Selecting a Theme

Themes (known also as styles) can be switched by appending the style=mytheme URL parameter, preceding it with ? or & as appropriate. This should allow you to navigate around the Web interface using the specified theme, although some operations may reset the theme.

To switch the default theme for your repository viewer, add the following to your .hg/hgrc file:

[web]
style = mytheme


CategoryWeb