
    vJ                         S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKJr  SSK	r	Sr
 " S S	\	R                  " \R                  \5      5      r " S
 S\5      r " S S\5      r " S S\5      r " S S\5      rg)a  Multiline output for Cloud SDK.

This module contains a set of classes that are useful for managing console
output that can be updated that spans multiple lines.

Currently only SimpleSuffixConsoleOutput is offered which only supports
updating the last added message. SimpleSuffixConsoleOutput is basically a
collection of semantically distinct messages to be outputted to the console.
These messages all have a suffix, and SimpleSuffixConsoleOutput supports
updating the suffix of the last added message. Calling UpdateConsole on
a SimpleSuffixConsoleOutput will update these messages and any changes
to the console.

Example usage:
  # Example for a simple spinner
  spinner = ['|', '/', '-', '\\']
  num_spinner_marks = len(spinner)

  # Define a ConsoleOutput message
  output = SimpleSuffixConsoleOutput(sys.stderr)

  # Add the message you want to be displayed for the spinner and update the
  # console to show the message.
  message = sscm.AddMessage('Instance is being created...')
  output.UpdateConsole()

  > Instance is being created

  # Start the spinner by updating the message and then updating the console.
  for i in range(20):
    output.UpdateMessage(message, spinner[i % num_spinner_marks])
    output.UpdateConsole()
    time.sleep(0.1)

  > Instance is being created...|
  > Instance is being created.../
  > ...

  output.UpdateMessage(message, 'done\n')
  output.UpdateConsole()

  > Instance is being created...done
    )absolute_import)division)unicode_literalsN)console_attr   c                       \ rS rSrSrS rSrg)ConsoleOutputK   zManages the printing and formatting of multiline console output.

It is up to implementations of this metaclass to determine how different
messages will added to the output.
c                     g)AUpdates the console output to show any updated or added messages.N selfs    ,lib/googlecloudsdk/core/console/multiline.pyUpdateConsoleConsoleOutput.UpdateConsoleR   s        r   N)__name__
__module____qualname____firstlineno____doc__r   __static_attributes__r   r   r   r	   r	   K   s    	r   r	   c                   Z   ^  \ rS rSrSrU 4S jr  S
S jr  S
S jrS rS r	S r
S	rU =r$ )SimpleSuffixConsoleOutputW   a  A simple, suffix-only implementation of ConsoleOutput.

In this context, simple means that only updating the last line is supported.
This means that this is supported in all ASCII environments as it only relies
on carriage returns ('\r') for modifying output. Suffix-only means that only
modifying the ending of messages is supported, either via a
detail_message_callback or by modifying the suffix of a SuffixConsoleMessage.
c                    > Xl         / U l        SU l        [        R                  " 5       U l        [        [        U ]#  5         g)=Constructor.

Args:
  stream: The output stream to write to.
r   N)	_stream	_messages_last_print_index	threadingLock_locksuperr   __init__r   stream	__class__s     r   r&   "SimpleSuffixConsoleOutput.__init__a   s5     LDND!DJ	
#T35r   c                 r    U R                      U R                  UUUS9sSSS5        $ ! , (       d  f       g= f)a  Adds a SuffixConsoleMessage to the SimpleSuffixConsoleOutput object.

Args:
  message: str, The message that will be displayed.
  detail_message_callback: func() -> str, A no argument function that will
    be called and the result will be appended to the message on each call
    to UpdateConsole.
  indentation_level: int, The indentation level of the message. Each
    indentation is represented by two spaces.

Returns:
  SuffixConsoleMessage, a message object that can be used to dynamically
  change the printed message.
detail_message_callbackindentation_levelNr$   _AddMessage)r   messager-   r.   s       r   
AddMessage$SimpleSuffixConsoleOutput.AddMessagem   s1      

