Skip to content

Commit 09cd228

Browse files
Merge pull request #292 from adamtheturtle/equation
Add support for maths equations
2 parents 168cb2a + 69940ea commit 09cd228

File tree

6 files changed

+183
-4
lines changed

6 files changed

+183
-4
lines changed

README.rst

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ For TODO list support, also add the `sphinx-immaterial <https://github.com/jbms/
7979
"sphinx_notion",
8080
]
8181
82+
For mathematical equation support, also add the ``sphinx.ext.mathjax`` extension:
83+
84+
.. code-block:: python
85+
86+
"""Configuration for Sphinx."""
87+
88+
extensions = [
89+
"sphinx.ext.mathjax",
90+
"sphinx_notion",
91+
]
92+
8293
PDF support is included by default with the sphinx-notionbuilder extension.
8394

8495
Supported markup
@@ -101,6 +112,7 @@ The following syntax is supported:
101112
- Tables
102113
- Strikethrough text
103114
- Colored text and text styles (bold, italic, monospace)
115+
- Mathematical equations (inline and block-level)
104116

105117
See a `sample document source <https://raw.githubusercontent.com/adamtheturtle/sphinx-notionbuilder/refs/heads/main/sample/index.rst>`_ and the `published Notion page <https://www.notion.so/Sphinx-Notionbuilder-Sample-2579ce7b60a48142a556d816c657eb55>`_.
106118

@@ -117,7 +129,7 @@ Audio files can be embedded using the ``audio`` directive. Both remote URLs and
117129
118130
The audio will be rendered as an audio player in the generated Notion page.
119131

120-
Using PDFs
132+
Using PDF
121133
----------
122134

123135
PDF files can be embedded using the ``pdf-include`` directive. Both remote URLs and local file paths are supported.
@@ -202,6 +214,45 @@ TODO lists with checkboxes can be created using the ``sphinx-immaterial.task_lis
202214
203215
The checkboxes will be rendered as interactive TODO items in the generated Notion page, with completed tasks showing as checked and incomplete tasks as unchecked.
204216

217+
Using Mathematical Equations
218+
-----------------------------
219+
220+
Mathematical equations can be embedded using the ``sphinx.ext.mathjax`` extension.
221+
Both inline and block-level equations are supported:
222+
223+
Inline Equations
224+
~~~~~~~~~~~~~~~~
225+
226+
Inline equations can be written using the ``:math:`` role:
227+
228+
.. code-block:: rst
229+
230+
This is an inline equation :math:`E = mc^2` in your text.
231+
232+
Here are some more examples:
233+
234+
- The quadratic formula: :math:`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
235+
- Euler's identity: :math:`e^{i\pi} + 1 = 0`
236+
237+
Block Equations
238+
~~~~~~~~~~~~~~~
239+
240+
Block-level equations can be written using the ``.. math::`` directive:
241+
242+
.. code-block:: rst
243+
244+
.. math::
245+
246+
E = mc^2
247+
248+
The Schrödinger equation:
249+
250+
.. math::
251+
252+
i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \hat{H}\Psi(\mathbf{r},t)
253+
254+
The equations will be rendered as proper mathematical notation in the generated Notion page, with inline equations appearing within the text flow and block equations appearing as separate equation blocks.
255+
205256
Unsupported Notion Block Types
206257
------------------------------
207258

@@ -212,7 +263,6 @@ Unsupported Notion Block Types
212263
- Column and column list
213264
- Divider
214265
- Embed
215-
- Equation
216266
- File
217267
- Link preview
218268
- Mention

sample/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
"sphinx_toolbox.collapse",
1212
"atsphinx.audioplayer",
1313
"sphinx_immaterial.task_lists",
14+
"sphinx.ext.mathjax",
1415
]

sample/index.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,49 @@ Here's some text before the PDF.
474474

475475
And here's some text after the PDF.
476476

477+
Mathematical Equations
478+
~~~~~~~~~~~~~~~~~~~~~~
479+
480+
The builder supports mathematical equations using the ``sphinx.ext.mathjax`` extension.
481+
482+
Inline Equations
483+
~~~~~~~~~~~~~~~~
484+
485+
You can include inline equations like this: :math:`E = mc^2` in your text.
486+
487+
Here are some more examples:
488+
489+
* The quadratic formula: :math:`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
490+
* The integral of x squared: :math:`\int x^2 dx = \frac{x^3}{3} + C`
491+
* Euler's identity: :math:`e^{i\pi} + 1 = 0`
492+
493+
Block Equations
494+
~~~~~~~~~~~~~~~
495+
496+
You can also include block-level equations:
497+
498+
.. math::
499+
500+
E = mc^2
501+
502+
The Schrödinger equation:
503+
504+
.. math::
505+
506+
i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \hat{H}\Psi(\mathbf{r},t)
507+
508+
Maxwell's equations:
509+
510+
.. math::
511+
512+
\nabla \cdot \mathbf{E} = \frac{\rho}{\epsilon_0}
513+
514+
\nabla \cdot \mathbf{B} = 0
515+
516+
\nabla \times \mathbf{E} = -\frac{\partial \mathbf{B}}{\partial t}
517+
518+
\nabla \times \mathbf{B} = \mu_0\mathbf{J} + \mu_0\epsilon_0\frac{\partial \mathbf{E}}{\partial t}
519+
477520
.. collapse:: Long code block
478521

