Skip to content

Commit

Permalink
Abstract the way plugins work so they behave like normal md extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
facelessuser committed Feb 22, 2023
1 parent 3d4b55c commit 6f53ed4
Show file tree
Hide file tree
Showing 17 changed files with 700 additions and 641 deletions.
50 changes: 24 additions & 26 deletions docs/src/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,32 +169,30 @@ markdown_extensions:
- pymdownx.tabbed:
alternate_style: true
- pymdownx.saneheaders:
- pymdownx.blocks:
blocks:
pymdownx.blocks.admonition:Admonition:
types:
- new
- settings
- note
- abstract
- info
- tip
- success
- question
- warning
- failure
- danger
- bug
- example
- quote
pymdownx.blocks.details:Details:
pymdownx.blocks.html:HTML:
pymdownx.blocks.definition:Definition:
pymdownx.blocks.tab:Tab:
alternate_style: True
tools.collapse_code:CollapseCode:
expand_text: ''
collapse_text: ''
- pymdownx.blocks.admonition:
types:
- new
- settings
- note
- abstract
- info
- tip
- success
- question
- warning
- failure
- danger
- bug
- example
- quote
- pymdownx.blocks.details:
- pymdownx.blocks.html:
- pymdownx.blocks.definition:
- pymdownx.blocks.tab:
alternate_style: True
- tools.collapse_code:
expand_text: ''
collapse_text: ''

extra:
social:
Expand Down
50 changes: 24 additions & 26 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,32 +169,30 @@ markdown_extensions:
- pymdownx.tabbed:
alternate_style: true
- pymdownx.saneheaders:
- pymdownx.blocks:
blocks:
pymdownx.blocks.admonition:Admonition:
types:
- new
- settings
- note
- abstract
- info
- tip
- success
- question
- warning
- failure
- danger
- bug
- example
- quote
pymdownx.blocks.details:Details:
pymdownx.blocks.html:HTML:
pymdownx.blocks.definition:Definition:
pymdownx.blocks.tab:Tab:
alternate_style: True
tools.collapse_code:CollapseCode:
expand_text: ''
collapse_text: ''
- pymdownx.blocks.admonition:
types:
- new
- settings
- note
- abstract
- info
- tip
- success
- question
- warning
- failure
- danger
- bug
- example
- quote
- pymdownx.blocks.details:
- pymdownx.blocks.html:
- pymdownx.blocks.definition:
- pymdownx.blocks.tab:
alternate_style: True
- tools.collapse_code:
expand_text: ''
collapse_text: ''

extra:
social:
Expand Down
74 changes: 25 additions & 49 deletions pymdownx/blocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import re
import yaml
import textwrap
import importlib

