a
    V$c.                     @   s  d dl mZmZmZmZ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 d dlZd dlZd dlZi ae ZG dd deZdd Zdd	 Zd
d Zdd Zdd Zdd Z dd Z!dd Z"dd Z#dd Z$dd Z%dd Z&dd Z'd a(d!d" Z)d#d$ Z*dS )%    )divisionabsolute_importwith_statementprint_functionunicode_literals)PY2
basestringbchrbordchropenpystrrangeroundstrtobytesunicodeNc                   @   s    e Zd ZdZdd Zdd ZdS )Linez.
    Represents a logical line in a file.
    c                 C   s:   | dd}|| _|| _|| _|| _|| _d| _d| _d S )N\/ )replacefilenamenumberstartend	end_delimtext	full_text)selfr   r   r    r    renpy/scriptedit.py__init__/   s    zLine.__init__c                 C   s   d | j| j| jS )Nz<Line {}:{} {!r}>)formatr   r   r   )r   r    r    r!   __repr__I   s    zLine.__repr__N)__name__
__module____qualname____doc__r"   r$   r    r    r    r!   r   *   s   r   c                 C   sN   |  ds|  dsdS | tv r$dS t|  tj| }tjj|dd dS )z}
    Ensures that the given filename and linenumber are loaded. Doesn't do
    anything if the filename can't be loaded.
    z.rpyz.rpycNT)	add_lines)endswithfilesaddrenpyparserunelide_filenamelist_logical_lines)r   fnr    r    r!   ensure_loadedM   s    
r2   c                 C   s6   |  dd} t|  | |ftv r.t| |f jS dS dS )zq
    Gets the text of the line with `filename` and `linenumber`, or the None if
    the line does not exist.
    r   r   N)r   r2   linesr   r   
linenumberr    r    r!   get_line_text_   s
    r6   c           	      C   s   |  dd} t|  i }t D ]l\}}|\}}|| kr||kr||7 }| j|7  _| j|7  _| j|7  _| j|7  _||||f< q |adS )a8  
    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.
    r   r   N)r   r2   r3   itemsr   r   r   r   )	r   r5   char_offsetline_offset	new_lineskeyliner1   lnr    r    r!   adjust_line_locationso   s    r>   c              	   C   s  | dd}tjjrtdt| t||f }td|j	}|
d}| sPd}|j	dsh|j	dsnd}nd}||  }||  | } t|j|j|j}||_	| |_|jt| |_|jt|  |_t|jd	d
}	|	 }
W d   n1 s0    Y  |
d|j |  |
|jd  }
t||t| | d tjj^ t|jdd
}	|	|
 W d   n1 sp0    Y  tjj|jdd W d   n1 s0    Y  |t||f< dS )z
    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.
    r   r   <config.clear_lines must be False for script editing to work.z *r   r   z

