o
    j3                     @  s  d 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
 ddgZdd	lmZ dd
lmZmZmZmZmZmZmZmZmZmZmZmZmZmZ erPddlmZ dZG dd deZ eddd<ddZ!eddd=ddZ"eddd=ddZ#eddd=ddZ$eddd=ddZ%G dd  d e
Z&eddd>d$d%Z'd?d*d+Z(		,d@dAd2d3Z)dBd5d6Z*dCd7d8Z+		,d@dDd:d;Z,e)Z-d,S )Ez
Grapheme cluster segmentation following Unicode Standard Annex #29.

This module provides pure-Python implementation of the grapheme cluster boundary algorithm as
defined in UAX #29: Unicode Text Segmentation.

https://www.unicode.org/reports/tr29/
    )annotations)IntEnum)	lru_cache)TYPE_CHECKINGOptional
NamedTuplezwcwidth.bisearchzwcwidth.table_grapheme   )bisearch)
GRAPHEME_L
GRAPHEME_T
GRAPHEME_VGRAPHEME_LVINCB_EXTENDINCB_LINKERGRAPHEME_LVTINCB_CONSONANTGRAPHEME_EXTENDGRAPHEME_CONTROLGRAPHEME_PREPENDGRAPHEME_SPACINGMARKEXTENDED_PICTOGRAPHICGRAPHEME_REGIONAL_INDICATOR)Iterator    c                   @  sH   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdS )GCBz'Grapheme Cluster Break property values.r   r                        	   
            N)__name__
__module____qualname____doc__OTHERCRLFCONTROLEXTENDZWJREGIONAL_INDICATORPREPENDSPACING_MARKLVTLVLVT r9   r9   /root/aizidognhua/tmp/workspace/projects/ec89d86c-575f-41c9-af57-ac45cbdbf775/venv/lib/python3.10/site-packages/wcwidth/grapheme.pyr   0   s     r   i   )maxsizeucsintreturnc                 C  s   | dkrt jS | dkrt jS | dkrt jS t| trt jS t| tr%t jS t| t	r-t j
S t| tr5t jS t| tr=t jS t| trEt jS t| trMt jS t| trUt jS t| tr]t jS t| tret jS t jS )z;Return the Grapheme_Cluster_Break property for a codepoint.r&   r#   i   )r   r,   r-   r0   	_bisearchr   r.   r   r/   r   r1   r   r2   r   r3   r
   r4   r   r5   r   r6   r   r7   r   r8   r+   r<   r9   r9   r:   _grapheme_cluster_breakF   s6   









rA   boolc                 C     t t| tS )z6Check if codepoint has Extended_Pictographic property.)rB   r?   r   r@   r9   r9   r:   _is_extended_pictographici      rD   c                 C  rC   )z,Check if codepoint has InCB=Linker property.)rB   r?   r   r@   r9   r9   r:   _is_incb_linkero   rE   rF   c                 C  rC   )z/Check if codepoint has InCB=Consonant property.)rB   r?   r   r@   r9   r9   r:   _is_incb_consonantu   rE   rG   c                 C  rC   )z,Check if codepoint has InCB=Extend property.)rB   r?   r   r@   r9   r9   r:   _is_incb_extend{   rE   rH   c                   @  s"   e Zd ZU dZded< ded< dS )BreakResultz*Result of grapheme cluster break decision.rB   should_breakr=   ri_countN)r'   r(   r)   r*   __annotations__r9   r9   r9   r:   rI      s   
 rI   prev_gcbcurr_gcbOptional[BreakResult]c                 C  s&  | t jkr|t jkrtdddS | t jt jt jfv r tdddS |t jt jt jfv r0tdddS | t jkrG|t jt jt jt jfv rGtdddS | t jt jfv r]|t jt j	fv r]tdddS | t jt j	fv rp|t j	krptdddS |t j
kr{tdddS |t jkrtdddS | t jkrtdddS dS )z
    Check simple GCB-pair-based break rules (cacheable).

    Returns BreakResult for rules that can be determined from GCB properties alone, or None if
    complex lookback rules (GB9c, GB11) need to be checked.
    Fr   rJ   rK   TN)r   r,   r-   rI   r.   r4   r5   r7   r8   r6   r/   r3   r2   )rM   rN   r9   r9   r:   _simple_break_check   s&   	" 


rQ   textstrcurr_idxrK   c           
      C  sf  t | |}|dur|S |tjkrtdddS t|| }t|rR|d }|dkr@tt|| r@|d8 }|dkr@tt|| s0|dkrRtt|| rRtdddS | tjkrt|r|d }|dkrt|| }t	|}	|	tj
krw|d8 }nt|rtdddS n|dksc| tjkr|tjkr|d dkrtd|d dS tdddS |tjkrdnd}td|dS )z
    Determine if there should be a grapheme cluster break between prev and curr.

    Implements UAX #29 grapheme cluster boundary rules.
    NFr   rP   r   r   T)rQ   r   r0   rI   ordrG   rH   rF   rD   rA   r/   r1   )
