| <xsl:stylesheet version="1.0" |
| xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
| xmlns:dc="http://purl.org/dc/elements/1.1/" |
| xmlns:dcq="http://purl.org/dc/qualifiers/1.0/" |
| xmlns:fo="http://www.w3.org/1999/XSL/Format" |
| xmlns:fn="http://www.w3.org/2005/xpath-functions"> |
| <xsl:output method="html"/> |
| <!-- Set to 1 to show explanations by default. Set to 0 to hide them --> |
| <xsl:variable name="show_explanation_default" select="0" /> |
| <!-- The characters within the Webdings font that show the triangles --> |
| <xsl:variable name="show_button_text" select="'▶'" /> |
| <xsl:variable name="hide_button_text" select="'▽'" /> |
| <!-- The suffix for names --> |
| <xsl:variable name="button_suffix" select="'__button'"/> |
| <xsl:variable name="body_suffix" select="'__body'"/> |
| <!-- For easy reference, the name of the button --> |
| <xsl:variable name="show_hide_all_button" select="'show_hide_all_button'"/> |
| |
| <!-- The top-level element --> |
| <xsl:template match="GUIDE"> |
| <HTML> |
| <HEAD> |
| <TITLE><xsl:value-of select="@title"/></TITLE> |
| <META http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| <LINK HREF="http://www.google.com/favicon.ico" type="image/x-icon" |
| rel="shortcut icon"/> |
| <LINK HREF="styleguide.css" |
| type="text/css" rel="stylesheet"/> |
| |
| <SCRIPT language="javascript" type="text/javascript"> |
| |
| function GetElementsByName(name) { |
| // Workaround a bug on old versions of opera. |
| if (document.getElementsByName) { |
| return document.getElementsByName(name); |
| } else { |
| return [document.getElementById(name)]; |
| } |
| } |
| |
| /** |
| * @param {string} namePrefix The prefix of the body name. |
| * @param {function(boolean): boolean} getVisibility Computes the new |
| * visibility state, given the current one. |
| */ |
| function ChangeVisibility(namePrefix, getVisibility) { |
| var bodyName = namePrefix + '<xsl:value-of select="$body_suffix"/>'; |
| var buttonName = namePrefix + '<xsl:value-of select="$button_suffix"/>'; |
| var bodyElements = GetElementsByName(bodyName); |
| var linkElement = GetElementsByName('link-' + buttonName)[0]; |
| if (bodyElements.length != 1) { |
| throw Error('ShowHideByName() got the wrong number of bodyElements: ' + |
| bodyElements.length); |
| } else { |
| var bodyElement = bodyElements[0]; |
| var buttonElement = GetElementsByName(buttonName)[0]; |
| var isVisible = bodyElement.style.display != "none"; |
| if (getVisibility(isVisible)) { |
| bodyElement.style.display = "inline"; |
| linkElement.style.display = "block"; |
| buttonElement.innerHTML = '<xsl:value-of select="$hide_button_text"/>'; |
| } else { |
| bodyElement.style.display = "none"; |
| linkElement.style.display = "none"; |
| buttonElement.innerHTML = '<xsl:value-of select="$show_button_text"/>'; |
| } |
| } |
| } |
| |
| function ShowHideByName(namePrefix) { |
| ChangeVisibility(namePrefix, function(old) { return !old; }); |
| } |
| |
| function ShowByName(namePrefix) { |
| ChangeVisibility(namePrefix, function() { return true; }); |
| } |
| |
| function ShowHideAll() { |
| var allButton = GetElementsByName("show_hide_all_button")[0]; |
| if (allButton.innerHTML == '<xsl:value-of select="$hide_button_text"/>') { |
| allButton.innerHTML = '<xsl:value-of select="$show_button_text"/>'; |
| SetHiddenState(document.getElementsByTagName("body")[0].childNodes, "none", '<xsl:value-of select="$show_button_text"/>'); |
| } else { |
| allButton.innerHTML = '<xsl:value-of select="$hide_button_text"/>'; |
| SetHiddenState(document.getElementsByTagName("body")[0].childNodes, "inline", '<xsl:value-of select="$hide_button_text"/>'); |
| } |
| } |
| |
| // Recursively sets state of all children |
| // of a particular node. |
| function SetHiddenState(root, newState, newButton) { |
| for (var i = 0; i != root.length; i++) { |
| SetHiddenState(root[i].childNodes, newState, newButton); |
| if (root[i].className == 'showhide_button') { |
| root[i].innerHTML = newButton; |
| } |
| if (root[i].className == 'stylepoint_body' || |
| root[i].className == 'link_button') { |
| root[i].style.display = newState; |
| } |
| } |
| } |
| |
| |
| function EndsWith(str, suffix) { |
| var l = str.length - suffix.length; |
| return l >= 0 && str.indexOf(suffix, l) == l; |
| } |
| |
| function RefreshVisibilityFromHashParam() { |
| var hashRegexp = new RegExp('#([^&#]*)$'); |
| var hashMatch = hashRegexp.exec(window.location.href); |
| var anchor = hashMatch && GetElementsByName(hashMatch[1])[0]; |
| var node = anchor; |
| var suffix = '<xsl:value-of select="$body_suffix"/>'; |
| while (node) { |
| var id = node.id; |
| var matched = id && EndsWith(id, suffix); |
| if (matched) { |
| var len = id.length - suffix.length; |
| ShowByName(id.substring(0, len)); |
| if (anchor.scrollIntoView) { |
| anchor.scrollIntoView(); |
| } |
| |
| return; |
| } |
| node = node.parentNode; |
| } |
| } |
| |
| window.onhashchange = RefreshVisibilityFromHashParam; |
| |
| window.onload = function() { |
| // if the URL contains "?showall=y", expand the details of all children |
| var showHideAllRegex = new RegExp("[\\?&](showall)=([^&#]*)"); |
| var showHideAllValue = showHideAllRegex.exec(window.location.href); |
| if (showHideAllValue != null) { |
| if (showHideAllValue[2] == "y") { |
| SetHiddenState(document.getElementsByTagName("body")[0].childNodes, |
| "inline", '<xsl:value-of select="$hide_button_text"/>'); |
| } else { |
| SetHiddenState(document.getElementsByTagName("body")[0].childNodes, |
| "none", '<xsl:value-of select="$show_button_text"/>'); |
| } |
| } |
| var showOneRegex = new RegExp("[\\?&](showone)=([^&#]*)"); |
| var showOneValue = showOneRegex.exec(window.location.href); |
| if (showOneValue) { |
| ShowHideByName(showOneValue[2]); |
| } |
| |
| |
| RefreshVisibilityFromHashParam(); |
| } |
| </SCRIPT> |
| </HEAD> |
| <BODY> |
| <H1><xsl:value-of select="@title"/></H1> |
| <xsl:apply-templates/> |
| </BODY> |
| </HTML> |
| </xsl:template> |
| |
| <xsl:template match="OVERVIEW"> |
| <xsl:variable name="button_text"> |
| <xsl:choose> |
| <xsl:when test="$show_explanation_default"> |
| <xsl:value-of select="$hide_button_text"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$show_button_text"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:variable> |
| <DIV style="margin-left: 50%; font-size: 75%;"> |
| <P> |
| Each style point has a summary for which additional information is available |
| by toggling the accompanying arrow button that looks this way: |
| <SPAN class="showhide_button" style="margin-left: 0; float: none"> |
| <xsl:value-of select="$show_button_text"/></SPAN>. |
| You may toggle all summaries with the big arrow button: |
| </P> |
| <DIV style=" font-size: larger; margin-left: +2em;"> |
| <SPAN class="showhide_button" style="font-size: 180%; float: none"> |
| <xsl:attribute name="onclick"><xsl:value-of select="'javascript:ShowHideAll()'"/></xsl:attribute> |
| <xsl:attribute name="name"><xsl:value-of select="$show_hide_all_button"/></xsl:attribute> |
| <xsl:attribute name="id"><xsl:value-of select="$show_hide_all_button"/></xsl:attribute> |
| <xsl:value-of select="$button_text"/> |
| </SPAN> |
| Toggle all summaries |
| </DIV> |
| </DIV> |
| <xsl:call-template name="TOC"> |
| <xsl:with-param name="root" select=".."/> |
| </xsl:call-template> |
| <xsl:apply-templates/> |
| </xsl:template> |
| |
| <xsl:template match="PARTING_WORDS"> |
| <H2>Parting Words</H2> |
| <xsl:apply-templates/> |
| </xsl:template> |
| |
| <xsl:template match="CATEGORY"> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <H2> |
| <xsl:variable name="category_name"> |
| <xsl:call-template name="anchorname"> |
| <xsl:with-param name="sectionname" select="@title"/> |
| </xsl:call-template> |
| </xsl:variable> |
| <xsl:attribute name="name"><xsl:value-of select="$category_name"/></xsl:attribute> |
| <xsl:attribute name="id"><xsl:value-of select="$category_name"/></xsl:attribute> |
| <xsl:value-of select="@title"/> |
| </H2> |
| <xsl:apply-templates/> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="STYLEPOINT"> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <xsl:variable name="stylepoint_name"> |
| <xsl:call-template name="anchorname"> |
| <xsl:with-param name="sectionname" select="@title"/> |
| </xsl:call-template> |
| </xsl:variable> |
| <xsl:variable name="button_text"> |
| <xsl:choose> |
| <xsl:when test="$show_explanation_default"> |
| <xsl:value-of select="$hide_button_text"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$show_button_text"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:variable> |
| <H3> |
| <A> |
| <xsl:attribute name="name"><xsl:value-of select="$stylepoint_name"/></xsl:attribute> |
| <xsl:attribute name="id"><xsl:value-of select="$stylepoint_name"/></xsl:attribute> |
| <xsl:value-of select="@title"/> |
| </A> |
| </H3> |
| <xsl:variable name="buttonName"> |
| <xsl:value-of select="$stylepoint_name"/><xsl:value-of select="$button_suffix"/> |
| </xsl:variable> |
| <xsl:variable name="onclick_definition"> |
| <xsl:text>javascript:ShowHideByName('</xsl:text> |
| <xsl:value-of select="$stylepoint_name"/> |
| <xsl:text>')</xsl:text> |
| </xsl:variable> |
| <SPAN class="link_button" id="link-{$buttonName}" name="link-{$buttonName}"> |
| <A> |
| <xsl:attribute name="href">?showone=<xsl:value-of select="$stylepoint_name"/>#<xsl:value-of select="$stylepoint_name"/></xsl:attribute> |
| link |
| </A> |
| </SPAN> |
| <SPAN class="showhide_button"> |
| <xsl:attribute name="onclick"><xsl:value-of select="$onclick_definition"/></xsl:attribute> |
| <xsl:attribute name="name"><xsl:value-of select="$buttonName"/></xsl:attribute> |
| <xsl:attribute name="id"><xsl:value-of select="$buttonName"/></xsl:attribute> |
| <xsl:value-of select="$button_text"/> |
| </SPAN> |
| <xsl:apply-templates> |
| <xsl:with-param name="anchor_prefix" select="$stylepoint_name" /> |
| </xsl:apply-templates> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="SUMMARY"> |
| <xsl:param name="anchor_prefix" /> |
| <DIV style="display:inline;"> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <xsl:apply-templates/> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="BODY"> |
| <xsl:param name="anchor_prefix" /> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <DIV class="stylepoint_body"> |
| <xsl:attribute name="name"><xsl:value-of select="$anchor_prefix"/><xsl:value-of select="$body_suffix"/></xsl:attribute> |
| <xsl:attribute name="id"><xsl:value-of select="$anchor_prefix"/><xsl:value-of select="$body_suffix"/></xsl:attribute> |
| <xsl:attribute name="style"> |
| <xsl:choose> |
| <xsl:when test="$show_explanation_default">display: inline</xsl:when> |
| <xsl:otherwise>display: none</xsl:otherwise> |
| </xsl:choose> |
| </xsl:attribute> |
| <xsl:apply-templates/> |
| </DIV> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="DEFINITION"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <SPAN class="stylepoint_section">Definition: </SPAN> |
| <xsl:apply-templates/> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="PROS"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <SPAN class="stylepoint_section">Pros: </SPAN> |
| <xsl:apply-templates/> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="CONS"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <SPAN class="stylepoint_section">Cons: </SPAN> |
| <xsl:apply-templates/> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="DECISION"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <SPAN class="stylepoint_section">Decision: </SPAN> |
| <xsl:apply-templates/> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="TODO"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <DIV style="font-size: 150%;">TODO: |
| <xsl:apply-templates/> |
| </DIV> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="SUBSECTION"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <SPAN class="stylepoint_subsection"><xsl:value-of select="@title"/> </SPAN> |
| <xsl:apply-templates/> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="SUBSUBSECTION"> |
| <P> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <SPAN class="stylepoint_subsubsection"><xsl:value-of select="@title"/> </SPAN> |
| <xsl:apply-templates/> |
| </P> |
| </xsl:template> |
| |
| <xsl:template match="CODE_SNIPPET"> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <PRE><xsl:call-template name="print_without_leading_chars"> |
| <xsl:with-param name="text" select="."/> |
| <xsl:with-param name="strip" select="1"/> |
| <xsl:with-param name="is_firstline" select="1"/> |
| <xsl:with-param name="trim_count"> |
| <xsl:call-template name="num_leading_spaces"> |
| <xsl:with-param name="text" select="."/> |
| <xsl:with-param name="max_so_far" select="1000"/> |
| </xsl:call-template> |
| </xsl:with-param> |
| </xsl:call-template></PRE> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="BAD_CODE_SNIPPET"> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <PRE class="badcode"><xsl:call-template name="print_without_leading_chars"> |
| <xsl:with-param name="text" select="."/> |
| <xsl:with-param name="strip" select="1"/> |
| <xsl:with-param name="is_firstline" select="1"/> |
| <xsl:with-param name="trim_count"> |
| <xsl:call-template name="num_leading_spaces"> |
| <xsl:with-param name="text" select="."/> |
| <xsl:with-param name="max_so_far" select="1000"/> |
| </xsl:call-template> |
| </xsl:with-param> |
| </xsl:call-template></PRE> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="PY_CODE_SNIPPET"> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <PRE><xsl:call-template name="print_python_code"> |
| <xsl:with-param name="text" select="."/> |
| </xsl:call-template></PRE> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="BAD_PY_CODE_SNIPPET"> |
| <DIV> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <PRE class="badcode"><xsl:call-template name="print_python_code"> |
| <xsl:with-param name="text" select="."/> |
| </xsl:call-template></PRE> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template match="FUNCTION"> |
| <xsl:call-template name="print_function_name"> |
| <xsl:with-param name="text" select="."/> |
| </xsl:call-template> |
| </xsl:template> |
| |
| <xsl:template match="SYNTAX"> |
| <I> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <xsl:apply-templates/> |
| </I> |
| </xsl:template> |
| |
| |
| <!-- This passes through any HTML elements that the |
| XML doc uses for minor formatting --> |
| <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"> |
| <xsl:element name="{local-name()}"> |
| <xsl:copy-of select="@*"/> |
| <xsl:apply-templates/> |
| </xsl:element> |
| </xsl:template> |
| |
| <!-- Builds the table of contents --> |
| <xsl:template name="TOC"> |
| <xsl:param name="root"/> |
| <DIV class="toc"> |
| <DIV class="toc_title">Table of Contents</DIV> |
| <TABLE> |
| <xsl:for-each select="$root/CATEGORY"> |
| <TR valign="top"> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <TD> |
| <DIV class="toc_category"> |
| <A> |
| <xsl:attribute name="href"> |
| <xsl:text>#</xsl:text> |
| <xsl:call-template name="anchorname"> |
| <xsl:with-param name="sectionname" select="@title"/> |
| </xsl:call-template> |
| </xsl:attribute> |
| <xsl:value-of select="@title"/> |
| </A> |
| </DIV> |
| </TD><TD> |
| <DIV class="toc_stylepoint"> |
| <xsl:for-each select="./STYLEPOINT"> |
| <SPAN style="padding-right: 1em; white-space:nowrap;"> |
| <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| <A> |
| <xsl:attribute name="href"> |
| <xsl:text>#</xsl:text> |
| <xsl:call-template name="anchorname"> |
| <xsl:with-param name="sectionname" select="@title"/> |
| </xsl:call-template> |
| </xsl:attribute> |
| <xsl:value-of select="@title"/> |
| </A> |
| </SPAN> |
| <xsl:text> </xsl:text> |
| </xsl:for-each> |
| </DIV> |
| </TD> |
| </TR> |
| </xsl:for-each> |
| </TABLE> |
| </DIV> |
| </xsl:template> |
| |
| <xsl:template name="TOC_one_stylepoint"> |
| <xsl:param name="stylepoint"/> |
| </xsl:template> |
| |
| <!-- Creates a standard anchor given any text. |
| Substitutes underscore for characters unsuitable for URLs --> |
| <xsl:template name="anchorname"> |
| <xsl:param name="sectionname"/> |
| <!-- strange quoting necessary to strip apostrophes --> |
| <xsl:variable name="bad_characters" select="" ()#'""/> |
| <xsl:value-of select="translate($sectionname,$bad_characters,'_____')"/> |
| </xsl:template> |
| |
| <!-- Given text, evaluates to the number of leading spaces. --> |
| <!-- TODO(csilvers): deal well with leading tabs (treat as 8 spaces?) --> |
| <xsl:template name="num_leading_spaces_one_line"> |
| <xsl:param name="text"/> |
| <xsl:param name="current_count"/> |
| <xsl:choose> |
| <xsl:when test="starts-with($text, ' ')"> |
| <xsl:call-template name="num_leading_spaces_one_line"> |
| <xsl:with-param name="text" select="substring($text, 2)"/> |
| <xsl:with-param name="current_count" select="$current_count + 1"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$current_count"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:template> |
| |
| <!-- Given a block of text, each line terminated by \n, evaluates to |
| the indentation-level of that text; that is, the largest number |
| n such that every non-blank line starts with at least n spaces. --> |
| <xsl:template name="num_leading_spaces"> |
| <xsl:param name="text"/> |
| <xsl:param name="max_so_far"/> |
| <!-- TODO(csilvers): deal with case text doesn't end in a newline --> |
| <xsl:variable name="line" select="substring-before($text, '
')"/> |
| <xsl:variable name="rest" select="substring-after($text, '
')"/> |
| <xsl:variable name="num_spaces_this_line"> |
| <xsl:choose> |
| <xsl:when test="$line=''"> |
| <xsl:value-of select="$max_so_far"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:call-template name="num_leading_spaces_one_line"> |
| <xsl:with-param name="text" select="$line"/> |
| <xsl:with-param name="current_count" select="0"/> |
| </xsl:call-template> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:variable> |
| <xsl:variable name="new_max_so_far"> |
| <xsl:choose> |
| <xsl:when test="$num_spaces_this_line < $max_so_far"> |
| <xsl:value-of select="$num_spaces_this_line"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$max_so_far"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:variable> |
| <!-- now check if we're on the last line, and if not, recurse --> |
| <xsl:if test="$rest=''"> |
| <xsl:value-of select="$new_max_so_far"/> |
| </xsl:if> |
| <xsl:if test="not($rest='')"> |
| <xsl:call-template name="num_leading_spaces"> |
| <xsl:with-param name="text" select="$rest"/> |
| <xsl:with-param name="max_so_far" select="$new_max_so_far"/> |
| </xsl:call-template> |
| </xsl:if> |
| </xsl:template> |
| |
| <!-- Given text, determine the starting position of code. |
| This similar to num_leading_spaces_one_line but treats "Yes:" and "No:" |
| as spaces. Also, if there is no code on the first line, it searches |
| subsequent lines until a non-empty line is found. |
| Used to find the start of code in snippets like: |
| Yes: if(foo): |
| No : if(foo): |
| As well as: |
| Yes: |
| if (foo): |
| --> |
| <xsl:template name="code_start_index"> |
| <xsl:param name="text"/> |
| <xsl:param name="current_count"/> |
| <xsl:choose> |
| <xsl:when test="starts-with($text, ' ')"> |
| <xsl:call-template name="code_start_index"> |
| <xsl:with-param name="text" select="substring($text, 2)"/> |
| <xsl:with-param name="current_count" select="$current_count + 1"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:when test="starts-with($text, 'Yes:')"> |
| <xsl:call-template name="code_start_index"> |
| <xsl:with-param name="text" select="substring($text, 5)"/> |
| <xsl:with-param name="current_count" select="$current_count + 4"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:when test="starts-with($text, 'No:')"> |
| <xsl:call-template name="code_start_index"> |
| <xsl:with-param name="text" select="substring($text, 4)"/> |
| <xsl:with-param name="current_count" select="$current_count + 3"/> |
| </xsl:call-template> |
| </xsl:when> |
| <!-- This is only reached if the first line is entirely whitespace or |
| contains nothing but "Yes:" or "No:"--> |
| <xsl:when test="starts-with($text, '
')"> |
| <xsl:call-template name="code_start_index"> |
| <xsl:with-param name="text" select="substring($text, 2)"/> |
| <xsl:with-param name="current_count" select="0"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$current_count"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:template> |
| |
| <!-- Helper for ends_with_colon. Determine whether the given line is nothing |
| but spaces and python-style comments. --> |
| <xsl:template name="is_blank_or_comment"> |
| <xsl:param name="line"/> |
| <xsl:choose> |
| <xsl:when test="$line = ''"> |
| <xsl:value-of select="1"/> |
| </xsl:when> |
| <xsl:when test="starts-with($line, '
')"> |
| <xsl:value-of select="1"/> |
| </xsl:when> |
| <xsl:when test="starts-with($line, '#')"> |
| <xsl:value-of select="1"/> |
| </xsl:when> |
| <xsl:when test="starts-with($line, ' ')"> |
| <xsl:call-template name="is_blank_or_comment"> |
| <xsl:with-param name="line" select="substring($line, 2)"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="0"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:template> |
| |
| <!-- Determine whether the given line ends with a colon. Note that Python |
| style comments are ignored so the following lines return True: |
| - def foo(): |
| - def foo(): # Bar |
| - if(foo): |
| |
| But some code may confuse this function. For example the following are |
| also consider to "end_with_colon" even though they don't for Python |
| - foo(": #") |
| - foo() # No need for : |
| --> |
| <xsl:template name="ends_with_colon"> |
| <xsl:param name="line"/> |
| <xsl:param name="found_colon"/> |
| <xsl:choose> |
| <xsl:when test="$line = ''"> |
| <xsl:value-of select="$found_colon"/> |
| </xsl:when> |
| <xsl:when test="starts-with($line, '
')"> |
| <xsl:value-of select="$found_colon"/> |
| </xsl:when> |
| <xsl:when test="starts-with($line, ' ')"> |
| <xsl:call-template name="ends_with_colon"> |
| <xsl:with-param name="line" select="substring($line, 2)"/> |
| <xsl:with-param name="found_colon" select="$found_colon"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:when test="starts-with($line, ':')"> |
| <xsl:variable name="rest_is_comment"> |
| <xsl:call-template name="is_blank_or_comment"> |
| <xsl:with-param name="line" select="substring($line, 2)"/> |
| </xsl:call-template> |
| </xsl:variable> |
| <xsl:choose> |
| <xsl:when test="$rest_is_comment = '1'"> |
| <xsl:value-of select="1"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:call-template name="ends_with_colon"> |
| <xsl:with-param name="line" select="substring($line, 2)"/> |
| <xsl:with-param name="found_colon" select="0"/> |
| </xsl:call-template> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:call-template name="ends_with_colon"> |
| <xsl:with-param name="line" select="substring($line, 2)"/> |
| <xsl:with-param name="found_colon" select="0"/> |
| </xsl:call-template> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:template> |
| |
| <!-- Prints one line of python code with proper indent and calls itself |
| recursively for the rest of the text. |
| This template uses "a", "b", "c" and "d" to refer to four key column |
| numbers. They are: |
| - a: the indentation common to all lines in a code snippet. This is |
| stripped out to allow for cleaner code in the xml. |
| - b: the indentation of the most out-dented line of code. This is |
| different from "a" when code is labelled with "Yes:" or "No:" |
| - c: the indentation of the current python block, in other words, the |
| indentation of the first line of this block, which is the |
| indentation of the last line we saw that ended with a colon. |
| - d: the "total" indentation of the line, ignorng possible "Yes:" or |
| "No:" text on the line. |
| |
| For example, for the last line of the following code snippet, the |
| positions of a, b, c and d are indicated below: |
| Yes: def Foo(): |
| if bar(): |
| a += 1 |
| baz() |
| a b c d |
| |
| The algorithm is: |
| 1) Split the text into first line and the rest. Note that the |
| substring-before function is supposed to handle the case where the |
| character is not present in the string but does not so we |
| automatically ignore the last line of the snippet which is always |
| empty (the closing snippet tag). This is consistent with the |
| behavior or print_without_leading_chars. |
| 2) If the current is empty (only whitespace), print newline and call |
| itself recursively on the rest of the text with the rest of the |
| parameters unchanged. |
| 3) Otherwise, measure "d" |
| 4) Measure "c" by taking: |
| - the value of "d" if the previous line ended with a colon or the |
| current line is outdented compare to the previous line |
| - the indent of the previous line otherwise |
| 5) Print line[a:c] (Note that we ignore line[0:a]) |
| 6) Print line[b:c] in an external span (in order to double the block |
| indent in external code). |
| 7) Print line[c:<end>] with function names processed to produce both |
| internal and external names. |
| 8) If there are more lines, recurse. |
| --> |
| <xsl:template name="print_python_line_recursively"> |
| <xsl:param name="text"/> |
| <xsl:param name="a"/> |
| <xsl:param name="b"/> |
| <xsl:param name="previous_indent"/> |
| <xsl:param name="previous_ends_with_colon"/> |
| <xsl:param name="is_first_line"/> |
| <xsl:variable name="line" select="substring-before($text, '
')"/> |
| <xsl:variable name="rest" select="substring-after($text, '
')"/> |
| <xsl:choose> |
| <xsl:when test="substring($line, $b) = '' and not($rest = '')"> |
| <xsl:if test="not($is_first_line = '1')"> |
| <xsl:text>
</xsl:text> |
| </xsl:if> |
| <xsl:call-template name="print_python_line_recursively"> |
| <xsl:with-param name="text" select="$rest"/> |
| <xsl:with-param name="a" select="$a"/> |
| <xsl:with-param name="b" select="$b"/> |
| <xsl:with-param name="previous_indent" select="$previous_indent"/> |
| <xsl:with-param name="previous_ends_with_colon" |
| select="$previous_ends_with_colon"/> |
| <xsl:with-param name="is_first_line" select="0"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:variable name="indent_after_b"> |
| <xsl:call-template name="num_leading_spaces_one_line"> |
| <xsl:with-param name="text" select="substring($line, $b + 1)"/> |
| <xsl:with-param name="current_count" select="0"/> |
| </xsl:call-template> |
| </xsl:variable> |
| <xsl:variable name="d" select="$b + $indent_after_b"/> |
| <xsl:variable name="c"> |
| <xsl:choose> |
| <xsl:when test="$previous_ends_with_colon = '1' or |
| $previous_indent > $d"> |
| <xsl:value-of select="$d"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$previous_indent"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:variable> |
| |
| <xsl:value-of select="substring($line, $a + 1, $c - $a)"/> |
| <span class="external"> |
| <xsl:value-of select="substring($line, $b + 1, $c - $b)"/> |
| </span> |
| <xsl:call-template name="munge_function_names_in_text"> |
| <xsl:with-param name="stripped_line" |
| select="substring($line, $c + 1)"/> |
| </xsl:call-template> |
| <xsl:if test="not(substring($rest, $a) = '')"> |
| <xsl:text>
</xsl:text> |
| <xsl:call-template name="print_python_line_recursively"> |
| <xsl:with-param name="text" select="$rest"/> |
| <xsl:with-param name="a" select="$a"/> |
| <xsl:with-param name="b" select="$b"/> |
| <xsl:with-param name="previous_indent" select="$c"/> |
| <xsl:with-param name="previous_ends_with_colon"> |
| <xsl:call-template name="ends_with_colon"> |
| <xsl:with-param name="line" select="$line"/> |
| <xsl:with-param name="found_colon" select="0"/> |
| </xsl:call-template> |
| </xsl:with-param> |
| <xsl:with-param name="is_first_line" select="0"/> |
| </xsl:call-template> |
| </xsl:if> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:template> |
| |
| <!-- Print python code with internal and external styles. |
| In order to conform with PEP-8 externally, we identify 2-space indents |
| and an external-only 4-space indent. |
| Function names that are marked with $$FunctionName/$$ have an external |
| lower_with_underscore version added. --> |
| <xsl:template name="print_python_code"> |
| <xsl:param name="text"/> |
| |
| <xsl:variable name="a"> |
| <xsl:call-template name="num_leading_spaces"> |
| <xsl:with-param name="text" select="."/> |
| <xsl:with-param name="max_so_far" select="1000"/> |
| </xsl:call-template> |
| </xsl:variable> |
| |
| <xsl:variable name="b"> |
| <xsl:call-template name="code_start_index"> |
| <xsl:with-param name="text" select="$text"/> |
| <xsl:with-param name="current_count" select="0"/> |
| </xsl:call-template> |
| </xsl:variable> |
| |
| <xsl:call-template name="print_python_line_recursively"> |
| <xsl:with-param name="text" select="$text"/> |
| <xsl:with-param name="a" select="$a"/> |
| <xsl:with-param name="b" select="$b"/> |
| <xsl:with-param name="previous_indent" select="$b"/> |
| <xsl:with-param name="previous_ends_with_colon" select="0"/> |
| <xsl:with-param name="is_first_line" select="1"/> |
| </xsl:call-template> |
| </xsl:template> |
| |
| <!-- Given a block of text, each line terminated by \n, and a number n, |
| emits the text with the first n characters of each line |
| deleted. If strip==1, then we omit blank lines at the beginning |
| and end of the text (but not the middle!) --> |
| <!-- TODO(csilvers): deal well with leading tabs (treat as 8 spaces?) --> |
| <xsl:template name="print_without_leading_chars"> |
| <xsl:param name="text"/> |
| <xsl:param name="trim_count"/> |
| <xsl:param name="strip"/> |
| <xsl:param name="is_firstline"/> |
| <!-- TODO(csilvers): deal with case text doesn't end in a newline --> |
| <xsl:variable name="line" select="substring-before($text, '
')"/> |
| <xsl:variable name="rest" select="substring-after($text, '
')"/> |
| <xsl:variable name="stripped_line" select="substring($line, $trim_count+1)"/> |
| <xsl:choose> |
| <!-- $line (or $rest) is considered empty if we'd trim the entire line --> |
| <xsl:when test="($strip = '1') and ($is_firstline = '1') and |
| (string-length($line) <= $trim_count)"> |
| </xsl:when> |
| <xsl:when test="($strip = '1') and |
| (string-length($rest) <= $trim_count)"> |
| <xsl:value-of select="$stripped_line"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$stripped_line"/> |
| <xsl:text>
</xsl:text> |
| </xsl:otherwise> |
| </xsl:choose> |
| <xsl:if test="not($rest='')"> |
| <xsl:call-template name="print_without_leading_chars"> |
| <xsl:with-param name="text" select="$rest"/> |
| <xsl:with-param name="trim_count" select="$trim_count"/> |
| <xsl:with-param name="strip" select="$strip"/> |
| <xsl:with-param name="is_firstline" select="0"/> |
| </xsl:call-template> |
| </xsl:if> |
| </xsl:template> |
| |
| <!-- Given a line of code, find function names that are marked with $$ /$$ and |
| print out the line with the internal and external versions of the |
| function names.--> |
| <xsl:template name="munge_function_names_in_text"> |
| <xsl:param name="stripped_line"/> |
| <xsl:choose> |
| <xsl:when test="contains($stripped_line, '$$')"> |
| <xsl:value-of select="substring-before($stripped_line, '$$')"/> |
| <xsl:call-template name="print_function_name"> |
| <xsl:with-param name="text" select="substring-after(substring-before($stripped_line, '/$$'), '$$')"/> |
| </xsl:call-template> |
| <xsl:call-template name="munge_function_names_in_text"> |
| <xsl:with-param name="stripped_line" select="substring-after($stripped_line, '/$$')"/> |
| </xsl:call-template> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$stripped_line"/> |
| </xsl:otherwise> |
| </xsl:choose> |
| </xsl:template> |
| |
| <!-- Given a function name, print out both the internal and external version |
| of the function name in their respective spans.--> |
| <xsl:template name="print_function_name"> |
| <xsl:param name="text"/> |
| <xsl:call-template name="convert_camel_case_to_lowercase_with_under"> |
| <xsl:with-param name="text" select="$text"/> |
| </xsl:call-template> |
| </xsl:template> |
| |
| <!-- Given a single word of text convert it from CamelCase to |
| lower_with_under. |
| This means replacing each uppercase character with _ followed by the |
| lowercase version except for the first character which is replaced |
| without adding the _.--> |
| <xsl:template name="convert_camel_case_to_lowercase_with_under"> |
| <xsl:param name="text"/> |
| <xsl:param name="is_recursive_call"/> |
| <xsl:variable name="first_char" select="substring($text, 1, 1)"/> |
| <xsl:variable name="rest" select="substring($text, 2)"/> |
| <xsl:choose> |
| <xsl:when test="contains('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $first_char)"> |
| <xsl:if test="$is_recursive_call='1'"> |
| <xsl:text>_</xsl:text> |
| </xsl:if> |
| <xsl:value-of select="translate($first_char, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/> |
| </xsl:when> |
| <xsl:otherwise> |
| <xsl:value-of select="$first_char" /> |
| </xsl:otherwise> |
| </xsl:choose> |
| <xsl:if test="not($rest='')"> |
| <xsl:call-template name="convert_camel_case_to_lowercase_with_under"> |
| <xsl:with-param name="text" select="$rest"/> |
| <xsl:with-param name="is_recursive_call" select="1"/> |
| </xsl:call-template> |
| </xsl:if> |
| </xsl:template> |
| </xsl:stylesheet> |
| |