"9-  / 
s   (
6c                 h    [        UU R                  UUS9nU R                  R                  U5        U$ )Nr,   )SuffixConsoleMessager   r    append)r   r1   r-   r.   console_messages        r   r0   %SimpleSuffixConsoleOutput._AddMessage   s6    * 7+	-O
 	NN/*r   c                 &   U(       d  [        S5      eXR                  ;  a  [        S5      eU R                  (       a  XR                  S   :w  a  [        S5      eU R                     UR                  U5        SSS5        g! , (       d  f       g= f)z5Updates the suffix of the given SuffixConsoleMessage.A message must be passed.8The given message does not belong to this output object.z+Only the last added message can be updated.N)
ValueErrorr    r$   _UpdateSuffix)r   r1   
new_suffixs      r   UpdateMessage'SimpleSuffixConsoleOutput.UpdateMessage   sm    233nn$
DF F~~'^^B%77DEE	J' 
s   'B
Bc                 p    U R                      U R                  5         S S S 5        g ! , (       d  f       g = fNr$   _UpdateConsoler   s    r   r   'SimpleSuffixConsoleOutput.UpdateConsole       	
 
   '
5c                    U R                   (       a  U R                  [        U R                   5      S-
  :  ah  U R                   U R                  S  H.  nUR                  5         U R                  R                  S5        M0     [        U R                   5      S-
  U l        U R                   U R                     R                  5         gg)r      r<   
N)r    r!   lenPrintr   write)r   r1   s     r   rE   (SimpleSuffixConsoleOutput._UpdateConsole   s    ~~			3t~~#6#:	; ~~d&<&<R@G
--/
,,

T
" A "%T^^!4q!8
nnT++,224 r   )r!   r$   r    r   )Nr   )r   r   r   r   r   r&   r2   r0   r@   r   rE   r   __classcell__r)   s   @r   r   r   W   s;    
6 9=#$/, :>$%
(5 5r   r   c                   d    \ rS rSrSr  SS jrS rSS jrS r\	S 5       r
S	 rS
 rS rS rSrg)r5      z/A suffix-only implementation of ConsoleMessage.Nc                 D   X l         Xl        X0l        [        R                  " 5       R                  5       S   S-
  U l        U R                  S:  a  SU l        X@l        XPl        SU l	        U R                  [        U-  -
  S::  a  SU l	        SU l        / U l        SU l        g)a  Constructor.

Args:
  message: str, the message that this object represents.
  stream: The output stream to write to.
  suffix: str, The suffix that will be appended to the very end of the
    message.
  detail_message_callback: func() -> str, A no argument function that will
    be called and the result will be added after the message and before the
    suffix on every call to Print().
  indentation_level: int, The indentation level of the message. Each
    indentation is represented by two spaces.
r   rJ   FTN)r   _message_suffixr   ConsoleAttrGetTermSize_console_width_detail_message_callback_level
_no_outputINDENTATION_WIDTH
_num_lines_lines_has_printed)r   r1   r(   suffixr-   r.   s         r   r&   SuffixConsoleMessage.__init__   s     LML '224@@B1EIDQd$;!#K DO03DDE!K doDODKDr   c                 d    [        U[        R                  5      (       d  [        S5      eXl        g)z$Updates the suffix for this message.2expected a string or other character buffer objectN)
isinstancesixstring_types	TypeErrorrV   )r   ra   s     r   r>   "SuffixConsoleMessage._UpdateSuffix   s&    fc..//JKKLr   c                    U R                   S:X  d  U R                  (       a  gU R                  5       nU(       d  gU R                  (       a  U(       al  SU l        U R	                  5         U R                  U5      U l        [        U R                  5      U l        U R                   H  nU R                  U5        M     gU R                  U5      n[        U5      nXPR                  :  a6  U R                  R                  S5        U H  nU R                  U5        M     OU R                  U5      nU R                  U-
  S::  aB  XPR                  -
  S-   nU R	                  5         USU-  S  H  nU R                  U5        M     O5U R                  R                  S5        U H  nU R                  U5        M     X@l        XPl        g)a  Prints out the message to the console.

The implementation of this function assumes that when called, the
cursor position of the terminal is on the same line as the last line
that this function printed (and nothing more). The exception for this is if
this is the first time that print is being called on this message or if
print_all is True. The implementation should also return the cursor to
the last line of the printed message. The cursor position in this case
should be at the end of printed text to avoid text being overwritten.

Args:
  print_all: bool, if the entire message should be printed instead of just
    updating the message.
r   NTrK   rJ   r<   )rY   r\   
GetMessager`   
_ClearLine_SplitMessageIntoLinesr_   rL   r^   
_WriteLiner   rN   _GetNumMatchingLines)r   	print_allr1   line	new_linesnew_num_linesmatching_lineslines_to_prints           r   rM   SuffixConsoleMessage.Print   su    a4?? ooG 	d oo//8dkDKK(do++$ ++G4I	NM& ll$  00;n	>	)Q	. '81<b>123D
//$
 4 	4 D
//$
  K#Or   c                     U R                   (       a3  U R                  5       nU(       a  U R                  U-   U R                  -   $ U R                  U R                  -   $ rC   )rZ   rU   rV   )r   detail_messages     r   rk   SuffixConsoleMessage.GetMessage(  sG    $$446n	}}~-<<==4<<''r   c                 B    U R                   [        U R                  -  -
  $ z=The effective width when the indentation level is considered.rY   r]   r[   r   s    r   effective_width$SuffixConsoleMessage.effective_width/       "3dkk"ABBr   c                     Sn[        [        [        U5      U R                  5      5       H   nX   U R                  U   :w  a    U$ US-  nM"     U$ )Nr   rJ   )rangeminrL   r^   r_   )r   rr   rt   is       r   ro   )SuffixConsoleMessage._GetNumMatchingLines4  sT    N3s9~t78	Q	' n 9 r   c                     / nSnU[        U5      :  aZ  UR                  XX0R                  -    5        X0R                  -  nU[        U5      :  a  US==   S-  ss'   U[        U5      :  a  MZ  U$ )?Converts message into a list of strs, each representing a line.r   r<   rK   )rL   r6   r}   )r   r1   linesposs       r   rm   +SuffixConsoleMessage._SplitMessageIntoLines<  so    E
C
G
ll7s#7#7789	!!!c	s7|	b	T	 G
 Lr   c                 r    U R                   R                  SR                  SU R                  -  5      5        g Nz{} r   rN   formatrY   r   s    r   rl   SuffixConsoleMessage._ClearLineI  (    LLxsT-@-@'@ABr   c                     U R                   R                  U R                  [        -  S-  U-   5        U R                   R	                  5         g Nr   )r   rN   r[   r]   flushr   rq   s     r   rn   SuffixConsoleMessage._WriteLineL  s8    LLt{{%66<tCDLLr   )
rY   rZ   r`   r[   r_   rU   r\   r^   r   rV   ) Nr   )F)r   r   r   r   r   r&   r>   rM   rk   propertyr}   ro   rm   rl   rn   r   r   r   r   r5   r5      sM    7-/?@(TF$P( C CCr   r5   c                   X   ^  \ rS rSrSrU 4S jrSS jrSS jrS rS r	S r
S	 rS
rU =r$ )MultilineConsoleOutputiQ  a  An implementation of ConsoleOutput which supports multiline updates.

This means all messages can be updated and actually have their output
be updated on the terminal. The main difference between this class and
the simple suffix version is that updates here are updates to the entire
message as this provides more flexibility.

This class accepts messages containing ANSI escape codes. The width
calculations will be handled correctly currently only in this class.
c                    > Xl         / U l        SU l        [        R                  " 5       U l        SU l        SU l        [        [        U ]+  5         g)r   r   FN)r   r    r!   r"   r#   r$   _last_total_lines_may_have_updater%   r   r&   r'   s     r   r&   MultilineConsoleOutput.__init__]  sE     LDND!DJD!D	
 $02r   c                 p    U R                      U R                  UUS9sSSS5        $ ! , (       d  f       g= f)ag  Adds a MultilineConsoleMessage to the MultilineConsoleOutput object.

Args:
  message: str, The message that will be displayed.
  indentation_level: int, The indentation level of the message. Each
    indentation is represented by two spaces.

Returns:
  MultilineConsoleMessage, a message object that can be used to dynamically
  change the printed message.
r.   Nr/   )r   r1   r.   s      r   r2   !MultilineConsoleOutput.AddMessagek  s.     

-  / 
s   '
5c                 t    SU l         [        UU R                  US9nU R                  R	                  U5        U$ )NTr   )r   MultilineConsoleMessager   r    r6   )r   r1   r.   r7   s       r   r0   "MultilineConsoleOutput._AddMessage|  s;     D-+-O 	NN/*r   c                     U(       d  [        S5      eXR                  ;  a  [        S5      eU R                     UR                  U5        SU l        SSS5        g! , (       d  f       g= f)z9Updates the message of the given MultilineConsoleMessage.r:   r;   TN)r=   r    r$   _UpdateMessager   )r   r1   new_messages      r   r@   $MultilineConsoleOutput.UpdateMessage  sT    233nn$
DF F	[)"d 
s   A
A)c                 p    U R                      U R                  5         S S S 5        g ! , (       d  f       g = frC   rD   r   s    r   r   $MultilineConsoleOutput.UpdateConsole  rG   rH   c                 $    SR                  U5      $ )zEReturns an ANSI control sequences that moves the cursor up num_lines.z[{}A)r   )r   	num_liness     r   _GetAnsiCursorUpSequence/MultilineConsoleOutput._GetAnsiCursorUpSequence  s    Y''r   c                    U R                   (       d  gU R                  (       a4  U R                  R                  U R	                  U R                  5      5        SnSnU R
                   Hi  nUR                  nX-  nUR                  (       d  U(       a   X#R                  -  nUR                  5         MK  U R                  R                  SU-  5        Mk     Xl        SU l         g)r   Nr   FrK   )
r   r   r   rN   r   r    r   
has_updatenum_lines_changedrM   )r   total_linesforce_print_restr1   r   s        r   rE   %MultilineConsoleOutput._UpdateConsole  s      
 
ll66t7M7MNOK>>##ik			/555 	4)+, " )!Dr   )r!   r   r$   r   r    r   r   )r   r   r   r   r   r&   r2   r0   r@   r   r   rE   r   rP   rQ   s   @r   r   r   Q  s0    	3/"	#(" "r   r   c                       \ rS rSrSrSS jr\S 5       r\S 5       r\S 5       r	\S 5       r
S rS	 rS
 r\S 5       rS rS rSrg)r   i  z-A multiline implementation of ConsoleMessage.c                 r   X l         [        R                  " 5       U l        U R                  R	                  5       S   S-
  U l        U R
                  S:  a  SU l        X0l        SU l        U R
                  [        U-  -
  S::  a  SU l        SU l	        / U l
        SU l        SU l        U R                  U5        g)zConstructor.

Args:
  message: str, the message that this object represents.
  stream: The output stream to write to.
  indentation_level: int, The indentation level of the message. Each
    indentation is represented by two spaces.
r   rJ   FTN)r   r   GetConsoleAttr_console_attrrX   rY   r[   r\   r]   rU   r_   _has_update_num_lines_changedr   )r   r1   r(   r.   s       r   r&    MultilineConsoleMessage.__init__  s     L
 &446D,,88:1=ADQd#K DO03DDE!K doDMDKD#D r   c                     U R                   $ rC   )r_   r   s    r   r   MultilineConsoleMessage.lines  s    ;;r   c                 ,    [        U R                  5      $ rC   )rL   r_   r   s    r   r   !MultilineConsoleMessage.num_lines  s    t{{r   c                     U R                   $ rC   )r   r   s    r   r   "MultilineConsoleMessage.has_update  s    r   c                     U R                   $ rC   )r   r   s    r   r   )MultilineConsoleMessage.num_lines_changed  s    """r   c                 Z   [        U[        R                  5      (       d  [        S5      eXR                  :w  ar  Xl        U R
                  (       a  g[        U R                  5      nU R                  U R                  5      U l        SU l	        U[        U R                  5      :g  U l
        gg)z,Updates the message for this Message object.rd   NT)re   rf   rg   rh   rU   r\   rL   r_   rm   r   r   )r   r   num_old_liness      r   r   &MultilineConsoleMessage._UpdateMessage  s    k3#3#344JKKmm#!m	$++&m//>dkd -T[[1A Ad $r   c                     U R                   R                  XR                  5      n[        [	        U5      5       H  nX#==   S-  ss'   M     U$ )r   rK   )r   	SplitLiner}   r   rL   )r   r1   r   r   s       r   rm   .MultilineConsoleMessage._SplitMessageIntoLines  sB    ((2F2FGE3u:h$h Lr   c                     U R                   (       a  gU R                   H$  nU R                  5         U R                  U5        M&     SU l        g)zPrints out the message to the console.

The implementation of this function assumes that when called, the
cursor position of the terminal is where the message should start printing.
NF)r\   r_   rl   rn   r   r   s     r   rM   MultilineConsoleMessage.Print  s<     
oo
ood  Dr   c                 B    U R                   [        U R                  -  -
  $ r{   r|   r   s    r   r}   'MultilineConsoleMessage.effective_width	  r   r   c                 r    U R                   R                  SR                  SU R                  -  5      5        g r   r   r   s    r   rl   "MultilineConsoleMessage._ClearLine  r   r   c                 h    U R                   R                  U R                  [        -  S-  U-   5        g r   )r   rN   r[   r]   r   s     r   rn   "MultilineConsoleMessage._WriteLine  s(    LLt{{%66<tCDr   )	r   rY   r   r[   r_   rU   r\   r   r   Nr   )r   r   r   r   r   r&   r   r   r   r   r   r   rm   rM   r}   rl   rn   r   r   r   r   r   r     s    5 !D       # #B C CCEr   r   )r   
__future__r   r   r   abcr"   googlecloudsdk.core.consoler   rf   r]   with_metaclassABCMetaobjectr	   r   r5   r   r   r   r   r   <module>r      s    *X '  ' 
  4 
  		C&&s{{F; 		R5 R5la6 aH^"] ^"B`Ef `Er   