rM   rN   rR   rT   rK   resultcurr_ucsiprev_ucs	prev_propr9   r9   r:   _should_break   s<   



r[   Nunistrstartend
int | NoneIterator[str]c           
      c  s    | sdS t | }|du r|}||ks||krdS t||}|}d}tt| | }|tjkr1d}t|d |D ]#}tt| | }t||| ||}	|	j}|	j	rY| || V  |}|}q8| || V  dS )uI  
    Iterate over grapheme clusters by UAX #29 extended grapheme cluster rules.

    Grapheme clusters are "user-perceived characters" - what a user would
    consider a single character, which may consist of multiple Unicode
    codepoints (e.g., a base character with combining marks, emoji sequences).

    :param unistr: The Unicode string to segment.
    :param start: Starting index (default 0).
    :param end: Ending index (default len(unistr)).
    :yields: Grapheme cluster substrings.

    Example::

        >>> list(iter_graphemes('cafe\u0301'))
        ['c', 'a', 'f', 'é']
        >>> list(iter_graphemes('ok\U0001F468\u200D\U0001F469\u200D\U0001F467'))
        ['o', 'k', '👨\u200d👩\u200d👧']
        >>> list(iter_graphemes('ok\U0001F1FA\U0001F1F8'))
        ['o', 'k', '🇺🇸']

    .. versionadded:: 0.3.0
    Nr   r   )
lenminrA   rU   r   r1   ranger[   rK   rJ   )
r\   r]   r^   lengthcluster_startrK   rM   idxrN   rV   r9   r9   r:   _iter_graphemes_python   s.   

rg   posc                 C  sl  t | |d  }|dkr|dkr| |d  dkr|d S |dk rF|dkrB|dkrBt | |d  }|dkrBt|tjkrBt| |d S |d S |d }|dkr}|| tk r}t | | }d|  krddk rgn nnt|tjkron|d8 }|dkr}|| tk sT|}tt | | }|tjkrdnd}t|d |D ]}	tt | |	 }
t	||
| |	|}|j
}|jr|	}|
}q|S )a  
    Find the start of the grapheme cluster containing the character before pos.

    Scans backwards from pos to find a safe starting point, then iterates forward using standard
    break rules to find the actual cluster boundary.

    :param text: The Unicode string.
    :param pos: Position to search before (exclusive).
    :returns: Start position of the grapheme cluster.
    r   r#   r      r   r   )rU   rA   r   r2   _find_cluster_startMAX_GRAPHEME_SCANr.   r1   rc   r[   rK   rJ   )rR   rh   	target_cpprev_cp
safe_startcpre   left_gcbrK   rX   	right_gcbrV   r9   r9   r:   rk   5  s:    	rk   c                 C  s    |dkrdS t | t|t| S )a  
    Find the grapheme cluster boundary immediately before a position.

    :param unistr: The Unicode string to search.
    :param pos: Position in the string (0 < pos <= len(unistr)).
    :returns: Start index of the grapheme cluster containing the character at pos-1.

    Example::

        >>> grapheme_boundary_before('Hello \U0001F44B\U0001F3FB', 8)
        6
        >>> grapheme_boundary_before('a\r\nb', 3)
        1

    .. versionadded:: 0.3.6
    r   )rk   rb   ra   )r\   rh   r9   r9   r:   grapheme_boundary_beforei  s   rs   Optional[int]c                 c  s    | sdS t | }|du r|nt||}t|d}||ks!||kr#dS |}||krCt| |}||k r4dS | || V  |}||ks)dS dS )a  
    Iterate over grapheme clusters in reverse order (last to first).

    :param unistr: The Unicode string to segment.
    :param start: Starting index (default 0).
    :param end: Ending index (default len(unistr)).
    :yields: Grapheme cluster substrings in reverse order.

    Example::

        >>> list(iter_graphemes_reverse('cafe\u0301'))
        ['e\u0301', 'f', 'a', 'c']

    .. versionadded:: 0.3.6
    Nr   )ra   rb   maxrk   )r\   r]   r^   rd   rh   re   r9   r9   r:   iter_graphemes_reverse  s    

rv   )r<   r=   r>   r   )r<   r=   r>   rB   )rM   r   rN   r   r>   rO   )rM   r   rN   r   rR   rS   rT   r=   rK   r=   r>   rI   )r   N)r\   rS   r]   r=   r^   r_   r>   r`   )rR   rS   rh   r=   r>   r=   )r\   rS   rh   r=   r>   r=   )r\   rS   r]   r=   r^   rt   r>   r`   ).r*   
__future__r   enumr   	functoolsr   typingr   r   r   __lazy_modules__r	   r?   table_graphemer
   r   r   r   r   r   r   r   r   r   r   r   r   r   collections.abcr   rl   r   rA   rD   rF   rG   rH   rI   rQ   r[   rg   rk   rs   rv   iter_graphemesr9   r9   r9   r:   <module>   sJ    	@"
0:
D
4*