U
    .eD                     @  s   d Z ddlmZ ddlZddlmZmZ ddlmZ ddl	m
Z
mZmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ e
rddlmZ ddlmZ dddgZG dd dZ e dddZ!G dd dZ"G dd dZ#dS )a%  
An :class:`~.KeyProcessor` receives callbacks for the keystrokes parsed from
the input in the :class:`~prompt_toolkit.inputstream.InputStream` instance.

The `KeyProcessor` will according to the implemented keybindings call the
correct callbacks when new key presses are feed through `feed`.
    )annotationsN)Tasksleep)deque)TYPE_CHECKINGAnyDeque	Generator)get_app)EditingMode)vi_navigation_mode)Keys)Event   )BindingKeyBindingsBase)Application)BufferKeyProcessorKeyPressKeyPressEventc                   @  sB   e Zd ZdZdddddddZd	d
ddZdddddZdS )r   z
    :param key: A `Keys` instance or text (one character).
    :param data: The received string on stdin. (Often vt100 escape codes.)
    Nz
Keys | str
str | NoneNone)keydatareturnc                 C  sH   t |tst|dkst|d kr8t |tr4|j}n|}|| _|| _d S )Nr   )
isinstancer   lenAssertionErrorvaluer   r   )selfr   r    r!   L/tmp/pip-unpacked-wheel-_x9ru1vw/prompt_toolkit/key_binding/key_processor.py__init__)   s    
zKeyPress.__init__strr   c                 C  s   | j j d| jd| jdS )Nz(key=z, data=))	__class____name__r   r   r    r!   r!   r"   __repr__5   s    zKeyPress.__repr__objectbool)otherr   c                 C  s&   t |tsdS | j|jko$| j|jkS )NF)r   r   r   r   )r    r-   r!   r!   r"   __eq__8   s    
zKeyPress.__eq__)N)r(   
__module____qualname____doc__r#   r*   r.   r!   r!   r!   r"   r   #   s   ?_Flush)r   c                   @  s   e Zd ZdZdddddZdddd	Zd
ddddZd
ddddZddddZd0ddddddZ	d1d
dddddZ
ddddZd
ddd Zd!d
dd"d#d$Zd%dd&d'd(Zd%dd&d)d*Zddd+d,Zddd-d.Zd/S )2r   aP  
    Statemachine that receives :class:`KeyPress` instances and according to the
    key bindings in the given :class:`KeyBindings`, calls the matching handlers.

    ::

        p = KeyProcessor(key_bindings)

        # Send keys into the processor.
        p.feed(KeyPress(Keys.ControlX, ''))
        p.feed(KeyPress(Keys.ControlC, '')

        # Process all the keys in the queue.
        p.process_keys()

        # Now the ControlX-ControlC callback will be called if this sequence is
        # registered in the key bindings.

    :param key_bindings: `KeyBindingsBase` instance.
    r   r   )key_bindingsr   c                 C  s,   || _ t| | _t| | _d | _|   d S N)	_bindingsr   before_key_pressafter_key_press_flush_wait_taskreset)r    r4   r!   r!   r"   r#   [   s
    

zKeyProcessor.__init__r%   c                 C  s:   g | _ d | _t | _g | _d | _|  | _| jd  d S r5   )	_previous_key_sequence_previous_handlerr   input_queue
key_bufferarg_process_process_coroutinesendr)   r!   r!   r"   r:   e   s    
zKeyProcessor.resetlist[KeyPress]zlist[Binding])key_pressesr   c                 C  s(   t dd |D }dd | j|D S )zw
        For a list of :class:`KeyPress` instances. Give the matching handlers
        that would handle this.
        c                 s  s   | ]}|j V  qd S r5   r   .0kr!   r!   r"   	<genexpr>}   s     z,KeyProcessor._get_matches.<locals>.<genexpr>c                 S  s   g | ]}|  r|qS r!   filterrG   br!   r!   r"   
<listcomp>   s      z-KeyProcessor._get_matches.<locals>.<listcomp>)tupler6   Zget_bindings_for_keys)r    rD   keysr!   r!   r"   _get_matchesx   s    zKeyProcessor._get_matchesr,   c                 C  s:   t dd |D }dd | j|D }tdd |D S )z
        For a list of :class:`KeyPress` instances. Return True if there is any
        handler that is bound to a suffix of this keys.
        c                 s  s   | ]}|j V  qd S r5   rE   rF   r!   r!   r"   rI      s     z:KeyProcessor._is_prefix_of_longer_match.<locals>.<genexpr>c                 S  s   h | ]
}|j qS r!   rJ   rL   r!   r!   r"   	<setcomp>   s    z:KeyProcessor._is_prefix_of_longer_match.<locals>.<setcomp>c                 s  s   | ]}| V  qd S r5   r!   )rG   fr!   r!   r"   rI      s     )rO   r6   Zget_bindings_starting_with_keysany)r    rD   rP   filtersr!   r!   r"   _is_prefix_of_longer_match   s
    
z'KeyProcessor._is_prefix_of_longer_matchzGenerator[None, KeyPress, None]c           
      c  s  | j }d}d}|rd}ndV }|tkr,d}n
