Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Added level control for TOC and wikipedia style auto-numbering #102

Closed
wants to merge 4 commits into from

1 participant

@cdman

For example having the following options: {"extras": {"toc": {"min-header-level": 2, "max-header-level": 4, "number-html-toc": True}}}

And the following input:
# README for Blah

    ## Introduction

    ## The Meat

    ### Beef

    ##### Steak

    ##### Burgers

    ### Chicken

    ### Pork

    #### Mmmmmmmm, bacon

    # At the *top* level again!?

The output should be:

1 Introduction

2 The Meat

2.1 Beef

2.2 Chicken

2.3 Pork

2.3.1 Mmmmmmmm, bacon

@cdman

Closing, as it has been reposted at #132

@cdman cdman closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 13, 2012
  1. @cdman

    Added level control for TOC (min/max levels to include) and auto-numb…

    cdman authored
    …ering for generated html
Commits on Sep 14, 2012
  1. @cdman
  2. @cdman
Commits on Sep 27, 2012
  1. @cdman
This page is out of date. Refresh to see the latest.
View
62 lib/markdown2.py
@@ -333,6 +333,12 @@ def convert(self, text):
rv = UnicodeWithAttrs(text)
if "toc" in self.extras:
rv._toc = self._toc
+ rv._number_toc = self.extras["toc"] and self.extras["toc"].get("number-html-toc", False)
+ if self.extras["toc"]:
+ rv._min_header_level = self.extras["toc"].get(
+ "min-header-level", rv._min_header_level)
+ rv._max_header_level = self.extras["toc"].get(
+ "max-header-level", rv._max_header_level)
if "metadata" in self.extras:
rv.metadata = self.metadata
return rv
@@ -1238,19 +1244,7 @@ def _toc_add_entry(self, level, id, name):
_setext_h_re = re.compile(r'^(.+)[ \t]*\n(=+|-+)[ \t]*\n+', re.M)
def _setext_h_sub(self, match):
n = {"=": 1, "-": 2}[match.group(2)[0]]
- demote_headers = self.extras.get("demote-headers")
- if demote_headers:
- n = min(n + demote_headers, 6)
- header_id_attr = ""
- if "header-ids" in self.extras:
- header_id = self.header_id_from_text(match.group(1),
- self.extras["header-ids"], n)
- if header_id:
- header_id_attr = ' id="%s"' % header_id
- html = self._run_span_gamut(match.group(1))
- if "toc" in self.extras and header_id:
- self._toc_add_entry(n, header_id, html)
- return "<h%d%s>%s</h%d>\n\n" % (n, header_id_attr, html, n)
+ return self._h_sub(n, match.group(1))
_atx_h_re = re.compile(r'''
^(\#{1,6}) # \1 = string of #'s
@@ -1263,19 +1257,22 @@ def _setext_h_sub(self, match):
''', re.X | re.M)
def _atx_h_sub(self, match):
n = len(match.group(1))
+ return self._h_sub(n, match.group(2))
+
+ def _h_sub(self, level, text):
demote_headers = self.extras.get("demote-headers")
if demote_headers:
- n = min(n + demote_headers, 6)
+ level = min(level + demote_headers, 6)
header_id_attr = ""
if "header-ids" in self.extras:
- header_id = self.header_id_from_text(match.group(2),
- self.extras["header-ids"], n)
+ header_id = self.header_id_from_text(text,
+ self.extras["header-ids"], level)
if header_id:
header_id_attr = ' id="%s"' % header_id
- html = self._run_span_gamut(match.group(2))
+ html = self._run_span_gamut(text)
if "toc" in self.extras and header_id:
- self._toc_add_entry(n, header_id, html)
- return "<h%d%s>%s</h%d>\n\n" % (n, header_id_attr, html, n)
+ self._toc_add_entry(level, header_id, html)
+ return "<h%d%s>%s</h%d>\n\n" % (level, header_id_attr, html, level)
def _do_headers(self, text):
# Setext-style headers:
@@ -1890,39 +1887,58 @@ class UnicodeWithAttrs(unicode):
"""
metadata = None
_toc = None
- def toc_html(self):
+ _min_header_level = 1
+ _max_header_level = 6
+ _number_toc = False
+ def render_toc_html(self, min_header_level=None, max_header_level=None, number_toc=None):
"""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
+ min_header_level = self._min_header_level if min_header_level is None else min_header_level
+ max_header_level = self._max_header_level if max_header_level is None else max_header_level
+ number_toc = self._number_toc if number_toc is None else number_toc
def indent():
return ' ' * (len(h_stack) - 1)
lines = []
h_stack = [0] # stack of header-level numbers
+ counters = []
for level, id, name in self._toc:
+ if level < min_header_level or level > max_header_level:
+ continue
+ level = level - min_header_level + 1
if level > h_stack[-1]:
lines.append("%s<ul>" % indent())
h_stack.append(level)
+ counters.append(1)
elif level == h_stack[-1]:
lines[-1] += "</li>"
+ counters[-1] += 1
else:
while level < h_stack[-1]:
h_stack.pop()
+ counters.pop()
if not lines[-1].endswith("</li>"):
lines[-1] += "</li>"
lines.append("%s</ul></li>" % indent())
- lines.append('%s<li><a href="#%s">%s</a>' % (
- indent(), id, name))
+ counters[-1] += 1
+ if number_toc:
+ lines.append('%s<li>%s <a href="#%s">%s</a>' % (
+ indent(), '.'.join(str(c) for c in counters),
+ id, name))
+ else:
+ lines.append('%s<li><a href="#%s">%s</a>' % (
+ indent(), id, name))
while len(h_stack) > 1:
h_stack.pop()
if not lines[-1].endswith("</li>"):
lines[-1] += "</li>"
lines.append("%s</ul>" % indent())
return '\n'.join(lines) + '\n'
- toc_html = property(toc_html)
+ toc_html = property(render_toc_html)
## {{{ http://code.activestate.com/recipes/577257/ (r1)
_slugify_strip_re = re.compile(r'[^\w\s-]')
View
19 test/tm-cases/toc_3.html
@@ -0,0 +1,19 @@
+<h1 id="readme-for-blah">README for Blah</h1>
+
+<h2 id="introduction">Introduction</h2>
+
+<h2 id="the-meat">The Meat</h2>
+
+<h3 id="beef">Beef</h3>
+
+<h5 id="steak">Steak</h5>
+
+<h5 id="burgers">Burgers</h5>
+
+<h3 id="chicken">Chicken</h3>
+
+<h3 id="pork">Pork</h3>
+
+<h4 id="mmmmmmmm-bacon">Mmmmmmmm, bacon</h4>
+
+<h1 id="at-the-top-level-again">At the <em>top</em> level again!?</h1>
View
1  test/tm-cases/toc_3.opts
@@ -0,0 +1 @@
+{"extras": {"toc": {"min-header-level": 2, "max-header-level": 4, "number-html-toc": True}}}
View
1  test/tm-cases/toc_3.tags
@@ -0,0 +1 @@
+toc extra
View
20 test/tm-cases/toc_3.text
@@ -0,0 +1,20 @@
+# README for Blah
+
+## Introduction
+
+## The Meat
+
+### Beef
+
+##### Steak
+
+##### Burgers
+
+### Chicken
+
+### Pork
+
+#### Mmmmmmmm, bacon
+
+# At the *top* level again!?
+
View
12 test/tm-cases/toc_3.toc_html
@@ -0,0 +1,12 @@
+<ul>
+ <li>1 <a href="#introduction">Introduction</a></li>
+ <li>2 <a href="#the-meat">The Meat</a>
+ <ul>
+ <li>2.1 <a href="#beef">Beef</a></li>
+ <li>2.2 <a href="#chicken">Chicken</a></li>
+ <li>2.3 <a href="#pork">Pork</a>
+ <ul>
+ <li>2.3.1 <a href="#mmmmmmmm-bacon">Mmmmmmmm, bacon</a></li>
+ </ul></li>
+ </ul></li>
+</ul>
View
13 test/tm-cases/toc_4.html
@@ -0,0 +1,13 @@
+<h1 id="title">Title</h1>
+
+<h1 id="title-2">Title</h1>
+
+<h2 id="subtitle">Subtitle</h2>
+
+<h3 id="sub-subtitle">Sub-subtitle</h3>
+
+<h1 id="title-3">Title</h1>
+
+<h2 id="subtitle-2">Subtitle</h2>
+
+<h3 id="sub-subtitle-2">Sub-subtitle</h3>
View
1  test/tm-cases/toc_4.opts
@@ -0,0 +1 @@
+{"extras": {"toc": {"number-html-toc": True}}}
View
15 test/tm-cases/toc_4.text
@@ -0,0 +1,15 @@
+Title
+=====
+
+# Title
+
+Subtitle
+--------
+
+### Sub-subtitle
+
+# Title
+
+## Subtitle
+
+### Sub-subtitle
View
17 test/tm-cases/toc_4.toc_html
@@ -0,0 +1,17 @@
+<ul>
+ <li>1 <a href="#title">Title</a>
+ <ul>
+ <li>1.1 <a href="#subtitle">Subtitle</a></li>
+ </ul></li>
+ <li>2 <a href="#title-2">Title</a>
+ <ul>
+ <li>2.1 <a href="#sub-subtitle">Sub-subtitle</a></li>
+ </ul></li>
+ <li>3 <a href="#title-3">Title</a>
+ <ul>
+ <li>3.1 <a href="#subtitle-2">Subtitle</a>
+ <ul>
+ <li>3.1.1 <a href="#sub-subtitle-2">Sub-subtitle</a></li>
+ </ul></li>
+ </ul></li>
+</ul>
Something went wrong with that request. Please try again.