§
    øžyj«³  ã                   óð  — d Z ddlZddlmZmZmZmZ ddlmZ i dd“dd“dd	“d
d	“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“dddddddœ¥Z	de
de
fd„Zd e
d!e
d"e
defd#„Z	 dWd e
d%eeeef                  d&ede
fd'„Z	 dXd e
d!e
d"e
d)edee
eee
         ee
         f         f
d*„Zd e
d%eeeef                  d!e
d"e
dee
         f
d+„Zd,e
de
fd-„Zde
dee
         fd.„Zd/e
d!e
d"e
de
fd0„Zd"e
d e
d%eeeef                  de
fd1„Zd e
d%eeeef                  d!e
d"e
de
f
d2„Z	 dYd e
d%eeeef                  d"e
d!ee
         de
f
d3„Zd e
d4e
deeeef                  fd5„Zd e
d4e
deeeef                  fd6„Zd e
d4e
deeeef                  fd7„Zd e
d4e
deeeef                  fd8„Zd e
d4e
deeeef                  fd9„Zd e
d4e
deeeef                  fd:„Zd;e
dee         fd<„Zd=ee         d>eeeef                  deeeef                  fd?„Zd e
d4e
deeeef                  fd@„Z d e
d4e
deeeef                  fdA„Z!d e
d4e
deeeef                  fdB„Z"dCee
         dDedEedFedeeef         f
dG„Z#d e
dCee
         dHee
         d4e
dIe
deeeef                  fdJ„Z$d;e
dKe
dLeeeef                  deeeef                  fdM„Z%d,e
de
fdN„Z&dZd!e
d e
dQedRede
f
dS„Z'dTee
         dUed!e
d e
de
f
dV„Z(dS )[aP  
Fuzzy Matching Module for File Operations

Implements a multi-strategy matching chain to robustly find and replace text,
accommodating variations in whitespace, indentation, and escaping common
in LLM-generated code.

The 9-strategy chain (inspired by OpenCode), tried in order:
1. Exact match - Direct string comparison
2. Line-trimmed - Strip leading/trailing whitespace per line
3. Whitespace normalized - Collapse multiple spaces/tabs to single space
4. Indentation flexible - Ignore indentation differences entirely
5. Escape normalized - Convert \n literals to actual newlines
6. Trimmed boundary - Trim first/last line whitespace only
7. Block anchor - Match first+last lines, use similarity for middle
8. Context-aware - 50% line similarity threshold

Multi-occurrence matching is handled via the replace_all flag.

Usage:
    from tools.fuzzy_match import fuzzy_find_and_replace
    
    new_content, match_count, strategy, error = fuzzy_find_and_replace(
        content="def foo():\n    pass",
        old_string="def foo():",
        new_string="def bar():",
        replace_all=False
    )
é    N)ÚTupleÚOptionalÚListÚCallable)ÚSequenceMatcheru   â€œú"u   â€�u   â€˜ú'u   â€™u   â€”z--u   â€“Ú-u   â€¦ú...õ   Â Ú u   âˆ’u   â€€u   â€�u   â€‚u   â€ƒu   â€„u   â€…u   â€†u   â€‡)u   â€ˆu   â€‰u   â€Šu   â€¯u   â�Ÿu   ã€€ÚtextÚreturnc                 óp   — t                                ¦   «         D ]\  }}|                      ||¦  «        } Œ| S )zBNormalizes Unicode characters to their standard ASCII equivalents.)ÚUNICODE_MAPÚitemsÚreplace)r   ÚcharÚrepls      ú7/home/ragecks/.hermes/hermes-agent/tools/fuzzy_match.pyÚ_unicode_normalizer   <   s;   € å!×'Ò'Ñ)Ô)ð (ð (‰
ˆˆdØ�|Š|˜D $Ñ'Ô'ˆˆØ€Kó    ÚcontentÚ
old_stringÚ
new_stringc                 óx   — |r%t          |                     ¦   «         ¦  «        dk     rdS || vrdS ||k    rdS || vS )uº  Return True when the requested edit is already present in the file.

    Production trajectory mining shows the most common patch failure is a
    re-send of an edit that already landed (old_string == new_string, or
    old_string gone while new_string is present) â€” the model's intent is
    "make the file contain this text", and it already does. Callers use
    this to convert those errors into an explicit success-shaped no-op so
    the model moves on instead of re-reading and re-patching.

    Deliberately conservative:
    - new_string must be non-trivial (>= 8 chars stripped) â€” a tiny target
      matching by coincidence must not mask a genuine typo'd edit;
    - new_string must appear EXACTLY in the content (no fuzzy matching â€”
      approximate presence is not proof the edit landed);
    - when old_string differs from new_string, old_string must be GONE
      (still-present old text means the edit is at best half-applied).
    é   FT)ÚlenÚstrip)r   r   r   s      r   Úis_already_appliedr    C   sZ   € ð$ ð �˜Z×-Ò-Ñ/Ô/Ñ0Ô0°1Ò4Ð4ØˆuØ˜Ð Ð ØˆuØ�ZÒÐØˆtØ˜WÐ$Ð$r   é   ÚmatchesÚcapc                 ó  — g }|d|…         D ]»\  }}|                       dd|¦  «        dz   }|                      dd|¦  «        dz   }|                      d|¦  «        }|dk    rt          | ¦  «        }| ||…                              ¦   «         }	t          |	¦  «        dk    r|	dd…         dz   }	|                     d	|› d
|	› �¦  «         Œ¼t          |¦  «        |z
  }
|
dk    r|                     d|
› d�¦  «         d                     |¦  «        S )a  Render up to ``cap`` match positions as 'L<line>: <snippet>' rows.

    Gives the model the information it needs to disambiguate an ambiguous
    old_string in ONE follow-up (add neighboring context, or choose
    replace_all) instead of re-reading the file to find the occurrences.
    NÚ
r   é   éÿÿÿÿéP   éM   r   z  Lz: z
  ... and z more)ÚcountÚrfindÚfindr   r   ÚappendÚjoin)r   r"   r#   ÚrowsÚstartÚ_endÚline_noÚ
line_startÚline_endÚsnippetÚextras              r   Ú_format_match_locationsr7   ^   s*  € ð €DØ˜t ˜t”}ð 	0ð 	0‰ˆˆtØ—-’-  a¨Ñ/Ô/°!Ñ3ˆØ—]’] 4¨¨EÑ2Ô2°QÑ6ˆ
Ø—<’<  jÑ1Ô1ˆØ�rŠ>ˆ>Ý˜7‘|”|ˆHØ˜* XÐ-Ô.×4Ò4Ñ6Ô6ˆÝˆw‰<Œ<˜"ÒÐØ˜c˜r˜c”l UÑ*ˆGØ�ŠÐ.˜'Ð.Ð. WÐ.Ð.Ñ/Ô/Ð/Ð/Ý�‰LŒL˜3Ñ€EØˆq‚y€yØ�ŠÐ- Ð-Ð-Ð-Ñ.Ô.Ð.Ø�9Š9�T‰?Œ?Ðr   FÚreplace_allc           
      ó  — |s| dddfS |                      ¦   «         s| dddfS ||k    r| dddfS dt          fdt          fdt          fd	t          fd
