styleguide.xsl 36 KB

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