
    ^hP                     ^   S r SSKrSSKJrJrJr  SSKJr  SSKJ	r	  SSK
JrJrJrJrJrJrJrJrJr  SSKJrJr  S\\   S	\\\\4      4S
 jrS\\\4   S	\4S jrS\\\\4      S\S	\\\\4      4S jrS\\\\4      S\S\S	\\\\4      4S jrS\S\\\\4      S	S4S jr S\S	\4S jr! " S S\S   5      r"S\S\#\   S	S4S jr$S\S	S4S jr%S\\   S\S	S4S jr&S\S	\4S jr'S \	\\\   4   S	\#\   4S! jr(\ " S" S#5      5       r)S\S\S	\\)   4S$ jr*S%\S&\\)   S'\S	\4S( jr+g))z?Functions related to Black's formatting by line ranges feature.    N)
CollectionIteratorSequence)	dataclass)Union)	LNSTANDALONE_COMMENTLeafNodeVisitor
first_leaf furthest_ancestor_with_last_leaf	last_leafsyms)ASYNCNEWLINEline_rangesreturnc                    / nU  Ha  nUR                  S5      n[        U5      S:w  a  [        SU< 35      e [        US   5      n[        US   5      nUR	                  XE45        Mc     U$ ! [         a    [        SU< 35      S ef = f)N-   z:Incorrect --line-ranges format, expect 'START-END', found r      z<Incorrect --line-ranges value, expect integer ranges, found )splitlen
ValueErrorintappend)r   lines	lines_strpartsstartends         F/home/james-whalen/.local/lib/python3.13/site-packages/black/ranges.pyparse_line_rangesr$      s    #%E 	$u:?=" 		'aMEeAh-C LL%&! !" L  	=" 	s   A,,Br   c                 4    U (       + =(       d    U S   U S   :*  $ )z(Returns whether the line range is valid.r   r    )r   s    r#   is_valid_line_ranger'   ,   s    9,aE!H,,    src_contentsc                     U(       d  / $ / nUR                  S5      nUR                  S5      (       d  US-  nU  H<  u  pEXC:  a  M  [        US5      nXT:  a  M  [        XS5      nUR	                  XE45        M>     U$ )a  Returns the valid line ranges for the given source.

This removes ranges that are entirely outside the valid lines.

Other ranges are normalized so that the start values are at least 1 and the
end values are at most the (1-based) index of the last source line.

r   )countendswithmaxminr   )r   r)   
good_linessrc_line_countr!   r"   s         r#   sanitized_linesr2   1   s     	J!''-N  &&!
!E1;#&5,'  r(   original_sourcemodified_sourcec                    [        X5      n/ nSn[        U 5       H  u  pg[        UUU5      n[        UUU5      n	UnU[        U5      :  d  U	[        U5      :  a  MA  X8   n
X9   nU
R                  (       a  U
R
                  nOXjR                  -
  U
R
                  -   nUR                  (       a  UR                  nOX{R                  -
  UR
                  -   nX4n[        U5      (       d  M  UR                  U5        M     U$ )aN  Returns the adjusted line ranges based on edits from the original code.

This computes the new line ranges by diffing original_source and
modified_source, and adjust each range based on how the range overlaps with
the diffs.

Note the diff can contain lines outside of the original line ranges. This can
happen when the formatting has to be done in adjacent to maintain consistent
local results. For example:

1. def my_func(arg1, arg2,
2.             arg3,):
3.   pass

If it restricts to line 2-2, it can't simply reformat line 2, it also has
to reformat line 1:

1. def my_func(
2.     arg1,
3.     arg2,
4.     arg3,
5. ):
6.   pass

In this case, we will expand the line ranges to also include the whole diff
block.

Args:
  lines: a collection of line ranges.
  original_source: the original source.
  modified_source: the modified source.
r   )
_calculate_lines_mappingssorted_find_lines_mapping_indexr   is_changed_blockmodified_startoriginal_startmodified_endr'   r   )r   r3   r4   lines_mappings	new_linescurrent_mapping_indexr!   r"   start_mapping_indexend_mapping_indexstart_mappingend_mapping	new_startnew_end	new_ranges                  r#   adjusted_linesrG   M   s   J /PNI Um
7!

 6

 !4#n"559JcO
 :
 &;$7))%44I 444}7S7SS  ''!..G6669S9SSG(	y))Y'C $D r(   src_nodec                     [        5       nU H"  u  p4UR                  [        X4S-   5      5        M$     [        U5      n[	        UR                  U 5      5      n[        X5        g)a  Converts unchanged lines to STANDALONE_COMMENT.

