You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			88 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			88 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
import re
 | 
						|
from typing import TYPE_CHECKING, Match
 | 
						|
 | 
						|
if TYPE_CHECKING:
 | 
						|
    from ..block_parser import BlockParser
 | 
						|
    from ..core import BaseRenderer, BlockState, InlineState
 | 
						|
    from ..inline_parser import InlineParser
 | 
						|
    from ..markdown import Markdown
 | 
						|
 | 
						|
__all__ = ["spoiler"]
 | 
						|
 | 
						|
_BLOCK_SPOILER_START = re.compile(r"^ {0,3}! ?", re.M)
 | 
						|
_BLOCK_SPOILER_MATCH = re.compile(r"^( {0,3}![^\n]*\n)+$")
 | 
						|
 | 
						|
INLINE_SPOILER_PATTERN = r">!\s*(?P<spoiler_text>.+?)\s*!<"
 | 
						|
 | 
						|
 | 
						|
def parse_block_spoiler(block: "BlockParser", m: Match[str], state: "BlockState") -> int:
 | 
						|
    text, end_pos = block.extract_block_quote(m, state)
 | 
						|
    if not text.endswith("\n"):
 | 
						|
        # ensure it endswith \n to make sure
 | 
						|
        # _BLOCK_SPOILER_MATCH.match works
 | 
						|
        text += "\n"
 | 
						|
 | 
						|
    depth = state.depth()
 | 
						|
    if not depth and _BLOCK_SPOILER_MATCH.match(text):
 | 
						|
        text = _BLOCK_SPOILER_START.sub("", text)
 | 
						|
        tok_type = "block_spoiler"
 | 
						|
    else:
 | 
						|
        tok_type = "block_quote"
 | 
						|
 | 
						|
    # scan children state
 | 
						|
    child = state.child_state(text)
 | 
						|
    if state.depth() >= block.max_nested_level - 1:
 | 
						|
        rules = list(block.block_quote_rules)
 | 
						|
        rules.remove("block_quote")
 | 
						|
    else:
 | 
						|
        rules = block.block_quote_rules
 | 
						|
 | 
						|
    block.parse(child, rules)
 | 
						|
    token = {"type": tok_type, "children": child.tokens}
 | 
						|
    if end_pos:
 | 
						|
        state.prepend_token(token)
 | 
						|
        return end_pos
 | 
						|
    state.append_token(token)
 | 
						|
    return state.cursor
 | 
						|
 | 
						|
 | 
						|
def parse_inline_spoiler(inline: "InlineParser", m: Match[str], state: "InlineState") -> int:
 | 
						|
    text = m.group("spoiler_text")
 | 
						|
    new_state = state.copy()
 | 
						|
    new_state.src = text
 | 
						|
    children = inline.render(new_state)
 | 
						|
    state.append_token({"type": "inline_spoiler", "children": children})
 | 
						|
    return m.end()
 | 
						|
 | 
						|
 | 
						|
def render_block_spoiler(renderer: "BaseRenderer", text: str) -> str:
 | 
						|
    return '<div class="spoiler">\n' + text + "</div>\n"
 | 
						|
 | 
						|
 | 
						|
def render_inline_spoiler(renderer: "BaseRenderer", text: str) -> str:
 | 
						|
    return '<span class="spoiler">' + text + "</span>"
 | 
						|
 | 
						|
 | 
						|
def spoiler(md: "Markdown") -> None:
 | 
						|
    """A mistune plugin to support block and inline spoiler. The
 | 
						|
    syntax is inspired by stackexchange:
 | 
						|
 | 
						|
    .. code-block:: text
 | 
						|
 | 
						|
        Block level spoiler looks like block quote, but with `>!`:
 | 
						|
 | 
						|
        >! this is spoiler
 | 
						|
        >!
 | 
						|
        >! the content will be hidden
 | 
						|
 | 
						|
        Inline spoiler is surrounded by `>!` and `!<`, such as >! hide me !<.
 | 
						|
 | 
						|
    :param md: Markdown instance
 | 
						|
    """
 | 
						|
    # reset block quote parser with block spoiler parser
 | 
						|
    md.block.register("block_quote", None, parse_block_spoiler)
 | 
						|
    md.inline.register("inline_spoiler", INLINE_SPOILER_PATTERN, parse_inline_spoiler)
 | 
						|
    if md.renderer and md.renderer.NAME == "html":
 | 
						|
        md.renderer.register("block_spoiler", render_block_spoiler)
 | 
						|
        md.renderer.register("inline_spoiler", render_inline_spoiler)
 |