t
          fdt          fdt          fdt          fdt          fg	}ddh}|D �]\  }} || |¦  «        }|rðt          |¦  «        dk    r-|s+t          | |¦  «        }	| dddt          |¦  «        › d|	› �fc S |r3t          |¦  «        dk    r ||v r| dddt          |¦  «        › d|› d�fc S |dk    rt          | |||¦  «        }
|
r| dd|
fc S t          || |¦  «        }|dk    rt          | |||¦  «        }t          | |||dk    r|nd¬¦  «        }|t          |¦  «        |dfc S �Œ| dddfS )a)  
    Find and replace text using a chain of increasingly fuzzy matching strategies.

    Args:
        content: The file content to search in
        old_string: The text to find
        new_string: The replacement text
        replace_all: If True, replace all occurrences; if False, require uniqueness

    Returns:
        Tuple of (new_content, match_count, strategy_name, error_message)
        - If successful: (modified_content, number_of_replacements, strategy_used, None)
        - If failed: (original_content, 0, None, error_description)
    r   Nzold_string cannot be emptyuA   old_string is only whitespace â€” provide non-blank text to matchz'old_string and new_string are identicalÚexactÚline_trimmedÚwhitespace_normalizedÚindentation_flexibleÚescape_normalizedÚtrimmed_boundaryÚunicode_normalizedÚblock_anchorÚcontext_awarer&   zFound zc matches for old_string. Provide more context to make it unique, or use replace_all=True. Matches:
z approximate matches via the 'z‘' strategy; replace_all only applies to exact matches. Provide the precise text (whitespace included) so an exact/line-trimmed match can be made.)r   z1Could not find a match for old_string in the file)r   Ú_strategy_exactÚ_strategy_line_trimmedÚ_strategy_whitespace_normalizedÚ_strategy_indentation_flexibleÚ_strategy_escape_normalizedÚ_strategy_trimmed_boundaryÚ_strategy_unicode_normalizedÚ_strategy_block_anchorÚ_strategy_context_awarer   r7   Ú_detect_escape_driftÚ_maybe_unescape_new_stringÚ _preserve_unicode_in_replacementÚ_apply_replacements)r   r   r   r8   Ú
strategiesÚ_SIMILARITY_STRATEGIESÚstrategy_nameÚstrategy_fnr"   Ú	locationsÚ	drift_errÚeffective_newÚnew_contents                r   Úfuzzy_find_and_replacerX   w   s¥  € ð  ð >Ø˜˜4Ð!=Ð=Ð=à×ÒÑÔð eð
 ˜˜4Ð!dÐdÐdà�ZÒÐØ˜˜4Ð!JÐJÐJð 
•/Ð"Ø	Õ/Ð0Ø	 Õ"AÐBØ	Õ!?Ð@Ø	Õ9Ð:Ø	Õ7Ð8Ø	Õ;Ð<Ø	Õ/Ð0Ø	Õ1Ð2ð
.€Jð" -¨oÐ>Ðà&0ð RBñ RBÑ"ˆ�{Ø�+˜g zÑ2Ô2ˆàð O	Bå�7‰|Œ|˜aÒÐ¨ÐÝ3°G¸WÑEÔE�	Ø  4ð-�S ™\œ\ð -ð -à!*ð-ð -ðð ð ð ð ð �s 7™|œ|¨aÒ/Ð/°MÐE[Ð4[Ð4[Ø  4ð=�S ™\œ\ð =ð =Ø%ð=ð =ð =ðð ð ð ð"  Ò'Ð'Ý0°¸'À:ÈzÑZÔZ�	Øð 7Ø" A t¨YÐ6Ð6Ð6Ð6õ2 7Ø˜G Wñô ˆMð Ð 4Ò4Ð4Ý @Ø˜W j°-ñ!ô !�õ .Ø˜ -Ø)6¸'Ò)AÐ)A˜:˜:Àtðñ ô ˆKð ¥ G¡¤¨m¸TÐAÐAÐAÐAñ_O	Bðd �A�tÐPÐPÐPr   c                 ó¦   ‡ — d|vrd|vrdS d                      ˆ fd„|D ¦   «         ¦  «        }dD ]!}||v r||v r||vr|d         }d|›d	|›d
�c S Œ"dS )u'  Detect tool-call escape-drift artifacts in new_string.

    Looks for ``\'`` or ``\"`` sequences that are present in both
    old_string and new_string (i.e. the model copy-pasted them as "context"
    it intended to preserve) but don't exist in the matched region of the
    file. That pattern indicates the transport layer inserted spurious
    shell-style escapes around apostrophes or quotes â€” writing new_string
    verbatim would literally insert ``\'`` into source code.

    Returns an error string if drift is detected, None otherwise.
    ú\'ú\"NÚ c              3   ó2   •K  — | ]\  }}‰||…         V — Œd S ©N© ©Ú.0r0   Úendr   s      €r   ú	<genexpr>z'_detect_escape_drift.<locals>.<genexpr>  ó0   øè è € ÐKÐK±Z°U¸C˜g e¨C iÔ0ÐKÐKÐKÐKÐKÐKr   )rZ   r[   r&   zNEscape-drift detected: old_string and new_string contain the literal sequence a   but the matched region of the file does not. This is almost always a tool-call serialization artifact where an apostrophe or quote got prefixed with a spurious backslash. Re-read the file with read_file and pass old_string/new_string without backslash-escaping z characters.)r.   )r   r"   r   r   Úmatched_regionsÚsuspectÚplains   `      r   rL   rL      s»   ø€ ð  �JÐÐ 5°
Ð#:Ð#:Øˆtð —g’gÐKÐKÐKÐKÀ7ÐKÑKÔKÑKÔK€Oà!ð ð ˆØ�jÐ Ð  W°
Ð%:Ð%:¸wÈoÐ?]Ð?]Ø˜A”JˆEð<Ø(/ð<ð <ð ',ð<ð <ð <ðð ð øð ˆ4r   Úlinec                 ó˜   — d}|t          | ¦  «        k     r,| |         dv r"|dz  }|t          | ¦  «        k     r
| |         dv °"| d|…         S )z=Return the leading whitespace prefix of a line (spaces/tabs).r   ©r   ú	r&   N©r   )rh   Úis     r   Ú_leading_whitespacern   (  sY   € à	€AØ
�c�$‰iŒiŠ-ˆ-˜D œG {Ð2Ð2Ø	ˆQ‰ˆð �c�$‰iŒiŠ-ˆ-˜D œG {Ð2Ð2à���Œ8€Or   c                 óf   — |                       d¦  «        D ]}|                     ¦   «         r|c S ŒdS )z›Return the first line of ``text`` that has any non-whitespace content.

    Returns ``None`` if no such line exists (text is empty or all whitespace).
    r%   N)Úsplitr   )r   rh   s     r   Ú_first_meaningful_linerq   0  sB   € ð
 —