The idea is similar to how `# fmt: on/off` is implemented. It also converts the
nodes between those markers as a single `STANDALONE_COMMENT` leaf node with
the unformatted code as its value. `STANDALONE_COMMENT` is a "fake" token
that will be formatted as-is with its prefix normalized.

Here we perform two passes:

1. Visit the top-level statements, and convert them to a single
   `STANDALONE_COMMENT` when unchanged. This speeds up formatting when some
   of the top-level statements aren't changed.
2. Convert unchanged "unwrapped lines" to `STANDALONE_COMMENT` nodes line by
   line. "unwrapped lines" are divided by the `NEWLINE` token. e.g. a
   multi-line statement is *one* "unwrapped line" that ends with `NEWLINE`,
   even though this statement itself can span multiple lines, and the
   tokenizer only sees the last '\n' as the `NEWLINE` token.

NOTE: During pass (2), comment prefixes and indentations are ALWAYS
normalized even when the lines aren't changed. This is fixable by moving
more formatting to pass (1). However, it's hard to get it correct when
incorrect indentations are used. So we defer this to future optimizations.
r   N)setupdaterange_TopLevelStatementsVisitorlistvisit_convert_unchanged_line_by_line)rH   r   	lines_setr!   r"   visitor_s          r#   convert_unchanged_linesrT      sS    0 %I
uAg./ (3GW]]8$%A#H8r(   nodec                     [        U [        5      (       a  U R                  [        :H  $ U R                   H  n[        U5      (       d  M    g   g)NTF)
isinstancer
   typer	   children_contains_standalone_comment)rU   childs     r#   rZ   rZ      s@    $yy...]]E+E22 # r(   c                   \    \ rS rSrSrS\\   4S jrS\S\	S   4S jr
S\S\	S   4S	 jrS
rg)rM      z
A node visitor that converts unchanged top-level statements to
STANDALONE_COMMENT.

