ó
ÔŒ\c           @  sê   d  d l  m Z d  d l Z d  d l Z d  d l Z i  a e ƒ  Z d e f d „  ƒ  YZ	 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 a d „  Z d „  Z d S(   iÿÿÿÿ(   t   print_functionNt   Linec           B  s    e  Z d  Z d „  Z d „  Z RS(   s.   
    Represents a logical line in a file.
    c         C  sL   | j  d d ƒ } | |  _ | |  _ | |  _ | |  _ | |  _ d |  _ d  S(   Ns   \t   /t    (   t   replacet   filenamet   numbert   startt   endt	   end_delimt   text(   t   selfR   R   R   (    (    s   renpy/scriptedit.pyt   __init__-   s    					c         C  s   d j  |  j |  j |  j ƒ S(   Ns   <Line {}:{} {!r}>(   t   formatR   R   R
   (   R   (    (    s   renpy/scriptedit.pyt   __repr__C   s    (   t   __name__t
   __module__t   __doc__R   R   (    (    (    s   renpy/scriptedit.pyR   (   s   	c         C  sk   |  j  d ƒ p |  j  d ƒ s" d S|  t k r2 d St j |  ƒ t j j |  ƒ } t j j | d t ƒd S(   s}   
    Ensures that the given filename and linenumber are loaded. Doesn't do
    anything if the filename can't be loaded.
    s   .rpys   .rpycNt	   add_lines(   t   endswitht   filest   addt   renpyt   parsert   unelide_filenamet   list_logical_linest   True(   R   t   fn(    (    s   renpy/scriptedit.pyt   ensure_loadedG   s    c         C  sG   |  j  d d ƒ }  t |  ƒ |  | f t k r? t |  | f j Sd Sd S(   sq   
    Gets the text of the line with `filename` and `linenumber`, or the None if
    the line does not exist.
    s   \R   N(   R   R   t   linesR
   t   None(   R   t
   linenumber(    (    s   renpy/scriptedit.pyt   get_line_textY   s
    
c   	      C  sÆ   |  j  d d ƒ }  t |  ƒ i  } x— t j ƒ  D]‰ \ } } | \ } } | |  k r¨ | | k r¨ | | 7} | j | 7_ | j | 7_ | j | 7_ | j | 7_ n  | | | | f <q/ W| a d S(   s8  
    Adjusts the locations in the line data structure.

    `filename`, `linenumber`
        The filename and first line number to adjust.

    `char_offset`
        The number of characters in the file to offset the code by,.

    `line_offset`
        The number of line in the file to offset the code by.
    s   \R   N(   R   R   R   t	   iteritemsR   R   R   R	   (	   R   R   t   char_offsett   line_offsett	   new_linest   keyt   lineR   t   ln(    (    s   renpy/scriptedit.pyt   adjust_line_locationsi   s    

c         C  sø  | j  d d ƒ } t j j r- t d ƒ ‚ n  t | ƒ t | | f } t j d | j	 ƒ } | j
 d ƒ } |  sz d } n  | j	 j d ƒ sŸ | j	 j d ƒ r¨ d } n d } | |  } | |  | }  t | j | j | j ƒ } | | _	 |  | _ | j t | ƒ | _ | j t |  ƒ | _ t j | j d	 d
 ƒ  }	 |	 j ƒ  }
 Wd QX|
 | j  |  |
 | j }
 t | | t |  ƒ |  j d ƒ ƒ t j j L t j | j d d
 ƒ  }	 |	 j |
 ƒ Wd QXt j j | j d t ƒWd QX| t | | f <d S(   s¹   
    Adds `code` immediately before `filename` and `linenumber`. Those must
    correspond to an existing line, and the code is inserted with the same
    indentation as that line.
    s   \R   s<   config.clear_lines must be False for script editing to work.s    *i    R   s   
s   
t   rs   utf-8Nt   wt   force(   R   R   t   configt   clear_linest	   ExceptionR   R   t   ret   matchR
   t   groupR   R   R   R   R   t	   full_textt   lenR   R	   t   codecst   opent   readR(   t   countt   loadert	   auto_lockt   writet   add_autoR   (   t   codeR   R   t   old_linet   mt   indentt   line_endingt   raw_codet   new_linet   ft   data(    (    s   renpy/scriptedit.pyt   insert_line_before   s8    
	%	
		"c         C  s.  |  j  d d ƒ }  t j j r- t d ƒ ‚ n  t |  ƒ t |  | f } t j | j	 d d ƒ  } | j
 ƒ  } Wd QX| | j | j !} | | j  | | j } t |  | f =t |  | t | ƒ | j d ƒ ƒ t j j L t j | j	 d d ƒ  } | j | ƒ Wd QXt j j | j	 d	 t ƒWd QXd S(
   si   
    Removes `linenumber` from `filename`. The line must exist and correspond
    to a logical line.
    s   \R   s<   config.clear_lines must be False for script editing to work.R)   s   utf-8Ns   
R*   R+   (   R   R   R,   R-   R.   R   R   R4   R5   R   R6   R   R	   R(   R3   R7   R8   R9   R:   R;   R   (   R   R   R&   RC   RD   R<   (    (    s   renpy/scriptedit.pyt   remove_lineÄ   s    
$c         C  sC   |  j  d d ƒ }  t |  ƒ |  | f t k r2 d St |  | f j S(   s~   
    Returns the full text of `linenumber` from `filename`, including
    any comment or delimiter characters that exist.
    s   \R   N(   R   R   R   R   R2   (   R   R   (    (    s   renpy/scriptedit.pyt   get_full_textä   s
    
c         C  s\   t  |  ƒ g  } xE t j j j D]4 } | j |  k r  | j | k r  | j | ƒ q  q  W| S(   sC   
    Returns a list of nodes that are found on the given line.
    (   R   R   t   gamet   scriptt	   all_stmtsR   R   t   append(   R   R   t   rvt   i(    (    s   renpy/scriptedit.pyt   nodes_on_lineô   s    
c         C  sj   t  |  ƒ g  t j j j D]- } | j |  k r | j | k r | j ^ q } | sW g  St |  t | ƒ ƒ S(   sL   
    Returns a list of nodes that are found at or after the given line.
    (	   R   R   RH   RI   RJ   R   R   RN   t   min(   R   R   RM   R   (    (    s   renpy/scriptedit.pyt   nodes_on_line_at_or_after  s    
c         C  sÓ   g  } g  } xp |  D]h } x. |  D] } | j  | k r  Pq  q  W| j | ƒ x. |  D] } | j  | k rQ PqQ qQ W| j | ƒ q Wt | ƒ d k r  t d ƒ ‚ n  t | ƒ d k rÁ t d ƒ ‚ n  | d | d f S(   sÄ   
    Finds the first and last nodes in `nodes`, a list of nodes. This assumes
    that all the nodes are "simple", with no control flow, and that all of
    the relevant nodes are in `nodes`.
    i   s%   Could not find unique first AST node.s$   Could not find unique last AST node.i    (   t   nextRK   R3   R.   (   t   nodest   firstst   lastsRM   t   j(    (    s   renpy/scriptedit.pyt   first_and_last_nodes  s     c         C  sN   xG t  j j j D]6 } | j |  k r | j | k r | j | 7_ q q Wd S(   sí   
    This adjusts the line numbers in the the ast.

    `filename`
        The filename to adjust.

    `linenumber`
        The first line to adjust.

    `offset`
        The amount to adjust by. Positive numbers increase the line
    N(   R   RH   RI   RJ   R   R   (   R   R   t   offsetRM   (    (    s   renpy/scriptedit.pyt   adjust_ast_linenumbers7  s    c   
      C  s  t  | | ƒ } t | ƒ \ } } t | j | d ƒ t j j j | j |  d | ƒ\ } } | j ƒ  } t j j j	 j
 | ƒ | s‡ d Sx+ t j j j	 D] }	 |	 j | | d ƒ q— Wt j j | | ƒ x( t j j D] }	 |	 j | | d ƒ qÕ Wt j j j | | d ƒ d S(   sr   
    Adds `code`, which must be a textual line of Ren'Py code,
    before the given filename and line number.
    i   R   Ni    (   RP   RV   RX   R   R   RH   RI   t   load_stringt   popRJ   t   removet   replace_nextt   astt   chain_blockt   contextst   replace_nodet   log(
   R<   R   R   RR   t   oldt   _t   blockt   _initt   ret_stmtRM   (    (    s   renpy/scriptedit.pyt   add_to_ast_beforeJ  s    'c         C  s0   y! t  |  | ƒ } t | ƒ t SWn t SXd S(   sƒ   
    Returns True if it's possible to add a line before the given filename
    and linenumber, and False if it's not possible.
    N(   RN   RV   R   t   False(   R   R   RR   (    (    s   renpy/scriptedit.pyt   can_add_beforei  s    
c   	      C  sÜ   t  |  | ƒ } t | ƒ \ } } g  } xI t j j j D]8 } | | k rO q7 n  | j | | j ƒ | j | ƒ q7 W| t j j _ t j j j	 } x4 t
 | ƒ D]& } | | | k rž | j | | <qž qž Wt |  | d ƒ d S(   sû   
    Removes from the AST all statements that happen to be at `filename`
    and `linenumber`, then adjusts the line numbers appropriately.

    There's an assumption that the statement(s) on the line are "simple",
    not involving control flow.
    iÿÿÿÿN(   RN   RV   R   RH   RI   RJ   R\   RQ   RK   t   namemapt   listRX   (	   R   R   RR   t   firstt   lastt	   new_stmtsRM   Rj   t   k(    (    s   renpy/scriptedit.pyt   remove_from_astx  s    	i   c          C  sx   d t  }  t  d 7a  t j j j t j j ƒ  j ƒ } | j } | j } t	 |  | | ƒ t
 |  | | ƒ t j j ƒ  d  S(   Ns   'Hello world %f'i   (   t   serialR   RH   RI   t   lookupt   contextt   currentR   R   Rg   RE   t   exportst   restart_interaction(   t   st   nodeR   R   (    (    s   renpy/scriptedit.pyt   test_add   s    

!		c          C  sp   t  j j j t  j j ƒ  j ƒ }  |  j } |  j } t | | ƒ t	 | | ƒ t  j
 j d d d t d t ƒ d  S(   Nt   checkpointsi    R+   t   greedy(   R   RH   RI   Rr   Rs   Rt   R   R   Rp   RF   Ru   t   rollbackR   (   Rx   R   R   (    (    s   renpy/scriptedit.pyt   test_remove¯  s    !		(   t
   __future__R    R   R/   R4   R   t   setR   t   objectR   R   R    R(   RE   RF   RG   RN   RP   RV   RX   Rg   Ri   Rp   Rq   Ry   R}   (    (    (    s   renpy/scriptedit.pyt   <module>   s,   				&	5	 				!				%	