|| |r
| |}|rNd}n
| |}dd |D }|rr|}d}|s|r| j|d |dd d |dd= q
|s
|s
d}d}tt|ddD ]H}	| |d|	 }|r| j|d |d|	 d |d|	= d} q
q|s
|dd	= q
dS )
z
        Coroutine implementing the key match algorithm. Key strokes are sent
        into this generator, and it calls the appropriate handlers.
        FNTc                 S  s   g | ]}|  r|qS r!   )eager)rG   mr!   r!   r"   rN      s      z)KeyProcessor._process.<locals>.<listcomp>)key_sequencer   r   )r>   r3   appendrQ   rV   _call_handlerranger   )
r    bufferretryflushr   matchesZis_prefix_of_longer_matchZeager_matchesfoundir!   r!   r"   r@      sB    



zKeyProcessor._processFr   )	key_pressfirstr   c                 C  s"   |r| j | n| j | dS )z
        Add a new :class:`KeyPress` to the input queue.
        (Don't forget to call `process_keys` in order to process the queue.)

        :param first: If true, insert before everything else.
        N)r=   
appendleftr[   )r    rd   re   r!   r!   r"   feed   s    zKeyProcessor.feed)rD   re   r   c                 C  s&   |r| j t| n| j | dS )zG
        :param first: If true, insert before everything else.
        N)r=   
extendleftreversedextend)r    rD   re   r!   r!   r"   feed_multiple   s    zKeyProcessor.feed_multiplec                   s   t   dd fdd}dd fdd}d}| r| }|tk}|jtjk}|sd|sdj  zj| W n& t	k
r   
     Y nX |s2|s2j  q2|s  d	S )
a,  
        Process all the keys in the `input_queue`.
        (To be called after `feed`.)

        Note: because of the `feed`/`process_keys` separation, it is
              possible to call `feed` from inside a key binding.
              This function keeps looping until the queue is empty.
        r,   r%   c                     s(    j rtdd jD S tjS d S )Nc                 s  s   | ]}|j tjkr|V  qd S r5   r   r   CPRResponserF   r!   r!   r"   rI      s      z?KeyProcessor.process_keys.<locals>.not_empty.<locals>.<genexpr>)is_donerT   r=   r,   r!   appr    r!   r"   	not_empty   s    z,KeyProcessor.process_keys.<locals>.not_emptyr   c                    s8    j r*dd jD d } j|  | S j S d S )Nc                 S  s   g | ]}|j tjkr|qS r!   rl   rF   r!   r!   r"   rN      s      z?KeyProcessor.process_keys.<locals>.get_next.<locals>.<listcomp>r   )rn   r=   removepopleft)Zcprro   r!   r"   get_next   s
    z+KeyProcessor.process_keys.<locals>.get_nextFN)r
   r3   r   r   rm   r7   ZfirerA   rB   	Exceptionr:   empty_queuer8   _start_timeout)r    rq   rt   Zis_flushrd   Zis_cprr!   ro   r"   process_keys   s(    		
zKeyProcessor.process_keysc                 C  s&   t | j}| j  dd |D }|S )zF
        Empty the input queue. Return the unprocessed input.
        c                 S  s   g | ]}|j tjkr|qS r!   rl   rF   r!   r!   r"   rN   '  s      z,KeyProcessor.empty_queue.<locals>.<listcomp>)listr=   clear)r    rD   r!   r!   r"   rv     s    

zKeyProcessor.empty_queuer   )handlerrZ   r   c                 C  s$  t  }|jj}t|jj}|jj}| j}d | _tt	
| ||| j|| jkd}||rd|jj  ddlm}	 z|| | | W n |	k
r   |j  Y nX |r| | || _|| _| r |jjr|r|jj}
|
d k	r|
| |jjr |r |D ]}|j j|j7  _qd S )N)r?   rZ   previous_key_sequence	is_repeatr   )EditReadOnlyBuffer)r
   Zemacs_stateZis_recordingr,   vi_stateZrecording_registertemporary_navigation_moder?   r   weakrefrefr;   r<   Zsave_beforerp   current_bufferZsave_to_undo_stackprompt_toolkit.bufferr~   call_fix_vi_cursor_positionoutputZbell_leave_vi_temp_navigation_modeZrecord_in_macroZcurrent_recordingrj   r   )r    r{   rZ   rp   Zwas_recording_emacsZwas_recording_viZwas_temporary_navigation_moder?   eventr~   Z	recordingrH   r!   r!   r"   r\   *  sB    	




zKeyProcessor._call_handlerr   )r   r   c                 C  sH   |j }|j}|j}t rD|jjrDt|jjdkrD| jd8  _||_dS )z
        After every command, make sure that if we are in Vi navigation mode, we
        never put the cursor after the last character of a line. (Unless it's
        an empty line.)
        r   r   N)	rp   r   preferred_columnr   documentZis_cursor_at_the_end_of_liner   current_lineZcursor_position)r    r   rp   Zbuffr   r!   r!   r"   r   ]  s    z$KeyProcessor._fix_vi_cursor_positionc                 C  s4   |j }|jtjkr0|jjdkr0| jdkr0d|j_dS )z
        If we're in Vi temporary navigation (normal) mode, return to
        insert/replace mode after executing one action.
        NF)rp   Zediting_moder   ZVIr   Zoperator_funcr?   r   )r    r   rp   r!   r!   r"   r   r  s    z+KeyProcessor._leave_vi_temp_navigation_modec                   sb   t  }|jdkrdS dd fdd}ddfdd jrPj  || _dS )a%  
        Start auto flush timeout. Similar to Vim's `timeoutlen` option.

        Start a background coroutine with a timer. When this timeout expires
        and no key was pressed in the meantime, we flush all data in the queue
        and call the appropriate key binding handlers.
        Nr   r%   c                     s&   t I dH  tjdkr"   dS )zWait for timeout.Nr   )r   r   r>   r!   