’
˜4Ñ Ô ð ð ˆØ�:Š:‰<Œ<ð 	ØˆKˆKˆKð	àˆ4r   Úfile_regionc                 óN  — |s|S t          |¦  «        }t          | ¦  «        }|�|€|S t          |¦  «        }t          |¦  «        }||k    r|S g }|                     d¦  «        D ]«}|                     ¦   «         s|                     |¦  «         Œ,t          |¦  «        }	|	                     |¦  «        r0|t          |¦  «        d…         }
|                     ||
z   ¦  «         Œ€|                     ||                     d¦  «        z   ¦  «         Œ¬d                     |¦  «        S )a[  Adjust ``new_string`` so its indentation matches ``file_region``.

    Used after a non-exact fuzzy match: the LLM may have sent old_string and
    new_string with a different indent than the file actually has (e.g.
    2-space indent in tool args vs 4-space indent on disk). The fuzzy
    strategy successfully matched anyway, but writing ``new_string`` verbatim
    would corrupt the file's indentation.

    Approach:

    1. For each non-blank line in ``new_string``, compute its indent
       *relative* to the shallowest non-blank line of ``old_string`` (the
       LLM's base indent).
    2. Anchor that relative indent onto the file's actual base indent (the
       leading whitespace of the file_region's first non-blank line).
    3. Re-emit each non-blank line as ``file_base + (line_indent - llm_base)``.

    Blank lines and lines less-indented than the LLM's base are anchored
    directly to the file's base indent.

    No-op cases (returns ``new_string`` unchanged):
    - file_region or old_string has no meaningful line
    - LLM base indent equals file base indent
    - new_string is empty
    Nr%   ú 	)	rq   rn   rp   r   r-   Ú
startswithr   Úlstripr.   )rr   r   r   Ú	old_firstÚ
file_firstÚ
old_indentÚfile_indentÚ	out_linesrh   Úline_indentÚ	remainders              r   Ú_reindent_replacementr~   ;  sF  € ð4 ð ØÐå& zÑ2Ô2€IÝ'¨Ñ4Ô4€JØÐ˜JÐ.ØÐå$ YÑ/Ô/€JÝ% jÑ1Ô1€Kà�[Ò Ð ØÐð €IØ× Ò  Ñ&Ô&ð ?ð ?ˆØ�zŠz‰|Œ|ð 	à×Ò˜TÑ"Ô"Ð"ØÝ)¨$Ñ/Ô/ˆØ×!Ò! *Ñ-Ô-ð 	?ð �S ™_œ_Ð-Ð-Ô.ˆIØ×Ò˜[¨9Ñ4Ñ5Ô5Ð5Ð5ð ×Ò˜[¨4¯;ª;°uÑ+=Ô+=Ñ=Ñ>Ô>Ð>Ð>Ø�9Š9�YÑÔÐr   c                 óÚ   ‡— d| vrd| vr| S d                      ˆfd„|D ¦   «         ¦  «        }| }d|v rd|v r|                     dd¦  «        }d|v rd|v r|                     dd¦  «        }|S )u  Conditionally unescape ``\t``/``\r`` in new_string.

    LLMs frequently send the two-character sequences ``\t`` (backslash + t)
    and ``\r`` (backslash + r) inside JSON tool-call arguments where they
    meant a real tab or carriage-return byte. Writing the string verbatim
    corrupts tab-indented files with literal backslash-letter pairs.

    The unescape is only applied per-sequence when the *matched region of
    the file* actually contains the corresponding control character â€” that
    is, we only convert ``\t`` -> tab when the file region we're replacing
    contains a real tab byte. Files that legitimately contain the literal
    two-character string ``"\t"`` (e.g. a Python source line that defines
    ``sep = "\t"``) get a backslash+t in the matched region instead of a
    tab, so we leave new_string alone.

    ``\n`` is intentionally excluded: newlines serialize correctly through
    JSON and rewriting backslash-n would corrupt escape sequences in
    string literals far more often than it would help.
    ú\tú\rr\   c              3   ó2   •K  — | ]\  }}‰||…         V — Œd S r^   r_   r`   s      €r   rc   z-_maybe_unescape_new_string.<locals>.<genexpr>—  rd   r   rk   ú)r.   r   )r   r   r"   re   Úouts    `   r   rM   rM   |  sœ   ø€ ð0 �JÐÐ 5°
Ð#:Ð#:ØÐà—g’gÐKÐKÐKÐKÀ7ÐKÑKÔKÑKÔK€OØ
€CØ�€|€|˜ Ð/Ð/Ø�kŠk˜% Ñ&Ô&ˆØ�€|€|˜ Ð/Ð/Ø�kŠk˜% Ñ&Ô&ˆØ€Jr   c                 ó(  ‡ — d                      ˆ fd„|D ¦   «         ¦  «        }t          |¦  «        }t          |¦  «        }||k    r|S t          |¦  «        }i }t          |dd…         ¦  «        D ]\  }	}
|
|vr|	||
<   Œt	          d||¦  «        }|                     ¦   «         }g }|D ]Õ\  }}}}}|dk    ry|                     |d¦  «        }|}|t          |¦  «        k     r0||         |k     r$|dz  }|t          |¦  «        k     r||         |k     °$|                     |||…         ¦  «         Œ‡|dk    r|                     |||…         ¦  «         Œ«|d	k    rŒ²|d
k    r|                     |||…         ¦  «         ŒÖd                      |¦  «        S )u“  Preserve Unicode characters from the file in the replacement string.

    When strategy 7 (unicode_normalized) matched, the file has Unicode
    characters (em-dashes, smart quotes, ellipsis, non-breaking spaces)
    but old_string/new_string from the LLM are ASCII equivalents.
    Writing new_string verbatim would silently corrupt the file's
    Unicode â€” em-dashes become two hyphens, smart quotes become
    straight quotes.

    This function aligns the replacement with the file's actual Unicode
    by diffing old_stringâ†’new_string and applying only the actual edits
    to the file's original text, preserving Unicode for unchanged portions.
    r\   c              3   ó2   •K  — | ]\  }}‰||…         V — Œd S r^   r_   r`   s      €r   rc   z3_preserve_unicode_in_replacement.<locals>.<genexpr>²  s0   øè è € ÐGÐG±°¸˜' %¨ )Ô,ÐGÐGÐGÐGÐGÐGr   Nr'   Úequalr   r&   r   ÚdeleteÚinsert)	r.   r   Ú_build_orig_to_norm_mapÚ	enumerater   Úget_opcodesÚgetr   r-   )r   r"   r   r   rr   Únorm_oldÚ	norm_fileÚfile_orig_to_normÚfile_norm_to_origÚorig_posÚnpÚsmÚopcodesÚresult_partsÚtagÚi1Úi2Új1Új2Ú
orig_startÚorig_ends   `                    r   rN   rN      s÷  ø€ ð$ —'’'ÐGÐGÐGÐG¸wÐGÑGÔGÑGÔG€Kõ " *Ñ-Ô-€HÝ" ;Ñ/Ô/€Ið �9ÒÐØÐõ 0°Ñ<Ô<ÐØ(*ÐÝ!Ð"3°C°R°CÔ"8Ñ9Ô9ð -ð -‰ˆ�"ØÐ&Ð&Ð&Ø$,Ð˜bÑ!øõ 
˜˜x¨Ñ	4Ô	4€BØ�nŠnÑÔ€Gð !€LØ&ð 3ð 3ÑˆˆR��R˜Ø�'Š>ˆ>à*×.Ò.¨r°1Ñ5Ô5ˆJØ!ˆHà�3˜{Ñ+Ô+Ò+Ð+Ø% hÔ/°"Ò4Ð4à˜A‘�ð �3˜{Ñ+Ô+Ò+Ð+Ø% hÔ/°"Ò4Ð4ð ×Ò ¨J°xÐ,?Ô @ÑAÔAÐAÐAØ�IÒÐØ×Ò 
¨2¨b¨5Ô 1Ñ2Ô2Ð2Ð2Ø�HŠ_ˆ_ØØ�HŠ_ˆ_Ø×Ò 
¨2¨b¨5Ô 1Ñ2Ô2Ð2øà�7Š7�<Ñ Ô Ð r   c                 ó°   — t          |d„ d¬¦  «        }| }|D ]=\  }}|�| ||…         }t          |||¦  «        }	n|}	|d|…         |	z   ||d…         z   }Œ>|S )aË  
    Apply replacements at the given positions.

    Args:
        content: Original content
        matches: List of (start, end) positions to replace
        new_string: Replacement text
        old_string: When non-None, signals that the match came from a
            non-exact fuzzy strategy; ``new_string`` is re-indented to
            match the file's actual indentation before substitution.

    Returns:
        Content with replacements applied
    c                 ó   — | d         S ©Nr   r_   ©Úxs    r   ú<lambda>z%_apply_replacements.<locals>.<lambda>ö  s
   € °1°Q´4€ r   T)ÚkeyÚreverseN)Úsortedr~   )