rutf-8NwTforce)r   r-   configclear_lines	Exceptionr2   r3   rematchr   groupr*   r   r   r   r   r   lenr   r   codecsr   readr>   countloader	auto_lockwriteadd_auto)coder   r5   old_linemindentline_endingraw_codenew_linefdatar    r    r!   insert_line_before   s8    
& 
*2r]   c              	   C   s4  |  dd} tjjrtdt|  t| |f }t|j	dd}|
 }W d   n1 s^0    Y  ||j|j }|d|j ||jd  }t| |f= t| |t| |d  tjj\ t|j	dd}|| W d   n1 s0    Y  tjj|j	d	d
 W d   n1 s&0    Y  dS )zi
    Removes `linenumber` from `filename`. The line must exist and correspond
    to a logical line.
    r   r   r?   rA   rB   Nr@   rC   TrD   )r   r-   rF   rG   rH   r2   r3   rM   r   r   rN   r   r   r>   rL   rO   rP   rQ   rR   rS   )r   r5   r<   r[   r\   rT   r    r    r!   remove_line   s    &

(r^   c                 C   s2   |  dd} t|  | |ftvr$dS t| |f jS )z~
    Returns the full text of `linenumber` from `filename`, including
    any comment or delimiter characters that exist.
    r   r   N)r   r2   r3   r   r4   r    r    r!   get_full_text   s
    r_   c                 C   sH   t |  g }tjjjD ],}|j| kr|j|kr|jdkr|| q|S )zC
    Returns a list of nodes that are found on the given line.
    never)	r2   r-   gamescript	all_stmtsr   r5   rollbackappend)r   r5   rvir    r    r!   nodes_on_line   s    rh   c                    s8   t    fddtjjjD }|s*g S t t|S )zL
    Returns a list of nodes that are found at or after the given line.
    c                    s0   g | ](}|j  kr|jkr|jd kr|jqS )r`   )r   r5   rd   ).0rg   r4   r    r!   
<listcomp>  s
   


z-nodes_on_line_at_or_after.<locals>.<listcomp>)r2   r-   ra   rb   rc   rh   min)r   r5   r3   r    r4   r!   nodes_on_line_at_or_after
  s    rl   c                 C   s   g }g }| D ]H}| D ]}|j |u r q2q|| | D ]}|j |u r6 qq6|| qt|dkrjtdt|dkr~td|d |d fS )z
    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`.
       z%Could not find unique first AST node.z$Could not find unique last AST node.r   )nextre   rL   rH   )nodesfirstslastsrg   jr    r    r!   first_and_last_nodes  s     


rs   c                 C   s6   t jjjD ]&}|j| kr
|j|kr
| j|7  _q
dS )z
    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-   ra   rb   rc   r   r5   )r   r5   offsetrg   r    r    r!   adjust_ast_linenumbers>  s    ru   c           
      C   s   t ||}t|\}}t|j|d tjjj|j| |d\}}| }tjjj	
| |s^dS tjjj	D ]}	|	||d  qhtj|| tjjD ]}	|	||d  qtjj||d  dS )zr
    Adds `code`, which must be a textual line of Ren'Py code,
    before the given filename and line number.
    rm   )r5   Nr   )rl   rs   ru   r   r-   ra   rb   load_stringpoprc   removereplace_nextastchain_blockcontextsreplace_nodelog)
rT   r   r5   ro   old_block_initret_stmtrg   r    r    r!   add_to_ast_beforeQ  s    
r   c                 C   s2   zt | |}t| W dS  ty,   Y dS 0 dS )z
    Returns True if it's possible to add a line before the given filename
    and linenumber, and False if it's not possible.
    TFN)rh   rs   rH   )r   r5   ro   r    r    r!   can_add_beforep  s    
r   c           	      C   s   t | |}t|\}}g }tjjjD ]&}||v r2q$|||j || q$|tjj_tjjj	}t
|D ]}|| |v rh|j||< qht| |d dS )z
    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.
    N)rh   rs   r-   ra   rb   rc   ry   rn   re   namemaplistru   )	r   r5   ro   firstlast	new_stmtsrg   r   kr    r    r!   remove_from_ast  s    	


r   rm   c                  C   sX   dt  } t d7 a tjjtj j}|j}|j}t	| || t
| || tj  d S )Nz'Hello world %f'rm   )serialr-   ra   rb   lookupcontextcurrentr   r5   r   r]   exportsrestart_interaction)snoder   r5   r    r    r!   test_add  s    r   c                  C   sL   t jjt j j} | j}| j}t|| t	|| t j
jdddd d S )Nr   T)checkpointsrE   greedy)r-   ra   rb   r   r   r   r   r5   r   r^   r   rd   )r   r   r5   r    r    r!   test_remove  s    

r   )+
__future__r   r   r   r   r   renpy.compatr   r   r	   r
   r   r   r   r   r   r   r   r   r-   rI   rM   r3   setr+   objectr   r2   r6   r>   r]   r^   r_   rh   rl   rs   ru   r   r   r   r   r   r   r    r    r    r!   <module>   s.   8#&5 !%