comparison en/ch11-template.xml @ 658:b90b024729f1

WIP DocBook snapshot that all compiles. Mirabile dictu!
author Bryan O'Sullivan <bos@serpentine.com>
date Wed, 18 Feb 2009 00:22:09 -0800
parents en/ch11-template.tex@5cd47f721686
children 21c62e09b99f
comparison
equal deleted inserted replaced
657:8631da51309b 658:b90b024729f1
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
2
3 <chapter id="chap:template">
4 <title>Customising the output of Mercurial</title>
5
6 <para>Mercurial provides a powerful mechanism to let you control how
7 it displays information. The mechanism is based on templates.
8 You can use templates to generate specific output for a single
9 command, or to customise the entire appearance of the built-in web
10 interface.</para>
11
12 <sect1 id="sec:style">
13 <title>Using precanned output styles</title>
14
15 <para>Packaged with Mercurial are some output styles that you can
16 use immediately. A style is simply a precanned template that
17 someone wrote and installed somewhere that Mercurial can
18 find.</para>
19
20 <para>Before we take a look at Mercurial's bundled styles, let's
21 review its normal output.</para>
22
23 <para><!-- &interaction.template.simple.normal; --></para>
24
25 <para>This is somewhat informative, but it takes up a lot of
26 space&emdash;five lines of output per changeset. The
27 <literal>compact</literal> style reduces this to three lines,
28 presented in a sparse manner.</para>
29
30 <para><!-- &interaction.template.simple.compact; --></para>
31
32 <para>The <literal>changelog</literal> style hints at the
33 expressive power of Mercurial's templating engine. This style
34 attempts to follow the GNU Project's changelog
35 guidelines<citation>web:changelog</citation>.</para>
36
37 <para><!-- &interaction.template.simple.changelog; --></para>
38
39 <para>You will not be shocked to learn that Mercurial's default
40 output style is named <literal>default</literal>.</para>
41
42 <sect2>
43 <title>Setting a default style</title>
44
45 <para>You can modify the output style that Mercurial will use
46 for every command by editing your <filename role="special">
47 /.hgrc</filename>\ file, naming the style you would prefer
48 to use.</para>
49
50 <programlisting>[ui] style = compact</programlisting>
51
52 <para>If you write a style of your own, you can use it by either
53 providing the path to your style file, or copying your style
54 file into a location where Mercurial can find it (typically
55 the <literal>templates</literal> subdirectory of your
56 Mercurial install directory).</para>
57
58 </sect2>
59 </sect1>
60 <sect1>
61 <title>Commands that support styles and templates</title>
62
63 <para>All of Mercurial's
64 <quote><literal>log</literal>-like</quote> commands let you use
65 styles and templates: <command role="hg-cmd">hg
66 incoming</command>, <command role="hg-cmd">hg log</command>,
67 <command role="hg-cmd">hg outgoing</command>, and <command
68 role="hg-cmd">hg tip</command>.</para>
69
70 <para>As I write this manual, these are so far the only commands
71 that support styles and templates. Since these are the most
72 important commands that need customisable output, there has been
73 little pressure from the Mercurial user community to add style
74 and template support to other commands.</para>
75
76 </sect1>
77 <sect1>
78 <title>The basics of templating</title>
79
80 <para>At its simplest, a Mercurial template is a piece of text.
81 Some of the text never changes, while other parts are
82 <emphasis>expanded</emphasis>, or replaced with new text, when
83 necessary.</para>
84
85 <para>Before we continue, let's look again at a simple example of
86 Mercurial's normal output.</para>
87
88 <para><!-- &interaction.template.simple.normal; --></para>
89
90 <para>Now, let's run the same command, but using a template to
91 change its output.</para>
92
93 <para><!-- &interaction.template.simple.simplest; --></para>
94
95 <para>The example above illustrates the simplest possible
96 template; it's just a piece of static text, printed once for
97 each changeset. The <option
98 role="hg-opt-log">--template</option> option to the <command
99 role="hg-cmd">hg log</command> command tells Mercurial to use
100 the given text as the template when printing each
101 changeset.</para>
102
103 <para>Notice that the template string above ends with the text
104 <quote><literal>\n</literal></quote>. This is an
105 <emphasis>escape sequence</emphasis>, telling Mercurial to print
106 a newline at the end of each template item. If you omit this
107 newline, Mercurial will run each piece of output together. See
108 section <xref linkend="sec:template:escape"/> for more details
109 of escape sequences.</para>
110
111 <para>A template that prints a fixed string of text all the time
112 isn't very useful; let's try something a bit more
113 complex.</para>
114
115 <para><!-- &interaction.template.simple.simplesub; --></para>
116
117 <para>As you can see, the string
118 <quote><literal>{desc}</literal></quote> in the template has
119 been replaced in the output with the description of each
120 changeset. Every time Mercurial finds text enclosed in curly
121 braces (<quote><literal>{</literal></quote> and
122 <quote>\texttt{}}</quote>), it will try to replace the braces
123 and text with the expansion of whatever is inside. To print a
124 literal curly brace, you must escape it, as described in section
125 <xref
126 linkend="sec:template:escape"/>.</para>
127
128 </sect1>
129 <sect1 id="sec:template:keyword">
130 <title>Common template keywords</title>
131
132 <para>You can start writing simple templates immediately using the
133 keywords below.</para>
134
135 <itemizedlist>
136 <listitem><para><literal
137 role="template-keyword">author</literal>: String. The
138 unmodified author of the changeset.</para>
139 </listitem>
140 <listitem><para><literal
141 role="template-keyword">branches</literal>: String. The
142 name of the branch on which the changeset was committed.
143 Will be empty if the branch name was
144 <literal>default</literal>.</para>
145 </listitem>
146 <listitem><para><literal role="template-keyword">date</literal>:
147 Date information. The date when the changeset was
148 committed. This is <emphasis>not</emphasis> human-readable;
149 you must pass it through a filter that will render it
150 appropriately. See section <xref
151 linkend="sec:template:filter"/> for more information
152 on filters. The date is expressed as a pair of numbers. The
153 first number is a Unix UTC timestamp (seconds since January
154 1, 1970); the second is the offset of the committer's
155 timezone from UTC, in seconds.</para>
156 </listitem>
157 <listitem><para><literal role="template-keyword">desc</literal>:
158 String. The text of the changeset description.</para>
159 </listitem>
160 <listitem><para><literal
161 role="template-keyword">files</literal>: List of strings.
162 All files modified, added, or removed by this
163 changeset.</para>
164 </listitem>
165 <listitem><para><literal
166 role="template-keyword">file_adds</literal>: List of
167 strings. Files added by this changeset.</para>
168 </listitem>
169 <listitem><para><literal
170 role="template-keyword">file_dels</literal>: List of
171 strings. Files removed by this changeset.</para>
172 </listitem>
173 <listitem><para><literal role="template-keyword">node</literal>:
174 String. The changeset identification hash, as a
175 40-character hexadecimal string.</para>
176 </listitem>
177 <listitem><para><literal
178 role="template-keyword">parents</literal>: List of
179 strings. The parents of the changeset.</para>
180 </listitem>
181 <listitem><para><literal role="template-keyword">rev</literal>:
182 Integer. The repository-local changeset revision
183 number.</para>
184 </listitem>
185 <listitem><para><literal role="template-keyword">tags</literal>:
186 List of strings. Any tags associated with the
187 changeset.</para>
188 </listitem></itemizedlist>
189
190 <para>A few simple experiments will show us what to expect when we
191 use these keywords; you can see the results below.</para>
192
193 <!-- &interaction.template.simple.keywords; -->
194
195 <para>As we noted above, the date keyword does not produce
196 human-readable output, so we must treat it specially. This
197 involves using a <emphasis>filter</emphasis>, about which more
198 in section <xref
199 linkend="sec:template:filter"/>.</para>
200
201 <para><!-- &interaction.template.simple.datekeyword; --></para>
202
203 </sect1>
204 <sect1 id="sec:template:escape">
205 <title>Escape sequences</title>
206
207 <para>Mercurial's templating engine recognises the most commonly
208 used escape sequences in strings. When it sees a backslash
209 (<quote><literal>\</literal></quote>) character, it looks at the
210 following character and substitutes the two characters with a
211 single replacement, as described below.</para>
212
213 <itemizedlist>
214 <listitem><para><literal>\textbackslash\textbackslash</literal>:
215 Backslash, <quote><literal>\</literal></quote>, ASCII
216 134.</para>
217 </listitem>
218 <listitem><para><literal>\textbackslash n</literal>: Newline,
219 ASCII 12.</para>
220 </listitem>
221 <listitem><para><literal>\textbackslash r</literal>: Carriage
222 return, ASCII 15.</para>
223 </listitem>
224 <listitem><para><literal>\textbackslash t</literal>: Tab, ASCII
225 11.</para>
226 </listitem>
227 <listitem><para><literal>\textbackslash v</literal>: Vertical
228 tab, ASCII 13.</para>
229 </listitem>
230 <listitem><para><literal>\textbackslash {</literal>: Open curly
231 brace, <quote><literal>{</literal></quote>, ASCII
232 173.</para>
233 </listitem>
234 <listitem><para><literal>\textbackslash }</literal>: Close curly
235 brace, <quote><literal>}</literal></quote>, ASCII
236 175.</para>
237 </listitem></itemizedlist>
238
239 <para>As indicated above, if you want the expansion of a template
240 to contain a literal <quote><literal>\</literal></quote>,
241 <quote><literal>{</literal></quote>, or
242 <quote><literal>{</literal></quote> character, you must escape
243 it.</para>
244
245 </sect1>
246 <sect1 id="sec:template:filter">
247 <title>Filtering keywords to change their results</title>
248
249 <para>Some of the results of template expansion are not
250 immediately easy to use. Mercurial lets you specify an optional
251 chain of <emphasis>filters</emphasis> to modify the result of
252 expanding a keyword. You have already seen a common filter,
253 <literal role="template-kw-filt-date">isodate</literal>, in
254 action above, to make a date readable.</para>
255
256 <para>Below is a list of the most commonly used filters that
257 Mercurial supports. While some filters can be applied to any
258 text, others can only be used in specific circumstances. The
259 name of each filter is followed first by an indication of where
260 it can be used, then a description of its effect.</para>
261
262 <itemizedlist>
263 <listitem><para><literal
264 role="template-filter">addbreaks</literal>: Any text. Add
265 an XHTML <quote><literal>&lt;br/&gt;</literal></quote> tag
266 before the end of every line except the last. For example,
267 <quote><literal>foo\nbar</literal></quote> becomes
268 <quote><literal>foo&lt;br/&gt;\nbar</literal></quote>.</para>
269 </listitem>
270 <listitem><para><literal
271 role="template-kw-filt-date">age</literal>: <literal
272 role="template-keyword">date</literal> keyword. Render
273 the age of the date, relative to the current time. Yields a
274 string like <quote><literal>10
275 minutes</literal></quote>.</para>
276 </listitem>
277 <listitem><para><literal
278 role="template-filter">basename</literal>: Any text, but
279 most useful for the <literal
280 role="template-keyword">files</literal> keyword and its
281 relatives. Treat the text as a path, and return the
282 basename. For example,
283 <quote><literal>foo/bar/baz</literal></quote> becomes
284 <quote><literal>baz</literal></quote>.</para>
285 </listitem>
286 <listitem><para><literal
287 role="template-kw-filt-date">date</literal>: <literal
288 role="template-keyword">date</literal> keyword. Render a
289 date in a similar format to the Unix <literal
290 role="template-keyword">date</literal> command, but with
291 timezone included. Yields a string like <quote><literal>Mon
292 Sep 04 15:13:13 2006 -0700</literal></quote>.</para>
293 </listitem>
294 <listitem><para><literal
295 role="template-kw-filt-author">domain</literal>: Any text,
296 but most useful for the <literal
297 role="template-keyword">author</literal> keyword. Finds
298 the first string that looks like an email address, and
299 extract just the domain component. For example,
300 <quote><literal>Bryan O'Sullivan
301 &lt;bos@serpentine.com&gt;</literal></quote> becomes
302 <quote><literal>serpentine.com</literal></quote>.</para>
303 </listitem>
304 <listitem><para><literal
305 role="template-kw-filt-author">email</literal>: Any text,
306 but most useful for the <literal
307 role="template-keyword">author</literal> keyword. Extract
308 the first string that looks like an email address. For
309 example, <quote><literal>Bryan O'Sullivan
310 &lt;bos@serpentine.com&gt;</literal></quote> becomes
311 <quote><literal>bos@serpentine.com</literal></quote>.</para>
312 </listitem>
313 <listitem><para><literal
314 role="template-filter">escape</literal>: Any text.
315 Replace the special XML/XHTML characters
316 <quote><literal>&amp;</literal></quote>,
317 <quote><literal>&lt;</literal></quote> and
318 <quote><literal>&gt;</literal></quote> with XML
319 entities.</para>
320 </listitem>
321 <listitem><para><literal
322 role="template-filter">fill68</literal>: Any text. Wrap
323 the text to fit in 68 columns. This is useful before you
324 pass text through the <literal
325 role="template-filter">tabindent</literal> filter, and
326 still want it to fit in an 80-column fixed-font
327 window.</para>
328 </listitem>
329 <listitem><para><literal
330 role="template-filter">fill76</literal>: Any text. Wrap
331 the text to fit in 76 columns.</para>
332 </listitem>
333 <listitem><para><literal
334 role="template-filter">firstline</literal>: Any text.
335 Yield the first line of text, without any trailing
336 newlines.</para>
337 </listitem>
338 <listitem><para><literal
339 role="template-kw-filt-date">hgdate</literal>: <literal
340 role="template-keyword">date</literal> keyword. Render
341 the date as a pair of readable numbers. Yields a string
342 like <quote><literal>1157407993
343 25200</literal></quote>.</para>
344 </listitem>
345 <listitem><para><literal
346 role="template-kw-filt-date">isodate</literal>: <literal
347 role="template-keyword">date</literal> keyword. Render
348 the date as a text string in ISO 8601 format. Yields a
349 string like <quote><literal>2006-09-04 15:13:13
350 -0700</literal></quote>.</para>
351 </listitem>
352 <listitem><para><literal
353 role="template-filter">obfuscate</literal>: Any text, but
354 most useful for the <literal
355 role="template-keyword">author</literal> keyword. Yield
356 the input text rendered as a sequence of XML entities. This
357 helps to defeat some particularly stupid screen-scraping
358 email harvesting spambots.</para>
359 </listitem>
360 <listitem><para><literal
361 role="template-kw-filt-author">person</literal>: Any text,
362 but most useful for the <literal
363 role="template-keyword">author</literal> keyword. Yield
364 the text before an email address. For example,
365 <quote><literal>Bryan O'Sullivan
366 &lt;bos@serpentine.com&gt;</literal></quote> becomes
367 <quote><literal>Bryan O'Sullivan</literal></quote>.</para>
368 </listitem>
369 <listitem><para><literal
370 role="template-kw-filt-date">rfc822date</literal>:
371 <literal role="template-keyword">date</literal> keyword.
372 Render a date using the same format used in email headers.
373 Yields a string like <quote><literal>Mon, 04 Sep 2006
374 15:13:13 -0700</literal></quote>.</para>
375 </listitem>
376 <listitem><para><literal
377 role="template-kw-filt-node">short</literal>: Changeset
378 hash. Yield the short form of a changeset hash, i.e. a
379 12-character hexadecimal string.</para>
380 </listitem>
381 <listitem><para><literal
382 role="template-kw-filt-date">shortdate</literal>: <literal
383 role="template-keyword">date</literal> keyword. Render
384 the year, month, and day of the date. Yields a string like
385 <quote><literal>2006-09-04</literal></quote>.</para>
386 </listitem>
387 <listitem><para><literal role="template-filter">strip</literal>:
388 Any text. Strip all leading and trailing whitespace from
389 the string.</para>
390 </listitem>
391 <listitem><para><literal
392 role="template-filter">tabindent</literal>: Any text.
393 Yield the text, with every line except the first starting
394 with a tab character.</para>
395 </listitem>
396 <listitem><para><literal
397 role="template-filter">urlescape</literal>: Any text.
398 Escape all characters that are considered
399 <quote>special</quote> by URL parsers. For example,
400 <literal>foo bar</literal> becomes
401 <literal>foo%20bar</literal>.</para>
402 </listitem>
403 <listitem><para><literal
404 role="template-kw-filt-author">user</literal>: Any text,
405 but most useful for the <literal
406 role="template-keyword">author</literal> keyword. Return
407 the <quote>user</quote> portion of an email address. For
408 example, <quote><literal>Bryan O'Sullivan
409 &lt;bos@serpentine.com&gt;</literal></quote> becomes
410 <quote><literal>bos</literal></quote>.</para>
411 </listitem></itemizedlist>
412
413 <!-- &interaction.template.simple.manyfilters; -->
414
415 <note>
416 <para> If you try to apply a filter to a piece of data that it
417 cannot process, Mercurial will fail and print a Python
418 exception. For example, trying to run the output of the
419 <literal role="template-keyword">desc</literal> keyword into
420 the <literal role="template-kw-filt-date">isodate</literal>
421 filter is not a good idea.</para>
422 </note>
423
424 <sect2>
425 <title>Combining filters</title>
426
427 <para>It is easy to combine filters to yield output in the form
428 you would like. The following chain of filters tidies up a
429 description, then makes sure that it fits cleanly into 68
430 columns, then indents it by a further 8 characters (at least
431 on Unix-like systems, where a tab is conventionally 8
432 characters wide).</para>
433
434 <para><!-- &interaction.template.simple.combine; --></para>
435
436 <para>Note the use of <quote><literal>\t</literal></quote> (a
437 tab character) in the template to force the first line to be
438 indented; this is necessary since <literal
439 role="template-keyword">tabindent</literal> indents all
440 lines <emphasis>except</emphasis> the first.</para>
441
442 <para>Keep in mind that the order of filters in a chain is
443 significant. The first filter is applied to the result of the
444 keyword; the second to the result of the first filter; and so
445 on. For example, using <literal>fill68|tabindent</literal>
446 gives very different results from
447 <literal>tabindent|fill68</literal>.</para>
448
449
450 </sect2>
451 </sect1>
452 <sect1>
453 <title>From templates to styles</title>
454
455 <para>A command line template provides a quick and simple way to
456 format some output. Templates can become verbose, though, and
457 it's useful to be able to give a template a name. A style file
458 is a template with a name, stored in a file.</para>
459
460 <para>More than that, using a style file unlocks the power of
461 Mercurial's templating engine in ways that are not possible
462 using the command line <option
463 role="hg-opt-log">--template</option> option.</para>
464
465 <sect2>
466 <title>The simplest of style files</title>
467
468 <para>Our simple style file contains just one line:</para>
469
470 <para><!-- &interaction.template.simple.rev; --></para>
471
472 <para>This tells Mercurial, <quote>if you're printing a
473 changeset, use the text on the right as the
474 template</quote>.</para>
475
476 </sect2>
477 <sect2>
478 <title>Style file syntax</title>
479
480 <para>The syntax rules for a style file are simple.</para>
481
482 <itemizedlist>
483 <listitem><para>The file is processed one line at a
484 time.</para>
485 </listitem>
486 <listitem><para>Leading and trailing white space are
487 ignored.</para>
488 </listitem>
489 <listitem><para>Empty lines are skipped.</para>
490 </listitem>
491 <listitem><para>If a line starts with either of the characters
492 <quote><literal>#</literal></quote> or
493 <quote><literal>;</literal></quote>, the entire line is
494 treated as a comment, and skipped as if empty.</para>
495 </listitem>
496 <listitem><para>A line starts with a keyword. This must start
497 with an alphabetic character or underscore, and can
498 subsequently contain any alphanumeric character or
499 underscore. (In regexp notation, a keyword must match
500 <literal>[A-Za-z_][A-Za-z0-9_]*</literal>.)</para>
501 </listitem>
502 <listitem><para>The next element must be an
503 <quote><literal>=</literal></quote> character, which can
504 be preceded or followed by an arbitrary amount of white
505 space.</para>
506 </listitem>
507 <listitem><para>If the rest of the line starts and ends with
508 matching quote characters (either single or double quote),
509 it is treated as a template body.</para>
510 </listitem>
511 <listitem><para>If the rest of the line <emphasis>does
512 not</emphasis> start with a quote character, it is
513 treated as the name of a file; the contents of this file
514 will be read and used as a template body.</para>
515 </listitem></itemizedlist>
516
517 </sect2>
518 </sect1>
519 <sect1>
520 <title>Style files by example</title>
521
522 <para>To illustrate how to write a style file, we will construct a
523 few by example. Rather than provide a complete style file and
524 walk through it, we'll mirror the usual process of developing a
525 style file by starting with something very simple, and walking
526 through a series of successively more complete examples.</para>
527
528 <sect2>
529 <title>Identifying mistakes in style files</title>
530
531 <para>If Mercurial encounters a problem in a style file you are
532 working on, it prints a terse error message that, once you
533 figure out what it means, is actually quite useful.</para>
534
535 <!-- &interaction.template.svnstyle.syntax.input; -->
536
537 <para>Notice that <filename>broken.style</filename> attempts to
538 define a <literal>changeset</literal> keyword, but forgets to
539 give any content for it. When instructed to use this style
540 file, Mercurial promptly complains.</para>
541
542 <para><!-- &interaction.template.svnstyle.syntax.error;
543 --></para>
544
545 <para>This error message looks intimidating, but it is not too
546 hard to follow.</para>
547
548 <itemizedlist>
549 <listitem><para>The first component is simply Mercurial's way
550 of saying <quote>I am giving up</quote>.</para>
551 <programlisting>___abort___: broken.style:1: parse
552 error</programlisting>
553 </listitem>
554 <listitem><para>Next comes the name of the style file that
555 contains the error.</para>
556 <programlisting>
557 abort: ___broken.style___:1: parse error
558 </programlisting>
559 </listitem>
560 <listitem><para>Following the file name is the line number
561 where the error was encountered.</para>
562 <programlisting>abort: broken.style:___1___: parse
563 error</programlisting>
564 </listitem>
565 <listitem><para>Finally, a description of what went
566 wrong.</para>
567 <programlisting>abort: broken.style:1: ___parse
568 error___</programlisting>
569 </listitem>
570 <listitem><para>The description of the problem is not always
571 clear (as in this case), but even when it is cryptic, it
572 is almost always trivial to visually inspect the offending
573 line in the style file and see what is wrong.</para>
574 </listitem></itemizedlist>
575
576 </sect2>
577 <sect2>
578 <title>Uniquely identifying a repository</title>
579
580 <para>If you would like to be able to identify a Mercurial
581 repository <quote>fairly uniquely</quote> using a short string
582 as an identifier, you can use the first revision in the
583 repository. <!-- &interaction.template.svnstyle.id; --> This
584 is not guaranteed to be unique, but it is nevertheless useful
585 in many cases.</para>
586 <itemizedlist>
587 <listitem><para>It will not work in a completely empty
588 repository, because such a repository does not have a
589 revision zero.</para>
590 </listitem>
591 <listitem><para>Neither will it work in the (extremely rare)
592 case where a repository is a merge of two or more formerly
593 independent repositories, and you still have those
594 repositories around.</para>
595 </listitem></itemizedlist>
596 <para>Here are some uses to which you could put this
597 identifier:</para>
598 <itemizedlist>
599 <listitem><para>As a key into a table for a database that
600 manages repositories on a server.</para>
601 </listitem>
602 <listitem><para>As half of a {<emphasis>repository
603 ID</emphasis>, <emphasis>revision ID</emphasis>} tuple.
604 Save this information away when you run an automated build
605 or other activity, so that you can <quote>replay</quote>
606 the build later if necessary.</para>
607 </listitem></itemizedlist>
608
609 </sect2>
610 <sect2>
611 <title>Mimicking Subversion's output</title>
612
613 <para>Let's try to emulate the default output format used by
614 another revision control tool, Subversion. <!--
615 &interaction.template.svnstyle.short; --></para>
616
617 <para>Since Subversion's output style is fairly simple, it is
618 easy to copy-and-paste a hunk of its output into a file, and
619 replace the text produced above by Subversion with the
620 template values we'd like to see expanded. <!--
621 &interaction.template.svnstyle.template; --></para>
622
623 <para>There are a few small ways in which this template deviates
624 from the output produced by Subversion.</para>
625 <itemizedlist>
626 <listitem><para>Subversion prints a <quote>readable</quote>
627 date (the <quote>\texttt{Wed, 27 Sep 2006}</quote> in the
628 example output above) in parentheses. Mercurial's
629 templating engine does not provide a way to display a date
630 in this format without also printing the time and time
631 zone.</para>
632 </listitem>
633 <listitem><para>We emulate Subversion's printing of
634 <quote>separator</quote> lines full of
635 <quote><literal>-</literal></quote> characters by ending
636 the template with such a line. We use the templating
637 engine's <literal role="template-keyword">header</literal>
638 keyword to print a separator line as the first line of
639 output (see below), thus achieving similar output to
640 Subversion.</para>
641 </listitem>
642 <listitem><para>Subversion's output includes a count in the
643 header of the number of lines in the commit message. We
644 cannot replicate this in Mercurial; the templating engine
645 does not currently provide a filter that counts the number
646 of lines the template generates.</para>
647 </listitem></itemizedlist>
648 <para>It took me no more than a minute or two of work to replace
649 literal text from an example of Subversion's output with some
650 keywords and filters to give the template above. The style
651 file simply refers to the template. <!--
652 &interaction.template.svnstyle.style; --></para>
653
654 <para>We could have included the text of the template file
655 directly in the style file by enclosing it in quotes and
656 replacing the newlines with
657 <quote><literal>\n</literal></quote> sequences, but it would
658 have made the style file too difficult to read. Readability
659 is a good guide when you're trying to decide whether some text
660 belongs in a style file, or in a template file that the style
661 file points to. If the style file will look too big or
662 cluttered if you insert a literal piece of text, drop it into
663 a template instead.</para>
664
665 </sect2>
666 </sect1>
667 </chapter>
668
669 <!--
670 local variables:
671 sgml-parent-document: ("00book.xml" "book" "chapter")
672 end:
673 -->