• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<xsl:stylesheet version="1.0"
2xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
4xmlns:dc="http://purl.org/dc/elements/1.1/"
5xmlns:dcq="http://purl.org/dc/qualifiers/1.0/"
6xmlns:fo="http://www.w3.org/1999/XSL/Format"
7xmlns:fn="http://www.w3.org/2005/xpath-functions">
8  <xsl:output method="html"/>
9  <!-- Set to 1 to show explanations by default.  Set to 0 to hide them -->
10  <xsl:variable name="show_explanation_default" select="0" />
11  <!-- The characters within the Webdings font that show the triangles -->
12  <xsl:variable name="show_button_text" select="'&#x25B6;'" />
13  <xsl:variable name="hide_button_text" select="'&#x25BD;'" />
14  <!-- The suffix for names -->
15  <xsl:variable name="button_suffix" select="'__button'"/>
16  <xsl:variable name="body_suffix" select="'__body'"/>
17  <!-- For easy reference, the name of the button -->
18  <xsl:variable name="show_hide_all_button" select="'show_hide_all_button'"/>
19
20  <!-- The top-level element -->
21  <xsl:template match="GUIDE">
22      <HTML>
23          <HEAD>
24              <TITLE><xsl:value-of select="@title"/></TITLE>
25              <META http-equiv="Content-Type" content="text/html; charset=utf-8"/>
26              <LINK HREF="https://www.google.com/favicon.ico" type="image/x-icon"
27                    rel="shortcut icon"/>
28              <LINK HREF="styleguide.css"
29                    type="text/css" rel="stylesheet"/>
30
31              <SCRIPT language="javascript" type="text/javascript">
32
33                function GetElementsByName(name) {
34                  // Workaround a bug on old versions of opera.
35                  if (document.getElementsByName) {
36                    return document.getElementsByName(name);
37                  } else {
38                    return [document.getElementById(name)];
39                  }
40                }
41
42                /**
43                 * @param {string} namePrefix The prefix of the body name.
44                 * @param {function(boolean): boolean} getVisibility Computes the new
45                 *     visibility state, given the current one.
46                 */
47                function ChangeVisibility(namePrefix, getVisibility) {
48                  var bodyName = namePrefix + '<xsl:value-of select="$body_suffix"/>';
49                  var buttonName = namePrefix + '<xsl:value-of select="$button_suffix"/>';
50                  var bodyElements = GetElementsByName(bodyName);
51                  var linkElement = GetElementsByName('link-' + buttonName)[0];
52                  if (bodyElements.length != 1) {
53                    throw Error('ShowHideByName() got the wrong number of bodyElements:  ' +
54                        bodyElements.length);
55                  } else {
56                    var bodyElement = bodyElements[0];
57                    var buttonElement = GetElementsByName(buttonName)[0];
58                    var isVisible = bodyElement.style.display != "none";
59                    if (getVisibility(isVisible)) {
60                      bodyElement.style.display = "inline";
61                      linkElement.style.display = "block";
62                      buttonElement.innerHTML = '<xsl:value-of select="$hide_button_text"/>';
63                    } else {
64                      bodyElement.style.display = "none";
65                      linkElement.style.display = "none";
66                      buttonElement.innerHTML = '<xsl:value-of select="$show_button_text"/>';
67                    }
68                  }
69                }
70
71                function ShowHideByName(namePrefix) {
72                  ChangeVisibility(namePrefix, function(old) { return !old; });
73                }
74
75                function ShowByName(namePrefix) {
76                  ChangeVisibility(namePrefix, function() { return true; });
77                }
78
79                function ShowHideAll() {
80                  var allButton = GetElementsByName("show_hide_all_button")[0];
81                  if (allButton.innerHTML == '<xsl:value-of select="$hide_button_text"/>') {
82                    allButton.innerHTML = '<xsl:value-of select="$show_button_text"/>';
83                    SetHiddenState(document.getElementsByTagName("body")[0].childNodes, "none", '<xsl:value-of select="$show_button_text"/>');
84                  } else {
85                    allButton.innerHTML = '<xsl:value-of select="$hide_button_text"/>';
86                    SetHiddenState(document.getElementsByTagName("body")[0].childNodes, "inline", '<xsl:value-of select="$hide_button_text"/>');
87                  }
88                }
89
90                // Recursively sets state of all children
91                // of a particular node.
92                function SetHiddenState(root, newState, newButton) {
93                  for (var i = 0; i != root.length; i++) {
94                    SetHiddenState(root[i].childNodes, newState, newButton);
95                    if (root[i].className == 'showhide_button')  {
96                      root[i].innerHTML = newButton;
97                    }
98                    if (root[i].className == 'stylepoint_body' ||
99                        root[i].className == 'link_button')  {
100                      root[i].style.display = newState;
101                    }
102                  }
103                }
104
105
106                function EndsWith(str, suffix) {
107                  var l = str.length - suffix.length;
108                  return l >= 0 &amp;&amp; str.indexOf(suffix, l) == l;
109                }
110
111                function RefreshVisibilityFromHashParam() {
112                  var hashRegexp = new RegExp('#([^&amp;#]*)$');
113                  var hashMatch = hashRegexp.exec(window.location.href);
114                  var anchor = hashMatch &amp;&amp; GetElementsByName(hashMatch[1])[0];
115                  var node = anchor;
116                  var suffix = '<xsl:value-of select="$body_suffix"/>';
117                  while (node) {
118                    var id = node.id;
119                    var matched = id &amp;&amp; EndsWith(id, suffix);
120                    if (matched) {
121                      var len = id.length - suffix.length;
122                      ShowByName(id.substring(0, len));
123                      if (anchor.scrollIntoView) {
124                        anchor.scrollIntoView();
125                      }
126
127                      return;
128                    }
129                    node = node.parentNode;
130                  }
131                }
132
133                window.onhashchange = RefreshVisibilityFromHashParam;
134
135                window.onload = function() {
136                  // if the URL contains "?showall=y", expand the details of all children
137                  var showHideAllRegex = new RegExp("[\\?&amp;](showall)=([^&amp;#]*)");
138                  var showHideAllValue = showHideAllRegex.exec(window.location.href);
139                  if (showHideAllValue != null) {
140                    if (showHideAllValue[2] == "y") {
141                      SetHiddenState(document.getElementsByTagName("body")[0].childNodes,
142                          "inline", '<xsl:value-of select="$hide_button_text"/>');
143                    } else {
144                      SetHiddenState(document.getElementsByTagName("body")[0].childNodes,
145                          "none", '<xsl:value-of select="$show_button_text"/>');
146                    }
147                  }
148                  var showOneRegex = new RegExp("[\\?&amp;](showone)=([^&amp;#]*)");
149                  var showOneValue = showOneRegex.exec(window.location.href);
150                  if (showOneValue) {
151                    ShowHideByName(showOneValue[2]);
152                  }
153
154
155                  RefreshVisibilityFromHashParam();
156                }
157              </SCRIPT>
158          </HEAD>
159          <BODY>
160            <H1><xsl:value-of select="@title"/></H1>
161              <xsl:apply-templates/>
162          </BODY>
163      </HTML>
164  </xsl:template>
165
166  <xsl:template match="OVERVIEW">
167    <xsl:variable name="button_text">
168      <xsl:choose>
169        <xsl:when test="$show_explanation_default">
170          <xsl:value-of select="$hide_button_text"/>
171        </xsl:when>
172        <xsl:otherwise>
173          <xsl:value-of select="$show_button_text"/>
174        </xsl:otherwise>
175      </xsl:choose>
176    </xsl:variable>
177    <DIV style="margin-left: 50%; font-size: 75%;">
178      <P>
179        Each style point has a summary for which additional information is available
180        by toggling the accompanying arrow button that looks this way:
181        <SPAN class="showhide_button" style="margin-left: 0; float: none">
182          <xsl:value-of select="$show_button_text"/></SPAN>.
183        You may toggle all summaries with the big arrow button:
184      </P>
185      <DIV style=" font-size: larger; margin-left: +2em;">
186        <SPAN class="showhide_button" style="font-size: 180%; float: none">
187          <xsl:attribute name="onclick"><xsl:value-of select="'javascript:ShowHideAll()'"/></xsl:attribute>
188          <xsl:attribute name="name"><xsl:value-of select="$show_hide_all_button"/></xsl:attribute>
189          <xsl:attribute name="id"><xsl:value-of select="$show_hide_all_button"/></xsl:attribute>
190          <xsl:value-of select="$button_text"/>
191        </SPAN>
192        Toggle all summaries
193      </DIV>
194    </DIV>
195    <xsl:call-template name="TOC">
196      <xsl:with-param name="root" select=".."/>
197    </xsl:call-template>
198    <xsl:apply-templates/>
199  </xsl:template>
200
201  <xsl:template match="PARTING_WORDS">
202    <H2>Parting Words</H2>
203    <xsl:apply-templates/>
204  </xsl:template>
205
206  <xsl:template match="CATEGORY">
207    <DIV>
208      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
209      <H2>
210        <xsl:variable name="category_name">
211          <xsl:call-template name="anchorname">
212            <xsl:with-param name="sectionname" select="@title"/>
213          </xsl:call-template>
214        </xsl:variable>
215        <xsl:attribute name="name"><xsl:value-of select="$category_name"/></xsl:attribute>
216        <xsl:attribute name="id"><xsl:value-of select="$category_name"/></xsl:attribute>
217        <xsl:value-of select="@title"/>
218      </H2>
219      <xsl:apply-templates/>
220    </DIV>
221  </xsl:template>
222
223  <xsl:template match="STYLEPOINT">
224    <DIV>
225      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
226      <xsl:variable name="stylepoint_name">
227        <xsl:call-template name="anchorname">
228          <xsl:with-param name="sectionname" select="@title"/>
229        </xsl:call-template>
230      </xsl:variable>
231      <xsl:variable name="button_text">
232        <xsl:choose>
233          <xsl:when test="$show_explanation_default">
234            <xsl:value-of select="$hide_button_text"/>
235          </xsl:when>
236          <xsl:otherwise>
237            <xsl:value-of select="$show_button_text"/>
238          </xsl:otherwise>
239        </xsl:choose>
240      </xsl:variable>
241      <H3>
242        <A>
243          <xsl:attribute name="name"><xsl:value-of select="$stylepoint_name"/></xsl:attribute>
244          <xsl:attribute name="id"><xsl:value-of select="$stylepoint_name"/></xsl:attribute>
245          <xsl:value-of select="@title"/>
246        </A>
247      </H3>
248      <xsl:variable name="buttonName">
249        <xsl:value-of select="$stylepoint_name"/><xsl:value-of select="$button_suffix"/>
250      </xsl:variable>
251      <xsl:variable name="onclick_definition">
252        <xsl:text>javascript:ShowHideByName('</xsl:text>
253        <xsl:value-of select="$stylepoint_name"/>
254        <xsl:text>')</xsl:text>
255      </xsl:variable>
256      <SPAN class="link_button" id="link-{$buttonName}" name="link-{$buttonName}">
257        <A>
258          <xsl:attribute name="href">?showone=<xsl:value-of select="$stylepoint_name"/>#<xsl:value-of select="$stylepoint_name"/></xsl:attribute>
259          link
260        </A>
261      </SPAN>
262      <SPAN class="showhide_button">
263        <xsl:attribute name="onclick"><xsl:value-of select="$onclick_definition"/></xsl:attribute>
264        <xsl:attribute name="name"><xsl:value-of select="$buttonName"/></xsl:attribute>
265        <xsl:attribute name="id"><xsl:value-of select="$buttonName"/></xsl:attribute>
266        <xsl:value-of select="$button_text"/>
267      </SPAN>
268      <xsl:apply-templates>
269        <xsl:with-param name="anchor_prefix" select="$stylepoint_name" />
270      </xsl:apply-templates>
271    </DIV>
272  </xsl:template>
273
274  <xsl:template match="SUMMARY">
275    <xsl:param name="anchor_prefix" />
276    <DIV style="display:inline;">
277      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
278      <xsl:apply-templates/>
279    </DIV>
280  </xsl:template>
281
282  <xsl:template match="BODY">
283    <xsl:param name="anchor_prefix" />
284    <DIV>
285      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
286      <DIV class="stylepoint_body">
287        <xsl:attribute name="name"><xsl:value-of select="$anchor_prefix"/><xsl:value-of select="$body_suffix"/></xsl:attribute>
288        <xsl:attribute name="id"><xsl:value-of select="$anchor_prefix"/><xsl:value-of select="$body_suffix"/></xsl:attribute>
289        <xsl:attribute name="style">
290          <xsl:choose>
291            <xsl:when test="$show_explanation_default">display: inline</xsl:when>
292            <xsl:otherwise>display: none</xsl:otherwise>
293          </xsl:choose>
294        </xsl:attribute>
295        <xsl:apply-templates/>
296      </DIV>
297    </DIV>
298  </xsl:template>
299
300  <xsl:template match="DEFINITION">
301    <P>
302      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
303      <SPAN class="stylepoint_section">Definition:  </SPAN>
304      <xsl:apply-templates/>
305    </P>
306  </xsl:template>
307
308  <xsl:template match="PROS">
309    <P>
310      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
311      <SPAN class="stylepoint_section">Pros:  </SPAN>
312      <xsl:apply-templates/>
313    </P>
314  </xsl:template>
315
316  <xsl:template match="CONS">
317    <P>
318      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
319      <SPAN class="stylepoint_section">Cons: </SPAN>
320      <xsl:apply-templates/>
321    </P>
322  </xsl:template>
323
324  <xsl:template match="DECISION">
325    <P>
326      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
327      <SPAN class="stylepoint_section">Decision:  </SPAN>
328      <xsl:apply-templates/>
329    </P>
330  </xsl:template>
331
332  <xsl:template match="TODO">
333    <P>
334      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
335      <DIV style="font-size: 150%;">TODO:
336        <xsl:apply-templates/>
337      </DIV>
338    </P>
339  </xsl:template>
340
341  <xsl:template match="SUBSECTION">
342    <P>
343      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
344      <SPAN class="stylepoint_subsection"><xsl:value-of select="@title"/>  </SPAN>
345      <xsl:apply-templates/>
346    </P>
347  </xsl:template>
348
349  <xsl:template match="SUBSUBSECTION">
350    <P>
351      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
352      <SPAN class="stylepoint_subsubsection"><xsl:value-of select="@title"/>  </SPAN>
353      <xsl:apply-templates/>
354    </P>
355  </xsl:template>
356
357  <xsl:template match="CODE_SNIPPET">
358    <DIV>
359      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
360      <PRE><xsl:call-template name="print_without_leading_chars">
361           <xsl:with-param name="text" select="."/>
362           <xsl:with-param name="strip" select="1"/>
363           <xsl:with-param name="is_firstline" select="1"/>
364           <xsl:with-param name="trim_count">
365             <xsl:call-template name="num_leading_spaces">
366               <xsl:with-param name="text" select="."/>
367               <xsl:with-param name="max_so_far" select="1000"/>
368             </xsl:call-template>
369           </xsl:with-param>
370         </xsl:call-template></PRE>
371    </DIV>
372  </xsl:template>
373
374  <xsl:template match="BAD_CODE_SNIPPET">
375    <DIV>
376      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
377      <PRE class="badcode"><xsl:call-template name="print_without_leading_chars">
378           <xsl:with-param name="text" select="."/>
379           <xsl:with-param name="strip" select="1"/>
380           <xsl:with-param name="is_firstline" select="1"/>
381           <xsl:with-param name="trim_count">
382             <xsl:call-template name="num_leading_spaces">
383               <xsl:with-param name="text" select="."/>
384               <xsl:with-param name="max_so_far" select="1000"/>
385             </xsl:call-template>
386           </xsl:with-param>
387         </xsl:call-template></PRE>
388    </DIV>
389  </xsl:template>
390
391  <xsl:template match="PY_CODE_SNIPPET">
392    <DIV>
393      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
394      <PRE><xsl:call-template name="print_python_code">
395             <xsl:with-param name="text" select="."/>
396           </xsl:call-template></PRE>
397    </DIV>
398  </xsl:template>
399
400  <xsl:template match="BAD_PY_CODE_SNIPPET">
401    <DIV>
402      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
403      <PRE class="badcode"><xsl:call-template name="print_python_code">
404                             <xsl:with-param name="text" select="."/>
405                           </xsl:call-template></PRE>
406    </DIV>
407  </xsl:template>
408
409  <xsl:template match="FUNCTION">
410    <xsl:call-template name="print_function_name">
411      <xsl:with-param name="text" select="."/>
412    </xsl:call-template>
413  </xsl:template>
414
415  <xsl:template match="SYNTAX">
416    <I>
417      <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
418      <xsl:apply-templates/>
419    </I>
420  </xsl:template>
421
422
423  <!-- This passes through any HTML elements that the
424    XML doc uses for minor formatting -->
425  <xsl:template match="a|address|blockquote|br|center|cite|code|dd|div|dl|dt|em|hr|i|img|li|ol|p|pre|span|table|td|th|tr|ul|var|A|ADDRESS|BLOCKQUOTE|BR|CENTER|CITE|CODE|DD|DIV|DL|DT|EM|HR|I|LI|OL|P|PRE|SPAN|TABLE|TD|TH|TR|UL|VAR">
426      <xsl:element name="{local-name()}">
427          <xsl:copy-of select="@*"/>
428          <xsl:apply-templates/>
429      </xsl:element>
430  </xsl:template>
431
432    <!-- Builds the table of contents -->
433  <xsl:template name="TOC">
434    <xsl:param name="root"/>
435    <DIV class="toc">
436      <DIV class="toc_title">Table of Contents</DIV>
437      <TABLE>
438      <xsl:for-each select="$root/CATEGORY">
439        <TR valign="top">
440          <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
441          <TD>
442          <DIV class="toc_category">
443            <A>
444              <xsl:attribute name="href">
445                <xsl:text>#</xsl:text>
446                <xsl:call-template name="anchorname">
447                  <xsl:with-param name="sectionname" select="@title"/>
448                </xsl:call-template>
449              </xsl:attribute>
450              <xsl:value-of select="@title"/>
451            </A>
452          </DIV>
453          </TD><TD>
454            <DIV class="toc_stylepoint">
455              <xsl:for-each select="./STYLEPOINT">
456                <SPAN style="padding-right: 1em; white-space:nowrap;">
457                  <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
458                  <A>
459                    <xsl:attribute name="href">
460                      <xsl:text>#</xsl:text>
461                      <xsl:call-template name="anchorname">
462                        <xsl:with-param name="sectionname" select="@title"/>
463                      </xsl:call-template>
464                    </xsl:attribute>
465                    <xsl:value-of select="@title"/>
466                  </A>
467                </SPAN>
468                <xsl:text> </xsl:text>
469              </xsl:for-each>
470            </DIV>
471          </TD>
472        </TR>
473      </xsl:for-each>
474      </TABLE>
475    </DIV>
476  </xsl:template>
477
478  <xsl:template name="TOC_one_stylepoint">
479    <xsl:param name="stylepoint"/>
480  </xsl:template>
481
482  <!-- Creates a standard anchor given any text.
483       Substitutes underscore for characters unsuitable for URLs  -->
484  <xsl:template name="anchorname">
485    <xsl:param name="sectionname"/>
486    <!-- strange quoting necessary to strip apostrophes -->
487    <xsl:variable name="bad_characters" select="&quot; ()#'&quot;"/>
488    <xsl:value-of select="translate($sectionname,$bad_characters,'_____')"/>
489  </xsl:template>
490
491  <!-- Given text, evaluates to the number of leading spaces. -->
492  <!-- TODO(csilvers): deal well with leading tabs (treat as 8 spaces?) -->
493  <xsl:template name="num_leading_spaces_one_line">
494    <xsl:param name="text"/>
495    <xsl:param name="current_count"/>
496    <xsl:choose>
497      <xsl:when test="starts-with($text, ' ')">
498        <xsl:call-template name="num_leading_spaces_one_line">
499          <xsl:with-param name="text" select="substring($text, 2)"/>
500          <xsl:with-param name="current_count" select="$current_count + 1"/>
501        </xsl:call-template>
502      </xsl:when>
503      <xsl:otherwise>
504        <xsl:value-of select="$current_count"/>
505      </xsl:otherwise>
506    </xsl:choose>
507  </xsl:template>
508
509  <!-- Given a block of text, each line terminated by \n, evaluates to
510       the indentation-level of that text; that is, the largest number
511       n such that every non-blank line starts with at least n spaces. -->
512  <xsl:template name="num_leading_spaces">
513    <xsl:param name="text"/>
514    <xsl:param name="max_so_far"/>
515    <!-- TODO(csilvers): deal with case text doesn't end in a newline -->
516    <xsl:variable name="line" select="substring-before($text, '&#xA;')"/>
517    <xsl:variable name="rest" select="substring-after($text, '&#xA;')"/>
518    <xsl:variable name="num_spaces_this_line">
519      <xsl:choose>
520        <xsl:when test="$line=''">
521           <xsl:value-of select="$max_so_far"/>
522        </xsl:when>
523        <xsl:otherwise>
524          <xsl:call-template name="num_leading_spaces_one_line">
525            <xsl:with-param name="text" select="$line"/>
526            <xsl:with-param name="current_count" select="0"/>
527          </xsl:call-template>
528        </xsl:otherwise>
529      </xsl:choose>
530    </xsl:variable>
531    <xsl:variable name="new_max_so_far">
532       <xsl:choose>
533         <xsl:when test="$num_spaces_this_line &lt; $max_so_far">
534           <xsl:value-of select="$num_spaces_this_line"/>
535         </xsl:when>
536         <xsl:otherwise>
537           <xsl:value-of select="$max_so_far"/>
538         </xsl:otherwise>
539       </xsl:choose>
540    </xsl:variable>
541    <!-- now check if we're on the last line, and if not, recurse -->
542    <xsl:if test="$rest=''">
543      <xsl:value-of select="$new_max_so_far"/>
544    </xsl:if>
545    <xsl:if test="not($rest='')">
546      <xsl:call-template name="num_leading_spaces">
547        <xsl:with-param name="text" select="$rest"/>
548        <xsl:with-param name="max_so_far" select="$new_max_so_far"/>
549      </xsl:call-template>
550    </xsl:if>
551  </xsl:template>
552
553  <!-- Given text, determine the starting position of code.
554       This similar to num_leading_spaces_one_line but treats "Yes:" and "No:"
555       as spaces. Also, if there is no code on the first line, it searches
556       subsequent lines until a non-empty line is found.
557       Used to find the start of code in snippets like:
558       Yes: if(foo):
559       No : if(foo):
560       As well as:
561       Yes:
562         if (foo):
563  -->
564  <xsl:template name="code_start_index">
565    <xsl:param name="text"/>
566    <xsl:param name="current_count"/>
567    <xsl:choose>
568      <xsl:when test="starts-with($text, ' ')">
569        <xsl:call-template name="code_start_index">
570          <xsl:with-param name="text" select="substring($text, 2)"/>
571          <xsl:with-param name="current_count" select="$current_count + 1"/>
572        </xsl:call-template>
573      </xsl:when>
574      <xsl:when test="starts-with($text, 'Yes:')">
575        <xsl:call-template name="code_start_index">
576          <xsl:with-param name="text" select="substring($text, 5)"/>
577          <xsl:with-param name="current_count" select="$current_count + 4"/>
578        </xsl:call-template>
579      </xsl:when>
580      <xsl:when test="starts-with($text, 'No:')">
581        <xsl:call-template name="code_start_index">
582          <xsl:with-param name="text" select="substring($text, 4)"/>
583          <xsl:with-param name="current_count" select="$current_count + 3"/>
584        </xsl:call-template>
585      </xsl:when>
586      <!-- This is only reached if the first line is entirely whitespace or
587           contains nothing but "Yes:" or "No:"-->
588      <xsl:when test="starts-with($text, '&#xA;')">
589        <xsl:call-template name="code_start_index">
590          <xsl:with-param name="text" select="substring($text, 2)"/>
591          <xsl:with-param name="current_count" select="0"/>
592        </xsl:call-template>
593      </xsl:when>
594      <xsl:otherwise>
595        <xsl:value-of select="$current_count"/>
596      </xsl:otherwise>
597    </xsl:choose>
598  </xsl:template>
599
600  <!-- Helper for ends_with_colon. Determine whether the given line is nothing
601       but spaces and python-style comments. -->
602  <xsl:template name="is_blank_or_comment">
603    <xsl:param name="line"/>
604    <xsl:choose>
605      <xsl:when test="$line = ''">
606        <xsl:value-of select="1"/>
607      </xsl:when>
608      <xsl:when test="starts-with($line, '&#xA;')">
609        <xsl:value-of select="1"/>
610      </xsl:when>
611      <xsl:when test="starts-with($line, '#')">
612        <xsl:value-of select="1"/>
613      </xsl:when>
614      <xsl:when test="starts-with($line, ' ')">
615        <xsl:call-template name="is_blank_or_comment">
616          <xsl:with-param name="line" select="substring($line, 2)"/>
617        </xsl:call-template>
618      </xsl:when>
619      <xsl:otherwise>
620        <xsl:value-of select="0"/>
621      </xsl:otherwise>
622    </xsl:choose>
623  </xsl:template>
624
625  <!-- Determine whether the given line ends with a colon. Note that Python
626       style comments are ignored so the following lines return True:
627       - def foo():
628       - def foo():  # Bar
629       - if(foo):
630
631       But some code may confuse this function. For example the following are
632       also consider to "end_with_colon" even though they don't for Python
633       - foo(":  #")
634       - foo() # No need for :
635  -->
636  <xsl:template name="ends_with_colon">
637    <xsl:param name="line"/>
638    <xsl:param name="found_colon"/>
639    <xsl:choose>
640      <xsl:when test="$line = ''">
641        <xsl:value-of select="$found_colon"/>
642      </xsl:when>
643      <xsl:when test="starts-with($line, '&#xA;')">
644        <xsl:value-of select="$found_colon"/>
645      </xsl:when>
646      <xsl:when test="starts-with($line, ' ')">
647        <xsl:call-template name="ends_with_colon">
648          <xsl:with-param name="line" select="substring($line, 2)"/>
649          <xsl:with-param name="found_colon" select="$found_colon"/>
650        </xsl:call-template>
651      </xsl:when>
652      <xsl:when test="starts-with($line, ':')">
653        <xsl:variable name="rest_is_comment">
654          <xsl:call-template name="is_blank_or_comment">
655            <xsl:with-param name="line" select="substring($line, 2)"/>
656          </xsl:call-template>
657        </xsl:variable>
658        <xsl:choose>
659          <xsl:when test="$rest_is_comment = '1'">
660            <xsl:value-of select="1"/>
661          </xsl:when>
662          <xsl:otherwise>
663            <xsl:call-template name="ends_with_colon">
664              <xsl:with-param name="line" select="substring($line, 2)"/>
665              <xsl:with-param name="found_colon" select="0"/>
666            </xsl:call-template>
667          </xsl:otherwise>
668        </xsl:choose>
669      </xsl:when>
670      <xsl:otherwise>
671        <xsl:call-template name="ends_with_colon">
672          <xsl:with-param name="line" select="substring($line, 2)"/>
673          <xsl:with-param name="found_colon" select="0"/>
674        </xsl:call-template>
675      </xsl:otherwise>
676    </xsl:choose>
677  </xsl:template>
678
679  <!-- Prints one line of python code with proper indent and calls itself
680       recursively for the rest of the text.
681       This template uses "a", "b", "c" and "d" to refer to four key column
682       numbers. They are:
683       - a: the indentation common to all lines in a code snippet. This is
684            stripped out to allow for cleaner code in the xml.
685       - b: the indentation of the most out-dented line of code. This is
686            different from "a" when code is labelled with "Yes:" or "No:"
687       - c: the indentation of the current python block, in other words, the
688            indentation of the first line of this block, which is the
689            indentation of the last line we saw that ended with a colon.
690       - d: the "total" indentation of the line, ignorng possible "Yes:" or
691            "No:" text on the line.
692
693       For example, for the last line of the following code snippet, the
694       positions of a, b, c and d are indicated below:
695           Yes: def Foo():
696                  if bar():
697                    a += 1
698                    baz()
699           a    b c d
700
701       The algorithm is:
702       1) Split the text into first line and the rest. Note that the
703          substring-before function is supposed to handle the case where the
704          character is not present in the string but does not so we
705          automatically ignore the last line of the snippet which is always
706          empty (the closing snippet tag). This is consistent with the
707          behavior or print_without_leading_chars.
708       2) If the current is empty (only whitespace), print newline and call
709          itself recursively on the rest of the text with the rest of the
710          parameters unchanged.
711       3) Otherwise, measure "d"
712       4) Measure "c" by taking:
713          - the value of "d" if the previous line ended with a colon or the
714            current line is outdented compare to the previous line
715          - the indent of the previous line otherwise
716       5) Print line[a:c] (Note that we ignore line[0:a])
717       6) Print line[b:c] in an external span (in order to double the block
718          indent in external code).
719       7) Print line[c:<end>] with function names processed to produce both
720          internal and external names.
721       8) If there are more lines, recurse.
722  -->
723  <xsl:template name="print_python_line_recursively">
724    <xsl:param name="text"/>
725    <xsl:param name="a"/>
726    <xsl:param name="b"/>
727    <xsl:param name="previous_indent"/>
728    <xsl:param name="previous_ends_with_colon"/>
729    <xsl:param name="is_first_line"/>
730    <xsl:variable name="line" select="substring-before($text, '&#xA;')"/>
731    <xsl:variable name="rest" select="substring-after($text, '&#xA;')"/>
732    <xsl:choose>
733      <xsl:when test="substring($line, $b) = '' and not($rest = '')">
734        <xsl:if test="not($is_first_line = '1')">
735          <xsl:text>&#xA;</xsl:text>
736        </xsl:if>
737        <xsl:call-template name="print_python_line_recursively">
738          <xsl:with-param name="text" select="$rest"/>
739          <xsl:with-param name="a" select="$a"/>
740          <xsl:with-param name="b" select="$b"/>
741          <xsl:with-param name="previous_indent" select="$previous_indent"/>
742          <xsl:with-param name="previous_ends_with_colon"
743                          select="$previous_ends_with_colon"/>
744          <xsl:with-param name="is_first_line" select="0"/>
745        </xsl:call-template>
746      </xsl:when>
747      <xsl:otherwise>
748        <xsl:variable name="indent_after_b">
749          <xsl:call-template name="num_leading_spaces_one_line">
750            <xsl:with-param name="text" select="substring($line, $b + 1)"/>
751            <xsl:with-param name="current_count" select="0"/>
752          </xsl:call-template>
753        </xsl:variable>
754        <xsl:variable name="d" select="$b + $indent_after_b"/>
755        <xsl:variable name="c">
756           <xsl:choose>
757             <xsl:when test="$previous_ends_with_colon = '1' or
758                             $previous_indent > $d">
759               <xsl:value-of select="$d"/>
760             </xsl:when>
761             <xsl:otherwise>
762               <xsl:value-of select="$previous_indent"/>
763             </xsl:otherwise>
764           </xsl:choose>
765        </xsl:variable>
766
767        <xsl:value-of select="substring($line, $a + 1, $c - $a)"/>
768        <span class="external">
769           <xsl:value-of select="substring($line, $b + 1, $c - $b)"/>
770        </span>
771        <xsl:call-template name="munge_function_names_in_text">
772          <xsl:with-param name="stripped_line"
773             select="substring($line, $c + 1)"/>
774        </xsl:call-template>
775        <xsl:if test="not(substring($rest, $a) = '')">
776          <xsl:text>&#xA;</xsl:text>
777          <xsl:call-template name="print_python_line_recursively">
778            <xsl:with-param name="text" select="$rest"/>
779            <xsl:with-param name="a" select="$a"/>
780            <xsl:with-param name="b" select="$b"/>
781            <xsl:with-param name="previous_indent" select="$c"/>
782            <xsl:with-param name="previous_ends_with_colon">
783              <xsl:call-template name="ends_with_colon">
784                <xsl:with-param name="line" select="$line"/>
785                <xsl:with-param name="found_colon" select="0"/>
786              </xsl:call-template>
787            </xsl:with-param>
788            <xsl:with-param name="is_first_line" select="0"/>
789          </xsl:call-template>
790        </xsl:if>
791      </xsl:otherwise>
792    </xsl:choose>
793  </xsl:template>
794
795  <!-- Print python code with internal and external styles.
796       In order to conform with PEP-8 externally, we identify 2-space indents
797       and an external-only 4-space indent.
798       Function names that are marked with $$FunctionName/$$ have an external
799       lower_with_underscore version added. -->
800  <xsl:template name="print_python_code">
801    <xsl:param name="text"/>
802
803    <xsl:variable name="a">
804       <xsl:call-template name="num_leading_spaces">
805         <xsl:with-param name="text" select="."/>
806         <xsl:with-param name="max_so_far" select="1000"/>
807       </xsl:call-template>
808    </xsl:variable>
809
810    <xsl:variable name="b">
811      <xsl:call-template name="code_start_index">
812        <xsl:with-param name="text" select="$text"/>
813        <xsl:with-param name="current_count" select="0"/>
814      </xsl:call-template>
815    </xsl:variable>
816
817    <xsl:call-template name="print_python_line_recursively">
818      <xsl:with-param name="text" select="$text"/>
819      <xsl:with-param name="a" select="$a"/>
820      <xsl:with-param name="b" select="$b"/>
821      <xsl:with-param name="previous_indent" select="$b"/>
822      <xsl:with-param name="previous_ends_with_colon" select="0"/>
823      <xsl:with-param name="is_first_line" select="1"/>
824    </xsl:call-template>
825  </xsl:template>
826
827  <!-- Given a block of text, each line terminated by \n, and a number n,
828       emits the text with the first n characters of each line
829       deleted.  If strip==1, then we omit blank lines at the beginning
830       and end of the text (but not the middle!) -->
831  <!-- TODO(csilvers): deal well with leading tabs (treat as 8 spaces?) -->
832  <xsl:template name="print_without_leading_chars">
833    <xsl:param name="text"/>
834    <xsl:param name="trim_count"/>
835    <xsl:param name="strip"/>
836    <xsl:param name="is_firstline"/>
837    <!-- TODO(csilvers): deal with case text doesn't end in a newline -->
838    <xsl:variable name="line" select="substring-before($text, '&#xA;')"/>
839    <xsl:variable name="rest" select="substring-after($text, '&#xA;')"/>
840    <xsl:variable name="stripped_line" select="substring($line, $trim_count+1)"/>
841    <xsl:choose>
842      <!-- $line (or $rest) is considered empty if we'd trim the entire line -->
843      <xsl:when test="($strip = '1') and ($is_firstline = '1') and
844                      (string-length($line) &lt;= $trim_count)">
845      </xsl:when>
846      <xsl:when test="($strip = '1') and
847                      (string-length($rest) &lt;= $trim_count)">
848        <xsl:value-of select="$stripped_line"/>
849      </xsl:when>
850      <xsl:otherwise>
851        <xsl:value-of select="$stripped_line"/>
852        <xsl:text>&#xA;</xsl:text>
853      </xsl:otherwise>
854    </xsl:choose>
855    <xsl:if test="not($rest='')">
856      <xsl:call-template name="print_without_leading_chars">
857        <xsl:with-param name="text" select="$rest"/>
858        <xsl:with-param name="trim_count" select="$trim_count"/>
859        <xsl:with-param name="strip" select="$strip"/>
860        <xsl:with-param name="is_firstline" select="0"/>
861      </xsl:call-template>
862    </xsl:if>
863  </xsl:template>
864
865  <!-- Given a line of code, find function names that are marked with $$ /$$ and
866       print out the line with the internal and external versions of the
867       function names.-->
868  <xsl:template name="munge_function_names_in_text">
869    <xsl:param name="stripped_line"/>
870    <xsl:choose>
871      <xsl:when test="contains($stripped_line, '$$')">
872        <xsl:value-of select="substring-before($stripped_line, '$$')"/>
873        <xsl:call-template name="print_function_name">
874          <xsl:with-param name="text" select="substring-after(substring-before($stripped_line, '/$$'), '$$')"/>
875        </xsl:call-template>
876        <xsl:call-template name="munge_function_names_in_text">
877          <xsl:with-param name="stripped_line" select="substring-after($stripped_line, '/$$')"/>
878        </xsl:call-template>
879      </xsl:when>
880      <xsl:otherwise>
881        <xsl:value-of select="$stripped_line"/>
882     </xsl:otherwise>
883   </xsl:choose>
884  </xsl:template>
885
886  <!-- Given a function name, print out both the internal and external version
887       of the function name in their respective spans.-->
888  <xsl:template name="print_function_name">
889    <xsl:param name="text"/>
890      <xsl:call-template name="convert_camel_case_to_lowercase_with_under">
891        <xsl:with-param name="text" select="$text"/>
892      </xsl:call-template>
893  </xsl:template>
894
895  <!-- Given a single word of text convert it from CamelCase to
896       lower_with_under.
897       This means replacing each uppercase character with _ followed by the
898       lowercase version except for the first character which is replaced
899       without adding the _.-->
900  <xsl:template name="convert_camel_case_to_lowercase_with_under">
901    <xsl:param name="text"/>
902    <xsl:param name="is_recursive_call"/>
903    <xsl:variable name="first_char" select="substring($text, 1, 1)"/>
904    <xsl:variable name="rest" select="substring($text, 2)"/>
905    <xsl:choose>
906      <xsl:when test="contains('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $first_char)">
907        <xsl:if test="$is_recursive_call='1'">
908           <xsl:text>_</xsl:text>
909        </xsl:if>
910        <xsl:value-of select="translate($first_char, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>
911      </xsl:when>
912      <xsl:otherwise>
913        <xsl:value-of select="$first_char" />
914      </xsl:otherwise>
915    </xsl:choose>
916    <xsl:if test="not($rest='')">
917      <xsl:call-template name="convert_camel_case_to_lowercase_with_under">
918        <xsl:with-param name="text" select="$rest"/>
919        <xsl:with-param name="is_recursive_call" select="1"/>
920      </xsl:call-template>
921    </xsl:if>
922  </xsl:template>
923</xsl:stylesheet>
924
925