Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Implement inline-toc extra for TOC HTML insertion after first heading #280

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 15 additions & 3 deletions lib/markdown2.py
Expand Up @@ -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()

Expand Down Expand Up @@ -391,8 +391,20 @@ def convert(self, text):
text += "\n"

rv = UnicodeWithAttrs(text)
if "toc" in self.extras:
if ("toc" in self.extras or "inline-toc" in self.extras):
# Generate TOC HTML as a property to be able to hijack it in "inline-toc" for subsctitution
# TODO (Tomas Hubelbauer): See about using that as a static method without a need for a throwaway instance.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently needlessly inefficient, here I just take advantage of the fact that the object with toc_html on it is already created and replace its reference with a new copy. I will investigate static methods in Python to see if I can run inline-toc before line 393 and avoid having to create two objects.

  • Investigate using a static method and avoid creating a throwaway object

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not end up using staticmethod decorator because I wasn't sure if Python 2.2 and 2.3 are expected to be supported and even then it gave me a hard time with me calling it within UnicodeWithAttrs where it was defined but it reporting UnicodeWithAttrs.toc_html not existing.

rv._toc = self._toc
if "inline-toc" in self.extras:
if self._toc[0] is None:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have no headings, there is no need to prepend anything (toc_html with be either empty or just <ul></ul> I need to check), so this if can probably be simplified.

  • Check if if _toc[0] is None it makes sense to insert the TOC HTML or if it is empty and we can just skip

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed this to only include the TOC HTML if any heading exist.

rv = UnicodeWithAttrs(rv.toc_html + text)
else:
(level, id, name) = self._toc[0]
# Need to use a regex and rely on the HTML structure, tracking the regex's `end()` across all the HTML transformations would be extremely 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{} id=[\"\']{}[\"\']\>{}<\/h{}\>".format(level, id, re.escape(name), level)
text = re.sub(pattern, "\g<0>" + rv.toc_html, text)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to somehow check for the failure of the substitution and prepend the TOC HTML instead, but not sure what would be the best way to go about that.

Oh and this probably doesn't deal well with multiple headings with the same text, I need to check for that.

  • Verify this only replaces once and not multiple headings with the same level, id and text

rv = UnicodeWithAttrs(text)
if "metadata" in self.extras:
rv.metadata = self.metadata
return rv
Expand Down Expand Up @@ -1540,7 +1552,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 "<h%d%s>%s</h%d>\n\n" % (n, header_id_attr, html, n)

Expand Down