/src/PEAR2/Text/Markdown/Extra/DefList.php

https://github.com/pear2/Text_Markdown · PHP · 255 lines · 116 code · 21 blank · 118 comment · 3 complexity · 29989e4a7f5171d7bc26b2b1507fc1fe MD5 · raw file

  1. <?php
  2. /**
  3. *
  4. * Block class to form definition lists.
  5. *
  6. * Syntax is ...
  7. *
  8. * term
  9. * : definition
  10. *
  11. * term1
  12. * term2
  13. * : definition
  14. *
  15. * term
  16. * : definition 1
  17. * : definition 2
  18. *
  19. * @category Solar
  20. *
  21. * @package Markdown_Extra
  22. *
  23. * @author Michel Fortin <http://www.michelf.com/projects/php-markdown/>
  24. *
  25. * @author Paul M. Jones <pmjones@solarphp.com>
  26. *
  27. * @license http://opensource.org/licenses/bsd-license.php BSD
  28. *
  29. * @version $Id: DefList.php 4531 2010-04-12 17:23:56Z pmjones $
  30. *
  31. */
  32. namespace PEAR2\Text;
  33. class Markdown_Extra_DefList extends Markdown_Plugin
  34. {
  35. /**
  36. *
  37. * This is a block plugin.
  38. *
  39. * @var bool
  40. *
  41. */
  42. protected $_is_block = true;
  43. /**
  44. *
  45. * The tag to open a definition term.
  46. *
  47. * @var string
  48. *
  49. */
  50. protected $_dt_open = '<dt>';
  51. /**
  52. *
  53. * The tag to close a definition term.
  54. *
  55. * @var string
  56. *
  57. */
  58. protected $_dt_close = '</dt>';
  59. /**
  60. *
  61. * The tag to open a definition definition.
  62. *
  63. * @var string
  64. *
  65. */
  66. protected $_dd_open = '<dd>';
  67. /**
  68. *
  69. * The tag to close a definition definition.
  70. *
  71. * @var string
  72. *
  73. */
  74. protected $_dd_close = '</dd>';
  75. /**
  76. *
  77. * Processes source text to find definition lists.
  78. *
  79. * @param string $text The source text.
  80. *
  81. * @return string The transformed XHTML.
  82. *
  83. */
  84. public function parse($text)
  85. {
  86. $less_than_tab = $this->_getTabWidth() - 1;
  87. // Re-usable pattern to match any entire dl list:
  88. $whole_list = '
  89. ( # $1 = whole list
  90. ( # $2
  91. [ ]{0,'.$less_than_tab.'}
  92. ((?>.*\S.*\n)+) # $3 = defined term
  93. \n?
  94. [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
  95. )
  96. (?s:.+?)
  97. ( # $4
  98. \z
  99. |
  100. \n{2,}
  101. (?=\S)
  102. (?! # Negative lookahead for another term
  103. [ ]{0,'.$less_than_tab.'}
  104. (?: \S.*\n )+? # defined term
  105. \n?
  106. [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
  107. )
  108. (?! # Negative lookahead for another definition
  109. [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
  110. )
  111. )
  112. )
  113. '; // mx
  114. $text = preg_replace_callback(
  115. '{
  116. (?:(?<=\n\n)|\A\n?)
  117. ' . $whole_list . '
  118. }mx',
  119. array($this, '_parse'),
  120. $text
  121. );
  122. return $text;
  123. }
  124. /**
  125. *
  126. * Support callback for block quotes.
  127. *
  128. * @param array $matches Matches from preg_replace_callback().
  129. *
  130. * @return string The replacement text.
  131. *
  132. */
  133. protected function _parse($matches)
  134. {
  135. // Re-usable patterns to match list item bullets and number markers:
  136. $list = $matches[1];
  137. // Turn double returns into triple returns, so that we can make a
  138. // paragraph for the last item in a list, if necessary:
  139. $result = trim($this->_processItems($list));
  140. $result = "<dl>\n" . $result . "\n</dl>";
  141. return $this->_toHtmlToken($result) . "\n\n";
  142. }
  143. /**
  144. *
  145. * Process the contents of a definition list, splitting it into
  146. * individual list items.
  147. *
  148. * @param string $list_str The source text of the list block.
  149. *
  150. * @return string The replacement text.
  151. *
  152. */
  153. protected function _processItems($list_str)
  154. {
  155. $less_than_tab = $this->_getTabWidth() - 1;
  156. // trim trailing blank lines:
  157. $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
  158. // Process definition terms.
  159. $list_str = preg_replace_callback(
  160. '{
  161. (?:\n\n+|\A\n?) # leading line
  162. ( # definition terms = $1
  163. [ ]{0,'.$less_than_tab.'} # leading whitespace
  164. (?![:][ ]|[ ]) # negative lookahead for a definition
  165. # mark (colon) or more whitespace.
  166. (?: \S.* \n)+? # actual term (not whitespace).
  167. )
  168. (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed
  169. # with a definition mark.
  170. }xm',
  171. array($this, '_processDt'),
  172. $list_str
  173. );
  174. // Process actual definitions.
  175. $list_str = preg_replace_callback(
  176. '{
  177. \n(\n+)? # leading line = $1
  178. [ ]{0,'.$less_than_tab.'} # whitespace before colon
  179. [:][ ]+ # definition mark (colon)
  180. ((?s:.+?)) # definition text = $2
  181. (?= \n+ # stop at next definition mark,
  182. (?: # next term or end of text
  183. [ ]{0,'.$less_than_tab.'} [:][ ] |
  184. '.$this->_dt_open.' | \z
  185. )
  186. )
  187. }xm',
  188. array($this, '_processDd'),
  189. $list_str
  190. );
  191. return $list_str;
  192. }
  193. /**
  194. *
  195. * Support callback for processing item terms.
  196. *
  197. * @param array $matches Matches from preg_replace_callback().
  198. *
  199. * @return string The replacement text.
  200. *
  201. */
  202. protected function _processDt($matches)
  203. {
  204. $terms = explode("\n", trim($matches[1]));
  205. $text = '';
  206. foreach ($terms as $term) {
  207. $term = $this->_processSpans(trim($term));
  208. $text .= "\n{$this->_dt_open}" . $term . $this->_dt_close;
  209. }
  210. return $text . "\n";
  211. }
  212. /**
  213. *
  214. * Support callback for processing item definitions.
  215. *
  216. * @param array $matches Matches from preg_replace_callback().
  217. *
  218. * @return string The replacement text.
  219. *
  220. */
  221. protected function _processDd($matches)
  222. {
  223. $leading_line = $matches[1];
  224. $def = $matches[2];
  225. if ($leading_line || preg_match('/\n{2,}/', $def)) {
  226. $def = $this->_processBlocks($this->_outdent($def . "\n\n"));
  227. $def = "\n". $def ."\n";
  228. } else {
  229. $def = rtrim($def);
  230. $def = $this->_processSpans($this->_outdent($def));
  231. }
  232. return "\n{$this->_dd_open}" . $def . "{$this->_dd_close}\n";
  233. }
  234. }