# Fenced block placeholder for SuperFences
FENCED_BLOCK_RE = re.compile(
Expand Down Expand Up @@ -120,22 +119,14 @@ def revert_fenced_code(md, blocks):
class BlocksProcessor(BlockProcessor):
"""Generic block processor."""

def __init__(self, parser, md, config):
def __init__(self, parser, md):
"""Initialization."""

self.md = md

blocks = config['blocks']

if not blocks: # pragma: no cover
blocks = {}

# The Block classes indexable by name
self.blocks = {}
self.config = {}
for blk, cfg in blocks.items():
self.register(blk, cfg if cfg is not None else {})

self.empty_tags = set(['hr'])
self.block_level_tags = set(md.block_level_elements.copy())
self.block_level_tags.add('html')
Expand Down Expand Up @@ -168,35 +159,13 @@ def __init__(self, parser, md, config):
self.end = RE_END
self.yaml_line = RE_INDENT_YAML_LINE

def _import(self, plugin):
"""Import the plugin."""

module_name, class_name = plugin.split(':', 1)
module = importlib.import_module(module_name)
return getattr(module, class_name)

def register(self, b, config):
"""Register a block."""

if isinstance(b, str):
b = self._import(b)

if b.NAME in self.blocks:
raise ValueError('The block name {} is already registered!'.format(b.NAME))
self.blocks[b.NAME] = b
self.config[b.NAME] = self.set_configs(b.CONFIG, config)
b.on_register(self, self.md, self.config.get(b.NAME, {}))

def set_configs(self, default, config):
"""Set config for a block extension."""

d = {}
for key in default.keys():
if key in config:
d[key] = config[key]
else:
d[key] = default[key]
return d
self.config[b.NAME] = config

def test(self, parent, block):
"""Test to see if we should process the block."""
Expand Down Expand Up @@ -444,26 +413,15 @@ def run(self, parent, blocks):
break


class BlocksExtension(Extension):
class BlocksMgrExtension(Extension):
"""Add generic Blocks extension."""

def __init__(self, *args, **kwargs):
"""Initialize."""

self.config = {
'blocks': [{}, "Blocks extensions to load, if not defined, the default ones will be loaded."],
}

super().__init__(*args, **kwargs)

def extendMarkdown(self, md):
"""Add Blocks to Markdown instance."""

md.registerExtension(self)
util.escape_chars(md, ['/'])

config = self.getConfigs()
self.extension = BlocksProcessor(md.parser, md, config)
self.extension = BlocksProcessor(md.parser, md)
# We want to be right after list indentations are processed
md.parser.blockprocessors.register(self.extension, "blocks", 89)

Expand All @@ -473,7 +431,25 @@ def reset(self):
self.extension._reset()


def makeExtension(*args, **kwargs):
"""Return extension."""
class BlocksExtension(Extension):
"""Blocks Extension."""

def register_block_mgr(self, md):
"""Add Blocks to Markdown instance."""

if 'blocks' not in md.parser.blockprocessors:
ext = BlocksMgrExtension()
ext.extendMarkdown(md)
mgr = ext.extension
else:
mgr = md.parser.blockprocessors['blocks']
return mgr

def extendMarkdown(self, md):
"""Extend markdown."""

mgr = self.register_block_mgr(md)
self.extendMarkdownBlocks(md, mgr)

return BlocksExtension(*args, **kwargs)
def extendMarkdownBlocks(self, md, blocks):
"""Extend Markdown blocks."""
45 changes: 33 additions & 12 deletions pymdownx/blocks/admonition.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Admonitions."""
import xml.etree.ElementTree as etree
from .block import Block, type_html_identifier
from .. blocks import BlocksExtension
import re

RE_SEP = re.compile(r'[_-]+')
Expand All @@ -27,18 +28,6 @@ class Admonition(Block):
OPTIONS = {
'type': ['', type_html_identifier],
}
CONFIG = {
"types": ['note', 'attention', 'caution', 'danger', 'error', 'tip', 'hint', 'warning']
}

@classmethod
def on_register(cls, blocks_extension, md, config):
"""Handle registration event."""

# Generate an admonition subclass based on the given names.
for b in config.get('types', []):
subclass = RE_SEP.sub('', b.title())
blocks_extension.register(type(subclass, (Admonition,), {'OPTIONS': {}, 'NAME': b, 'CONFIG': {}}), {})

def on_parse(self):
"""Handle on parse event."""
Expand Down Expand Up @@ -73,3 +62,35 @@ def on_create(self, parent):
ad_title.text = title

return el


class AdmonitionExtension(BlocksExtension):
"""Admonition Blocks Extension."""

def __init__(self, *args, **kwargs):
"""Initialize."""

self.config = {
"types": [
['note', 'attention', 'caution', 'danger', 'error', 'tip', 'hint', 'warning'],
"Generate Admonition block extensions for the given types."
]
}

super().__init__(*args, **kwargs)

def extendMarkdownBlocks(self, md, blocks):
"""Extend Markdown blocks."""

blocks.register(Admonition, self.getConfigs())

# Generate an admonition subclass based on the given names.
for b in self.getConfig('types', []):
subclass = RE_SEP.sub('', b.title())
blocks.register(type(subclass, (Admonition,), {'OPTIONS': {}, 'NAME': b, 'CONFIG': {}}), {})


def makeExtension(*args, **kwargs):
"""Return extension."""

return AdmonitionExtension(*args, **kwargs)
4 changes: 0 additions & 4 deletions pymdownx/blocks/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,6 @@ def on_parse(self):

return True

@classmethod
def on_register(cls, block_processor, md, config):
"""Handle registration events."""

@abstractmethod
def on_create(self, parent):
"""Create the needed element and return it."""
Expand Down
16 changes: 16 additions & 0 deletions pymdownx/blocks/definition.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Definition."""
import xml.etree.ElementTree as etree
from .block import Block
from ..blocks import BlocksExtension


class Definition(Block):
Expand Down Expand Up @@ -47,3 +48,18 @@ def on_end(self, block):

for el in remove:
block.remove(el)


class DefinitionExtension(BlocksExtension):
"""Definition Blocks Extension."""

def extendMarkdownBlocks(self, md, blocks):
"""Extend Markdown blocks."""

blocks.register(Definition, self.getConfigs())


def makeExtension(*args, **kwargs):
"""Return extension."""

return DefinitionExtension(*args, **kwargs)
Loading

0 comments on commit 6f53ed4

Please sign in to comment.