r   r"   r   r   Úsorted_matchesÚresultr0   rb   rr   Úadjusteds
             r   rO   rO   ä  s„   € õ$ ˜G¨¨ÀÐFÑFÔF€Nà€FØ$ð :ð :‰
ˆˆsØÐ!Ø! %¨ )Ô,ˆKÝ,¨[¸*ÀjÑQÔQˆHˆHà!ˆHØ˜˜˜” (Ñ*¨V°C°D°D¬\Ñ9ˆˆà€Mr   Úpatternc                 ó¾   — g }d}	 |                       ||¦  «        }|dk    rn:|                     ||t          |¦  «        z   f¦  «         |t          |¦  «        z   }ŒW|S )zStrategy 1: Exact string match.r   Tr'   )r,   r-   r   )r   rª   r"   r0   Úposs        r   rC   rC     sp   € à€GØ€Eð
#Ø�lŠl˜7 EÑ*Ô*ˆØ�"Š9ˆ9ØØ�Š˜˜S¥3 w¡<¤<Ñ/Ð0Ñ1Ô1Ð1ð •c˜'‘l”lÑ"ˆð
#ð €Nr   c                 óÒ   — d„ |                      d¦  «        D ¦   «         }d                     |¦  «        }|                       d¦  «        }d„ |D ¦   «         }t          | ||||¦  «        S )zŽ
    Strategy 2: Match with line-by-line whitespace trimming.
    
    Strips leading/trailing whitespace from each line before matching.
    c                 ó6   — g | ]}|                      ¦   «         ‘ŒS r_   ©r   ©ra   rh   s     r   ú
<listcomp>z*_strategy_line_trimmed.<locals>.<listcomp>!  s    € ÐBÐBÐB d�T—Z’Z‘\”\ÐBÐBÐBr   r%   c                 ó6   — g | ]}|                      ¦   «         ‘ŒS r_   r¯   r°   s     r   r±   z*_strategy_line_trimmed.<locals>.<listcomp>%  s    € ÐGÐGÐG° §
¢
¡¤ÐGÐGÐGr   )rp   r.   Ú_find_normalized_matches)r   rª   Úpattern_linesÚpattern_normalizedÚcontent_linesÚcontent_normalized_liness         r   rD   rD     s}   € ð CÐB¨g¯mªm¸DÑ.AÔ.AÐBÑBÔB€MØŸš =Ñ1Ô1Ðà—M’M $Ñ'Ô'€MØGÐG¸ÐGÑGÔGÐõ $Ø�Ð 8ØÐ#ñô ð r   c                 ó~   — d„ } ||¦  «        } || ¦  «        }t          ||¦  «        }|sg S t          | ||¦  «        S )zC
    Strategy 3: Collapse multiple whitespace to single space.
    c                 ó.   — t          j        dd| ¦  «        S )Nz[ \t]+r   )ÚreÚsub©Úss    r   Ú	normalizez2_strategy_whitespace_normalized.<locals>.normalize2  s   € åŒv�i  aÑ(Ô(Ð(r   )rC   Ú_map_normalized_positions)r   rª   r¾   rµ   Úcontent_normalizedÚmatches_in_normalizeds         r   rE   rE   .  sj   € ð)ð )ð )ð #˜ 7Ñ+Ô+ÐØ"˜ 7Ñ+Ô+Ðõ ,Ð,>Ð@RÑSÔSÐà ð Øˆ	õ % WÐ.@ÐBWÑXÔXÐXr   c           	      óÎ   — |                       d¦  «        }d„ |D ¦   «         }d„ |                      d¦  «        D ¦   «         }t          | |||d                     |¦  «        ¦  «        S )z�
    Strategy 4: Ignore indentation differences entirely.
    
    Strips all leading whitespace from lines before matching.
    r%   c                 ó6   — g | ]}|                      ¦   «         ‘ŒS r_   ©rv   r°   s     r   r±   z2_strategy_indentation_flexible.<locals>.<listcomp>J  s    € ÐFÐFÐF°˜dŸkšk™mœmÐFÐFÐFr   c                 ó6   — g | ]}|                      ¦   «         ‘ŒS r_   rÄ   r°   s     r   r±   z2_strategy_indentation_flexible.<locals>.<listcomp>K  s    € ÐCÐCÐC t�T—[’[‘]”]ÐCÐCÐCr   )rp   r³   r.   )r   rª   r¶   Úcontent_stripped_linesr´   s        r   rF   rF   C  ss   € ð —M’M $Ñ'Ô'€MØFÐF¸ÐFÑFÔFÐØCÐC¨w¯}ª}¸TÑ/BÔ/BÐCÑCÔC€Må#Ø�Ð 6Ø�—’˜=Ñ)Ô)ñô ð r   c                 óN   — d„ } ||¦  «        }||k    rg S t          | |¦  «        S )zt
    Strategy 5: Convert escape sequences to actual characters.
    
    Handles \n -> newline, \t -> tab, etc.
    c                 ó~   — |                       dd¦  «                              dd¦  «                              dd¦  «        S )Nz\nr%   r€   rk   r�   rƒ   )r   r¼   s    r   Úunescapez-_strategy_escape_normalized.<locals>.unescapeY  s6   € à�yŠy˜ Ñ%Ô%×-Ò-¨e°TÑ:Ô:×BÒBÀ5È$ÑOÔOÐOr   )rC   )r   rª   rÉ   Úpattern_unescapeds       r   rG   rG   S  sG   € ðPð Pð Pð !˜ Ñ)Ô)Ðà˜GÒ#Ð#àˆ	å˜7Ð$5Ñ6Ô6Ð6r   c           	      ó  — |                      d¦  «        }|sg S |d                              ¦   «         |d<   t          |¦  «        dk    r|d                              ¦   «         |d<   d                     |¦  «        }|                       d¦  «        }g }t          |¦  «        }t	          t          |¦  «        |z
  dz   ¦  «        D ]Å}||||z   …         }|                     ¦   «         }	|	d                              ¦   «         |	d<   t          |	¦  «        dk    r|	d                              ¦   «         |	d<   d                     |	¦  «        |k    r<t          ||||z   t          | ¦  «        ¦  «        \  }
}|                     |
|f¦  «         ŒÆ|S )zŽ
    Strategy 6: Trim whitespace from first and last lines only.
    
    Useful when the pattern boundaries have whitespace differences.
    r%   r   r&   r'   )rp   r   r   r.   ÚrangeÚcopyÚ_calculate_line_positionsr-   )r   rª   r´   Úmodified_patternr¶   r"   Úpattern_line_countrm   Úblock_linesÚcheck_linesÚ	start_posÚend_poss               r   rH   rH   f  sœ  € ð —M’M $Ñ'Ô'€MØð Øˆ	ð % QÔ'×-Ò-Ñ/Ô/€M�!ÑÝ
