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). It is possible to set the location of the templates directory using the templates setting in the web section of an hgrc file such as /etc/mercurial/hgrc or the .hgrc file in the Web server user's home directory.

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 = shortlog.tmpl
shortlog = shortlog.tmpl
shortlogentry = shortlogentry.tmpl

naventry = '<a href="{url|urlescape}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 the content for naventry in the above example). 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 HTML themes already: paper (the default), gitweb, coal, monoblue and spartan. There are also templates that present data in some easy to use formats: an XML style for Atom and RSS feeds, a JSON style, and a raw theme that allows getting patches and source files as plain text.

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 a simplified version of the template for the tags page in the spartan theme:

{header}
<title>{repo|escape}: tags</title>
<link rel="alternate" type="application/atom+xml"
   href="{url|urlescape}atom-tags" title="Atom feed for {repo|escape}: tags">
<link rel="alternate" type="application/rss+xml"
   href="{url|urlescape}rss-tags" title="RSS feed for {repo|escape}: tags">
</head>
<body>

<div class="buttons">
<a href="{url|urlescape}log{sessionvars%urlparameter}">changelog</a>
<a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a>
<a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a>
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a>
<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a>
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<a type="application/rss+xml" href="{url|urlescape}rss-tags">rss</a>
<a type="application/atom+xml" href="{url|urlescape}atom-tags">atom</a>
</div>

<h2><a href="/">Mercurial</a> {pathdef%breadcrumb} / tags</h2>

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

{footer}

There are four main kinds of template operations in the above example:

Here, we define a fragment as a template defined in the map file that contributes to another template by providing a region of the final document, page or response.

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

bookmarks

bookmarks

per-repository

branches

named branches

per-repository

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

help

command/topic reference

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

The mercurial.hgweb.webcommands module contains a list of the supported commands in its __all__ attribute; the templates above correspond to many of these commands.

Fragments

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

Fragment

Purpose

Data Type

header

page header

special substitution without data

footer

page footer

special substitution without data

mimetype

content/media type

special substitution without data

diffblock

lines in a diff

(lines, parity)

filedifflink

link to diff

(node, file)

fileellipses

... or similar

special substitution without data

filenolink

reference to file

(node, file, parity)

filenodelink

link to file

(node, file, parity)

searchentry

search result

shortlogentry

tagentry

tag details (summary)

(node, tag, date, parity)

Data Types

/!\ Always refer to the actual command in mercurial.hgweb.webcommands for the exact available variables, this section is not generated from source code and may be out-of-date.

The following data types or structures are available to various templates and fragments:

Data Type

Members

annotate (fileannotate)

parity, rev, node, author, desc, file, targetline, line, lineid, linenumber

archives (index)

node, url, type, extension

bookmarks (summary)

parity, node, date, bookmark

branches (summary)

parity, node, date, branch

changeset

rev, node, author, desc, date, tags, branches, inbranch, parent, child, files, diff, branch, changesettag, changesetbranch, archives

entries (changelog)

parity, rev, node, author, desc, date, tags, branches, inbranch, parent, child, files, changelogtag

entries (filelog)

parity, filerev, node, author, desc, date, tags, branches, inbranch, parent, child, branch, rename, file

entries (index)

parity, contact, contact_sort, name, name_sort, url, description, description_sort, lastchange, lastchange_sort, archives

entries (search)

template of entries (changelog)

fileannotate

rev, node, author, desc, date, parent, child, branch, rename, file, annotate, permissions

filediff

rev, node, author, desc, date, parent, child, branch, rename, file, diff

manifest

rev, node, tags, branches, inbranch, archives, path, up, upparity, dentries, fentries

shortlog (summary)

template of shortlogentry

shortlogentry

parity, rev, node, author, desc, date, tags, branches, inbranch

Source: mercurial.hgweb.webcommands; in addition, the mercurial.hgweb.hgwebdir_mod module provides the hgwebdir.makeindex method which defines the data used to present the navigable index of repositories.

Note that some data types yield collections of templates, not values. Such templates are thus directly substituted into other templates. See also the selection of tag and branch representations below.

Tags and Branches

Data Type Member

Description

bookmarks (except summary)

list containing dictionaries mapping "name" to each bookmark name

branches (except summary)

list containing at most one dictionary mapping "name" to the branch name

inbranch

list containing at most one dictionary mapping "name" to the branch name

tag

tag name

tags

list containing dictionaries mapping "name" to each tag name

Inclusion and Substitutions

Although the above definition of a template ({variable} gets replaced with some text) would imply that arbitrary substitutions can be defined, in practice some limitations apply:

See the filters section below for a description of how filters can be applied to substitutions.

Limitations of Inclusion

It is not currently possible to define arbitrary substitutions in the map file and then reference them as if they were simple variables (like {url} or {repo|escape}). 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 following example:

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

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. The members in each variable mapping are given above in the fragments and data types tables.

Note that the tagentry template (or fragment) is successfully referenced here, and its contents used to format 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 when substituting values into templates, 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: {desc|strip|escape|firstline|nonempty}</h2>

The available filters include:

Name

Description

Example

Example Output

addbreaks

insert <br> tags for newlines

escape

escape text as HTML

obfuscate

disguise email addresses

person

Remove email address from user name

urlparameter

escape text for use in URL parameters

xmlescape

escape text as XML

Dates/Times

age

print a date in x days ago format

{date|age}

15 hours ago

date

print a date in default format

{date|date}

Mon Mar 29 15:16:05 2010 -0500

localdate

print a date in the local timezone

{date|localdate|rfc822date}

Mon, 29 Mar 2010 21:16:05 +0100

isodate

print a date in ISO 8601 format

{date|isodate}

2010-03-29 15:16 -0500

rfc822date

print a date in rfc822 format

{date|rfc822date}

Mon, 29 Mar 2010 15:16:05 -0500

rfc3339date

print a date in rfc3339 format

{date|rfc3339date}

2010-03-29T15:16:05-05:00

shortdate

print a date in short format

{date|shortdate}

2010-03-29

Formatting

firstline

print the first line of a multiline string

permissions

convert a permission code to ls-style formatting

short

print node ids in short form

{i} This table is not exhaustive, refer to templates for the full list.

Functions

Functions are a bit like filters but are used when parameterisation of an operation is required. For example, here's the strip function in use, removing line endings from a file's contents:

<span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>

In contrast, here's the strip filter being used on a description, removing all leading and trailing whitespace:

<div class="description">{desc|strip|escape|websub|nonempty}</div>

Given the potential for parameterisation, some more complicated functions are supported. For example, the if function can be used to decide which text shall be substituted according to some condition:

{if(isdirectory, '', '<a href="{url|urlescape}atom-log" title="subscribe to repository atom feed">Atom</a>')}

In the above example, used in the context of an index entry appearing in the summary view, if the entry has the isdirectory property, an empty string is substituted into the resulting output, otherwise a hyperlink to an Atom feed for the repository is substituted.

Functions were introduced in Mercurial 2.4 and are therefore not available to themes running on older versions.

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. If you only need some minor corrections to other themes, you have these options:

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

Theming (last edited 2016-09-22 13:13:04 by AntonShestakov)