hgbook

view en/ch11-template.xml @ 572:13513d2a128d

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