Find footnote definitions and store for later use.
| 232 | |
| 233 | |
| 234 | class FootnoteBlockProcessor(BlockProcessor): |
| 235 | """ Find footnote definitions and store for later use. """ |
| 236 | |
| 237 | RE = re.compile(r'^[ ]{0,3}\[\^([^\]]*)\]:[ ]*(.*)$', re.MULTILINE) |
| 238 | |
| 239 | def __init__(self, footnotes: FootnoteExtension): |
| 240 | super().__init__(footnotes.parser) |
| 241 | self.footnotes = footnotes |
| 242 | |
| 243 | def test(self, parent: etree.Element, block: str) -> bool: |
| 244 | return True |
| 245 | |
| 246 | def run(self, parent: etree.Element, blocks: list[str]) -> bool: |
| 247 | """ Find, set, and remove footnote definitions. """ |
| 248 | block = blocks.pop(0) |
| 249 | |
| 250 | m = self.RE.search(block) |
| 251 | if m: |
| 252 | id = m.group(1) |
| 253 | fn_blocks = [m.group(2)] |
| 254 | |
| 255 | # Handle rest of block |
| 256 | therest = block[m.end():].lstrip('\n') |
| 257 | m2 = self.RE.search(therest) |
| 258 | if m2: |
| 259 | # Another footnote exists in the rest of this block. |
| 260 | # Any content before match is continuation of this footnote, which may be lazily indented. |
| 261 | before = therest[:m2.start()].rstrip('\n') |
| 262 | fn_blocks[0] = '\n'.join([fn_blocks[0], self.detab(before)]).lstrip('\n') |
| 263 | # Add back to blocks everything from beginning of match forward for next iteration. |
| 264 | blocks.insert(0, therest[m2.start():]) |
| 265 | else: |
| 266 | # All remaining lines of block are continuation of this footnote, which may be lazily indented. |
| 267 | fn_blocks[0] = '\n'.join([fn_blocks[0], self.detab(therest)]).strip('\n') |
| 268 | |
| 269 | # Check for child elements in remaining blocks. |
| 270 | fn_blocks.extend(self.detectTabbed(blocks)) |
| 271 | |
| 272 | footnote = "\n\n".join(fn_blocks) |
| 273 | self.footnotes.setFootnote(id, footnote.rstrip()) |
| 274 | |
| 275 | if block[:m.start()].strip(): |
| 276 | # Add any content before match back to blocks as separate block |
| 277 | blocks.insert(0, block[:m.start()].rstrip('\n')) |
| 278 | return True |
| 279 | # No match. Restore block. |
| 280 | blocks.insert(0, block) |
| 281 | return False |
| 282 | |
| 283 | def detectTabbed(self, blocks: list[str]) -> list[str]: |
| 284 | """ Find indented text and remove indent before further processing. |
| 285 | |
| 286 | Returns: |
| 287 | A list of blocks with indentation removed. |
| 288 | """ |
| 289 | fn_blocks = [] |
| 290 | while blocks: |
| 291 | if blocks[0].startswith(' '*4): |
no outgoing calls
no test coverage detected
searching dependent graphs…