ˆ=ÑÔ˜AÒÐØ)¨"Ô-×3Ò3Ñ5Ô5ˆ�bÑà—y’y Ñ/Ô/Ðà—M’M $Ñ'Ô'€Mð €GÝ˜]Ñ+Ô+Ðå•3�}Ñ%Ô%Ð(:Ñ:¸QÑ>Ñ?Ô?ð 1ð 1ˆØ# A aÐ*<Ñ&<Ð$<Ô=ˆð "×&Ò&Ñ(Ô(ˆØ$ Qœ×-Ò-Ñ/Ô/ˆ�A‰Ýˆ{ÑÔ˜aÒÐØ)¨"œo×3Ò3Ñ5Ô5ˆK˜‰Oà�9Š9�[Ñ!Ô!Ð%5Ò5Ð5å!:Ø˜q !Ð&8Ñ"8½#¸g¹,¼,ñ"ô "ÑˆI�wð �NŠN˜I wÐ/Ñ0Ô0Ð0øà€Nr   Úoriginalc                 óÌ   — g }d}| D ]G}|                      |¦  «         t                               |¦  «        }||�t          |¦  «        ndz  }ŒH|                      |¦  «         |S )uï  Build a list mapping each original character index to its normalized index.

    Because UNICODE_MAP replacements may expand characters (e.g. em-dash â†’ '--',
    ellipsis â†’ '...'), the normalised string can be longer than the original.
    This map lets us convert positions in the normalised string back to the
    corresponding positions in the original string.

    Returns a list of length ``len(original) + 1``; entry ``i`` is the
    normalised index that character ``i`` maps to.
    r   Nr&   )r-   r   r�   r   )rÕ   r¨   Únorm_posr   r   s        r   rŠ   rŠ   �  sr   € ð €FØ€HØð 9ð 9ˆØ�Š�hÑÔÐÝ�Š˜tÑ$Ô$ˆØ Ð!1•C˜‘I”I�I°qÑ8ˆˆØ
‡M‚M�(ÑÔÐØ€Mr   Úorig_to_normÚnorm_matchesc                 ó,  — i }t          | dd…         ¦  «        D ]\  }}||vr|||<   Œg }t          | ¦  «        dz
  }|D ]T\  }}||vrŒ
||         }	|	}
|
|k     r#| |
         |k     r|
dz  }
|
|k     r| |
         |k     °|                     |	|
f¦  «         ŒU|S )zNConvert (start, end) positions in the normalised string to original positions.Nr'   r&   )r‹   r   r-   )rØ   rÙ   Únorm_to_orig_startr’   r×   ÚresultsÚorig_lenÚ
norm_startÚnorm_endrœ   r�   s              r   Ú_map_positions_norm_to_origrà   ¥  sò   € ð *,ÐÝ'¨°S°b°SÔ(9Ñ:Ô:ð 4ð 4Ñˆ�(ØÐ-Ð-Ð-Ø+3Ð˜xÑ(øà%'€GÝ�<Ñ Ô  1Ñ$€Hà ,ð 
/ð 
/Ñˆ
�HØÐ/Ð/Ð/ØØ'¨
Ô3ˆ
ð ˆØ˜Ò!Ð! l°8Ô&<¸xÒ&GÐ&GØ˜‰MˆHð ˜Ò!Ð! l°8Ô&<¸xÒ&GÐ&Gð 	�Š˜
 HÐ-Ñ.Ô.Ð.Ð.à€Nr   c                 óä   — t          |¦  «        }t          | ¦  «        }|| k    r||k    rg S t          ||¦  «        }|st          ||¦  «        }|sg S t          | ¦  «        }t	          ||¦  «        S )uø  Strategy 7: Unicode normalisation.

    Normalises smart quotes, em/en-dashes, ellipsis, and non-breaking spaces
    to their ASCII equivalents in both *content* and *pattern*, then runs
    exact and line_trimmed matching on the normalised copies.

    Positions are mapped back to the *original* string via
    ``_build_orig_to_norm_map`` â€” necessary because some UNICODE_MAP
    replacements expand a single character into multiple ASCII characters,
    making a naÃ¯ve position copy incorrect.
    )r   rC   rD   rŠ   rà   )r   rª   Únorm_patternÚnorm_contentrÙ   rØ   s         r   rI   rI   Â  s‰   € õ & gÑ.Ô.€LÝ% gÑ.Ô.€LØ�wÒÐ <°7Ò#:Ð#:Øˆ	å" <°Ñ>Ô>€LØð JÝ-¨l¸LÑIÔIˆàð Øˆ	å*¨7Ñ3Ô3€LÝ& |°\ÑBÔBÐBr   c           	      ó  — t          |¦  «        }t          | ¦  «        }|                     d¦  «        }t          |¦  «        dk     rg S |d                              ¦   «         }|d                              ¦   «         }|                     d¦  «        }|                      d¦  «        }t          |¦  «        }	g }
t	          t          |¦  «        |	z
  dz   ¦  «        D ]Y}||                              ¦   «         |k    r9|||	z   dz
                                ¦   «         |k    r|
                     |¦  «         ŒZg }t          |
¦  «        }|dk    rdnd}|
D ]³}|	dk    rd}nfd                     ||dz   ||	z   dz
  …         ¦  «        }d                     |dd…         ¦  «        }t          d	||¦  «                             ¦   «         }||k    r<t          ||||	z   t          | ¦  «        ¦  «        \  }}|                     ||f¦  «         Œ´|S )
z„
    Strategy 8: Match by anchoring on first and last lines.
    Adjusted with permissive thresholds and unicode normalization.
    r%   é   r   r'   r&   g      à?gffffffæ?ç      ð?N)
r   rp   r   r   rÌ   r-   r.   r   ÚratiorÎ   )r   rª   râ   rã   r´   Ú
first_lineÚ	last_lineÚnorm_content_linesÚorig_content_linesrÐ   Úpotential_matchesrm   r"   Úcandidate_countÚ	thresholdÚ
similarityÚcontent_middleÚpattern_middlerÓ   rÔ   s                       r   rJ   rJ   á  s5  € õ & gÑ.Ô.€LÝ% gÑ.Ô.€Là ×&Ò& tÑ,Ô,€MÝ
ˆ=ÑÔ˜AÒÐØˆ	à˜qÔ!×'Ò'Ñ)Ô)€JØ˜bÔ!×'Ò'Ñ)Ô)€Ið &×+Ò+¨DÑ1Ô1Ðà Ÿš tÑ,Ô,Ðå˜]Ñ+Ô+ÐàÐÝ•3Ð)Ñ*Ô*Ð-?Ñ?À!ÑCÑDÔDð (ð (ˆØ˜qÔ!×'Ò'Ñ)Ô)¨ZÒ7Ð7Ø˜qÐ#5Ñ5¸Ñ9Ô:×@Ò@ÑBÔBÀiÒOÐOØ×$Ò$ QÑ'Ô'Ð'øà€GÝÐ+Ñ,Ô,€Oð
 (¨1Ò,Ð,��°$€Iàð 1ð 1ˆØ Ò"Ð"ØˆJˆJð "ŸYšYÐ'9¸!¸A¹#¸aÐ@RÑ>RÐSTÑ>TÐ:TÔ'UÑVÔVˆNØ!ŸYšY }°Q°r°TÔ':Ñ;Ô;ˆNÝ(¨¨~¸~ÑNÔN×TÒTÑVÔVˆJà˜Ò"Ð"å!:Ø" A qÐ+=Ñ'=½sÀ7¹|¼|ñ"ô "ÑˆI�wð �NŠN˜I wÐ/Ñ0Ô0Ð0øà€Nr   c           	      óz  — |                      d¦  «        }|                       d¦  «        }|sg S t          |¦  «        }|t          |¦  «        k    rg S |d                              ¦   «         }|d                              ¦   «         }d}dt          dt          dt          fd„}g }	t          t          |¦  «        |z
  d	z   ¦  «        D ]ô}
