bos@559: bos@559: bos@559: bos@572: bos@559: Customising the output of Mercurial bos@559: bos@584: Mercurial provides a powerful mechanism to let you control how bos@559: it displays information. The mechanism is based on templates. bos@559: You can use templates to generate specific output for a single bos@559: command, or to customise the entire appearance of the built-in web bos@559: interface. bos@559: bos@559: bos@559: Using precanned output styles bos@559: bos@584: Packaged with Mercurial are some output styles that you can bos@559: use immediately. A style is simply a precanned template that bos@559: someone wrote and installed somewhere that Mercurial can bos@559: find. bos@559: bos@584: Before we take a look at Mercurial's bundled styles, let's bos@559: review its normal output. bos@559: bos@567: &interaction.template.simple.normal; bos@559: bos@584: This is somewhat informative, but it takes up a lot of bos@559: space&emdash;five lines of output per changeset. The bos@559: compact style reduces this to three lines, bos@559: presented in a sparse manner. bos@559: bos@567: &interaction.template.simple.compact; bos@559: bos@584: The changelog style hints at the bos@559: expressive power of Mercurial's templating engine. This style bos@559: attempts to follow the GNU Project's changelog bos@559: guidelinesweb:changelog. bos@559: bos@567: &interaction.template.simple.changelog; bos@559: bos@584: You will not be shocked to learn that Mercurial's default bos@559: output style is named default. bos@559: bos@559: bos@559: Setting a default style bos@559: bos@584: You can modify the output style that Mercurial will use bos@580: for every command by editing your ~/.hgrc file, naming the style bos@580: you would prefer to use. bos@580: bos@580: [ui] bos@580: style = compact bos@559: bos@584: If you write a style of your own, you can use it by either bos@559: providing the path to your style file, or copying your style bos@559: file into a location where Mercurial can find it (typically bos@559: the templates subdirectory of your bos@559: Mercurial install directory). bos@559: bos@559: bos@559: bos@559: bos@559: Commands that support styles and templates bos@559: bos@584: All of Mercurial's bos@559: log-like commands let you use bos@559: styles and templates: hg bos@559: incoming, hg log, bos@559: hg outgoing, and hg tip. bos@559: bos@584: As I write this manual, these are so far the only commands bos@559: that support styles and templates. Since these are the most bos@559: important commands that need customisable output, there has been bos@559: little pressure from the Mercurial user community to add style bos@559: and template support to other commands. bos@559: bos@559: bos@559: bos@559: The basics of templating bos@559: bos@584: At its simplest, a Mercurial template is a piece of text. bos@559: Some of the text never changes, while other parts are bos@559: expanded, or replaced with new text, when bos@559: necessary. bos@559: bos@584: Before we continue, let's look again at a simple example of bos@559: Mercurial's normal output. bos@559: bos@567: &interaction.template.simple.normal; bos@559: bos@584: Now, let's run the same command, but using a template to bos@559: change its output. bos@559: bos@567: &interaction.template.simple.simplest; bos@559: bos@584: The example above illustrates the simplest possible bos@559: template; it's just a piece of static text, printed once for bos@559: each changeset. The option to the hg log command tells Mercurial to use bos@559: the given text as the template when printing each bos@559: changeset. bos@559: bos@584: Notice that the template string above ends with the text bos@559: \n. This is an bos@559: escape sequence, telling Mercurial to print bos@559: a newline at the end of each template item. If you omit this bos@559: newline, Mercurial will run each piece of output together. See bos@592: for more details bos@559: of escape sequences. bos@559: bos@584: A template that prints a fixed string of text all the time bos@559: isn't very useful; let's try something a bit more bos@559: complex. bos@559: bos@567: &interaction.template.simple.simplesub; bos@559: bos@584: As you can see, the string bos@559: {desc} in the template has bos@559: been replaced in the output with the description of each bos@559: changeset. Every time Mercurial finds text enclosed in curly bos@559: braces ({ and bos@592: }), it will try to replace the bos@592: braces and text with the expansion of whatever is inside. To bos@592: print a literal curly brace, you must escape it, as described in bos@592: . bos@559: bos@559: bos@559: bos@559: Common template keywords bos@559: bos@584: You can start writing simple templates immediately using the bos@559: keywords below. bos@559: bos@559: bos@584: author: String. The bos@559: unmodified author of the changeset. bos@559: bos@584: branches: String. The bos@559: name of the branch on which the changeset was committed. bos@559: Will be empty if the branch name was bos@559: default. bos@559: bos@584: date: bos@559: Date information. The date when the changeset was bos@559: committed. This is not human-readable; bos@559: you must pass it through a filter that will render it bos@592: appropriately. See for more information bos@559: on filters. The date is expressed as a pair of numbers. The bos@559: first number is a Unix UTC timestamp (seconds since January bos@559: 1, 1970); the second is the offset of the committer's bos@559: timezone from UTC, in seconds. bos@559: bos@584: desc: bos@559: String. The text of the changeset description. bos@559: bos@584: files: List of strings. bos@559: All files modified, added, or removed by this bos@559: changeset. bos@559: bos@584: file_adds: List of bos@559: strings. Files added by this changeset. bos@559: bos@584: file_dels: List of bos@559: strings. Files removed by this changeset. bos@559: bos@584: node: bos@559: String. The changeset identification hash, as a bos@559: 40-character hexadecimal string. bos@559: bos@584: parents: List of bos@559: strings. The parents of the changeset. bos@559: bos@584: rev: bos@559: Integer. The repository-local changeset revision bos@559: number. bos@559: bos@584: tags: bos@559: List of strings. Any tags associated with the bos@559: changeset. bos@559: bos@559: bos@584: A few simple experiments will show us what to expect when we bos@559: use these keywords; you can see the results below. bos@559: bos@567: &interaction.template.simple.keywords; bos@559: bos@584: As we noted above, the date keyword does not produce bos@559: human-readable output, so we must treat it specially. This bos@559: involves using a filter, about which more bos@592: in . bos@559: bos@567: &interaction.template.simple.datekeyword; bos@559: bos@559: bos@559: bos@559: Escape sequences bos@559: bos@584: Mercurial's templating engine recognises the most commonly bos@559: used escape sequences in strings. When it sees a backslash bos@559: (\) character, it looks at the bos@559: following character and substitutes the two characters with a bos@559: single replacement, as described below. bos@559: bos@559: bos@584: \: bos@559: Backslash, \, ASCII bos@559: 134. bos@559: bos@584: \n: Newline, bos@559: ASCII 12. bos@559: bos@584: \r: Carriage bos@559: return, ASCII 15. bos@559: bos@584: \t: Tab, ASCII bos@559: 11. bos@559: bos@584: \v: Vertical bos@559: tab, ASCII 13. bos@559: bos@584: {: Open curly bos@559: brace, {, ASCII bos@559: 173. bos@559: bos@584: }: Close curly bos@559: brace, }, ASCII bos@559: 175. bos@559: bos@559: bos@584: As indicated above, if you want the expansion of a template bos@559: to contain a literal \, bos@559: {, or bos@559: { character, you must escape bos@559: it. bos@559: bos@559: bos@559: bos@559: Filtering keywords to change their results bos@559: bos@584: Some of the results of template expansion are not bos@559: immediately easy to use. Mercurial lets you specify an optional bos@559: chain of filters to modify the result of bos@559: expanding a keyword. You have already seen a common filter, bos@559: isodate, in bos@559: action above, to make a date readable. bos@559: bos@584: Below is a list of the most commonly used filters that bos@559: Mercurial supports. While some filters can be applied to any bos@559: text, others can only be used in specific circumstances. The bos@559: name of each filter is followed first by an indication of where bos@559: it can be used, then a description of its effect. bos@559: bos@559: bos@584: addbreaks: Any text. Add bos@559: an XHTML <br/> tag bos@559: before the end of every line except the last. For example, bos@559: foo\nbar becomes bos@559: foo<br/>\nbar. bos@559: bos@584: age: date keyword. Render bos@559: the age of the date, relative to the current time. Yields a bos@559: string like 10 bos@559: minutes. bos@559: bos@584: basename: Any text, but bos@559: most useful for the files keyword and its bos@559: relatives. Treat the text as a path, and return the bos@559: basename. For example, bos@559: foo/bar/baz becomes bos@559: baz. bos@559: bos@584: date: date keyword. Render a bos@559: date in a similar format to the Unix date command, but with bos@559: timezone included. Yields a string like Mon bos@559: Sep 04 15:13:13 2006 -0700. bos@559: bos@584: domain: Any text, bos@559: but most useful for the author keyword. Finds bos@559: the first string that looks like an email address, and bos@559: extract just the domain component. For example, bos@559: Bryan O'Sullivan bos@559: <bos@serpentine.com> becomes bos@559: serpentine.com. bos@559: bos@584: email: Any text, bos@559: but most useful for the author keyword. Extract bos@559: the first string that looks like an email address. For bos@559: example, Bryan O'Sullivan bos@559: <bos@serpentine.com> becomes bos@559: bos@serpentine.com. bos@559: bos@584: escape: Any text. bos@559: Replace the special XML/XHTML characters bos@559: &, bos@559: < and bos@559: > with XML bos@559: entities. bos@559: bos@584: fill68: Any text. Wrap bos@559: the text to fit in 68 columns. This is useful before you bos@559: pass text through the tabindent filter, and bos@559: still want it to fit in an 80-column fixed-font bos@559: window. bos@559: bos@584: fill76: Any text. Wrap bos@559: the text to fit in 76 columns. bos@559: bos@584: firstline: Any text. bos@559: Yield the first line of text, without any trailing bos@559: newlines. bos@559: bos@584: hgdate: date keyword. Render bos@559: the date as a pair of readable numbers. Yields a string bos@559: like 1157407993 bos@559: 25200. bos@559: bos@584: isodate: date keyword. Render bos@559: the date as a text string in ISO 8601 format. Yields a bos@559: string like 2006-09-04 15:13:13 bos@559: -0700. bos@559: bos@584: obfuscate: Any text, but bos@559: most useful for the author keyword. Yield bos@559: the input text rendered as a sequence of XML entities. This bos@559: helps to defeat some particularly stupid screen-scraping bos@559: email harvesting spambots. bos@559: bos@584: person: Any text, bos@559: but most useful for the author keyword. Yield bos@559: the text before an email address. For example, bos@559: Bryan O'Sullivan bos@559: <bos@serpentine.com> becomes bos@559: Bryan O'Sullivan. bos@559: bos@584: rfc822date: bos@559: date keyword. bos@559: Render a date using the same format used in email headers. bos@559: Yields a string like Mon, 04 Sep 2006 bos@559: 15:13:13 -0700. bos@559: bos@584: short: Changeset bos@559: hash. Yield the short form of a changeset hash, i.e. a bos@559: 12-character hexadecimal string. bos@559: bos@584: shortdate: date keyword. Render bos@559: the year, month, and day of the date. Yields a string like bos@559: 2006-09-04. bos@559: bos@584: strip: bos@559: Any text. Strip all leading and trailing whitespace from bos@559: the string. bos@559: bos@584: tabindent: Any text. bos@559: Yield the text, with every line except the first starting bos@559: with a tab character. bos@559: bos@584: urlescape: Any text. bos@559: Escape all characters that are considered bos@559: special by URL parsers. For example, bos@559: foo bar becomes bos@559: foo%20bar. bos@559: bos@584: user: Any text, bos@559: but most useful for the author keyword. Return bos@559: the user portion of an email address. For bos@559: example, Bryan O'Sullivan bos@559: <bos@serpentine.com> becomes bos@559: bos. bos@559: bos@559: bos@567: &interaction.template.simple.manyfilters; bos@559: bos@559: bos@584: If you try to apply a filter to a piece of data that it bos@559: cannot process, Mercurial will fail and print a Python bos@559: exception. For example, trying to run the output of the bos@559: desc keyword into bos@559: the isodate bos@559: filter is not a good idea. bos@559: bos@559: bos@559: bos@559: Combining filters bos@559: bos@584: It is easy to combine filters to yield output in the form bos@559: you would like. The following chain of filters tidies up a bos@559: description, then makes sure that it fits cleanly into 68 bos@559: columns, then indents it by a further 8 characters (at least bos@559: on Unix-like systems, where a tab is conventionally 8 bos@559: characters wide). bos@559: bos@567: &interaction.template.simple.combine; bos@559: bos@584: Note the use of \t (a bos@559: tab character) in the template to force the first line to be bos@559: indented; this is necessary since tabindent indents all bos@559: lines except the first. bos@559: bos@584: Keep in mind that the order of filters in a chain is bos@559: significant. The first filter is applied to the result of the bos@559: keyword; the second to the result of the first filter; and so bos@559: on. For example, using fill68|tabindent bos@559: gives very different results from bos@559: tabindent|fill68. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: From templates to styles bos@559: bos@584: A command line template provides a quick and simple way to bos@559: format some output. Templates can become verbose, though, and bos@559: it's useful to be able to give a template a name. A style file bos@559: is a template with a name, stored in a file. bos@559: bos@584: More than that, using a style file unlocks the power of bos@559: Mercurial's templating engine in ways that are not possible bos@559: using the command line option. bos@559: bos@559: bos@559: The simplest of style files bos@559: bos@584: Our simple style file contains just one line: bos@559: bos@567: &interaction.template.simple.rev; bos@559: bos@584: This tells Mercurial, if you're printing a bos@559: changeset, use the text on the right as the bos@559: template. bos@559: bos@559: bos@559: bos@559: Style file syntax bos@559: bos@584: The syntax rules for a style file are simple. bos@559: bos@559: bos@584: The file is processed one line at a bos@559: time. bos@559: bos@584: Leading and trailing white space are bos@559: ignored. bos@559: bos@584: Empty lines are skipped. bos@584: bos@584: If a line starts with either of the characters bos@559: # or bos@559: ;, the entire line is bos@559: treated as a comment, and skipped as if empty. bos@559: bos@584: A line starts with a keyword. This must start bos@559: with an alphabetic character or underscore, and can bos@559: subsequently contain any alphanumeric character or bos@559: underscore. (In regexp notation, a keyword must match bos@559: [A-Za-z_][A-Za-z0-9_]*.) bos@559: bos@584: The next element must be an bos@559: = character, which can bos@559: be preceded or followed by an arbitrary amount of white bos@559: space. bos@559: bos@584: If the rest of the line starts and ends with bos@559: matching quote characters (either single or double quote), bos@559: it is treated as a template body. bos@559: bos@584: If the rest of the line does bos@559: not start with a quote character, it is bos@559: treated as the name of a file; the contents of this file bos@559: will be read and used as a template body. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: Style files by example bos@559: bos@584: To illustrate how to write a style file, we will construct a bos@559: few by example. Rather than provide a complete style file and bos@559: walk through it, we'll mirror the usual process of developing a bos@559: style file by starting with something very simple, and walking bos@559: through a series of successively more complete examples. bos@559: bos@559: bos@559: Identifying mistakes in style files bos@559: bos@584: If Mercurial encounters a problem in a style file you are bos@559: working on, it prints a terse error message that, once you bos@559: figure out what it means, is actually quite useful. bos@559: bos@567: &interaction.template.svnstyle.syntax.input; bos@559: bos@584: Notice that broken.style attempts to bos@559: define a changeset keyword, but forgets to bos@559: give any content for it. When instructed to use this style bos@559: file, Mercurial promptly complains. bos@559: bos@567: &interaction.template.svnstyle.syntax.error; bos@559: bos@584: This error message looks intimidating, but it is not too bos@559: hard to follow. bos@559: bos@559: bos@584: The first component is simply Mercurial's way bos@559: of saying I am giving up. bos@580: ___abort___: broken.style:1: parse error bos@559: bos@584: Next comes the name of the style file that bos@559: contains the error. bos@580: abort: ___broken.style___:1: parse error bos@559: bos@584: Following the file name is the line number bos@559: where the error was encountered. bos@580: abort: broken.style:___1___: parse error bos@559: bos@584: Finally, a description of what went bos@559: wrong. bos@580: abort: broken.style:1: ___parse error___ bos@559: bos@584: The description of the problem is not always bos@559: clear (as in this case), but even when it is cryptic, it bos@559: is almost always trivial to visually inspect the offending bos@559: line in the style file and see what is wrong. bos@559: bos@559: bos@559: bos@559: bos@559: Uniquely identifying a repository bos@559: bos@584: If you would like to be able to identify a Mercurial bos@559: repository fairly uniquely using a short string bos@559: as an identifier, you can use the first revision in the bos@567: repository. bos@567: bos@567: &interaction.template.svnstyle.id; bos@567: bos@584: This is not guaranteed to be unique, but it is bos@567: nevertheless useful in many cases. bos@559: bos@584: It will not work in a completely empty bos@559: repository, because such a repository does not have a bos@559: revision zero. bos@559: bos@584: Neither will it work in the (extremely rare) bos@559: case where a repository is a merge of two or more formerly bos@559: independent repositories, and you still have those bos@559: repositories around. bos@559: bos@584: Here are some uses to which you could put this bos@559: identifier: bos@559: bos@584: As a key into a table for a database that bos@559: manages repositories on a server. bos@559: bos@584: As half of a {repository bos@559: ID, revision ID} tuple. bos@559: Save this information away when you run an automated build bos@559: or other activity, so that you can replay bos@559: the build later if necessary. bos@559: bos@559: bos@559: bos@559: bos@559: Mimicking Subversion's output bos@559: bos@584: Let's try to emulate the default output format used by bos@567: another revision control tool, Subversion. bos@567: bos@567: &interaction.template.svnstyle.short; bos@559: bos@584: Since Subversion's output style is fairly simple, it is bos@559: easy to copy-and-paste a hunk of its output into a file, and bos@559: replace the text produced above by Subversion with the bos@567: template values we'd like to see expanded. bos@567: bos@567: &interaction.template.svnstyle.template; bos@559: bos@584: There are a few small ways in which this template deviates bos@559: from the output produced by Subversion. bos@559: bos@584: Subversion prints a readable ori@561: date (the Wed, 27 Sep 2006 in the bos@559: example output above) in parentheses. Mercurial's bos@559: templating engine does not provide a way to display a date bos@559: in this format without also printing the time and time bos@559: zone. bos@559: bos@584: We emulate Subversion's printing of bos@559: separator lines full of bos@559: - characters by ending bos@559: the template with such a line. We use the templating bos@559: engine's header bos@559: keyword to print a separator line as the first line of bos@559: output (see below), thus achieving similar output to bos@559: Subversion. bos@559: bos@584: Subversion's output includes a count in the bos@559: header of the number of lines in the commit message. We bos@559: cannot replicate this in Mercurial; the templating engine bos@559: does not currently provide a filter that counts the number bos@559: of lines the template generates. bos@559: bos@584: It took me no more than a minute or two of work to replace bos@559: literal text from an example of Subversion's output with some bos@559: keywords and filters to give the template above. The style bos@567: file simply refers to the template. bos@567: bos@567: &interaction.template.svnstyle.style; bos@559: bos@584: We could have included the text of the template file bos@559: directly in the style file by enclosing it in quotes and bos@559: replacing the newlines with bos@559: \n sequences, but it would bos@559: have made the style file too difficult to read. Readability bos@559: is a good guide when you're trying to decide whether some text bos@559: belongs in a style file, or in a template file that the style bos@559: file points to. If the style file will look too big or bos@559: cluttered if you insert a literal piece of text, drop it into bos@559: a template instead. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: