U
    \>e4                     @  s   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
mZmZ e
r^dd	lm  mZ z<dd
lmZ ddlmZmZ ddlmZ ddlmZ dZW n ek
r   dZY nX dddddZG dd dZG dd deZG dd deZdd Zd	S )z
Adds code/syntax highlighting to standard Python-Markdown code blocks.

See the [documentation](https://Python-Markdown.github.io/extensions/code_hilite)
for details.
    )annotations   )	Extension   )Treeprocessor)parseBoolValue)TYPE_CHECKINGCallableAnyN)	highlight)get_lexer_by_nameguess_lexer)get_formatter_by_name)ClassNotFoundTFstrz	list[int])exprreturnc                 C  s:   | sg S zt tt|  W S  tk
r4   g  Y S X dS )zSupport our syntax for emphasizing certain lines of code.

    `expr` should be like '1 2' to emphasize lines 1 and 2 of a code block.
    Returns a list of integers, the line numbers to emphasize.
    N)listmapintsplit
ValueError)r    r   B/tmp/pip-unpacked-wheel-wj0og6ym/markdown/extensions/codehilite.pyparse_hl_lines*   s    r   c                   @  s>   e Zd ZdZddddZddddd	d
ZddddZdS )
CodeHiliteau	  
    Determine language of source code, and pass it on to the Pygments highlighter.

    Usage:

    ```python
    code = CodeHilite(src=some_code, lang='python')
    html = code.hilite()
    ```

    Arguments:
        src: Source string or any object with a `.readline` attribute.

    Keyword arguments:
        lang (str): String name of Pygments lexer to use for highlighting. Default: `None`.
        guess_lang (bool): Auto-detect which lexer to use.
            Ignored if `lang` is set to a valid value. Default: `True`.
        use_pygments (bool): Pass code to Pygments for code highlighting. If `False`, the code is
            instead wrapped for highlighting by a JavaScript library. Default: `True`.
        pygments_formatter (str): The name of a Pygments formatter or a formatter class used for
            highlighting the code blocks. Default: `html`.
        linenums (bool): An alias to Pygments `linenos` formatter option. Default: `None`.
        css_class (str): An alias to Pygments `cssclass` formatter option. Default: 'codehilite'.
        lang_prefix (str): Prefix prepended to the language. Default: "language-".

    Other Options:

    Any other options are accepted and passed on to the lexer and formatter. Therefore,
    valid options include any options which are accepted by the `html` formatter or
    whichever lexer the code's language uses. Note that most lexers do not have any
    options. However, a few have very useful options, such as PHP's `startinline` option.
    Any invalid options are ignored without error.

    * **Formatter options**: <https://pygments.org/docs/formatters/#HtmlFormatter>
    * **Lexer Options**: <https://pygments.org/docs/lexers/>

    Additionally, when Pygments is enabled, the code's language is passed to the
    formatter as an extra option `lang_str`, whose value being `{lang_prefix}{lang}`.
    This option has no effect to the Pygments' builtin formatters.

    Advanced Usage:

    ```python
    code = CodeHilite(
        src = some_code,
        lang = 'php',
        startinline = True,      # Lexer option. Snippet does not start with `<?php`.
        linenostart = 42,        # Formatter option. Snippet starts on line 42.
        hl_lines = [45, 49, 50], # Formatter option. Highlight lines 45, 49, and 50.
        linenos = 'inline'       # Formatter option. Avoid alignment problems.
    )
    html = code.hilite()
    ```

    r   )srcc                 K  s   || _ |dd | _|dd| _|dd| _|dd| _|dd| _d	|krd|d