||
|
|z   …         } |||d                              ¦   «         ¦  «        |k     rŒ8 |||d                              ¦   «         ¦  «        |k     rŒad
}t          ||¦  «        D ]B\  }}|                     ¦   «         }|sŒ |||                     ¦   «         ¦  «        dk     rd} nŒC|r<t          ||
|
|z   t          | ¦  «        ¦  «        \  }}|	                     ||f¦  «         Œõ|	S )ai  
    Strategy 9 (last resort): anchored line-by-line similarity.

    Only considers blocks whose first AND last lines closely match the
    pattern's first/last lines (an anchor pre-filter), then requires EVERY
    non-blank pattern line to be highly similar (>=0.80) to the aligned
    content line. The anchor filter keeps this from being an O(file x pattern)
    scan on every miss, and the all-lines requirement stops a single
    coincidental line-match from silently replacing an unrelated block
    (the old 50%-of-lines threshold accepted half-garbage patterns and
    destroyed the non-matching lines).
    r%   r   r'   gš™™™™™é?ÚaÚbr   c                 óX   — | |k    rdS t          d | |¦  «                             ¦   «         S )Nræ   )r   rç   )ró   rô   s     r   Ú_simz%_strategy_context_aware.<locals>._sim7  s.   € Ø�Š6ˆ6Ø�3Ý˜t Q¨Ñ*Ô*×0Ò0Ñ2Ô2Ð2r   r&   TF)	rp   r   r   ÚstrÚfloatrÌ   ÚziprÎ   r-   )r   rª   r´   r¶   rÐ   Ú	first_patÚlast_patÚANCHOR_THRESHOLDrö   r"   rm   rÑ   Ú	all_matchÚp_lineÚc_lineÚ
p_strippedrÓ   rÔ   s                     r   rK   rK     s  € ð —M’M $Ñ'Ô'€MØ—M’M $Ñ'Ô'€Màð Øˆ	å˜]Ñ+Ô+ÐØ�C Ñ.Ô.Ò.Ð.Øˆ	ð
 ˜aÔ ×&Ò&Ñ(Ô(€IØ˜RÔ ×&Ò&Ñ(Ô(€HØÐð3•ð 3�ð 3¥ð 3ð 3ð 3ð 3ð
 €GÝ•3�}Ñ%Ô%Ð(:Ñ:¸QÑ>Ñ?Ô?ð 1ð 1ˆØ# A aÐ*<Ñ&<Ð$<Ô=ˆð ˆ4�	˜; qœ>×/Ò/Ñ1Ô1Ñ2Ô2Ð5EÒEÐEØØˆ4�˜+ bœ/×/Ò/Ñ1Ô1Ñ2Ô2Ð5EÒEÐEØð ˆ	Ý! -°Ñ=Ô=ð 	ð 	‰NˆF�FØŸš™œˆJØð ØØˆt�J §¢¡¤Ñ/Ô/°$Ò6Ð6Ø!�	Ø�ð 7ð ð 	1Ý!:Ø˜q !Ð&8Ñ"8½#¸g¹,¼,ñ"ô "ÑˆI�wð �NŠN˜I wÐ/Ñ0Ô0Ð0øà€Nr   r¶   Ú
start_lineÚend_lineÚcontent_lengthc                 ó´   — t          d„ | d|…         D ¦   «         ¦  «        }t          d„ | d|…         D ¦   «         ¦  «        dz
  }t          ||¦  «        }||fS )a�  Calculate start and end character positions from line indices.

    Args:
        content_lines: List of lines (without newlines)
        start_line: Starting line index (0-based)
        end_line: Ending line index (exclusive, 0-based)
        content_length: Total length of the original content string

    Returns:
        Tuple of (start_pos, end_pos) in the original content
    c              3   ó:   K  — | ]}t          |¦  «        d z   V — ŒdS ©r&   Nrl   r°   s     r   rc   z,_calculate_line_positions.<locals>.<genexpr>l  s,   è è € ÐIÐI d•C˜‘I”I ‘MÐIÐIÐIÐIÐIÐIr   Nc              3   ó:   K  — | ]}t          |¦  «        d z   V — ŒdS r  rl   r°   s     r   rc   z,_calculate_line_positions.<locals>.<genexpr>m  s,   è è € ÐEÐE D•#�d‘)”)˜a‘-ÐEÐEÐEÐEÐEÐEr   r&   )ÚsumÚmin)r¶   r  r  r  rÓ   rÔ   s         r   rÎ   rÎ   _  sm   € õ ÐIÐI¨m¸K¸Z¸KÔ.HÐIÑIÔIÑIÔI€IÝÐEÐE¨M¸)¸8¸)Ô,DÐEÑEÔEÑEÔEÈÑI€GÝ�. 'Ñ*Ô*€GØ�gÐÐr   r·   rµ   c           	      ó`  — |                      d¦  «        }t          |¦  «        }g }t          t          |¦  «        |z
  dz   ¦  «        D ]d}d                     ||||z   …         ¦  «        }	|	|k    r<t	          ||||z   t          | ¦  «        ¦  «        \  }
}|                     |
|f¦  «         Œe|S )aœ  
    Find matches in normalized content and map back to original positions.
    
    Args:
        content: Original content string
        content_lines: Original content split by lines
        content_normalized_lines: Normalized content lines
        pattern: Original pattern
        pattern_normalized: Normalized pattern
    
    Returns:
        List of (start, end) positions in the original content
    r%   r&   )rp   r   rÌ   r.   rÎ   r-   )r   r¶   r·   rª   rµ   Úpattern_norm_linesÚnum_pattern_linesr"   rm   ÚblockrÓ   rÔ   s               r   r³   r³   r  sÍ   € ð  ,×1Ò1°$Ñ7Ô7ÐÝÐ.Ñ/Ô/Ðà€Gå•3Ð/Ñ0Ô0Ð3DÑDÀqÑHÑIÔIð 	1ð 	1ˆà—	’	Ð2°1°QÐ9JÑ5JÐ3JÔKÑLÔLˆàÐ&Ò&Ð&å!:Ø˜q !Ð&7Ñ"7½¸W¹¼ñ"ô "ÑˆI�wð �NŠN˜I wÐ/Ñ0Ô0Ð0øà€Nr   Ú
