Base class for block processors. Each subclass will provide the methods below to work with the source and tree. Each processor will need to define it's own `test` and `run` methods. The `test` method should return True or False, to indicate whether the current block should be proce
| 57 | |
| 58 | |
| 59 | class BlockProcessor: |
| 60 | """ Base class for block processors. |
| 61 | |
| 62 | Each subclass will provide the methods below to work with the source and |
| 63 | tree. Each processor will need to define it's own `test` and `run` |
| 64 | methods. The `test` method should return True or False, to indicate |
| 65 | whether the current block should be processed by this processor. If the |
| 66 | test passes, the parser will call the processors `run` method. |
| 67 | |
| 68 | Attributes: |
| 69 | BlockProcessor.parser (BlockParser): The `BlockParser` instance this is attached to. |
| 70 | BlockProcessor.tab_length (int): The tab length set on the `Markdown` instance. |
| 71 | |
| 72 | """ |
| 73 | |
| 74 | def __init__(self, parser: BlockParser): |
| 75 | self.parser = parser |
| 76 | self.tab_length = parser.md.tab_length |
| 77 | |
| 78 | def lastChild(self, parent: etree.Element) -> etree.Element | None: |
| 79 | """ Return the last child of an `etree` element. """ |
| 80 | if len(parent): |
| 81 | return parent[-1] |
| 82 | else: |
| 83 | return None |
| 84 | |
| 85 | def detab(self, text: str, length: int | None = None) -> tuple[str, str]: |
| 86 | """ Remove a tab from the front of each line of the given text. """ |
| 87 | if length is None: |
| 88 | length = self.tab_length |
| 89 | newtext = [] |
| 90 | lines = text.split('\n') |
| 91 | for line in lines: |
| 92 | if line.startswith(' ' * length): |
| 93 | newtext.append(line[length:]) |
| 94 | elif not line.strip(): |
| 95 | newtext.append('') |
| 96 | else: |
| 97 | break |
| 98 | return '\n'.join(newtext), '\n'.join(lines[len(newtext):]) |
| 99 | |
| 100 | def looseDetab(self, text: str, level: int = 1) -> str: |
| 101 | """ Remove a tab from front of lines but allowing dedented lines. """ |
| 102 | lines = text.split('\n') |
| 103 | for i in range(len(lines)): |
| 104 | if lines[i].startswith(' '*self.tab_length*level): |
| 105 | lines[i] = lines[i][self.tab_length*level:] |
| 106 | return '\n'.join(lines) |
| 107 | |
| 108 | def test(self, parent: etree.Element, block: str) -> bool: |
| 109 | """ Test for block type. Must be overridden by subclasses. |
| 110 | |
| 111 | As the parser loops through processors, it will call the `test` |
| 112 | method on each to determine if the given block of text is of that |
| 113 | type. This method must return a boolean `True` or `False`. The |
| 114 | actual method of testing is left to the needs of that particular |
| 115 | block type. It could be as simple as `block.startswith(some_string)` |
| 116 | or a complex regular expression. As the block type may be different |
nothing calls this directly
no outgoing calls
no test coverage detected