diff --git a/lib/markdown2.py b/lib/markdown2.py index 84d7d6c2..0e37be6e 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -241,7 +241,7 @@ def __init__(self, html4tags=False, tab_width=4, safe_mode=None, extras = dict([(e, None) for e in extras]) self.extras.update(extras) assert isinstance(self.extras, dict) - if "toc" in self.extras and "header-ids" not in self.extras: + if ("toc" in self.extras or "inline-toc" in self.extras) and "header-ids" not in self.extras: self.extras["header-ids"] = None # "toc" implies "header-ids" self._instance_extras = self.extras.copy() @@ -390,8 +390,16 @@ def convert(self, text): text += "\n" + # Insert TOC HTML into the MD HTML after the first heading element if any headings are present. + if ("inline-toc" in self.extras and self._toc[0] is not None): + (level, id, name) = self._toc[0] + # Use a regex and rely on the HTML structure as opposed to tracking the heading regex's `end()` across all the HTML transformations (unreliable) + # TODO (Tomas Hubelbauer): Consider looser regex which allows for more attributes in order to to find heading even when more extras add attributes to it (future-proof) + pattern = r"\{}<\/h{}\>".format(level, id, re.escape(name), level) + text = re.sub(pattern, "\g<0>\n" + calculate_toc_html(self._toc), text) + rv = UnicodeWithAttrs(text) - if "toc" in self.extras: + if ("toc" in self.extras or "inline-toc" in self.extras): rv._toc = self._toc if "metadata" in self.extras: rv.metadata = self.metadata @@ -1540,7 +1548,7 @@ def _h_sub(self, match): if header_id: header_id_attr = ' id="%s"' % header_id html = self._run_span_gamut(header_group) - if "toc" in self.extras and header_id: + if ("toc" in self.extras or "inline-toc" in self.extras) and header_id: self._toc_add_entry(n, header_id, html) return "%s\n\n" % (n, header_id_attr, html, n) @@ -2222,6 +2230,39 @@ class MarkdownWithExtras(Markdown): # ---- internal support functions +def calculate_toc_html(toc): + """Return the HTML for the current TOC. + + This expects the `_toc` attribute to have been set on this instance. + """ + if toc is None: + return None + + def indent(): + return ' ' * (len(h_stack) - 1) + lines = [] + h_stack = [0] # stack of header-level numbers + for level, id, name in toc: + if level > h_stack[-1]: + lines.append("%s" % indent()) + lines.append('%s
  • %s' % ( + indent(), id, name)) + while len(h_stack) > 1: + h_stack.pop() + if not lines[-1].endswith("
  • "): + lines[-1] += "" + lines.append("%s" % indent()) + return '\n'.join(lines) + '\n' + class UnicodeWithAttrs(unicode): """A subclass of unicode used for the return value of conversion to possibly attach some attributes. E.g. the "toc_html" attribute when @@ -2230,37 +2271,7 @@ class UnicodeWithAttrs(unicode): metadata = None _toc = None def toc_html(self): - """Return the HTML for the current TOC. - - This expects the `_toc` attribute to have been set on this instance. - """ - if self._toc is None: - return None - - def indent(): - return ' ' * (len(h_stack) - 1) - lines = [] - h_stack = [0] # stack of header-level numbers - for level, id, name in self._toc: - if level > h_stack[-1]: - lines.append("%s" % indent()) - lines.append('%s
  • %s' % ( - indent(), id, name)) - while len(h_stack) > 1: - h_stack.pop() - if not lines[-1].endswith("
  • "): - lines[-1] += "" - lines.append("%s" % indent()) - return '\n'.join(lines) + '\n' + return calculate_toc_html(self._toc) toc_html = property(toc_html) ## {{{ http://code.activestate.com/recipes/577257/ (r1)