normalizedÚnormalized_matchesc           
      ó  ‡— |sg S g }d}d}|t          | ¦  «        k     rý|t          |¦  «        k     rê| |         ||         k    r |                     |¦  «         |dz  }|dz  }n’| |         dv rI||         dk    r=|                     |¦  «         |dz  }|t          | ¦  «        k     r| |         dvr|dz  }n?| |         dv r|                     |¦  «         |dz  }n|                     |¦  «         |dz  }|t          | ¦  «        k     r|t          |¦  «        k     °ê|t          | ¦  «        k     r:|                     t          |¦  «        ¦  «         |dz  }|t          | ¦  «        k     °:i }i }t          |¦  «        D ]\  }}	|	|vr|||	<   |||	<   Œg }
|D ]ë\  Š}‰|v r	|‰         }n(t          ˆfd„t          |¦  «        D ¦   «         ¦  «        }|dz
  |v r||dz
           dz   }n||‰z
  z   }|t          |¦  «        k     rN||dz
           dk    r?|t          | ¦  «        k     r,| |         dv r"|dz  }|t          | ¦  «        k     r
| |         dv °"|
                     |t          |t          | ¦  «        ¦  «        f¦  «         Œì|
S )z�
    Map positions from normalized string back to original.
    
    This is a best-effort mapping that works for whitespace normalization.
    r   r&   rt   r   c              3   ó.   •K  — | ]\  }}|‰k    ¯|V — Œd S r^   r_   )ra   rm   ÚnrÞ   s      €r   rc   z,_map_normalized_positions.<locals>.<genexpr>Ð  s+   øè è € ÐVÐV¡4 1 aÀaÈ:ÂoÀo˜QÀoÀoÀoÀoÐVÐVr   )r   r-   r‹   r	  )rÕ   r  r  rØ   Úorig_idxÚnorm_idxrÛ   Únorm_to_orig_endr’   r×   Úoriginal_matchesrß   rœ   r�   rÞ   s                 @r   r¿   r¿   •  s-  ø€ ð ð Øˆ	ð €Là€HØ€Hà
•S˜‘]”]Ò
"Ð
" xµ#°j±/´/Ò'AÐ'AØ�HÔ ¨HÔ!5Ò5Ð5Ø×Ò Ñ)Ô)Ð)Ø˜‰MˆHØ˜‰MˆHˆHØ�hÔ 5Ð(Ð(¨Z¸Ô-AÀSÒ-HÐ-Hà×Ò Ñ)Ô)Ð)Ø˜‰MˆHà�#˜h™-œ-Ò'Ð'¨H°XÔ,>ÀeÐ,KÐ,KØ˜A‘�øØ�hÔ 5Ð(Ð(à×Ò Ñ)Ô)Ð)Ø˜‰MˆHˆHð ×Ò Ñ)Ô)Ð)Ø˜‰MˆHð' •S˜‘]”]Ò
"Ð
" xµ#°j±/´/Ò'AÐ'Að, •S˜‘]”]Ò
"Ð
"Ø×Ò�C 
™OœOÑ,Ô,Ð,Ø�A‰ˆð •S˜‘]”]Ò
"Ð
"ð
 ÐØÐå'¨Ñ5Ô5ð .ð .Ñˆ�(ØÐ-Ð-Ð-Ø+3Ð˜xÑ(Ø%-Ð˜Ñ"Ð"ð ÐØ 2ð Lð LÑˆ
�HàÐ+Ð+Ð+Ø+¨JÔ7ˆJˆJõ ÐVÐVÐVÐV­9°\Ñ+BÔ+BÐVÑVÔVÑVÔVˆJð �a‰<Ð+Ð+Ð+Ø'¨°1©Ô5¸Ñ9ˆHˆHà! X°
Ñ%:Ñ;ˆHð •c˜*‘o”oÒ%Ð%¨*°XÀ±\Ô*BÀcÒ*IÐ*IØ�S ™]œ]Ò*Ð*¨x¸Ô/AÀUÐ/JÐ/JØ˜A‘�ð �S ™]œ]Ò*Ð*¨x¸Ô/AÀUÐ/JÐ/Jð 	×Ò ­S°½3¸x¹=¼=Ñ-IÔ-IÐ JÑKÔKÐKÐKàÐr   c                 ó  — d}g }|t          | ¦  «        k     rO| |         dv rE|                     | |         dk    rdnd¦  «         |dz  }|t          | ¦  «        k     r
| |         dv °Ed                     |¦  «        | |d…         z   S )	uÅ   Render leading whitespace visibly (â†’ = tab, Â· = space).

    Only the leading run is visualized â€” interior spacing is rarely the
    culprit and full visualization makes lines unreadable.
    r   rj   rk   u   â†’õ   Â·r&   r\   N)r   r-   r.   )rh   rm   Úprefixs      r   Ú_visualize_whitespacer  æ  s”   € ð 	
€AØ€FØ
�c�$‰iŒiŠ-ˆ-˜D œG {Ð2Ð2Ø�Š˜t Aœw¨$š˜�e�e°DÑ9Ô9Ð9Ø	ˆQ‰ˆð �c�$‰iŒiŠ-ˆ-˜D œG {Ð2Ð2ð �7Š7�6‰?Œ?˜T ! " "œXÑ%Ð%r   rå   é   Úcontext_linesÚmax_resultsc                 óz  ‡‡— | r|sdS |                       ¦   «         }|                      ¦   «         Š|r‰sdS |d                              ¦   «         }|sd„ |D ¦   «         }|sdS |d         }g }t          ‰¦  «        D ]\\  }}	|	                     ¦   «         }
|
sŒt          d||
¦  «                             ¦   «         }|dk    r|                     ||f¦  «         Œ]|sdS |                     d„ ¬¦  «         |d|…         }g }t          ¦   «         }|D ]­\  }}t          d||z
  ¦  «        Št          t          ‰¦  «        |t          |¦  «        z   |z   ¦  «        }‰|f}||v rŒQ|                     |¦  «         d                     ˆˆfd	„t          |‰z
  ¦  «        D ¦   «         ¦  «        }|                     |¦  «         Œ®|sdS d
                     |¦  «        }‰|d         d                  }|                     ¦   «         |k    r8||d         k    r,|dt          |¦  «        › dt          |d         ¦  «        › d�z  }|S )zÕFind lines in content most similar to old_string for "did you mean?" feedback.

    Returns a formatted string showing the closest matching lines with context,
    or empty string if no useful match is found.
    r\   r   c                 ó^   — g | ]*}|                      ¦   «         ¯|                      ¦   «         ‘Œ+S r_   r¯   )ra   Úls     r   r±   z&find_closest_lines.<locals>.<listcomp>  s-   € Ð@Ð@Ð@ A°a·g²g±i´iÐ@�a—g’g‘i”iÐ@Ð@Ð@r   Ng333333Ó?c                 ó   — | d          S r    r_   r¡   s    r   r£   z$find_closest_lines.<locals>.<lambda>  s   € ˜q œt˜e€ r   )r¤   r%   c              3   óF   •K  — | ]}‰|z   d z   d›d‰‰|z            › �V — ŒdS )r&   Ú4dz| Nr_   )ra   Újr¶   r0   s     €€r   rc   z%find_closest_lines.<locals>.<genexpr>&  sY   øè è € ð 
ð 
àð �q‰y˜1‰}Ð=Ð=Ð= =°¸±Ô#;Ð=Ð=ð
ð 
ð 
ð 
ð 
ð 
r   z
---
r&   uF   

Whitespace difference detected (â†’ = tab, Â· = space):
  file has: z
  you sent: z.