d |d	< d|kr||dd|d< d|krd|d< d|d< || _d S )Nlang
guess_langTuse_pygmentslang_prefix	language-pygments_formatterhtmllinenoslinenumscssclass	css_class
codehiliteZwrapcodeFfull)r   popr   r   r   r    r"   options)selfr   r+   r   r   r   __init__s   s    zCodeHilite.__init__Tbool)shebangr   c                 C  s  | j d| _ | jdkr$|r$|   tr4| jr4zt| jf| j}W n^ tk
r   z(| j	rpt
| j f| j}ntd| j}W n  tk
r   td| j}Y nX Y nX | js|jd | _| j | j }t| jtrzt| jf| j}W n" tk
r   td| j}Y nX n| jf d|i| j}t| j ||S | j dd}|d	d
}|dd}|dd}g }| jr|d| j| j | jd r|d d}|rdd|}d| jd ||S dS )a6  
        Pass code to the [Pygments](https://pygments.org/) highlighter with
        optional line numbers. The output should then be styled with CSS to
        your liking. No styles are applied by default - only styling hooks
        (i.e.: `<span class="k">`).

        returns : A string of html.

        
Ntextr   r#   lang_str&&amp;<&lt;>&gt;"z&quot;z{}{}r$   r%    z class="{}" z)<pre class="{}"><code{}>{}
</code></pre>
r&   )r1   )r1   )r#   )r   stripr   _parseHeaderpygmentsr   r   r+   r   r   r   aliasesr    
isinstancer"   r   r   r   r   replaceappendformatjoin)r,   r/   lexerr2   	formattertxtclassesZ	class_strr   r   r   hilite   sP    
zCodeHilite.hiliteNone)r   c                 C  s   ddl }| jd}|d}|d|j}||}|rz|d | _	W n t
k
rh   d| _	Y nX |dr|d| | jd dkr|drd	| jd< t|d
| jd
< n|d| d|d| _dS )aP  
        Determines language of a code block from shebang line and whether the
        said line should be removed or left in place. If the shebang line
        contains a path (even a single /) then it is assumed to be a real
        shebang line and left alone. However, if no path is given
        (e.i.: `#!python` or `:::python`) then it is assumed to be a mock shebang
        for language identification of a code fragment and removed from the
        code block prior to processing for code highlighting. When a mock
        shebang (e.i: `#!python`) is found, line numbering is turned on. When
        colons are found in place of a shebang (e.i.: `:::python`), line
        numbering is left in the current state - off by default.

        Also parses optional list of highlight lines, like:

            :::python hl_lines="1 3"
        r   Nr0   a  
            (?:(?:^::+)|(?P<shebang>^[#]!)) # Shebang or 2 or more colons
            (?P<path>(?:/\w+)*[/ ])?        # Zero or 1 path
            (?P<lang>[\w#.+-]*)             # The language
            \s*                             # Arbitrary whitespace
            # Optional highlight lines, single- or double-quote-delimited
            (hl_lines=(?P<quot>"|')(?P<hl_lines>.*?)(?P=quot))?
            r   pathr$   r/   TZhl_lines)rer   r   r*   compileVERBOSEsearchgrouplowerr   
IndexErrorinsertr+   r   rD   r<   )r,   rL   linesflcmr   r   r   r=      s&    
	


zCodeHilite._parseHeaderN)T)__name__
__module____qualname____doc__r-   rI   r=   r   r   r   r   r   :   s   8;r   c                   @  s:   e Zd ZU dZded< dddddZdd	d
ddZdS )HiliteTreeprocessorz' Highlight source code in code blocks. zdict[str, Any]configr   )r1   r   c                 C  s(   | dd}| dd}| dd}|S )zUnescape code.r6   r5   r8   r7   r4   r3   )rA   )r,   r1   r   r   r   code_unescape  s    z!HiliteTreeprocessor.code_unescapezetree.ElementrJ   )rootr   c                 C  s   | d}|D ]}t|dkr|d jdkr| j }|d j}|dkrJqt| |f| jj	|
ddd|}| jj| }|  d	|_||_qdS )
z, Find code blocks and store in `htmlStash`. prer   r   codeNpygments_styledefault)
tab_lengthstylep)iterlentagr]   copyr1   r   r^   mdrd   r*   Z	htmlStashstorerI   clear)r,   r_   blocksblockZlocal_configr1   ra   placeholderr   r   r   run  s&    



zHiliteTreeprocessor.runN)rX   rY   rZ   r[   __annotations__r^   rq   r   r   r   r   r\      s   
	r\   c                   @  s    e Zd ZdZdd Zdd ZdS )CodeHiliteExtensionz7 Add source code highlighting to markdown code blocks. c              	   K  s   d dgddgddgddgdd	gdd
gddgddgd| _ | D ]^\}}|| j kr`| || q@t|trzt|dd}W n tk
r   Y nX |dg| j |< q@d S )NzOUse lines numbers. True|table|inline=yes, False=no, None=auto. Default: `None`.Tz/Automatic language detection - Default: `True`.r(   z9Set class name for wrapper <div> - Default: `codehilite`.rc   z@Pygments HTML Formatter Style (Colorscheme). Default: `default`.Fz;Use inline styles instead of CSS classes - Default `False`.z\Highlight code blocks with pygments. Disable if using a JavaScript library. Default: `True`.r!   zTPrefix prepended to the language when `use_pygments` is false. Default: `language-`.r#   zDUse a specific formatter for Pygments highlighting. Default: `html`.)r%   r   r'   rb   Z	noclassesr   r    r"   )Zpreserve_noner:   )r]   itemsZ	setConfigr@   r   r   r   )r,   kwargskeyvaluer   r   r   r-   &  sD            

zCodeHiliteExtension.__init__c                 C  s0   t |}|  |_|j|dd ||  dS )z1 Add `HilitePostprocessor` to Markdown instance. rI      N)r\   Z
getConfigsr]   treeprocessorsregisterZregisterExtension)r,   rk   Zhiliterr   r   r   extendMarkdownQ  s    
z"CodeHiliteExtension.extendMarkdownN)rX   rY   rZ   r[   r-   r{   r   r   r   r   rs   #  s   +rs   c                  K  s
   t f | S )N)rs   )ru   r   r   r   makeExtensionZ  s    r|   )r[   
__future__r   r:   r   ry   r   utilr   typingr   r	   r
   xml.etree.ElementTreeetreeElementTreer>   r   Zpygments.lexersr   r   Zpygments.formattersr   Zpygments.utilr   ImportErrorr   r   r\   rs   r|   r   r   r   r   <module>   s*   
 D&7