This is used in addition to _convert_unchanged_line_by_line, to
speed up formatting when there are unchanged top-level
classes/functions/statements.
rQ   c                     Xl         g N
_lines_set)selfrQ   s     r#   __init__#_TopLevelStatementsVisitor.__init__   s    #r(   rU   r   Nc              #     #    /  S h  vN   [        U5      nU(       d  g UR                  [        :X  d   SUR                   35       e[        U5      n[	        U5      R                  U R                  5      (       d  [        U5        g g  N7f)NzUnexpectedly found leaf.type=)r   rX   r   r   _get_line_rangeintersectionra   #_convert_node_to_standalone_comment)rb   rU   newline_leafancestors       r#   visit_simple_stmt,_TopLevelStatementsVisitor.visit_simple_stmt   s       (	?*<+<+<*=>	?(
 4LAx(55dooFF/9 G 	s   BB	BBc              #   D  #    /  S h  vN   [        U5      (       a  g UR                  nUb7  UR                  b*  UR                  R                  [        :X  a  UR                  nUb6  [        U5      R                  U R                  5      (       d  [        U5        g g g  N7fr_   )	rZ   parentprev_siblingrX   r   rf   rg   ra   rh   )rb   rU   semantic_parents      r#   visit_suite&_TopLevelStatementsVisitor.visit_suite   s     
 (-- ++&,,8#0055>"1"8"8&0

,t
'0( 0@0(&# 	s   B BBB r`   )__name__
__module____qualname____firstlineno____doc__rJ   r   rc   r   r   rk   rq   __static_attributes__r&   r(   r#   rM   rM      sH    $#c( $:d :x~ :"A A$ Ar(   rM   rQ   c                 p   U R                  5        GH  nUR                  [        :w  a  M  UR                  (       a  UR                  R                  [        R
                  :X  ah  / nUR                  nU(       a'  UR                  SU5        UR                  nU(       a  M'  [        U5      R                  U5      (       d  [        X2S9  M  M  UR                  (       Ga9  UR                  R                  [        R                  :X  Ga  UR                  R                  n/ nU(       ac  UR                  [        R                  :w  aE  UR                  SU5        UR                  nU(       a   UR                  [        R                  :w  a  ME  UR                  R                  nUbG  UR                  b:  UR                  R                  [        :X  a  UR                  SUR                  5        [        U5      R                  U5      (       d  [        X2S9  GM  GM  [        U5      nUR                  [        R                  :X  aE  UR                  (       a4  UR                  R                  [        R                  :X  a  UR                  n[        U5      R                  U5      (       a  GM  [!        U5        GM     g)z6Converts unchanged to STANDALONE_COMMENT line by line.r   )newlineN)leavesrX   r   rn   r   
match_stmtro   insertrf   rg   $_convert_nodes_to_standalone_commentsuiter   r   	decorator
decoratorsrh   )rU   rQ   leafnodes_to_ignorero   parent_siblinggrandparentrj   s           r#   rP   rP      s   99 ;;4;;++t>
 )+O,,L&&q,7+88 , #?3@@KK4_S L[[[T[[--; "[[55N O ^%8%8DJJ%F&&q.9!/!<!< !^%8%8DJJ%F ++,,K',,8,,11U:&&q+*B*BC"?3@@KK4_S L 8=H /OOOO((DOO;#??"8,99)DD3H=c r(   c           
         U R                   nU(       d  g[        U 5      n[        U 5      nU(       a  U(       d  gX#L a  gUR                  nSUl        U R	                  5       nUb  U R
                  [        R                  :X  a7  [        U [        5      (       d   eU R                  S[        [        S5      5        [        U 5      SS nUR                  U[        [        UUUS95        gg)z@Convert node to STANDALONE_COMMENT by modifying the tree inline.N r   r+   prefixfmt_pass_converted_first_leaf)rn   r   r   r   removerX   r   	decoratedrW   r   insert_childr
   r   strr	   )rU   rn   firstlastr   indexvalues          r#   rh   rh   3  s    [[FtET?D} 	
 \\FELKKME 99& dD)))) agt!45 D	#2".3		
# r(   nodesrz   c          
         U (       d  gU S   R                   n[        U S   5      nU(       a  U(       d  gUR                  nSUl        SR                  S U  5       5      nUR                  (       a  XQR                  -  nSUl        U S   R	                  5       nU SS  H  nUR	                  5         M     Ub!  UR                  U[        [        UUUS95        gg)zAConvert nodes to STANDALONE_COMMENT by modifying the tree inline.Nr   r   c              3   8   #    U  H  n[        U5      v   M     g 7fr_   )r   ).0rU   s     r#   	<genexpr>7_convert_nodes_to_standalone_comment.<locals>.<genexpr>r  s     0%$CII%s   r   r   )rn   r   r   joinr   r   r
   r	   )r   rz   rn   r   r   r   r   rU   s           r#   r~   r~   h  s    1X__FuQx E\\FELGG0%00E~~!HOOEab	 ".3		
 r(   r   c                     U R                   [        :X  a  U R                  $ U R                  [        U 5      R	                  S5      -   $ )z5Returns the line number of the leaf node's last line.r+   )rX   r   linenor   r,   )r   s    r#   _leaf_line_endr     s6    yyG{{ {{SY__T222r(   node_or_nodesc                 L   [        U [        5      (       au  U nU(       d
  [        5       $ [        US   5      n[	        US   5      nU(       a5  U(       a.  UR
                  n[        U5      n[        [        XES-   5      5      $ [        5       $ U n[        U[        5      (       a+  [        [        UR
                  [        U5      S-   5      5      $ [        U5      n[	        U5      nU(       a2  U(       a+  [        [        UR
                  [        U5      S-   5      5      $ [        5       $ )z5Returns the line range of this node or list of nodes.r   r   r   )	rW   rN   rJ   r   r   r   r   rL   r
   )r   r   r   r   
line_startline_endrU   s          r#   rf   rf     s    -&&5L58$r#TJ%d+HuZA6775LdD!!uT[[.*>*BCDDt$ET?D5~d/Ca/GHIIur(   c                   L    \ rS rSr% Sr\\S'   \\S'   \\S'   \\S'   \\S'   Srg	)
_LinesMappingi  z1-based lines mapping from original source to modified source.

Lines [original_start, original_end] from original source
are mapped to [modified_start, modified_end].

The ranges are inclusive on both ends.
r;   original_endr:   r<   r9   r&   N)	rs   rt   ru   rv   rw   r   __annotations__boolrx   r&   r(   r#   r   r     s'     r(   r   c                 .   [         R                  " SU R                  SS9UR                  SS95      nUR                  5       n/ n[	        U5       GH@  u  pVUS:X  aQ  UR
                  S:w  d  UR                  S:w  a0  UR                  [        SUR
                  SUR                  SS95        OkX5S-
     nUR                  [        UR
                  UR                  -   S-   UR
                  UR                  UR                  -   S-   UR                  SS95        U[        U5      S-
  :  d  M  UR                  [        UR
                  S-   UR
                  UR                  -   UR                  S-   UR                  UR                  -   SS95        GMC     U$ )a{  Returns a sequence of _LinesMapping by diffing the sources.

For example, given the following diff:
    import re
  - def func(arg1,
  -   arg2, arg3):
  + def func(arg1, arg2, arg3):
      pass
It returns the following mappings:
  original -> modified
   (1, 1)  ->  (1, 1), is_changed_block=False (the "import re" line)
   (2, 3)  ->  (2, 2), is_changed_block=True (the diff)
   (4, 4)  ->  (3, 3), is_changed_block=False (the "pass" line)

You can think of this visually as if it brings up a side-by-side diff, and tries
to map the line ranges from the left side to the right side:

  (1, 1)->(1, 1)    1. import re          1. import re
  (2, 3)->(2, 2)    2. def func(arg1,     2. def func(arg1, arg2, arg3):
                    3.   arg2, arg3):
  (4, 4)->(3, 3)    4.   pass             3.   pass

Args:
  original_source: the original source.
  modified_source: the modified source.
NT)keependsr   r   F)r;   r   r:   r<   r9   )difflibSequenceMatcher
splitlinesget_matching_blocks	enumerateabr   r   sizer   )r3   r4   matchermatching_blocksr=   iblockprevious_blocks           r#   r6   r6     s~   < %%""D"1""D"1G
 113O*,N o.6ww!|uww!|%%!'(%*WW'(%*WW). -U3N!!#1#3#3n6I6I#IA#M!&#1#3#3n6I6I#IA#M!&%) s?#a''!!#(77Q;!&5::!5#(77Q;!&5::!5%*1 /B r(   original_liner=   start_indexc                     UnU[        U5      :  a?  X   nUR                  U s=::  a  UR                  ::  a   U$   US-  nU[        U5      :  a  M?  U$ )zGReturns the original index of the lines mappings for the original line.r   )r   r;   r   )r   r=   r   r   mappings        r#   r8   r8     sa     E
#n%
% '!!]Jg6J6JJL K
	 #n%
%
 Lr(   ),rw   r   collections.abcr   r   r   dataclassesr   typingr   black.nodesr   r	   r
   r   r   r   r   r   r   blib2to3.pgen2.tokenr   r   r   rN   tupler   r$   r   r'   r2   rG   rT   rZ   rM   rJ   rP   rh   r~   r   rf   r   r6   r8   r&   r(   r#   <module>r      s2   E  : : ! 
 
 
 08C= T%S/5J ,-uS#X -4 -
eCHo&69c3h 8MeCHo&MM M 
%S/	M`9d 9:eCHo3N 9SW 9@r d 3A 3Al3>$ 3>3s8 3> 3>l2
b 2
T 2
j
 
$ 
SW 
<3 3# 35T"X#6 3s8 6   "LLL mL^]+  		r(   