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

Add a toc for html and latex exporter #2178

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c0f597f
Add a function to extract the titles and levels of headings from the …
HaudinFlorence Sep 16, 2024
9a84d24
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 16, 2024
2f1ab0b
Updates jinja templates.
HaudinFlorence Sep 16, 2024
5c22927
Update jinja templates and add style to the table of contents.
HaudinFlorence Sep 17, 2024
1c7427a
Add links to be able to go to the relevant sections when clicking on …
HaudinFlorence Sep 17, 2024
c86d451
Place the css inline in index.html.j2.
HaudinFlorence Sep 17, 2024
c23d1eb
Remove index.css from the git index.
HaudinFlorence Sep 17, 2024
8780c56
Add the include_tableofcontents traitlet and update the jinja templat…
HaudinFlorence Sep 18, 2024
3bdca36
Add the logics to include a table of contents for the latex exporter.
HaudinFlorence Sep 19, 2024
b318e57
Update nbconvertapp with removing toc from alias and with adding toc …
HaudinFlorence Oct 4, 2024
7d4b572
Try to fix failing CI tests.
HaudinFlorence Oct 4, 2024
28913c9
Try to fix pre-commit test.
HaudinFlorence Oct 7, 2024
a804318
Try to fix failing linting test.
HaudinFlorence Oct 7, 2024
c70f4fc
Update markdown.mistune.py and add docstrings to get 100% as a score …
HaudinFlorence Oct 7, 2024
f175d45
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
3b4bc4d
Apply suggestions from code review
HaudinFlorence Oct 7, 2024
36e8889
Apply other suggestions from code review.
HaudinFlorence Oct 7, 2024
efc0133
Fix linting issues.
HaudinFlorence Oct 7, 2024
7eeac98
Try to fix failing linting test.
HaudinFlorence Oct 8, 2024
9554b7e
Try to remove None check condition.
HaudinFlorence Oct 8, 2024
df17ef2
Restore None check condition in HTML exporter instead of _init_resources
HaudinFlorence Oct 9, 2024
e6f9d9e
Change method extract_titles_from_markdown_input to extract_titles_fr…
HaudinFlorence Oct 14, 2024
c03c701
Update extract_titles_from_notebook_node to fix some parsing issues.
HaudinFlorence Oct 25, 2024
093b120
Try to fix failing tests.
HaudinFlorence Oct 25, 2024
338f071
Remove condition on headers of level 1.
HaudinFlorence Nov 4, 2024
5803af7
Update extract_titles_from_notebook_node.
HaudinFlorence Nov 4, 2024
d9ffc0c
Change the logics to get the headers using parsing of the markdown ce…
HaudinFlorence Nov 6, 2024
3211755
Add sysmetically an id to the headers to be sure to have a defined href.
HaudinFlorence Nov 7, 2024
3b45be0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 7, 2024
6080520
Restore previous version of markdown_mistune.py.
HaudinFlorence Feb 3, 2025
c3e5899
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,7 @@ raw template
{%- endblock in_prompt -%}
"""


exporter_attr = AttrExporter()
output_attr, _ = exporter_attr.from_notebook_node(nb)
assert "raw template" in output_attr
Expand Down
57 changes: 57 additions & 0 deletions Untitled.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "e1ecc100-fae0-422f-bcf6-73fbb2bdd215",
"metadata": {},
"source": [
"#test"
]
},
{
"cell_type": "markdown",
"id": "23c99cdf-7405-4c4f-889e-2ce72db47d23",
"metadata": {},
"source": [
"##test1"
]
},
{
"cell_type": "markdown",
"id": "422906ca-be89-4a2a-823f-e498ea193767",
"metadata": {},
"source": [
"##test2"
]
},
{
"cell_type": "markdown",
"id": "ac26a764-016b-4a8d-82b0-b34f2961c36a",
"metadata": {},
"source": [
"##test3"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
8 changes: 7 additions & 1 deletion nbconvert/exporters/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
from nbformat import NotebookNode

from nbconvert.filters.highlight import Highlight2HTML
from nbconvert.filters.markdown_mistune import IPythonRenderer, MarkdownWithMath
from nbconvert.filters.markdown_mistune import (
IPythonRenderer,
MarkdownWithMath,
extract_titles_from_notebook_node,
)
from nbconvert.filters.widgetsdatatypefilter import WidgetsDataTypeFilter
from nbconvert.utils.iso639_1 import iso639_1

Expand Down Expand Up @@ -355,6 +359,7 @@ def resources_include_url(name):
return markupsafe.Markup(src)

resources = super()._init_resources(resources)

resources["theme"] = self.theme
resources["include_css"] = resources_include_css
resources["include_lab_theme"] = resources_include_lab_theme
Expand All @@ -370,4 +375,5 @@ def resources_include_url(name):
resources["should_sanitize_html"] = self.sanitize_html
resources["language_code"] = self.language_code
resources["should_not_encode_svg"] = self.skip_svg_encoding
resources["extract_titles_from_nodebook_node"] = extract_titles_from_notebook_node
return resources
4 changes: 4 additions & 0 deletions nbconvert/exporters/templateexporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ def default_config(self):
enable_async = Bool(False, help="Enable Jinja async template execution").tag(
affects_environment=True
)
include_tableofcontents = Bool(
False, allow_none=True, help="Enable to include a table of contents"
).tag(config=True, affects_template=True)

_last_template_file = ""
_raw_template_key = "<memory>"
Expand Down Expand Up @@ -684,4 +687,5 @@ def get_prefix_root_dirs(self):
def _init_resources(self, resources):
resources = super()._init_resources(resources)
resources["deprecated"] = deprecated
resources["include_tableofcontents"] = self.include_tableofcontents
return resources
38 changes: 38 additions & 0 deletions nbconvert/filters/markdown_mistune.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Iterable, Match, Optional, Protocol, Tuple

import bs4
import mistune
from mistune.renderers.markdown import MarkdownRenderer
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexer import Lexer
Expand Down Expand Up @@ -504,3 +506,39 @@ def render(self, source: str) -> str:
def markdown2html_mistune(source: str) -> str:
"""Convert a markdown string to HTML using mistune"""
return MarkdownWithMath(renderer=IPythonRenderer(escape=False)).render(source)


class HeadingExtractor(MarkdownRenderer):
"""A renderer to capture headings"""

def __init__(self):
"""Initialize the class."""
super().__init__()
self.headings = []

def heading(self, text, level):
"""Return an empty string for the headings to avoid outputting them."""
self.headings.append((level, text))
return ""


def extract_titles_from_markdown_input(markdown_input):
"""Create a Markdown parser with the HeadingExtractor renderer to collect all the headings of a notebook"""
""" The input argument is markdown_input that is a single string with all the markdown content concatenated """
""" The output is an array containing information about the headings such as their level, their text content, an identifier and a href that can be used in case of html converter.s"""
HaudinFlorence marked this conversation as resolved.
Show resolved Hide resolved
titles_array = []
renderer = HeadingExtractor()
extract_titles = mistune.create_markdown(renderer=renderer)
extract_titles(markdown_input)
headings = renderer.headings

""" Iterate on all headings to get the necessary information on the various titles """
HaudinFlorence marked this conversation as resolved.
Show resolved Hide resolved
for __, title in headings:
children = title["children"]
attrs = title["attrs"]
raw_text = children[0]["raw"]
header_level = attrs["level"]
id = raw_text.replace(" ", "-")
href = "#" + id
titles_array.append([header_level, raw_text, id, href])
return titles_array
5 changes: 5 additions & 0 deletions nbconvert/nbconvertapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ def validate(self, obj, value):
},
"""Whether the HTML in Markdown cells and cell outputs should be sanitized..""",
),
"toc": (
{"TemplateExporter": {"include_tableofcontents": True}},
"Generate a table of contents in the output (only compatible with HTML and Latex exporters)",
),
}
)

Expand Down Expand Up @@ -675,5 +679,6 @@ def _default_export_format(self):
# Main entry point
# -----------------------------------------------------------------------------


main = launch_new_instance = NbConvertApp.launch_instance
dejavu_main = DejavuApp.launch_instance
1 change: 1 addition & 0 deletions share/templates/lab/base.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% from 'celltags.j2' import celltags %}
{% from 'cell_id_anchor.j2' import cell_id_anchor %}


{% block codecell %}
{%- if not cell.outputs -%}
{%- set no_output_class="jp-mod-noOutputs" -%}
Expand Down
78 changes: 78 additions & 0 deletions share/templates/lab/index.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,56 @@ a.anchor-link {
display: block;
}
}
/* Table of Contents for the html exporter */
.jp-RenderedHTMLTOC-Title {
font-family: var(--jp-content-font-family);
font-size: 14px;
margin: 16px 0;
padding-left: 64px;
font-weight: bold;
}

.jp-RenderedHTMLTOC-Item-h1 {
font-family: var(--jp-content-font-family);
font-size: 14px;
margin: 0;
padding-left: 88px;
}

.jp-RenderedHTMLTOC-Item-h2 {
font-family: var(--jp-content-font-family);
font-size: 12px;
margin: 4px;
padding-left: 112px;
}

.jp-RenderedHTMLTOC-Item-h3 {
font-family: var(--jp-content-font-family);
font-size:10px;
margin: 4px;
padding-left: 136px;
}

.jp-RenderedHTMLTOC-Item-h4 {
font-family: var(--jp-content-font-family);
font-size: 8px;
margin: 4px;
padding-left: 160px;
}

.jp-RenderedHTMLTOC-Item-h5 {
font-family: var(--jp-content-font-family);
font-size: 7px;
margin: 4px;
padding-left: 184px;
}

.jp-RenderedHTMLTOC-Item-h6 {
font-family: var(--jp-content-font-family);
font-size: 6px;
margin: 2px;
padding-left: 208px;
}
</style>

{% endblock notebook_css %}
Expand All @@ -126,6 +176,34 @@ a.anchor-link {
<body class="jp-Notebook" data-jp-theme-light="true" data-jp-theme-name="JupyterLab Light">
{% endif %}
<main>
{%- block tableofcontents -%}
{%- if resources.include_tableofcontents -%}
{%- set tableofcontents= resources.extract_titles_from_nodebook_node(nb) -%}
<div class="jp-RenderedHTMLTOC-Title">Table of contents</div>
{%- for item in tableofcontents -%}
{%- set (header, level, href) = item -%}
<div class="
{%- if level==1 -%}
jp-RenderedHTMLCommon jp-RenderedHTMLTOC-Item-h1
{%- elif level==2 -%}
jp-RenderedHTMLCommon jp-RenderedHTMLTOC-Item-h2
{%- elif level==3 -%}
jp-RenderedHTMLCommon jp-RenderedHTMLTOC-Item-h3
{%- elif level==4 -%}
jp-RenderedHTMLCommon jp-RenderedHTMLTOC-Item-h4
{%- elif level==5 -%}
jp-RenderedHTMLCommon jp-RenderedHTMLTOC-Item-h5
{%- elif level==6 -%}
jp-RenderedHTMLCommon jp-RenderedHTMLTOC-Item-h6
{%- endif -%}"
>
<a href={{href}}>
{{header | safe}}
</a>
</div>
{%- endfor -%}
{%- endif -%}
{% endblock tableofcontents %}
{%- endblock body_header -%}

{% block body_footer %}
Expand Down
6 changes: 6 additions & 0 deletions share/templates/latex/base.tex.j2
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,17 @@ override this.-=))
((* endblock header *))

((* block body *))

\begin{document}
((* block predoc *))
((* block maketitle *))\maketitle((* endblock maketitle *))
((* block abstract *))((* endblock abstract *))
((* endblock predoc *))
((* block tableofcontents *))
((* if resources.include_tableofcontents *))
\tableofcontents
((* endif *))
((* endblock tableofcontents *))

((( super() )))

Expand Down
Loading
Loading