Use the exact whitespace shown in 'file has'.)Ú
splitlinesr   r‹   r   rç   r-   ÚsortÚsetÚmaxr	  r   Úaddr.   rÌ   r  )r   r   r  r  Ú	old_linesÚanchorÚ
candidatesÚscoredrm   rh   Ústrippedrç   ÚtopÚpartsÚseen_rangesÚ_Úline_idxrb   r¤   r5   r¨   Ú	best_liner¶   r0   s                         @@r   Úfind_closest_linesr5  ô  sÆ  øø€ ð ð ˜Wð Øˆrà×%Ò%Ñ'Ô'€IØ×&Ò&Ñ(Ô(€Màð ˜Mð Øˆrð �qŒ\×ÒÑ!Ô!€FØð à@Ð@¨Ð@Ñ@Ô@ˆ
Øð 	Ø�2Ø˜A”ˆð €FÝ˜]Ñ+Ô+ð &ð &‰ˆˆ4Ø—:’:‘<”<ˆØð 	ØÝ  f¨hÑ7Ô7×=Ò=Ñ?Ô?ˆØ�3Š;ˆ;Ø�MŠM˜5 !˜*Ñ%Ô%Ð%øàð Øˆrð ‡K‚K�O�O€KÑ$Ô$Ð$Ø
��+�Ô
€Cà€EÝ‘%”%€KØð ð ‰ˆˆ8Ý�A�x -Ñ/Ñ0Ô0ˆÝ•#�mÑ$Ô$ hµ°Y±´Ñ&?À-Ñ&OÑPÔPˆØ�cˆlˆØ�+ÐÐØØ�Š˜ÑÔÐØ—)’)ð 
ð 
ð 
ð 
ð 
å˜3 ™;Ñ'Ô'ð
ñ 
ô 
ñ 
ô 
ˆð 	�Š�WÑÔÐÐàð Øˆrà�^Š^˜EÑ"Ô"€Fð ˜c !œf QœiÔ(€IØ‡‚ÑÔ˜FÒ"Ð" y°I¸a´LÒ'@Ð'@Øð<Ý0°Ñ;Ô;ð<ð <å0°¸1´Ñ>Ô>ð<ð <ð <ñ	
ˆð €Mr   ÚerrorÚmatch_countc                 óv   — |dk    rdS | r|                       d¦  «        sdS t          ||¦  «        }|sdS d|z   S )u¬  Return a '\n\nDid you mean...' snippet for plain no-match errors.

    Gated so the hint only fires for actual "old_string not found" failures.
    Ambiguous-match ("Found N matches"), escape-drift, and identical-strings
    errors all have ``match_count == 0`` but a "did you mean?" snippet would
    be misleading â€” those failed for unrelated reasons.

    Returns an empty string when there's nothing useful to append.
    r   r\   zCould not findz&

Did you mean one of these sections?
)ru   r5  )r6  r7  r   r   Úhints        r   Úformat_no_match_hintr:  B  s^   € ð �aÒÐØˆrØð ˜×(Ò(Ð)9Ñ:Ô:ð ØˆrÝ˜j¨'Ñ2Ô2€DØð ØˆrØ6¸Ñ=Ð=r   )r!   )Fr^   )rå   r  ))Ú__doc__rº   Útypingr   r   r   r   Údifflibr   r   r÷   r   Úboolr    Úintr7   rX   rL   rn   rq   r~   rM   rN   rO   rC   rD   rE   rF   rG   rH   rŠ   rà   rI   rJ   rK   rÎ   r³   r¿   r  r5  r:  r_   r   r   ú<module>r@     s  ððð ð< 
€	€	€	Ø 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ø #Ð #Ð #Ð #Ð #Ð #ðØˆcðØ˜Sðàˆcðà˜Sðð ˆdðð ˜cðð ˆeð	ð ˜sð	ð ˆcðð ˆcðð ˜Sðð ˆcðð ˜Sðð  ˆcð!ð  ˜Sð!ð  #+¨Cð!ð" ˆcð#ð" !Ø˜SØØØð+ð ð €ð0˜Sð  Sð ð ð ð ð% ð %°ð %À#ð %È$ð %ð %ð %ð %ð8 ()ðð  Sð °4¸¸cÀ3¸h¼Ô3Hð Ø!$ðØ-0ðð ð ð ð4 16ðFQð FQ Cð FQ°Sð FQÀcð FQØ)-ðFQØ:?ÀÀSÈ(ÐSVÌ-ÐYaÐbeÔYfÐ@fÔ:gðFQð FQð FQð FQðR% #ð %°°U¸3À¸8´_Ô0Eð %Ø%(ð%Ø69ð%Ø>FÀs¼mð%ð %ð %ð %ðP˜cð  cð ð ð ð ð ð ¨°#¬ð ð ð ð ð>  sð > ¸ð > Èð > ÐQTð > ð > ð > ð > ðB!¨3ð !Ø(+ð!à(,¨U°3¸°8¬_Ô(=ð!àBEð!ð !ð !ð !ðHA!ØðA!Ø  c¨3 h¤Ô0ðA!àðA!à!$ðA!ð 	ðA!ð A!ð A!ð A!ðJ FJðð  ð ¨t°E¸#¸s¸(´OÔ/Dð Ø$'ðØ5=¸c´]ðØNQðð ð ð ðH˜Sð ¨3ð °4¸¸cÀ3¸h¼Ô3Hð ð ð ð ð$ Cð °#ð ¸$¸uÀSÈ#ÀX¼Ô:Oð ð ð ð ð(Y¨Sð Y¸3ð YÀ4ÈÈcÐSVÈhÌÔCXð Yð Yð Yð Yð*¨Cð ¸#ð À$ÀuÈSÐRUÈXÄÔBWð ð ð ð ð 7¨ð 7°sð 7¸tÀEÈ#ÈsÈ(ÄOÔ?Tð 7ð 7ð 7ð 7ð&'¨ð '°cð '¸dÀ5ÈÈcÈÄ?Ô>Sð 'ð 'ð 'ð 'ðT cð ¨d°3¬ið ð ð ð ð*Ø�s”)ðà�u˜S #˜X”Ô'ðð 
ˆ%��S�Œ/Ôðð ð ð ð:C¨#ð C¸ð CÀÀUÈ3ÐPSÈ8Ä_Ô@Uð Cð Cð Cð Cð>5 Cð 5°#ð 5¸$¸uÀSÈ#ÀX¼Ô:Oð 5ð 5ð 5ð 5ðp? Sð ?°3ð ?¸4ÀÀcÈ3ÀhÄÔ;Pð ?ð ?ð ?ð ?ðL¨T°#¬Yð ÀCð Ø(+ðØ=@ðØEJÈ3ÐPSÈ8Ä_ðð ð ð ð&  cð  ¸$¸s¼)ð  Ø8<¸S¼	ð à'*ð à@Cð àHLÈUÐSVÐX[ÐS[Ì_ÔH]ð ð  ð  ð  ðFN¨ð N¸ð NØ37¸¸cÀ3¸h¼Ô3HðNØMQÐRWÐX[Ð]`ÐX`ÔRaÔMbðNð Nð Nð Nðb& ð &¨ð &ð &ð &ð &ðKð K 3ð K°ð KÀSð KÐ[^ð KÐgjð Kð Kð Kð Kð\> ¨¤ð >¸Cð >Ø%(ð>Ø36ð>Ø;>ð>ð >ð >ð >ð >ð >r   