479522
.. code-block:: python

sample/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
callout
22
checkboxes
33
reStructuredText
4+
Schrödinger

src/sphinx_notion/__init__.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from ultimate_notion.blocks import BulletedItem as UnoBulletedItem
3838
from ultimate_notion.blocks import Callout as UnoCallout
3939
from ultimate_notion.blocks import Code as UnoCode
40+
from ultimate_notion.blocks import Equation as UnoEquation
4041
from ultimate_notion.blocks import Heading as UnoHeading
4142
from ultimate_notion.blocks import (
4243
Heading1 as UnoHeading1,
@@ -66,7 +67,7 @@
6667
from ultimate_notion.blocks import Video as UnoVideo
6768
from ultimate_notion.file import ExternalFile
6869
from ultimate_notion.obj_api.enums import BGColor, CodeLang, Color
69-
from ultimate_notion.rich_text import Text, text
70+
from ultimate_notion.rich_text import Text, math, text
7071

7172
_LOGGER = sphinx_logging.getLogger(name=__name__)
7273

@@ -322,6 +323,15 @@ def _(child: nodes.paragraph) -> Text:
322323
return _create_styled_text_from_node(child=child)
323324

324325

326+
@beartype
327+
@_process_rich_text_node.register
328+
def _(child: nodes.math) -> Text:
329+
"""
330+
Process math nodes by creating math rich text.
331+
"""
332+
return math(expression=child.astext())
333+
334+
325335
@beartype
326336
def _create_styled_text_from_node(*, child: nodes.Element) -> Text:
327337
"""Create styled text from a node with CSS class support.
@@ -1320,6 +1330,21 @@ def _(
13201330
return []
13211331

13221332

1333+
@beartype
1334+
@_process_node_to_blocks.register
1335+
def _(
1336+
node: nodes.math_block,
1337+
*,
1338+
section_level: int,
1339+
) -> list[Block]:
1340+
"""
1341+
Process math block nodes by creating Notion Equation blocks.
1342+
"""
1343+
del section_level
1344+
latex_content = node.astext()
1345+
return [UnoEquation(latex=latex_content)]
1346+
1347+
13231348
@beartype
13241349
@_process_node_to_blocks.register
13251350
def _(

tests/test_integration.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from ultimate_notion.blocks import BulletedItem as UnoBulletedItem
2222
from ultimate_notion.blocks import Callout as UnoCallout
2323
from ultimate_notion.blocks import Code as UnoCode
24+
from ultimate_notion.blocks import Equation as UnoEquation
2425
from ultimate_notion.blocks import (
2526
Heading1 as UnoHeading1,
2627
)
@@ -49,7 +50,7 @@
4950
from ultimate_notion.blocks import Video as UnoVideo
5051
from ultimate_notion.file import ExternalFile
5152
from ultimate_notion.obj_api.enums import BGColor, CodeLang, Color
52-
from ultimate_notion.rich_text import Text, text
53+
from ultimate_notion.rich_text import Text, math, text
5354

5455

5556
@beartype
@@ -2823,3 +2824,61 @@ def setup(app):
28232824
tmp_path=tmp_path,
28242825
conf_py_content=conf_py_content,
28252826
)
2827+
2828+
2829+
def test_inline_equation(
2830+
*,
2831+
make_app: Callable[..., SphinxTestApp],
2832+
tmp_path: Path,
2833+
) -> None:
2834+
"""
2835+
Inline equations become Notion math rich text.
2836+
"""
2837+
rst_content = """
2838+
This is an inline equation :math:`E = mc^2` in a paragraph.
2839+
"""
2840+
2841+
normal_text1 = text(text="This is an inline equation ")
2842+
equation_text = math(expression="E = mc^2")
2843+
normal_text2 = text(text=" in a paragraph.")
2844+
2845+
combined_text = normal_text1 + equation_text + normal_text2
2846+
2847+
expected_paragraph = UnoParagraph(text=combined_text)
2848+
2849+
expected_objects: list[Block] = [expected_paragraph]
2850+
2851+
_assert_rst_converts_to_notion_objects(
2852+
rst_content=rst_content,
2853+
expected_objects=expected_objects,
2854+
make_app=make_app,
2855+
tmp_path=tmp_path,
2856+
extensions=("sphinx_notion", "sphinx.ext.mathjax"),
2857+
)
2858+
2859+
2860+
def test_block_equation(
2861+
*,
2862+
make_app: Callable[..., SphinxTestApp],
2863+
tmp_path: Path,
2864+
) -> None:
2865+
"""
2866+
Block equations become Notion Equation blocks.
2867+
"""
2868+
rst_content = """
2869+
.. math::
2870+
2871+
E = mc^2
2872+
"""
2873+
2874+
expected_objects: list[Block] = [
2875+
UnoEquation(latex="E = mc^2"),
2876+
]
2877+
2878+
_assert_rst_converts_to_notion_objects(
2879+
rst_content=rst_content,
2880+
expected_objects=expected_objects,
2881+
make_app=make_app,
2882+
tmp_path=tmp_path,
2883+
extensions=("sphinx_notion", "sphinx.ext.mathjax"),
2884+
)

0 commit comments

Comments
 (0)