flush_keysr    timeoutr!   r"   wait  s    z)KeyProcessor._start_timeout.<locals>.waitc                     s     t    dS )zFlush keys.N)rg   r3   rx   r!   r)   r!   r"   r     s    
z/KeyProcessor._start_timeout.<locals>.flush_keys)r
   Z
timeoutlenr9   cancelZcreate_background_task)r    rp   r   r!   r   r"   rw   ~  s    	
zKeyProcessor._start_timeoutc                 C  s"   | j ttjddd |   dS )zG
        Send SIGINT. Immediately call the SIGINT key handler.
        rE   T)re   N)rg   r   r   SIGINTrx   r)   r!   r!   r"   send_sigint  s    zKeyProcessor.send_sigintN)F)F)r(   r/   r0   r1   r#   r:   rQ   rV   r@   rg   rk   rx   rv   r\   r   r   rw   r   r!   r!   r!   r"   r   E   s   

;	;3!c                   @  s   e Zd ZdZddddddddd	Zd
dddZed
dddZeddddZeddddZ	eddddZ
eddddZeddddZd
dddd Zeddd!d"Zd#S )$r   at  
    Key press event, delivered to key bindings.

    :param key_processor_ref: Weak reference to the `KeyProcessor`.
    :param arg: Repetition argument.
    :param key_sequence: List of `KeyPress` instances.
    :param previouskey_sequence: Previous list of `KeyPress` instances.
    :param is_repeat: True when the previous event was delivered to the same handler.
    z#weakref.ReferenceType[KeyProcessor]r   rC   r,   r   )key_processor_refr?   rZ   r|   r}   r   c                 C  s*   || _ || _|| _|| _|| _t | _d S r5   )_key_processor_refrZ   r|   r}   _argr
   _app)r    r   r?   rZ   r|   r}   r!   r!   r"   r#     s    zKeyPressEvent.__init__r$   r%   c                 C  s   d | j| j| jS )Nz:KeyPressEvent(arg={!r}, key_sequence={!r}, is_repeat={!r}))formatr?   rZ   r}   r)   r!   r!   r"   r*     s
    zKeyPressEvent.__repr__c                 C  s   | j d jS )NrY   )rZ   r   r)   r!   r!   r"   r     s    zKeyPressEvent.datar   c                 C  s   |   }|d krtd|S )Nz.KeyProcessor was lost. This should not happen.)r   ru   )r    	processorr!   r!   r"   key_processor  s    zKeyPressEvent.key_processorzApplication[Any]c                 C  s   | j S )z3
        The current `Application` object.
        )r   r)   r!   r!   r"   rp     s    zKeyPressEvent.appr   c                 C  s   | j jS )z%
        The current buffer.
        )rp   r   r)   r!   r!   r"   r     s    zKeyPressEvent.current_bufferintc                 C  s0   | j dkrdS t| j pd}t|dkr,d}|S )z&
        Repetition argument.
        -rY   r   i@B )r   r   )r    resultr!   r!   r"   r?     s    
zKeyPressEvent.argc                 C  s
   | j dk	S )zF
        True if repetition argument was explicitly provided.
        N)r   r)   r!   r!   r"   arg_present  s    zKeyPressEvent.arg_present)r   r   c                 C  sZ   |dkst | j}|dkr4|dks.|dks.t |}n|dkrB|}n| | }|| j_dS )zb
        Add digit to the input argument.

        :param data: the typed digit as string
        z-0123456789r   N)r   r   r   r?   )r    r   currentr   r!   r!   r"   append_to_arg_count  s    z!KeyPressEvent.append_to_arg_countc                 C  s   | j S )zFor backward-compatibility.)rp   r)   r!   r!   r"   cli  s    zKeyPressEvent.cliN)r(   r/   r0   r1   r#   r*   propertyr   r   rp   r   r?   r   r   r   r!   r!   r!   r"   r     s$   
)$r1   
__future__r   r   Zasyncior   r   collectionsr   typingr   r   r   r	   Z"prompt_toolkit.application.currentr
   Zprompt_toolkit.enumsr   Zprompt_toolkit.filters.appr   Zprompt_toolkit.keysr   Zprompt_toolkit.utilsr   r4   r   r   Zprompt_toolkit.applicationr   r   r   __all__r   r3   r   r   r!   r!   r!   r"   <module>   s0     d