Differences between revisions 3 and 17 (spanning 14 versions)
Revision 3 as of 2006-08-19 20:24:47
Size: 3114
Editor: jsipek
Comment:
Revision 17 as of 2010-10-11 15:47:08
Size: 11131
Editor: PaulBoddie
Comment: Added data type details, changed the example template, and reworded some of the explanations.
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Theming =
Line 4: Line 6:
{{{#!wiki note
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.
}}}

<<TableOfContents>>
Line 6: Line 14:
The hgweb engine looks up templates in a file named templates/map (or templates/map-<style> if a style is specified). It looks something like this:

{{{
default = "changelog"
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}'
Line 14: Line 23:
naventry = "<a href="?cmd=changelog;rev=#rev#">#label#</a> "
filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#">#file#</a> "
filenodelink = "<a href="?cmd=file;filenode=#filenode#;file=#file#">#file#</a> "
shortlog = shortlog.tmpl
shortlogentry = shortlogentry.tmpl
naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
Line 20: Line 29:
This maps a template name to either a file (for example 'header' is found in header.tmpl) or a simple quoted string (eg naventry). The latter is used for small templates where a separate file would be awkward.

A style is simply a separate map file and possibly some additional template files. Mercurial comes with a few styles already, including the default HTML style, an XML style for RSS feeds, and a 'raw' style that allows getting patches and source files as plain text, as well as a gitweb-lookalike style
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.
Line 26: Line 35:
Each template is simply a file or string with a number of tags of the form #variable# (or {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 default theme:

{{{
#header#
<title>#repo#: tags</title>
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>
Line 35: Line 44:
<a href="?cmd=changelog;rev=#rev#">changelog</a>
<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
<a href="{url}log{sessionvars%urlparameter}">changelog</a>
<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
<a href="{url}graph{sessionvars%urlparameter}">graph</a>
<a href="{url}branches{sessionvars%urlparameter}">branches</a>
<a href="{url}file/{node|short}/{sessionvars%urlparameter}">files</a>
Line 42: Line 54:
#entries%tagentry# {entries%tagentry}
Line 45: Line 57:
#footer#
}}}
{footer}
}}}

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

 * The ''inclusion'' of a fragment `{header}` which brings in text from another location
 * The ''substitution'' of a variable `{url}` which replaces the variable name with a proper value
 * The substitution of a variable which is then processed or ''filtered'', so that `{repo|escape}` replaces the variable name `repo` with a value that has been processed by the `escape` function
 * The ''interpolation'' `{entries%tagentry}` of values in a collection `entries` using a fragment `tagentry` which brings in text that will be processed according to each set of values

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''' ||
|| 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:

|| '''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'' ||
|| filenodelink || link to file || (`node`, `file`, `parity`) ||
|| searchentry || search result || shortlogentry ||
|| tagentry || tag details (summary) || (`node`, `tag`, `date`, `parity`) ||

==== Data Types ====

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` ||
|| changeset || `rev`, `node`, `author`, `desc`, `date`, `tags`, `branches`, `inbranch`, `parent`, `child`, `files`, `diff`, `branch`, `changesettag`, `changesetbranch`, `archives` ||
|| entries (search, 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` ||
|| 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` ||
|| shortlogentry || `parity`, `rev`, `node`, `author`, `desc`, `date`, `tags`, `branches`, `inbranch` ||

Source: `mercurial.hgweb.webcommands`

== 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:

 * Only fragments listed above as providing ''special substitution without data'' can be incorporated into a template or fragment using a simple inclusion or substitution
   * For example: `{header}`
   * See the note below about the limitations of inclusion
 * Thus, all other fragments must be used in ''interpolation'' operations, as described below
 * Only a selection of variables is defined for each template or fragment
   * For example: `{url}`
   * See the fragments and data types tables above for some guidance

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.
Line 50: Line 151:
Note the {{{#entries%tagentry#}}} line above. 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. Consider the `{entries%tagentry}` line in the example given above. 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` 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.
Line 57: Line 160:
<title>#repo|escape#: changeset #node|short#</title>
}}}

This applies the 'escape' filter to the 'desc' variable and the 'short' filter to the node variable.
<title>{repo|escape}: changeset {node|short}</title>
}}}

