markdown.obsidian.footnotes

Functions for parsing footnotes in Obsidian.md style markdown.
from fastcore.test import *

We use the following example:

# TODO The footnote below spans multiple lines  Find out if this affects any raw-text extraction.
# r'''[^3]: Here is an embedded image,  
# ![[Pasted image 20221009114121.png]]
# This is still part of the footnote.
#
# This is not part of the footnote'''

Finding footnote descriptions

Things like

[^1]: Hello, this is a footnote being described


source

find_footnote_descriptions_in_markdown_text

 find_footnote_descriptions_in_markdown_text (text:str)

Return ranges in the markdown text string where footnote descriptions occur.

By footnote descriptions, I mean some of the form [^label]: some description of the footnote.

Returns

  • list[tuple]
    • Each tuple is of the form (a,b) where text[a:b] is the full substring of a markdown footnote description.
Type Details
text str
Returns list Each tuple is of the form (a,b) where text[a:b] is the full substring of a markdown footnote description.

Examples

text_1 = r"""
This is some text with a footnote[^1]. In Obsidian.md, there will be a `[^1]` showing up and it will be clickable.

[^1]: And this is the text of the footnote. In the reading view of Obsidian.md, this will show in the bottom. This is also where the clickable `[^1]` sends us to.
[^2]: I'm another footnote. Note that I'm written above where I am first used and that does not create any problems.

This is another text[^2] and the footnote here is written above this text instead of below.

[^3]: I'm yet another footnote, but I'm not used. This will not create any problems, but this footnote will not appear in the reading view of Obsidian.md.
"""
ranges = find_footnote_descriptions_in_markdown_text(text_1)
for match_range in ranges:
    print(text_1[match_range[0]:match_range[1]])
test_eq(len(ranges), 3)
[^1]: And this is the text of the footnote. In the reading view of Obsidian.md, this will show in the bottom. This is also where the clickable `[^1]` sends us to.
[^2]: I'm another footnote. Note that I'm written above where I am first used and that does not create any problems.
[^3]: I'm yet another footnote, but I'm not used. This will not create any problems, but this footnote will not appear in the reading view of Obsidian.md.

Find and remove footnote mentions

Things like

There is going to be a footnote mention at the end here. 1


source

find_footnote_mentions_in_markdown_text

 find_footnote_mentions_in_markdown_text (text:str)

Return ranges in the markdown text string where footnote mentions occur.

By footnote mentions, I mean some of the form [^label] without any descriptions.

Returns

  • list[tuple]
    • Each tuple is of the form (a,b) where text[a:b] is a markdown footnote description.
Type Details
text str
Returns list Each tuple is of the form (a,b) where text[a:b] is a markdown footnote description.

Examples

text_2 = """
Now behold these footnotes[^2][^1]!

[^2]: Hi. I am footnote 2. I am written before footnote 1. In Obsidian.md's reading view, I will show up as with label `1` because I am the first footnote used.
[^1]: I am footnote 1. I am written after footnote 2. In Obsidian.md's reading view, I will show up as with label `2` because I am the second footnote used. Also note that I am used twice.

Here is a footnote[^not_a_number].

[^not_a_number]: I am a footnote, but I do not have a number label. In Obsidian.md's reading view, I will show up with label `3` because I am the third footnote used.

I am going to reuse footnote 1[^1], which will show with label `2`.

"""
ranges = find_footnote_mentions_in_markdown_text(text_2)

footnote_mentions = [text_2[match_range[0]:match_range[1]] for match_range in ranges]
for mention in footnote_mentions:
    print(mention)
test_eq(footnote_mentions, ['[^2]', '[^1]', '[^not_a_number]', '[^1]'])
[^2]
[^1]
[^not_a_number]
[^1]

source

remove_footnote_mentions_in_markdown_text

 remove_footnote_mentions_in_markdown_text (text:str)

Remove all footnote mentions from text.

text_3 = r"""
This is a text. See that there are two footnotes used here[^1][^2]?. The `remove_footnote_mentions_in_markdown_text` function
will remove these.

[^1]: Hi. I am a footnote. Unlike the footnote mentions, I am not going anywhere.
[^2]: Hi. I am another footnote. I am also not going anywhere.

[^3]: Hi. I am yet another footnote. I am unused and I am also not going anywhere.

"""
footnote_mentions_removed = remove_footnote_mentions_in_markdown_text(text_3)

test_eq([], find_footnote_mentions_in_markdown_text(footnote_mentions_removed))
print(footnote_mentions_removed)

This is a text. See that there are two footnotes used here?. The `remove_footnote_mentions_in_markdown_text` function
will remove these.

[^1]: Hi. I am a footnote. Unlike the footnote mentions, I am not going anywhere.
[^2]: Hi. I am another footnote. I am also not going anywhere.

[^3]: Hi. I am yet another footnote. I am unused and I am also not going anywhere.

Identifying footnote


source

embedded_note_of_footnote

 embedded_note_of_footnote (footnote:str)

Return the name of the note that the footnote description embeds assuming that the footnote only embeds a note.

Type Details
footnote str The full footnote description. May start and end with '\n' and other whitespace characters
Returns typing.Optional[str] The name of the note of the footnote, if applicable. None otherwise.
test_eq('note', embedded_note_of_footnote('[^1]:![[note#Hi]]'))
test_eq(None, embedded_note_of_footnote('[^1]: Hello'))
test_eq(None, embedded_note_of_footnote('[^1]:![[note#Hi]] but I have other stuff too'))

source

footnote_is_simple_embedded_note

 footnote_is_simple_embedded_note (footnote:str)

Return True if the footnote description is that of a simple embedded note.

Type Details
footnote str The full footnote description. May start and end with '\n' and other whitespace characters.
Returns bool
assert footnote_is_simple_embedded_note('[^1]:![[note#Hi]]')
assert not footnote_is_simple_embedded_note('[^1]: Hello')
assert not footnote_is_simple_embedded_note('[^1]:![[note#Hi]] but I have other stuff too')

Footnotes

  1. This is the footnote!↩︎