This applies the `escape` filter to the `repo` variable and the `short` filter to the `node` variable.
Line 64: Line 167:
<h2>changeset: #desc|escape|firstline#</h2> <h2>changeset: {repo|escape|firstline}</h2>
Line 69: Line 172:
 * escape: escape HTML
 * age: print a date in 'x days ago' format
 * date: print a date in default format
 * rfc822date: print a date in rfc822 format
 * addbreaks: insert <br> tags for newlines
 * obfuscate: disguise email addresses
 * short: print node ids in short form
 * firstline: print the first line of a multiline string
 * permissions: convert a permission code to ls-style formatting

== 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. Then you can add the following to your .hg/hgrc file:
 * `escape`: escape HTML
 * `age`: print a date in 'x days ago' format (e.g. {{{{date|age} }}}gives {{{15 hours ago}}})
 * `date`: print a date in default format (e.g. {{{{date|date} }}}gives {{{Mon Mar 29 15:16:05 2010 -0500}}})
 * `rfc822date`: print a date in rfc822 format (e.g. {{{{date|rfc822date} }}}gives {{{Mon, 29 Mar 2010 15:16:05 -0500}}})
 * `rfc3339date`: print a date in rfc3339 format (e.g. {{{{date|rfc3339date} }}}gives {{{2010-03-29T15:16:05-05:00}}})
 * `localdate`: print a date in the local timezone (e.g. {{{{date|localdate|rfc822date} }}}gives {{{Mon, 29 Mar 2010 21:16:05 +0100}}})
 * `shortdate`: print a date in short format (e.g. {{{{date|shortdate} }}}gives {{{2010-03-29}}})
 * `addbreaks`: insert <br> tags for newlines
 * `obfuscate`: disguise email addresses
 * `short`: print node ids in short form
 * `firstline`: print the first line of a multiline string
 * `permissions`: convert a permission code to ls-style formatting

== 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:
Line 87: Line 199:

----
CategoryWeb

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

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

<div class="buttons">
<a href="{url}log{sessionvars%urlparameter}">changelog</a>
<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
<a href="{url}graph{sessionvars%urlparameter}">graph</a>
<a href="{url}branches{sessionvars%urlparameter}">branches</a>
<a href="{url}file/{node|short}/{sessionvars%urlparameter}">files</a>
</div>

<h2>tags:</h2>

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

{footer}

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

  • The inclusion of a fragment {header} which brings in text from another location

  • The substitution of a variable {url} which replaces the variable name with a proper value

  • The substitution of a variable which is then processed or filtered, so that {repo|escape} replaces the variable name repo with a value that has been processed by the escape function

  • The interpolation {entries%tagentry} of values in a collection entries using a fragment tagentry which brings in text that will be processed according to each set of values

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

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:

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

filenodelink

link to file

(node, file, parity)

searchentry

search result

shortlogentry

tagentry

tag details (summary)

(node, tag, date, parity)

Data Types

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

changeset

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

entries (search, 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

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

shortlogentry

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

Source: mercurial.hgweb.webcommands

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:

  • Only fragments listed above as providing special substitution without data can be incorporated into a template or fragment using a simple inclusion or substitution

    • For example: {header}

    • See the note below about the limitations of inclusion
  • Thus, all other fragments must be used in interpolation operations, as described below

  • Only a selection of variables is defined for each template or fragment
    • For example: {url}

    • See the fragments and data types tables above for some guidance

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 example given above. 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 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:

  • escape: escape HTML

  • age: print a date in 'x days ago' format (e.g. {date|age} gives 15 hours ago)

  • date: print a date in default format (e.g. {date|date} gives Mon Mar 29 15:16:05 2010 -0500)

  • rfc822date: print a date in rfc822 format (e.g. {date|rfc822date} gives Mon, 29 Mar 2010 15:16:05 -0500)

  • rfc3339date: print a date in rfc3339 format (e.g. {date|rfc3339date} gives 2010-03-29T15:16:05-05:00)

  • localdate: print a date in the local timezone (e.g. {date|localdate|rfc822date} gives Mon, 29 Mar 2010 21:16:05 +0100)

  • shortdate: print a date in short format (e.g. {date|shortdate} gives 2010-03-29)

  • addbreaks: insert <br> tags for newlines

  • obfuscate: disguise email addresses

  • short: print node ids in short form

  • firstline: print the first line of a multiline string

  • permissions: convert a permission code to ls-style formatting

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

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