o
    NEg                    @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZ ddlmZ ddl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 ddlmZmZmZm Z  dd	l!m"Z"m#Z# dd
l$m%Z%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/m0Z0 ddl1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7 ddl8m9Z9m:Z: ddl;m<Z<m=Z=m>Z>m?Z?m@Z@ ddlAmBZBmCZCmDZDmEZEmFZFmGZGmHZH ddl mIZImJZJmKZK eFeBjLkre	jMNeOeG n6ddlAmPZPmQZQ eQR ZSeFeBjTkreQjUjVjWZXneFeBjYkrddlZZZddlAm[Z[ eZj\]e[dZ^eZ_e^eZj`jaZbdZczddldmeZe W n efy)   dZcY nw G dd dZgG dd dZhedg dZiG dd  d ejjZjdS )!av  Variant on standard library's cmd with extra features.

To use, simply import cmd2.Cmd instead of cmd.Cmd; use precisely as though you
were using the standard library's cmd, while enjoying the extra features.

Searchable command history (commands: "history")
Run commands from file, save to file, edit commands in file
Multi-line commands
Special-character shortcut commands (beyond cmd's "?" and "!")
Settable environment parameters
Parsing commands with `argparse` argument parsers (flags)
Redirection to file or paste buffer (clipboard) with > or >>
Easy transcript-based testing of applications (see examples/example.py)
Bash-style ``select`` available

Note that redirection with > and | will only work if `self.poutput()`
is used in place of `print`.

- Catherine Devlin, Jan 03 2008 - catherinedevlin.blogspot.com

Git repository on GitHub at https://github.com/python-cmd2/cmd2
    N)InteractiveConsole)
namedtuple)redirect_stdout)
AnyCallableDictIterableListMappingOptionalTupleTypeUnion   )ansi	constantspluginutils)DEFAULT_ARGUMENT_PARSERCompletionItem)can_clipget_paste_bufferwrite_to_paste_buffer)
CommandSet) CLASS_ATTR_DEFAULT_HELP_CATEGORYCOMMAND_FUNC_PREFIXCOMPLETER_FUNC_PREFIXHELP_FUNC_PREFIX)as_subcommand_towith_argparser)Cmd2ShlexErrorCommandSetRegistrationErrorEmbeddedConsoleExitEmptyStatementRedirectionErrorSkipPostcommandHooks)HistoryHistoryItem)MacroMacroArg	StatementStatementParsershlex_split)RlTyperl_get_pointrl_make_safe_promptrl_set_promptrl_type
rl_warningvt100_support)CompletionErrorSettableget_defining_class)rl_force_redisplayreadline)readline_librl_basic_quote_charactersT)embedFc                   @      e Zd ZdZdd ZdS )_SavedReadlineSettingszQreadline settings that are backed up when switching between readline environmentsc                 C   s   d | _ d| _d | _d S )N )	completerdelimsbasic_quotesself rD   c/var/www/eduai.edurigo.com/doc_train/edurigo_ai/Puru/venv/lib/python3.10/site-packages/cmd2/cmd2.py__init__   s   
z_SavedReadlineSettings.__init__N__name__
__module____qualname____doc__rF   rD   rD   rD   rE   r=          r=   c                   @   r<   )_SavedCmd2EnvzVcmd2 environment settings that are backed up when entering an interactive Python shellc                 C   s$   t  | _d | _g | _d | _d | _d S N)r=   readline_settingsreadline_modulehistory
sys_stdout	sys_stdinrB   rD   rD   rE   rF      s
   
z_SavedCmd2Env.__init__NrG   rD   rD   rD   rE   rM      rL   rM   DisabledCommandcommand_functionhelp_functioncompleter_functionc                        s  e Zd ZdZe ZdZejZ	ej
Zddddddddddddddd	d
edededededededeee  dedeee  deee  deeeef  deee  deddf fddZdddee dedee fddZd edee fd!d"Zdd#d$Zd%eddfd&d'Zd d(ed)efd*d+Zd,ed-efd.d/Zd,ed0efd1d2Zd%efd3d4Zd%efd5d6Zd%e ed f ddfd7d8Z!d%e ed f ddfd9d:Z"d;e#ddfd<d=Z$d>eddfd?d@Z%dAdB Z&e'defdCdDZ(e(j)dEeddfdFdDZ(defdGdHZ*e'defdIdJZ+d dKdLdMe,dNeddfdOdPZ-d dKddQdMe,dNedReddfdSdTZ.d dKddQdMe,dNedReddfdUdVZ/dKddQdMe,dNedReddfdWdXZ0dKdLdMe,dNeddfdYdZZ1dKdd[dMe,dNed\eddfd]d^Z2dd_d`Z3daedbedcede4ee ee f fdddeZ5dfedaedbedcedgedhedee fdidjZ6ddkdfedaedbedcedleee eef f dme deef dee fdndoZ7ddkdfedaedbedcedpe8ee eef f dme deef dee fdqdrZ9ddsdfedaedbedcedteeegef  dee fdudvZ:ddwdfedaedbedcedxedee fdydzZ;dfedaedbedced{edee fd|d}Z<e=d~ee de4ee ef fddZ>defddZ?dedee deddfddZ@dee ddfddZAdfedaedbedcededdfddZBdfededee fddZCdddfedaedbedcedeDjEdedee dee fddZFdefddZGdefddZHe'deeef fddZIdd ZJdee fddZKdee fddZLdeeM fddZNdeeM fddZOdeeM fddZPdee fddZQdee fddZRdeddfddZSdeTdeTfddZUdedeTdefddZVdd ZWdd ZXdaede4eeef fddZYdddddaededededef
ddZZdedeeT defddZ[dddÜdee e\ef  dededefddǄZ]daedeTfddɄZ^daedeTfdd˄Z_deTdee fdd̈́Z`deTdejafddτZbdeTdejaddfdd҄Zcd(edee fddԄZdd(edefddքZeddלde eTef dedefddلZfdeTdee fddۄZgddܜdededefddZhdedefddZidejfddZkdejfddZldddZmdZndZoepeneodZqeqjrdddZsdes_teueqdddeDjvddfddZwdZxdZyepexeydZzezj{ddddd ezj{d>dd ezj{d(deQd ezj{deDj|d e:d e}ddezex~ ddeDjvddfddZdZdZepedZej{d	d
ddd ej{deDjdeNdd e}ddeeddeDjvddfddZdZdZepedZej{ddddd ej{deDjdeNdd e}ddeeddeDjvddfddZdZdZepeedZejrdddZde_teuedddeDjvddfddZd Zd!Zd"ZepeedZej{dddd#d ej{d>d$d ej{d(d%eQd ej{deDj|d e:d e}d&deeddeDjvddfd'd(Zd)Zd*ZepedZej{d	d
dd+d ej{deDjd,eOdd e}d&deeddeDjvddfd-d.Zd/Zd0ZepedZej{dddd1d ej{deDjd2eOdd e}d&deeddeDjvddfd3d4Zdfedaedbedcedee f
d5d6Zdfedaedbedced7eeee f dee fd8d9Zepd:dZej{d;d<dd=d ej{d(eDjd>ed ej{d?eDj|d@ed eejdAddur6eejdA euedeDjvddf fdBdCZddDeddfdEdFZdGdH ZdIedee dDeddfdJdKZepdLdZeuedMeDjvddfdNdOZepdPedZeuedMeDjvdefdQdRZepdSdZeuedMeDjvdefdTdUZ	VddWe eee ee4e,ee f  f dedefdXdYZdfedaedbedced7eeee f dee fdZd[Zd\Zepedd]Zej{d;d<dd^d ej{d_eDjd`ePdad epegdbZej{dceDjddedde euedddeDjvddfdfdgZepdhdZej{d(die;dj ej{deDj|d e:d euedddeDjvddfdkdlZe=ddmdnZdoedefdpdqZdreddfdsdtZduZepedZej{d(eDjdvdw ej{dxeDj|dydw eueddddzdeDjvd{ee dee fd|d}Zepd~dZej{dde:dj ej{deDj|de:d euedeDjvdee fddZerepddZeuedMeDjvdee fddZdZepedZeàġ Zej{ddddd ej{ddddd ej{dddde:d ej{dddde:d ej{ddddd ejƐddZej{ddddd ej{ddddd ej{d;d<ddd ej{d	d
ddd dZej{deDjeȐdw eueÃdeDjvdee fddZdeDjvdee\ fddZʐdd Zːdd Z̐dee e\ef  deddfddZ͐dZepeΐdZej{deDjde:d eueσdeDjvddfddZАdee ddfddZe'dee fddZҐdZepeӐdZej{dddde:d ej{dde:dj eueԃdeDjvdee fddZeZe֐d7 Z֐dZepeedZej{ddd eue؃deDjvdee fddÄZِdee ddfdŐdƄZڐddedee ddfdɐdʄZېdeddfdːd̄ZܐdeddfdΐdτZd(eddfdАdфZސdeddfdӐdԄZd(ededdfd֐dׄZdededdfdؐdلZdeddfdڐdۄZddee defdݐdބZddߐdZedededdfddZededgdf ddfddZdedgdf ddfddZdedgdf ddfddZedeejgejf ddfddZdeejgejf ddfddZedededdfddZdeejgejf ddfddZdeejgejf ddfddZedeejgejf ddfddZdeejgejf ddfddZdede ed f defddZ  ZS (  CmduK  An easy but powerful framework for writing line-oriented command interpreters.

    Extends the Python Standard Library’s cmd package by adding a lot of useful features
    to the out of the box configuration.

    Line-oriented command interpreters are often useful for test harnesses, internal tools, and rapid prototypes.
    zcNotes:
  This command is for internal use and is not intended to be called from the
  command line.tabNr>   i  FT)persistent_history_filepersistent_history_lengthstartup_scriptsilent_startup_scriptuse_ipythonallow_cli_argstranscript_filesallow_redirectionmultiline_commandsterminators	shortcutscommand_setsauto_load_commandscompletekeyr[   r\   r]   r^   r_   r`   ra   rb   rc   rd   re   rf   rg   returnc                   s  |szd| _ W n	 ty   Y nw |   t j|||d d| _d| _|| _d| _d| _	d| _
tj| _d| _d| _d| _d| _t | _|   d| _d| _ddg| _|| _| | ddg| _t | _g | _d	| _t | _d| _t |||d
| _!d| _"g | _#t$% | _&d| _'d| _(d| _)d| _*d| _+d| _,d| _-d| _.g | _/|rt0j12t0j13|}t0j14|rd5t$6|}|r|d5t0j77 }| j/8| d| _9|	rt:; }|j<ddddd |= \}}|j>r|| _9n|r| j/?| n|
r|
| _9t@jABdrd | _C| _Dnd| _Cd| _DtE| _Fd| _GtHI | _Jt | _Kd| _LtjM| _Nd| _Od| _Pd| _Qd| _Rg | _Sg | _Td| _Ud| _Vg | _Wi | _X|rL|D ]}| Y| qC|rS| Z  | [ D ]}| j!\|\}}|slt]d5||qW| ^|  dS )a  An easy but powerful framework for writing line-oriented command
        interpreters. Extends Python's cmd package.

        :param completekey: readline name of a completion key, default to Tab
        :param stdin: alternate input file object, if not specified, sys.stdin is used
        :param stdout: alternate output file object, if not specified, sys.stdout is used
        :param persistent_history_file: file path to load a persistent cmd2 command history from
        :param persistent_history_length: max number of history items to write
                                          to the persistent history file
        :param startup_script: file path to a script to execute at startup
        :param silent_startup_script: if ``True``, then the startup script's output will be
                                      suppressed. Anything written to stderr will still display.
        :param use_ipython: should the "ipy" command be included for an embedded IPython shell
        :param allow_cli_args: if ``True``, then :meth:`cmd2.Cmd.__init__` will process command
                               line arguments as either commands to be run or, if ``-t`` or
                               ``--test`` are given, transcript files to run. This should be
                               set to ``False`` if your application parses its own command line
                               arguments.
        :param transcript_files: pass a list of transcript files to be run on initialization.
                                 This allows running transcript tests when ``allow_cli_args``
                                 is ``False``. If ``allow_cli_args`` is ``True`` this parameter
                                 is ignored.
        :param allow_redirection: If ``False``, prevent output redirection and piping to shell
                                  commands. This parameter prevents redirection and piping, but
                                  does not alter parsing behavior. A user can still type
                                  redirection and piping tokens, and they will be parsed as such
                                  but they won't do anything.
        :param multiline_commands: list of commands allowed to accept multi-line input
        :param terminators: list of characters that terminate a command. These are mainly
                            intended for terminating multiline commands, but will also
                            terminate single-line commands. If not supplied, the default
                            is a semicolon. If your app only contains single-line commands
                            and you want terminators to be treated as literals by the parser,
                            then set this to an empty list.
        :param shortcuts: dictionary containing shortcuts for commands. If not supplied,
                          then defaults to constants.DEFAULT_SHORTCUTS. If you do not want
                          any shortcuts, pass an empty dictionary.
        :param command_sets: Provide CommandSet instances to load during cmd2 initialization.
                             This allows CommandSets with custom constructor parameters to be
                             loaded.  This also allows the a set of CommandSets to be provided
                             when `auto_load_commands` is set to False
        :param auto_load_commands: If True, cmd2 will check for all subclasses of `CommandSet`
                                   that are currently loaded by Python and automatically
                                   instantiate and register all commands. If False, CommandSets
                                   must be manually installed with `register_command_set`.
        N)rh   stdinstdoutF2   z> eof_relative_run_scriptrQ   app)rd   rc   re   r>   zKDocumented commands (use 'help -v' for verbose/'help <topic>' for details):zNo help on {}z/{} is not a recognized command, alias, or macrozrun_script {}z> {}-tz--test
store_truez1Test against transcript(s) in FILE (wildcards OK)actionhelpwinmorez	less -RXFz
less -SRXFr   UncategorizedTInvalid command name {!r}: {})_do_ipyAttributeError_initialize_plugin_systemsuperrF   default_to_shellquit_on_sigintrb   always_show_hintdebugechorY   DEFAULT_EDITOReditorfeedback_to_outputquiettimingmax_completion_itemsdict	settablesbuild_settablescontinuation_prompt
self_in_pyhidden_commands_persistent_history_length_initialize_historyexclude_from_historymacros_py_historypy_bridge_name	py_locals_in_pyr+   statement_parserlast_result_script_dirr   ContextFlagsigint_protection_cur_pipe_proc_reader_redirecting_at_continuation_prompt_multiline_in_progress
doc_header
help_errordefault_errorbroken_pipe_warning_startup_commandsospathabspath
expanduserexistsformatquote_stringdevnullappend_transcript_filesargparseArgumentParseradd_argumentparse_known_argstestextendsysplatform
startswithpager
pager_chopr   	_can_clip	exit_code	threadingRLockterminal_lockdisabled_commandsdefault_categoryALPHABETICAL_SORT_KEYdefault_sort_keyallow_appended_spaceallow_closing_quotecompletion_hintcompletion_headercompletion_matchesdisplay_matchesmatches_delimitedmatches_sorted_installed_command_sets_cmd_to_command_setsregister_command_set_autoload_commandsget_all_commandsis_valid_command
ValueError_register_subcommands)rC   rh   rj   rk   r[   r\   r]   r^   r_   r`   ra   rb   rc   rd   re   rf   rg   
script_cmdparsercalloptscallargscommand_setcur_cmdvaliderrmsg	__class__rD   rE   rF      s   7






	zCmd.__init__)subclass_matchcommandset_typer   c                   s    fdd| j D S )a  
        Find all CommandSets that match the provided CommandSet type.
        By default, locates a CommandSet that is an exact type match but may optionally return all CommandSets that
        are sub-classes of the provided type
        :param commandset_type: CommandSet sub-class type to search for
        :param subclass_match: If True, return all sub-classes of provided type, otherwise only search for exact match
        :return: Matching CommandSets
        c                    s*   g | ]}t | ksrt| r|qS rD   )type
isinstance).0cmdsetr   r   rD   rE   
<listcomp>  s    z(Cmd.find_commandsets.<locals>.<listcomp>)r   )rC   r   r   rD   r   rE   find_commandsets  s   	zCmd.find_commandsetscommand_namec                 C   s   | j |S )z
        Finds the CommandSet that registered the command name
        :param command_name: command name to search
        :return: CommandSet that provided the command
        )r   get)rC   r   rD   rD   rE   find_commandset_for_command  s   zCmd.find_commandset_for_commandc                    sB   t  }dd jD  dtt ddf fdd| dS )z!Load modular command definitions.c                 S      g | ]}t |qS rD   r   r   r   rD   rD   rE   r         z*Cmd._autoload_commands.<locals>.<listcomp>commandset_typesri   Nc                    s`   | D ]+}|  }|r| qt|j}| v s-t|jdks-d|jvs-| }| qd S )Nr   rC   )__subclasses__inspect	signaturerF   len
parametersr   )r   cmdset_type
subclassesinit_sigr   existing_commandset_typesload_commandset_by_typerC   rD   rE   r     s   


z7Cmd._autoload_commands.<locals>.load_commandset_by_type)r   r   r   r	   r   )rC   all_commandset_defsrD   r   rE   r     s   zCmd._autoload_commandsr   c                    s  dd | j D }t |v rtdt j d  |  tj dd d}t td}g }zu|D ]`\}}|t	t
d }| ||t j || t| }	t |	d}
|
durf| ||
 ||	 t| }t |d}|dur| || ||  | j|< |rt|tjst|| q2| j   |      W dS  ty      |D ]}t| | q | j v r| j    | j v r؇ fd	d
| j D | _    w )z
        Installs a CommandSet, loading all commands defined in the CommandSet

        :param cmdset: CommandSet to load
        c                 S   r   rD   r   r   rD   rD   rE   r     r   z,Cmd.register_command_set.<locals>.<listcomp>zCommandSet z is already installedc                 S       t | tot| do| jtS NrH   r   r   hasattrrH   r   r   methrD   rD   rE   <lambda>%     
 z*Cmd.register_command_set.<locals>.<lambda>	predicateNc                    s   i | ]\}}| ur||qS rD   rD   )r   keyvalr   rD   rE   
<dictcomp>O      z,Cmd.register_command_set.<locals>.<dictcomp>) r   r   r!   rH   on_registerr   
getmembersgetattrr   r   r   _install_command_functionr   r   _install_completer_functionr   _install_help_functionr   r   r   CMD_ATTR_HELP_CATEGORYr   
categorizer   on_registered	Exceptionon_unregisterdelattrremovevaluesitemson_unregistered)rC   r   r   methodsr   installed_attributesmethod_namemethodcommandcompleter_func_namecmd_completerhelp_func_namecmd_helpattribrD   r  rE   r     sX   






zCmd.register_command_setr  command_wrapperc                 C   s   t | }t| |rtd||| j|\}}|s#td|||| jv r4| d| | j|= || jv rE| d| | j|= t	| || d S )Nz!Attribute already exists: {} ({})rx   zADeleting alias '{}' because it shares its name with a new commandzADeleting macro '{}' because it shares its name with a new command)
r   r   r!   r   r   r   aliasespwarningr   setattr)rC   r  r"  contextcmd_func_namer   r   rD   rD   rE   r  S  s   


zCmd._install_command_functioncmd_namer  c                 C   0   t | }t| |rtd|t| || d S NzAttribute already exists: {})r   r   r!   r   r%  )rC   r(  r  r  rD   rD   rE   r  k     
zCmd._install_completer_functionr   c                 C   r)  r*  )r   r   r!   r   r%  )rC   r(  r   r  rD   rD   rE   r  r  r+  zCmd._install_help_functionc                 C   s   || j v rm| | |  | | tj|dd d}|D ]B}|d ttd }|| jv r4| 	| || j
v r=| j
|= t| t|  t| t| rRt| t|  t| t| r`t| t|  q|  | j | dS dS )z|
        Uninstalls a CommandSet and unloads all associated commands
        :param cmdset: CommandSet to uninstall
        c                 S   r   r   r   r   rD   rD   rE   r     r   z,Cmd.unregister_command_set.<locals>.<lambda>r  r   N)r   _check_uninstallabler  _unregister_subcommandsr   r	  r   r   r   enable_commandr   r  r   r   r   r  r  )rC   r   r  r  r(  rD   rD   rE   unregister_command_sety  s.   





zCmd.unregister_command_setc                    s   t jdd d}|D ]3}|d ttd  }|| jv r#| j| j}n| |}t|tj	d } fdd |d ur> | qd S )Nc                 S   r   r   r   r   rD   rD   rE   r     r   z*Cmd._check_uninstallable.<locals>.<lambda>r  r   c                    s`   | j D ]*}t|tjr-|j D ]}t|tjd }|d ur%|ur%t	d | q d S qd S )NzACannot uninstall CommandSet when another CommandSet depends on it)
_actionsr   r   _SubParsersActionchoicesr  r
  r   PARSER_ATTR_COMMANDSETr!   )r   rs   	subparserattached_cmdsetcheck_parser_uninstallabler   rD   rE   r7    s   

z<Cmd._check_uninstallable.<locals>.check_parser_uninstallable)
r   r	  r   r   r   rV   cmd_funcr
  r   CMD_ATTR_ARGPARSER)rC   r   r  r  r   command_funccommand_parserrD   r6  rE   r,    s   


zCmd._check_uninstallablec                    s&  || u s|| j v stdtj|dd d}|D ]\}}t|tj}t|tjt|tj}| j	j
|dd\}}|sDtdt|| }	|	d }
|	d	d
 }|
| jv r^| j|
 j}n| |
}|d
u rqtd|
t|t|tjd
}|d
u rtd|
t|dtjdtt dtjf fdd  ||}|jD ]o}t|tjr|| t|tji }|g|d< |j|d< |j|d< |j|d< |j|d< |j|d< |j|d< |j|d< |j |d< |j!|d< |j"|d< d|d< |j#|fi |}tj$|i}|j%di | t&|tj'|  nqqd
S ) z
        Register subcommands with their base command

        :param cmdset: CommandSet or cmd2.Cmd subclass containing subcommands
        z;Cannot register subcommands with an unregistered CommandSetc                 S   .   t | tot| tjot| tjot| tjS rN   r   r   r   r   SUBCMD_ATTR_NAMESUBCMD_ATTR_COMMANDr9  r   rD   rD   rE   r        
 

z+Cmd._register_subcommands.<locals>.<lambda>r  T)is_subcommandzSubcommand {} is not valid: {}r   r   N4Could not find command "{}" needed by subcommand: {}BCould not find argparser for command "{}" needed by subcommand: {}rs   subcmd_namesri   c                    sj   |s| S | d}| jD ]!}t|tjr-|j D ]\}}||kr* ||    S q nqtd)Nr   zCould not find sub-command "{}")	popr0  r   r   r1  r2  r  r!   r   )rs   rD  
cur_subcmd
sub_actionchoice_namechoicefind_subcommandfull_command_namerD   rE   rK    s   

z2Cmd._register_subcommands.<locals>.find_subcommandparentsprogusagedescriptionepilogformatter_classprefix_charsfromfile_prefix_charsargument_defaultconflict_handlerallow_abbrevFadd_helprD   )(r   r!   r   r	  r
  r   r>  r?  r9  r   r   r   strsplitr   rV   r8  r   r   r	   r0  r   r1  remove_parserSUBCMD_ATTR_ADD_PARSER_KWARGSrN  rO  rP  rQ  rR  rS  rT  rU  rV  rW  
add_parserNS_ATTR_SUBCMD_HANDLERset_defaultsr%  r3  )rC   r   r  r  r  subcommand_namesubcmd_parsersubcommand_validr   command_tokensr   subcommand_namesr:  r;  target_parserrs   add_parser_kwargsattached_parserdefaultsrD   rJ  rE   r     sl   	

$














zCmd._register_subcommandsc           
      C   s   || u s|| j v stdtj|dd d}|D ]W\}}t|tj}t|tj}|| jv r4| j| j	}n| 
|}|du rGtd|t|t|tjd}|du r\td|t||jD ]}	t|	tjrn|	|  nq_qdS )zz
        Unregister subcommands from their base command

        :param cmdset: CommandSet containing subcommands
        z=Cannot unregister subcommands with an unregistered CommandSetc                 S   r<  rN   r=  r   rD   rD   rE   r   .  r@  z-Cmd._unregister_subcommands.<locals>.<lambda>r  NrB  rC  )r   r!   r   r	  r
  r   r>  r?  r   rV   r8  r   rY  r9  r0  r   r   r1  r[  )
rC   r   r  r  r  r`  r   r:  r;  rs   rD   rD   rE   r-  "  s8   	



zCmd._unregister_subcommandssettablec                 C   s   || j |j< dS )z
        Convenience method to add a settable parameter to ``self.settables``

        :param settable: Settable object being added
        N)r   name)rC   ri  rD   rD   rE   add_settableP  s   zCmd.add_settablerj  c                 C   s*   z| j |= W dS  ty   t|d w )z
        Convenience method for removing a settable parameter from ``self.settables``

        :param name: name of the settable being removed
        :raises: KeyError if the Settable matches this name
         is not a settable parameterN)r   KeyError)rC   rj  rD   rD   rE   remove_settableX  s
   zCmd.remove_settablec              
   C   s   |  tdtdtjtjtjtjtjtjgd |  tdtd |  tdtd |  tdtd	 |  td
td |  tdtd |  tdt	d |  tdtd |  tdtd dS )z1Create the dictionary of user-settable parametersallow_stylezDAllow ANSI text style sequences in output (valid values: {}, {}, {}))r2  r   zBDisplay tab completion hint even when completion suggestions printr   z Show full traceback on exceptionr   zEcho command issued into outputr   zProgram used by 'edit'r   z)Include nonessentials in '|', '>' resultsr   zBMaximum number of CompletionItems to display during tab completionr   z!Don't print nonessential feedbackr   zReport execution timesN)
rk  r5   rY  r   r   STYLE_TERMINALSTYLE_ALWAYSSTYLE_NEVERboolintrB   rD   rD   rE   r   d  s(   


zCmd.build_settablesc                 C   s   t jS )zERead-only property needed to support do_set when it reads allow_style)r   ro  rB   rD   rD   rE   ro  z  s   zCmd.allow_stylenew_valc                 C   s>   |  }|tjtjtjfv r|t_dS tdtjtjtj)zDSetter property needed to support do_set when it updates allow_stylez(must be {}, {}, or {} (case-insensitive)N)
capitalizer   rp  rq  rr  ro  r   r   )rC   ru  rD   rD   rE   ro    s   
c                 C   s   | j o
| jo
ttjkS )z*Return whether tab completion is supported)use_rawinputrh   r1   r-   NONErB   rD   rD   rE   _completion_supported     zCmd._completion_supportedc                 C   s   t | jS )a8  Read-only property to get the visible prompt with any ANSI style escape codes stripped.

        Used by transcript testing to make it easier and more reliable when users are doing things like coloring the
        prompt using ANSI color codes.

        :return: prompt stripped of any ANSI escape codes
        )r   strip_stylepromptrB   rD   rD   rE   visible_prompt  s   	zCmd.visible_prompt
endmsgr  c                C   sL   zt | jd|| W dS  ty%   | jr"tj| j Y dS Y dS w )a  Print message to self.stdout and appends a newline by default

        Also handles BrokenPipeError exceptions for when a command's output has
        been piped to another process and that process terminates before the
        cmd2 command is finished executing.

        :param msg: message to print (anything convertible to a str with '{}'.format() is OK)
        :param end: string appended after the end of the message, default a newline
        {}{}N)	r   style_aware_writerk   r   BrokenPipeErrorr   r   stderrwriterC   r  r  rD   rD   rE   poutput  s   
zCmd.poutputr  apply_styler  c                C   s0   |rt |}nd|}t tj||  dS )a  Print message to sys.stderr

        :param msg: message to print (anything convertible to a str with '{}'.format() is OK)
        :param end: string appended after the end of the message, default a newline
        :param apply_style: If True, then ansi.style_error will be applied to the message text. Set to False in cases
                            where the message text already has the desired style. Defaults to True.
        {}N)r   style_errorr   r  r   r  )rC   r  r  r  	final_msgrD   rD   rE   perror  s   
z
Cmd.perrorc                C   s"   |rt |}| j||dd dS )a  Wraps perror, but applies ansi.style_warning by default

        :param msg: message to print (anything convertible to a str with '{}'.format() is OK)
        :param end: string appended after the end of the message, default a newline
        :param apply_style: If True, then ansi.style_warning will be applied to the message text. Set to False in cases
                            where the message text already has the desired style. Defaults to True.
        Fr  N)r   style_warningr  )rC   r  r  r  rD   rD   rE   r$    s   
zCmd.pwarningc                C   s   | j rt dkrddl}|  t|tr dt|j	|}nd|}|r,t
|}| j s=d| jv r=d}|t
|7 }| j||dd	 dS )
a  Print Exception message to sys.stderr. If debug is true, print exception traceback if one exists.

        :param msg: message or Exception to print
        :param end: string appended after the end of the message, default a newline
        :param apply_style: If True, then ansi.style_error will be applied to the message text. Set to False in cases
                            where the message text already has the desired style. Defaults to True.
        )NNNr   Nz2EXCEPTION of type '{}' occurred with message: '{}'r  r   zF
To enable full traceback, run the following command: 'set debug true'Fr  )r   r   exc_info	traceback	print_excr   r  r   r   rH   r   r  r   r  r  )rC   r  r  r  r  r  warningrD   rD   rE   pexcept  s   


zCmd.pexceptc                C   s6   | j s| jr| j||d dS | j||dd dS dS )aL  For printing nonessential feedback.  Can be silenced with `quiet`.
        Inclusion in redirected output is controlled by `feedback_to_output`.

        :param msg: message to print (anything convertible to a str with '{}'.format() is OK)
        :param end: string appended after the end of the message, default a newline
        r  Fr  N)r   r   r  r  r  rD   rD   rE   	pfeedback  s
   zCmd.pfeedback)r  chopr  c          	      C   sD  t |}|du s|dkrdS z|ddl}d}| j r/| j r/tjds-tj	
ddur/d}|r| js|  s|  stj tj krKt|}||7 }| j}|rW| j}| j |j|d|jd}||d	d
 W d   W dS 1 syw   Y  W dS | j||d W dS  ty   | jrtj| j Y dS Y dS w )av  Print output using a pager if it would go off screen and stdout isn't currently being redirected.

        Never uses a pager inside of a script (Python or text) or when output is being redirected or piped or when
        stdout or stdin are not a fully functional terminal.

        :param msg: message to print to current stdout (anything convertible to a str with '{}'.format() is OK)
        :param end: string appended after the end of the message, default a newline
        :param chop: True -> causes lines longer than the screen width to be chopped (truncated) rather than wrapped
                              - truncated text is still accessible by scrolling with the right & left arrow keys
                              - chopping is ideal for displaying wide tabular data as is done in utilities like pgcli
                     False -> causes lines longer than the screen width to wrap to the next line
                              - wrapping is ideal when you want to keep users from having to use horizontal scrolling

        WARNING: On Windows, the text always wraps regardless of what the chop argument is set to
        Nr>   r   Fru   TERMT)shellrj   utf-8replacer  )rY  
subprocessrj   isattyrk   r   r   r   r   environr   r   in_pyscript	in_scriptr   ro  lowerrr  r{  r   r   r   PopenPIPEcommunicateencoder  r  r   r  r  )	rC   r  r  r  msg_strr  functional_terminalr   	pipe_procrD   rD   rE   ppaged  s4   
&z
Cmd.ppagedc                 C   sh   d| _ d| _d| _d| _g | _g | _d| _d| _tt	j
kr%t| j dS tt	jkr2| jtjj_dS dS )zr
        Resets tab completion settings
        Needs to be called each time readline runs tab completion
        Tr>   FN)r   r   r   r   r   r   r   r   r1   r-   GNUr8   #set_completion_display_matches_hook_display_matches_gnu_readline
PYREADLINE_display_matches_pyreadlinerlmode_display_completionsrB   rD   rD   rE   _reset_completion_defaults,  s   

zCmd._reset_completion_defaultslinebegidxendidxc              
   C   s  ddl }d}| tj}|d| }|}	 zt|d| }	|s)||kr)|	d W n> tyg }
 z1t|
dkrS|rS|d }|dd }|d| }||7 }|d }n
g g fW  Y d}
~
S W Y d}
~
nd}
~
ww q| j|	}dd |D }|r|d	 dd	 |d	< ||fS )
ag  Used by tab completion functions to get all tokens through the one being completed.

        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :return: A 2 item tuple where the items are
                 **On Success**
                 - tokens: list of unquoted tokens - this is generally the list needed for tab completion functions
                 - raw_tokens: list of tokens with any quotes preserved = this can be used to know if a token was quoted
                 or is missing a closing quote
                 Both lists are guaranteed to have at least 1 item. The last item in both lists is the token being tab
                 completed
                 **On Failure**
                 - Two empty lists
        r   Nr>   TzNo closing quotationr   c                 S   s   g | ]}t |qS rD   )r   strip_quotes)r   	cur_tokenrD   rD   rE   r   u  s    z-Cmd.tokens_for_completion.<locals>.<listcomp>)	copyr   QUOTESr,   r   r   rY  r   split_on_punctuation)rC   r  r  r  r  unclosed_quotequotes_to_trytmp_line
tmp_endidxinitial_tokensex
raw_tokenstokensrD   rD   rE   tokens_for_completion@  s8   

zCmd.tokens_for_completiontextmatch_against	delimiterc                 C   sz   t |||||}|r;d| _tj|}||}	d}
|	r#t|	d }
|D ]}||}||
 }|s4|}| j	| q%|S )a  
        Performs tab completion against a list but each match is split on a delimiter and only
        the portion of the match being tab completed is shown as the completion suggestions.
        This is useful if you match against strings that are hierarchical in nature and have a
        common delimiter.

        An easy way to illustrate this concept is path completion since paths are just directories/files
        delimited by a slash. If you are tab completing items in /home/user you don't get the following
        as suggestions:

        /home/user/file.txt     /home/user/program.c
        /home/user/maps/        /home/user/cmd2.py

        Instead you are shown:

        file.txt                program.c
        maps/                   cmd2.py

        For a large set of data, this can be visually more pleasing and easier to search.

        Another example would be strings formatted with the following syntax: company::department::name
        In this case the delimiter would be :: and the user could easily narrow down what they are looking
        for if they were only shown suggestions in the category they are at in the string.

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param match_against: the list being matched against
        :param delimiter: what delimits each portion of the matches (ex: paths are delimited by a slash)
        :return: a list of possible tab completions
        Tr   r   )
r   basic_completer   r   r   commonprefixrZ  r   r   r   )rC   r  r  r  r  r  r  matchescommon_prefixprefix_tokensdisplay_token_index	cur_matchmatch_tokensdisplay_tokenrD   rD   rE   delimiter_complete  s   "

zCmd.delimiter_complete)all_else	flag_dictr  c                C   s   |  |||\}}|sg S g }	|}
t|dkr#|d }||v r#|| }
t|
tr3t|||||
}	|	S t|
r>|
||||}	|	S )a  Tab completes based on a particular flag preceding the token being completed.

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param flag_dict: dictionary whose structure is the following:
                          `keys` - flags (ex: -c, --create) that result in tab completion for the next argument in the
                          command line
                          `values` - there are two types of values:
                          1. iterable list of strings to match against (dictionaries, lists, etc.)
                          2. function that performs tab completion (ex: path_complete)
        :param all_else: an optional parameter for tab completing any token that isn't preceded by a flag in flag_dict
        :return: a list of possible tab completions
        r   r  r   r   r   r   r  callable)rC   r  r  r  r  r  r  r  _completions_matchesr  flagrD   rD   rE   flag_based_complete  s   
zCmd.flag_based_complete
index_dictc                C   sz   |  |||\}}|sg S g }	t|d }
|
|v r||
 }n|}t|tr0t|||||}	|	S t|r;|||||}	|	S )a  Tab completes based on a fixed position in the input string.

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param index_dict: dictionary whose structure is the following:
                           `keys` - 0-based token indexes into command line that determine which tokens perform tab
                           completion
                           `values` - there are two types of values:
                           1. iterable list of strings to match against (dictionaries, lists, etc.)
                           2. function that performs tab completion (ex: path_complete)
        :param all_else: an optional parameter for tab completing any token that isn't at an index in index_dict
        :return: a list of possible tab completions
        r   r  )rC   r  r  r  r  r  r  r  r  r  indexr  rD   rD   rE   index_based_complete  s   

zCmd.index_based_completepath_filterr  c                   s.  dt t f fdd}d |t|ks#|t|k r%|| tjjkr%d t }d}dds=tjt d}	d}nMddg}
|
D ]
}|v rMg   S qCd }	d	ry	tjjd
}|dkrf| S tj
|	}	d| tj
ntjstjt |	}	d}d_t|	}durfdd|D }t|d
krtj|d rd_d_|jjd d_t|D ]+\}}jtj| tj|r r||  tjj7  < j|  tjj7  < q|r|tjjkr|n|tjj fdd|D }rfdd|D }|S )a  Performs completion of local file system paths

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param path_filter: optional filter function that determines if a path belongs in the results
                            this function takes a path as its argument and returns True if the path should
                            be kept in the results
        :return: a list of possible tab completions
        ri   c                     s   d_ d_g } tjdr+tj}tj|r)} r$|tjj	7 }| 
| | S dd l}| D ] }tj|jrSd|j }|rS rN|tjj	7 }| 
| q3| S )NFru   r   ~)r   r   r   r   r   r   r   r   isdirsepr   pwdgetpwallpw_dirpw_name)usersexpanded_pathuserr  cur_pwcur_user)add_trailing_sep_if_dirrC   r  rD   rE   complete_users"  s*   



z)Cmd.path_complete.<locals>.complete_usersFTr>   *?r  r   r  Nc                    s   g | ]} |r|qS rD   rD   )r   cr  rD   rE   r         z%Cmd.path_complete.<locals>.<listcomp>r   r  c                       g | ]	}|  d dqS r>   r   r  r   cur_path)
to_replacerD   rE   r         c                    s   g | ]	}|  d qS )r   r  r  )expanded_tilde_pathorig_tilde_pathrD   rE   r     r  )r	   rY  r   r   r   r  getcwdjoinr   findr   dirnamer   globr  r   r   sortr   r   	enumerater   r   basename)rC   r  r  r  r  r  r  cwd	cwd_added
search_str	wildcardswildcard	sep_indexr  r  r  rD   )r  r  r  r  rC   r  r  rE   path_complete  sd   &(

zCmd.path_complete)complete_blankr
  c                C   sD   |s|sg S | dstjj|vrt|S | j||||dd dS )a  Performs completion of executables either in a user's path or a given path

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param complete_blank: If True, then a blank will complete all shell commands in a user's path. If False, then
                               no completion is performed. Defaults to False to match Bash shell behavior.
        :return: a list of possible tab completions
        r  c                 S   s   t j| pt | t jS rN   )r   r   r  accessX_OK)r   rD   rD   rE   r     r  z(Cmd.shell_cmd_complete.<locals>.<lambda>r  )r   r   r   r  r   get_exes_in_pathr	  )rC   r  r  r  r  r
  rD   rD   rE   shell_cmd_complete  s   
zCmd.shell_cmd_completecompfuncc                 C   s  |  |||\}}|sg S t|dkrd}d}	d}
d}d}d}|D ]I}|tjv rMd}|tjkr=|tjkr8g   S d}	d}
n+|tjv sD|
rHg   S d}	d}
n| jrhd}d}|tjkr\d}n|	sf|tjtjfv rhd}|}q!|ru| ||||S |r| 	||||S |rg S |||||S )a  Called by complete() as the first tab completion function for all commands
        It determines if it should tab complete for redirection (|, >, >>) or use the
        completer function for the current command

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param compfunc: the completer function for the current command
                         this will be called if we aren't completing for redirection
        :return: a list of possible tab completions
        r   FNT)
r  r   r   REDIRECTION_TOKENSREDIRECTION_PIPErb   REDIRECTION_OUTPUTREDIRECTION_APPENDr  r	  )rC   r  r  r  r  r  r  r  has_redirectionin_pipein_file_redirdo_shell_completiondo_path_completionprior_tokenr  rD   rD   rE   _redirect_complete  sJ   



zCmd._redirect_completematches_to_displayc                    sB   t tjkrd nt tjkrd n| dfS  fdd| D t fS )a}  Adds padding to the matches being displayed as tab completion suggestions.
        The default padding of readline/pyreadine is small and not visually appealing
        especially if matches have spaces. It appears very squished together.

        :param matches_to_display: the matches being padded
        :return: the padded matches and length of padding that was added
        z  z   r   c                    s   g | ]}|  qS rD   rD   r   r  paddingrD   rE   r   !  r   z/Cmd._pad_matches_to_display.<locals>.<listcomp>)r1   r-   r  r  r   )r  rD   r  rE   _pad_matches_to_display  s   
	
zCmd._pad_matches_to_displayc                 C   sB   d}| j r| jr|d| j 7 }| jr|s|d7 }|d| j 7 }|S )zYBuild completion metadata string which can contain a hint and CompletionItem table headerr>   r~  )r   r   r   )rC   metadatarD   rD   rE   !_build_completion_metadata_string#  s   z%Cmd._build_completion_metadata_stringsubstitutionr  longest_match_lengthc                 C   s   t tjkrh| jr| j}d}|D ]}t|}||kr|}qn|}| |\}}||7 }t|dd}dd |D }	tj	dt
|	 d   }
||
d< |	|
dd< d|
d< tj|   t|
t
|	| t  dS dS )	ay  Prints a match list using GNU readline's rl_display_match_list()
        This exists to print self.display_matches if it has data. Otherwise matches prints.

        :param substitution: the substitution written to the command line
        :param matches: the tab completion matches to display
        :param longest_match_length: longest printed length of the matches
        r   r  encodingc                 S   s   g | ]}t |d dqS )r  r$  )bytesr  rD   rD   rE   r   S  r  z5Cmd._display_matches_gnu_readline.<locals>.<listcomp>r   r  N)r1   r-   r  r   r   style_aware_wcswidthr  r&  ctypesc_char_pr   r   rk   r  r!  r9   rl_display_match_listr7   )rC   r"  r  r#  r  r  
cur_lengthpadding_lengthencoded_substitutionencoded_matchesstrings_arrayrD   rD   rE   r  3  s.   
	

z!Cmd._display_matches_gnu_readlinec                 C   sN   t tjkr%| jr| j}n|}| |\}}tjjj	| 
  t| dS dS )zPrints a match list using pyreadline's _display_completions()
        This exists to print self.display_matches if it has data. Otherwise matches prints.

        :param matches: the tab completion matches to display
        N)r1   r-   r  r   r  r8   r  r  consoler  r!  orig_pyreadline_display)rC   r  r  r  rD   rD   rE   r  i  s   
zCmd._display_matches_pyreadlineshortcut_to_restorec                    s@  d| j |}|j}|| jv r| j| nd}|j}	t|t|  }
|	d|
 7 }	t|	t|krBt|	t| }||7 }||7 }|	}| |||\}}t|dkrUdS d|d }|r|d tj	v r|d |d| 
|d }||kr||| | }|}|| jv r| j}nO||  v rt| tj| d}|du r| |}t|tjd}|dur|durddl}|j| j|t|tj|d}n| j}n| jr|t|v r| j}n| j}| |||||| _| jrt| j| _t| j| _| jsddl}|| j| _sbd}tj !| j}| j"r3tj !| j}d|v s0|r2t#d	d
 | jD r2d}n|rCt#dd
 | jD rCd}|rat#dd
 | jD rTdndfdd| jD | _nrpfdd| jD | _ r~ fdd| jD | _t| jdkr| j$rr| jd  7  < dS dS dS dS dS )a3  
        Helper function for complete() that performs command-specific tab completion

        :param text: the string prefix we are attempting to match (all matches must begin with it)
        :param line: the current input line with leading whitespace removed
        :param begidx: the beginning index of the prefix text
        :param endidx: the ending index of the prefix text
        :param shortcut_to_restore: if not blank, then this shortcut was removed from text and needs to be
                                    prepended to all the matches
        r>   N r   r  r   )	argparserpreserve_quotescmd_setFc                 s       | ]}d |v V  qdS r3  NrD   r   matchrD   rD   rE   	<genexpr>      z.Cmd._completion_for_command.<locals>.<genexpr>Tc                 s   r7  r8  rD   r9  rD   rD   rE   r;  	  r<  c                 s   r7  )"NrD   r9  rD   rD   rE   r;    r<  'r=  c                       g | ]} | qS rD   rD   r9  )r  rD   rE   r     r   z/Cmd._completion_for_command.<locals>.<listcomp>c                    r  r  r  r9  )text_to_removerD   rE   r     r  c                    r?  rD   rD   r9  )r2  rD   rE   r     r   )%r   parse_command_onlyr  r   command_and_argsr   rstripr  r   r  rfindr   r	  r   r
  r   r8  r9  	functoolspartial_complete_argparse_commandCMD_ATTR_PRESERVE_QUOTEScompletedefaultr}   r   r  r  r   remove_duplicatesr   r  r   r   r  r   anyr   )rC   r  r  r  r  r2  	statementr  r6  expanded_linerstripped_lendiffr  r  raw_completion_tokenactual_begidxr  funcr4  rE  r  	add_quoter  display_prefixrD   )r2  r@  r  rE   _completion_for_command  s   


6zCmd._completion_for_commandstatec              
   C   s8  z|dkr|    | jr(| j }|t  }t|t  }t|t  }n"t }| }t|t| }t	t | d}t	t | d}d}	|dkrp| j
jD ]\}
}||
ro|
}	|t|	d }|t|	7 } nqT|dkr~| |||||	 n|  }t|||||| _t| jdkr|t|kr| jr| jd  d7  < | js| jj| jd | jj| jd d| _z| j| W W S  ty   Y W dS w  ty } z#t|}|r|jrt|}ttjd| d  t   W Y d}~dS d}~w t!y } z| "  | #| t   W Y d}~dS d}~ww )	u  Override of cmd2's complete method which returns the next possible completion for 'text'

        This completer function is called by readline as complete(text, state), for state in 0, 1, 2, …,
        until it returns a non-string value. It should return the next possible completion starting with text.

        Since readline suppresses any exception raised in completer functions, they can be difficult to debug.
        Therefore this function wraps the actual tab completion logic and prints to stderr any exception that
        occurs before returning control to readline.

        :param text: the current word that user is typing
        :param state: non-negative integer
        :return: the next possible completion for text or None
        r   r>   Nr   r3  r  Tr~  )$r  r   r   lstripr8   get_line_bufferr   
get_begidx
get_endidxmaxr   re   r   rU  /_get_commands_aliases_and_macros_for_completionr   r  r   r   r   r   r   r   
IndexErrorr4   rY  r  r   r  r  r   rk   r7   r  r  r  )rC   r  rV  lstripped_previousr  r  r  	orig_linenum_strippedr2  shortcutr  r  r  err_strerD   rD   rE   complete"  sj   


 

zCmd.completer6  r4  r5  r6  c                C   sJ   ddl m} ||| }	| |||\}
}|r|n|
}|	j||||||dS )z)Completion function for argparse commandsr   ArgparseCompleterre  )argparse_completerrg  r  complete_command)rC   r  r  r  r  r4  r5  r6  rg  r?   r  r  tokens_to_parserD   rD   rE   rG    s
   
zCmd._complete_argparse_commandc                 C   s
   | j duS )z'Return whether a text script is runningN)_current_script_dirrB   rD   rD   rE   r    s   
zCmd.in_scriptc                 C      | j S )z$Return whether a pyscript is running)r   rB   rD   rD   rE   r    s   zCmd.in_pyscriptc                 C   s   | j jS )zFRead-only property to access the aliases stored in the StatementParser)r   r#  rB   rD   rD   rE   r#    s   zCmd.aliasesc                 C   s   t | S )zZReturn an alphabetized list of names comprising the attributes of the cmd2 class instance.)dirrB   rD   rD   rE   	get_names  s   zCmd.get_namesc                        fdd   D S )zReturn a list of all commandsc                    8   g | ]}| tjrtt |r|ttjd  qS rN   )r   r   r   r  r
  r   r   rj  rB   rD   rE   r     
    
z(Cmd.get_all_commands.<locals>.<listcomp>rn  rB   rD   rB   rE   r     rz  zCmd.get_all_commandsc                    ro  )z?Return a list of commands that have not been hidden or disabledc                    $   g | ]}| j vr| jvr|qS rD   r   r   )r   r  rB   rD   rE   r         z,Cmd.get_visible_commands.<locals>.<listcomp>)r   rB   rD   rB   rE   get_visible_commands  rz  zCmd.get_visible_commandsc                        fdd j D S )z@Return list of current alias names and values as CompletionItemsc                    s   g | ]
}t | j| qS rD   )r   r#  r   cur_keyrB   rD   rE   r     s    z3Cmd._get_alias_completion_items.<locals>.<listcomp>)r#  rB   rD   rB   rE   _get_alias_completion_items     zCmd._get_alias_completion_itemsc                    rx  )z@Return list of current macro names and values as CompletionItemsc                       g | ]}t | j| jqS rD   )r   r   valuery  rB   rD   rE   r     r  z3Cmd._get_macro_completion_items.<locals>.<listcomp>)r   rB   rD   rB   rE   _get_macro_completion_items  r|  zCmd._get_macro_completion_itemsc                    rx  )zIReturn list of current settable names and descriptions as CompletionItemsc                    r}  rD   )r   r   rP  ry  rB   rD   rE   r     r  z6Cmd._get_settable_completion_items.<locals>.<listcomp>)r   rB   rD   rB   rE   _get_settable_completion_items  r|  z"Cmd._get_settable_completion_itemsc                 C   s0   t |  }t | j}t | j}t||B |B S )zIReturn a list of visible commands, aliases, and macros for tab completion)setrw  r#  r   list)rC   visible_commandsalias_namesmacro_namesrD   rD   rE   r\    s   

z3Cmd._get_commands_aliases_and_macros_for_completionc                    s(    fdd   D } fdd|D S )zReturn a list of help topicsc                    rp  rN   )r   r   r   r  r
  r   rq  rB   rD   rE   r     rr  z'Cmd.get_help_topics.<locals>.<listcomp>c                    rt  rD   ru  )r   topicrB   rD   rE   r     rv  rs  )rC   
all_topicsrD   rB   rE   get_help_topics  s   zCmd.get_help_topicssignumc                 C   s&   | j dur
| j   | jstddS )zSignal handler for SIGINTs which typically come from Ctrl-C events.

        If you need custom SIGINT behavior, then override this function.

        :param signum: signal number
        :param frame: required param for signal handlers
        NzGot a keyboard interrupt)r   send_sigintr   KeyboardInterrupt)rC   r  framerD   rD   rE   sigint_handler  s
   

zCmd.sigint_handlerrL  c                 C      |S )aV  Hook method executed just before the command is executed by
        :meth:`~cmd2.Cmd.onecmd` and after adding it to history.

        :param statement: subclass of str which also contains the parsed input
        :return: a potentially modified version of the input Statement object

        See :meth:`~cmd2.Cmd.register_postparsing_hook` and
        :meth:`~cmd2.Cmd.register_precmd_hook` for more robust ways
        to run hooks before the command is executed. See
        :ref:`features/hooks:Postparsing Hooks` and
        :ref:`features/hooks:Precommand Hooks` for more information.
        rD   )rC   rL  rD   rD   rE   precmd  s   z
Cmd.precmdstopc                 C   r  )a5  Hook method executed just after a command is executed by
        :meth:`~cmd2.Cmd.onecmd`.

        :param stop: return `True` to request the command loop terminate
        :param statement: subclass of str which also contains the parsed input

        See :meth:`~cmd2.Cmd.register_postcmd_hook` and :meth:`~cmd2.Cmd.register_cmdfinalization_hook` for more robust ways
        to run hooks after the command is executed. See
        :ref:`features/hooks:Postcommand Hooks` and
        :ref:`features/hooks:Command Finalization Hooks` for more information.
        rD   )rC   r  rL  rD   rD   rE   postcmd  s   zCmd.postcmdc                 C      dS )a6  Hook method executed once when the :meth:`~.cmd2.Cmd.cmdloop()`
        method is called.

        See :meth:`~cmd2.Cmd.register_preloop_hook` for a more robust way
        to run hooks before the command loop begins. See
        :ref:`features/hooks:Application Lifecycle Hooks` for more information.
        NrD   rB   rD   rD   rE   preloop     zCmd.preloopc                 C   r  )aB  Hook method executed once when the :meth:`~.cmd2.Cmd.cmdloop()`
        method is about to return.

        See :meth:`~cmd2.Cmd.register_postloop_hook` for a more robust way
        to run hooks after the command loop completes. See
        :ref:`features/hooks:Application Lifecycle Hooks` for more information.
        NrD   rB   rD   rD   rE   postloop  r  zCmd.postloopc                 C   s   | j |}|j|j|jfS )ar  Parse the line into a command name and a string containing the arguments.

        NOTE: This is an override of a parent class method.  It is only used by other parent class methods.

        Different from the parent class method, this ignores self.identchars.

        :param line: line read by readline
        :return: tuple containing (command, args, line)
        )r   rA  r  argsrB  )rC   r  rL  rD   rD   rE   	parseline  s   
zCmd.parseline)add_to_historyraise_keyboard_interruptpy_bridge_callr  r  r  c                C   s  ddl }d}d}zz| |}td|}| jD ]}	|	|}|jr$ nq|j}|j}|r/td}
z| j |r<d| j	_
| |}
W d   n1 sKw   Y  |j  }t|}| jD ]}	|	|}q]|j}| |}| j||d}t||}| jD ]}	|	|}q||j}| ||}| jr| d|j  |  W | j |
dur| ||
 |rd| j	_
W d   n1 sw   Y  n+| j |
dur| ||
 |rd| j	_
W d   w W d   w 1 sw   Y  w W nx ttfy   Y nn ty } z| d| W Y d}~nXd}~w ty) } z| | W Y d}~nAd}~w tyC } z|r9|s9|W Y d}~n'd}~w tyN   d}Y n tye } z| | W Y d}~nd}~ww W z	|  ||}W |S  ty } z|r|s|W Y d}~|S W Y d}~|S d}~w ty   d}Y |S  ty } z| | W Y d}~|S d}~ww z|  ||}W w  ty } z|r|s|W Y d}~w W Y d}~w d}~w ty   d}Y w  ty } z| | W Y d}~w d}~ww )a  Top-level function called by cmdloop() to handle parsing a line and running the command and all of its hooks.

        :param line: command line to run
        :param add_to_history: If True, then add this command to history. Defaults to True.
        :param raise_keyboard_interrupt: if True, then KeyboardInterrupt exceptions will be raised if stop isn't already
                                         True. This is used when running commands in a loop to be able to stop the whole
                                         loop and not just the current command. Defaults to False.
        :param py_bridge_call: This should only ever be set to True by PyBridge to signify the beginning
                               of an app() call from Python. It is used to enable/disable the storage of the
                               command's stdout.
        :return: True if running of commands should stop
        r   NFr  zElapsed: {}TzInvalid syntax: {})!datetime_input_line_to_statementr   PostparsingData_postparsing_hooksr  rL  r#   r   rk   pause_storage_redirect_outputnowPrecommandData_precmd_hooksr  onecmdPostcommandData_postcmd_hooksr  r   r  r   _restore_outputr%   r    r  r$   r  
SystemExitr  r  _run_cmdfinalization_hooks)rC   r  r  r  r  r  r  rL  datarR  redir_saved_state	timestartr  rD   rD   rE   onecmd_plus_hooks  s   








 
	

zCmd.onecmd_plus_hooksc                 C   s   | j " tjds| j rddl}|ddg}|  W d   n1 s(w   Y  t	
||}| jD ]}||}q6|jS )z"Run the command finalization hooksru   r   Nsttysane)r   r   r   r   rj   r  r  r  r  r   CommandFinalizationData_cmdfinalization_hooksr  )rC   r  rL  r  procr  rR  rD   rD   rE   r    s   

zCmd._run_cmdfinalization_hooks)r  stop_on_keyboard_interruptcmdsr  c                C   s   |D ]F}t |tr|j}| jr| d| j| z| j|||dr&W  dS W q tyH } z|r>| 	| W Y d}~ dS W Y d}~qd}~ww dS )a>  
        Used when commands are being run in an automated fashion like text scripts or history replays.
        The prompt and command line for each command will be printed if echo is True.

        :param cmds: commands to run
        :param add_to_history: If True, then add these commands to history. Defaults to True.
        :param stop_on_keyboard_interrupt: stop command loop if Ctrl-C is pressed instead of just
                                           moving to the next command. Defaults to True.
        :return: True if running of commands should stop
        r  )r  r  TNF)
r   r'   rawr   r  r   r|  r  r  r  )rC   r  r  r  r  rc  rD   rD   rE   runcmds_plus_hooks  s(   

zCmd.runcmds_plus_hooksc              
   C   s
  	 z| j |}|jr|jrW nn|jsW niW n ty)   | j |}|js' Y nw zNz"d| _|d | _| | j	}|dkrEd}| 
| d| j|}W n& tys } z| jrZ|| 
d | j d}W Y d}~W d| _nd}~ww W d| _nd| _w q|jst|S )	aV  Keep accepting lines of input until the command is complete.

        There is some pretty hacky code here to handle some quirks of
        self._read_command_line(). It returns a literal 'eof' if the input
        pipe runs out. We can't refactor it because we need to retain
        backwards compatibility with the standard library version of cmd.

        :param line: the line being parsed
        :return: the completed Statement
        :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation)
        :raises: EmptyStatement when the resulting Statement is blank
        Tr~  rm   r  ^Cr>   NF)r   parsemultiline_command
terminatorr    rA  r   r   _read_command_liner   r  r   r  r~   r  r#   )rC   r  rL  nextliner  rD   rD   rE   _complete_statement  sJ   


	.zCmd._complete_statementc                 C   s   g }d}	 |  |}|du r|j}|j| j v r0|j|vr0||j | |}|du r/tnnq||jkrNt|j	||j|j
|j|j|j|j|j|jd
}|S )aq  
        Parse the user's input line and convert it to a Statement, ensuring that all macros are also resolved

        :param line: the line being parsed
        :return: parsed command line as a Statement
        :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation)
        :raises: EmptyStatement when the resulting Statement is blank
        NT)	r  r  arg_listr  r  suffixpipe_tooutput	output_to)r  r  r  r   keysr   _resolve_macror#   r*   r  r  r  r  r  r  r  r  )rC   r  used_macrosr_  rL  rD   rD   rE   r    s6   	



zCmd._input_line_to_statementc           	      C   s
  |j | j vrtd|j | j|j  }t|j|jk r+| d|j |j dS |j	}t
|jdd dd}|D ]4}|jrNd|j d	 }d
|j d }nd
|j d }|jt|j }|j|dd}|d | |d  }q:|j|jd D ]}|d| 7 }qw||j S )z
        Resolve a macro and return the resulting string

        :param statement: the parsed statement from the command line
        :return: the resolved macro or None on error
        z{} is not a macroz.The macro '{}' expects at least {} argument(s)Nc                 S   rl  rN   )start_index)marD   rD   rE   r   9	  s    z$Cmd._resolve_macro.<locals>.<lambda>T)r  reversez{{z}}{}r   )maxsplitr   r3  )r  r   r  rm  r   r   r  minimum_arg_countr  r~  sorted
is_escaped
number_strargvrt  rsplitpost_command)	rC   rL  macroresolvedreverse_arg_listargr  replacementpartsrD   rD   rE   r   	  s0   
zCmd._resolve_macroc              
   C   s*  ddl }ddl}t| jtj| j| j}d}| jsn|j	rt
 \}}||d}||d}	t }
tjdkr=|j|
d< nd|
d< |j|j	f|t| jtjrQ|jn| jttjtjr]|jntjdd	|
}z|d
 W n
 |jyw   Y nw |jdur|  |	  td|jd|_t|| jtj}|	 t_| _nl|jrddl}|js| j std|jr|jt!j"krdnd}ztt#|j|dd}	W n t$y } ztd|d}~ww d|_|	 t_| _n"|j%dd}	d|_|	 t_| _|jt!j"kr| j&t'  | j(  || _|j| _|S )a*  Set up a command's output redirection for >, >>, and |.

        :param statement: a parsed statement from the user
        :return: A bool telling if an error occurred and a utils.RedirectionSavedState object
        :raises: RedirectionError if an error occurs trying to pipe or redirect
        r   Nrwwin32creationflagsTstart_new_session)rj   rk   r  r  g?z9Pipe process exited with code {} before command could runzRCannot redirect to paste buffer; missing 'pyperclip' and/or pyperclip dependenciesar   )r  	bufferingzFailed to redirect because - {}zw+)r  ))ior  r   RedirectionSavedStaterk   r   r   r   rb   r  r   pipeopenr   r   CREATE_NEW_PROCESS_GROUPr  r   StdSimr  r  waitTimeoutExpired
returncodecloser$   r   redirecting
ProcReaderr  tempfiler  r   r   r  r  OSErrorTemporaryFiler  r   flush)rC   rL  r  r  r  cmd_pipe_proc_readerread_fdwrite_fdsubproc_stdin
new_stdoutkwargsr  r  r  r  rD   rD   rE   r  M	  s~   




zCmd._redirect_outputsaved_redir_statec                 C   s   |j r9|jr|js| jd t| j  z| j  W n	 ty&   Y nw |j	| _|j
t_| jdur9| j  |j| _|j| _dS )zHandles restoring state after output redirection

        :param statement: Statement object which contains the parsed input from the user
        :param saved_redir_state: contains information needed to restore state data
        r   N)r  r  r  rk   seekr   readr  r  saved_self_stdoutsaved_sys_stdoutr   r   r  saved_pipe_proc_readersaved_redirectingr   )rC   rL  r  rD   rD   rE   r  	  s   

zCmd._restore_outputc                 C   s   |  |}|rt| |S dS )z
        Get the function for a command

        :param command: the name of the command

        :Example:

        >>> helpfunc = self.cmd_func('help')

        helpfunc now contains a reference to the ``do_help`` method
        N)_cmd_func_namer
  )rC   r  	func_namerD   rD   rE   r8  	  s   

zCmd.cmd_funcc                 C   s"   t j| }tt| |dr|S dS )zGet the method name associated with a given command.

        :param command: command to look up method name which implements it
        :return: method name which implements the given command
        Nr>   )r   r   r  r
  )rC   r  targetrD   rD   rE   r  	  s   
zCmd._cmd_func_namer  c                C   sp   t |ts
| |}| |j}|r+|j| jvr&|j| jvr&|r&| j| ||}n| 	|}|du r6d}|S )a   This executes the actual do_* method for a command.

        If the command provided doesn't exist, then it executes default() instead.

        :param statement: intended to be a Statement instance parsed command from the input stream, alternative
                          acceptance of a str is present only for backward compatibility with cmd
        :param add_to_history: If True, then add this command to history. Defaults to True.
        :return: a flag indicating whether the interpretation of commands should stop
        NF)
r   r*   r  r8  r  r   r   rQ   r   default)rC   rL  r  rR  r  rD   rD   rE   r  	  s   



z
Cmd.onecmdc                 C   sH   | j rd| jvr| j| | |jS | j|j}| j	|dd dS )zExecuted when the command given isn't a recognized command implemented by a do_* method.

        :param statement: Statement object with parsed input
        r  Fr  N)
r}   r   rQ   r   do_shellrB  r   r   r  r  )rC   rL  err_msgrD   rD   rE   r  	
  s   
zCmd.defaultallow_completionr|  r  c                   s  d d fdd} fdd}j rtj rwz:t|}j |s*|  W d   n1 s4w   Y  t|}W j |sG|  W d   n1 sQw   Y  nhj |sg|  W d   w W d   w 1 sqw   Y  w t }jrtj	d
|| n7j rj|dd	 j  j }t|d
krd}nj }t|rjrd
|| nd}|dS )a  
        Read input from appropriate stdin value. Also allows you to disable tab completion while input is being read.

        :param prompt: prompt to display to user
        :param allow_completion: if True, then tab completion of commands is enabled. This generally should be
                                 set to False unless reading the command line. Defaults to False.
        :return: the line read from stdin with all trailing new lines removed
        :raises: any exceptions raised by input() and stdin.readline()
        FNc                      s2     r st tdd  d dS dS dS )z(Turn off completion while entering inputc                  _   s   d S rN   rD   r  r  rD   rD   rE   r   .
      z<Cmd.read_input.<locals>.disable_completion.<locals>.<lambda>TN)ry  r8   get_completerset_completerrD   completion_disabledorig_completerrC   rD   rE   disable_completion'
  s
   z*Cmd.read_input.<locals>.disable_completionc                      s&     r rt d dS dS dS )z3Restore tab completion when finished entering inputFN)ry  r8   r
  rD   r  rD   rE   enable_completion1
  s   
z)Cmd.read_input.<locals>.enable_completion{}{}
r>   r  r   rm   r  z
)rw  r   rj   r  r/   r   inputr   rk   r  r   r  r  r8   r   rC  )rC   r|  r  r  r  safe_promptr  rD   r  rE   
read_input
  sX   

	

 




zCmd.read_inputc                 C   sn   z0zz| j   W n	 ty   Y nw | j|ddW W | j   S  ty0   Y W | j   dS w | j   w )a  
        Read command line from appropriate stdin

        :param prompt: prompt to display to user
        :return: command line text of 'eof' if an EOFError was caught
        :raises: whatever exceptions are raised by input() except for EOFError
        Tr  rm   )r   releaseRuntimeErrorr  acquireEOFError)rC   r|  rD   rD   rE   r  f
  s   zCmd._read_command_linec                 C   s   t  }|  rPttjkrtttjj	|_
dt_	t |_t| j d}|dtj7 }|dtj7 }|d| jj7 }t |_t| t| jd  |S )zx
        Set up readline with cmd2-specific settings

        :return: Class containing saved readline settings
        Nz 	
r>   z
: complete)r=   ry  r1   r-   r  r(  castr:   c_void_pr~  rA   r8   r	  r?   r
  rd  r  r   r  REDIRECTION_CHARSr   rd   get_completer_delimsr@   set_completer_delimsparse_and_bindrh   )rC   rO   completer_delimsrD   rD   rE   _set_up_cmd2_readline|
  s   



zCmd._set_up_cmd2_readlinerO   c                 C   s`   |   r,t|j t|j ttjkr t	d |j
t_dS ttjkr.ttjj_dS dS dS )zu
        Restore saved readline settings

        :param readline_settings: the readline settings to restore
        N)ry  r8   r
  r?   r  r@   r1   r-   r  r  rA   r:   r~  r  r1  r  r  r  )rC   rO   rD   rD   rE   _restore_readline
  s   


	zCmd._restore_readlinec                 C   sB  d}zz| j  |  }W d   n1 sw   Y  | | j}| j  |sUz| | j}W n tyM } z| jr<|| 	d d}W Y d}~nd}~ww | 
|}|r'W | j  |durk| | W d   dS W d   dS 1 svw   Y  dS | j  |dur| | W d   w W d   w 1 sw   Y  w )zRepeatedly issue a prompt, accept input, parse an initial prefix
        off the received input, and dispatch to action methods, passing them
        the remainder of the line as argument.

        This serves the same role as cmd.cmdloop().
        Nr  r>   )r   r  r  r   clearr  r|  r  r~   r  r  r   )rC   saved_readline_settingsr  r  r  rD   rD   rE   _cmdloop
  s>   



*zCmd._cmdloopz[Manage aliases

An alias is a command that enables replacement of a word by another string.zSee also:
  macro)rP  rQ  
subcommand
SUBCOMMAND)destmetavar)r5  r  c                 C      |j  }|| dS )zManage aliasesNcmd2_handlerr   rC   r  handlerrD   rD   rE   do_alias
     
zCmd.do_aliasCreate or overwrite an aliasa{  Notes:
  If you want to use redirection, pipes, or terminators in the value of the
  alias, then quote them.

  Since aliases are resolved during parsing, tab completion will function as
  it would for the actual command the alias resolves to.

Examples:
  alias create ls !ls -lF
  alias create show_log !cat "log file.txt"
  alias create save_results print_results ">" out.txt
z-sz--silentrq   z@do not print message confirming alias was created or
overwrittenrr   zname of this alias)rt   zwhat the alias resolves to)rt   choices_methodcommand_argszarguments to pass to command)nargsrt   completer_methodaliascreatec                 C   s   | j |j\}}|s| d| dS |j|  v r#| d dS |j| jv r0| d dS tj}|	| j j
 t|j| |j}|jrQ|dd|j 7 }|jsh|j| jv r\dnd}| d|j| || j|j< dS )	r/  zInvalid alias name: {}Nz,Alias cannot have the same name as a commandz*Alias cannot have the same name as a macror3  overwrittencreatedzAlias '{}' {})r   r   rj  r  r   r   r   r   r  r   rd   r   unquote_specific_tokensr1  r  r  silentr#  r  )rC   r  r   r   tokens_to_unquoter~  resultrD   rD   rE   _alias_create  s(   

zCmd._alias_createzdelete aliasesz8Delete specified aliases or all aliases if --all is used)rP  z-az--allzdelete all aliasesnameszalias(es) to deleteValue)r2  rt   r0  descriptive_headerdeletec                 C   |   |j r| j  | d dS |js| d dS t|jD ]}|| jv r3| j|= | d| q| d| qdS )zDelete aliaseszAll aliases deletedz/Either --all or alias name(s) must be specifiedzAlias '{}' deletedzAlias '{}' does not existN)	allr#  r!  r  r=  r  r   rJ  r   rC   r  cur_namerD   rD   rE   _alias_delete1     

zCmd._alias_deletezlist aliaseszList specified aliases in a reusable form that can be saved to a startup
script to preserve aliases across sessions

Without arguments, all aliases will be listed.z-wz--with_silentz~include --silent flag with listed aliases
Use this option when saving to a startup script that
should silently create aliases.zalias(es) to listr  c           
      C   s   d}|j r	|d7 }tj}|| jj |jrt|j}nt	| j
| jd}g }|D ];}|| j
vr6|| q)t| j
| }|d }|dd }t|| |}	|rZ|	dd| 7 }	| d|||	 q)|D ]
}| d	| qgdS )
z3List some or all aliases as 'alias create' commandszalias create	 --silentr  r   r   Nr3  {} {} {}zAlias '{}' not found)with_silentr   r  r   r   rd   r=  r   rJ  r  r#  r   r   r,   quote_specific_tokensr  r  r   r  
rC   r  
create_cmdtokens_to_quoteto_list	not_foundrj  r  r  r  rD   rD   rE   _alias_listP  s0   

zCmd._alias_listzXManage macros

A macro is similar to an alias, but it can contain argument placeholders.zSee also:
  aliasc                 C   r(  )zManage macrosNr)  r+  rD   rD   rE   do_macro  r.  zCmd.do_macrozcreate or overwrite a macroCreate or overwrite a macroa  A macro is similar to an alias, but it can contain argument placeholders.
Arguments are expressed when creating a macro using {#} notation where {1}
means the first argument.

The following creates a macro called my_macro that expects two arguments:

  macro create my_macro make_dinner --meat {1} --veggie {2}

When the macro is called, the provided arguments are resolved and the
assembled command is run. For example:

  my_macro beef broccoli ---> make_dinner --meat beef --veggie broccoli

Notes:
  To use the literal string {1} in your command, escape it this way: {{1}}.

  Extra arguments passed to a macro are appended to resolved command.

  An argument number can be repeated in a macro. In the following example the
  first argument will populate both {1} instances.

    macro create ft file_taxes -p {1} -q {2} -r {1}

  To quote an argument in the resolved command, quote it during creation.

    macro create backup !cp "{1}" "{1}.orig"

  If you want to use redirection, pipes, or terminators in the value of the
  macro, then quote them.

    macro create show_results print_results -type {1} "|" less

  Because macros do not resolve until after hitting Enter, tab completion
  will only complete paths while typing a macro.z@do not print message confirming macro was created or
overwrittenzname of this macrozwhat the macro resolves tor  c                 C   s  | j |j\}}|s| d| dS |j|  v r#| d dS |j| jv r0| d dS tj}|	| j j
 t|j| |j}|jrQ|dd|j 7 }g }ttj|}d}t }		 z8| }
ttj|
 d }t|}|dk r| d	 W dS |	| ||kr|}|t|
 |d
d W n	 ty   Y nw q`t|	|kr| d| dS ttj|}	 z| }
ttj|
 d }|t|
 |dd W n	 ty   Y nw q|j s|j| j!v rdnd}| "d|j| t#|j|||d| j!|j< dS )rR  zInvalid macro name: {}Nz,Macro cannot have the same name as a commandz+Macro cannot have the same name as an aliasr3  r   Tr   z'Argument numbers must be greater than 0F)r  r  r  zINot all numbers between 1 and {} are present in the argument placeholdersr6  r7  zMacro '{}' {})rj  r~  r  r  )$r   r   rj  r  r   r   r#  r   r  r   rd   r   r8  r1  r  r  refinditerr)   macro_normal_arg_patternr  __next__findalldigit_patterngrouprt  addr   startStopIterationr   macro_escaped_arg_patternr9  r   r  r(   )rC   r  r   r   r:  r~  r  normal_matchesmax_arg_numarg_numsr  cur_num_strcur_numescaped_matchesr;  rD   rD   rE   _macro_create  sp   



zCmd._macro_createzdelete macrosz6Delete specified macros or all macros if --all is usedzdelete all macroszmacro(s) to deletec                 C   rA  )zDelete macroszAll macros deletedz/Either --all or macro name(s) must be specifiedzMacro '{}' deletedzMacro '{}' does not existN)	rB  r   r!  r  r=  r  r   rJ  r   rC  rD   rD   rE   _macro_delete  rF  zCmd._macro_deletezlist macroszList specified macros in a reusable form that can be saved to a startup script
to preserve macros across sessions

Without arguments, all macros will be listed.z|include --silent flag with listed macros
Use this option when saving to a startup script that
should silently create macros.zmacro(s) to listc           
      C   s   d}|j r	|d7 }tj}|| jj |jrt|j}nt	| j
| jd}g }|D ]<}|| j
vr6|| q)t| j
| j}|d }|dd }t|| |}	|r[|	dd| 7 }	| d|||	 q)|D ]
}| d	| qhdS )
z2List some or all macros as 'macro create' commandszmacro createrG  r  r   r   Nr3  rH  zMacro '{}' not found)rI  r   r  r   r   rd   r=  r   rJ  r  r   r   r   r,   r~  rJ  r  r  r   r  rK  rD   rD   rE   _macro_list3  s0   

zCmd._macro_listc                 C   s6   t |  }t |  }t||B }t|||||S )z&Completes the command argument of help)r  r  rw  r  r   r  )rC   r  r  r  r  topicsr  strs_to_matchrD   rD   rE   complete_help_commandW  s   zCmd.complete_help_command
arg_tokensc                 C   sv   |d d }|s
g S |  |}t|tjd}|du s|du r g S |g|d  }	ddlm}
 |
|| }||	||||S )z*Completes the subcommands argument of helpr  r   Nsubcommandsr   rf  )r8  r
  r   r9  rh  rg  complete_subcommand_help)rC   r  r  r  r  rj  r  rR  r4  r  rg  r?   rD   rD   rE   complete_help_subcommands`  s   

zCmd.complete_help_subcommandsGList available commands or provide detailed help for a specific commandz-vz	--verbosez6print a list of all commands with descriptions of eachzcommand to retrieve help forrk  z"subcommand(s) to retrieve help forcomplete_helpc           	         s   |j r|jr| |j dS | |j }t| tj|j  d}t|tjd}|durK|durKddlm	} ||| }|j g|j
 }| j||dd dS |durXt |j  dS |durk|jdurk| t| dS | j|j }| j|dd dS )rn  Nr   rf  r>   r  Fr  )r  verbose
_help_menur8  r
  r   r   r9  rh  rg  rk  r  format_helpr|   do_helprK   pydocgetdocr   r   r  )	rC   r  rR  	help_funcr4  rg  r?   r  r  r   rD   rE   rs    s    
zCmd.do_helprp  c                 C   s   |   \}}}}t|dkr"| dt| j | | j|| n5| dt| j | jdt| jdd t|	 | j
dD ]}| ||| | qC| | j|| | | j|dd | | j|dd dS )	z7Show a list of commands which help can be displayed forr   r  z

r  r     P   N)_build_command_infor   r  r   rY  
doc_leader_print_topicsr   r  r  r   r   print_topicsmisc_headerundoc_header)rC   rp  	cmds_catscmds_doc
cmds_undochelp_topicscategoryrD   rD   rE   rq    s   zCmd._help_menuc           
      C   s   t |  | jd}t |  | jd}g }g }i }|D ]D}| |}d}||v r4|| t|tjs4d}t|tj	rNt
|tj	}	||	g  ||	 | q|jsS|rY|| q|| q||||fS )Nr  FT)r  r  r   rw  r8  r  r   r   r9  r  r
  
setdefaultr   rK   )
rC   r  r  r  r  r  r  rR  has_help_funcr  rD   rD   rE   ry    s(   


zCmd._build_command_infoheaderc              
   C   s  ddl }|r|s| ||dd dS | jdt| d}|D ]}t|}||kr.|}q!|d7 }|dk r9d}| jrI| jdjd	| jdd
 | 	 }|D ]}| 
|}	t|	tjs||v rt| tj| }
| }t| | j}z|| _|
  W || _n|| _w W d   n1 sw   Y  | }n|	j}|sd	g}n'g }d}| D ]}| }|dr|r nq|r|| d}q|r nq|D ]}| jdj|||d d	}qqO| jd dS dS )zXCustomized version of print_topics that can switch between verbose or traditional outputr   Nrw  rx  {}
      z{:{ruler}<{width}}
r>   )rulerwidthF:Tz{: <{col_width}}{doc}
)	col_widthdocr~  )r  r|  rk   r  r   rY  r   r'  r  r  r8  r   r   r9  r
  r   StringIOr   getvaluerK   
splitlinesstripr   r   )rC   r  r  rp  r  widestr  r  rg  r8  rv  r;  stdout_origr  	doc_blockfound_firstdoc_linestripped_linerD   rD   rE   r{    sp   






zCmd._print_topicsList available shortcutsr  c                    s@   t  jj fddd}ddd |D } d| dS )	r  c                    s     | d S )Nr   )r   )xrB   rD   rE   r   *  s    z"Cmd.do_shortcuts.<locals>.<lambda>r  r~  c                 s   s$    | ]}d  |d |d V  qdS )z{}: {}r   r   N)r   )r   scrD   rD   rE   r;  +  s   " z#Cmd.do_shortcuts.<locals>.<genexpr>z Shortcuts for other commands:
{}N)r  r   re   r  r  r   )rC   r  sorted_shortcutsr;  rD   rB   rE   do_shortcuts&  s   zCmd.do_shortcutsCalled when <Ctrl>-D is pressedc                 C   r  )r  TrD   rC   r  rD   rD   rE   do_eof0     z
Cmd.do_eofExit this applicationc                 C   r  )r  TrD   r  rD   rD   rE   do_quit8  r  zCmd.do_quitYour choice? optsc              
   C   s  |}t |trtt| | }g }|D ]0}t |tr%|||f qz||d |d f W q tyF   ||d |d f Y qw t|D ]\}\}}| d|d |f  qK	 z| 	|}	W n! t
yt   d}	|   Y n ty }
 z| d |
d}
~
ww |	sq]ttjkrt }|dkrt|d  zt|	}|dk rt||d  d W S  ttfy   | d|	t| Y nw q^)	a  Presents a numbered menu to the user.  Modeled after
           the bash shell's SELECT.  Returns the item chosen.

           Argument ``opts`` can be:

             | a single string -> will be split into one-word options
             | a list of strings -> will be offered as options
             | a list of tuples -> interpreted as (value, text), so
                                   that the return value can differ from
                                   the text advertised to the user r   r   z	  %2d. %sTr>   r  Nz:{!r} isn't a valid choice. Pick a number between 1 and {}:)r   rY  r  ziprZ  r   r]  r  r  r  r  r  r1   r-   rx  r8   get_current_history_lengthremove_history_itemrt  r   r   r   )rC   r  r|  
local_optsfulloptionsoptidxr  r  responser  hlenrI  rD   rD   rE   select>  sT   




z
Cmd.selectc              
   C   s   |d d }z| j | }W n ty   t|d w ttjgd}d}	|j|	|	|j|j|j	|j
|j|jd ddlm}
 |
|| }| |||\}}||||||S )	z#Completes the value argument of setparamr   rl  rM  r~  )r'  rt   r2  choices_functionr0  rX   r3  r   rf  )r   rm  r4   r   rY   set_parser_parentr   rP  r2  r  r0  rX   r3  rh  rg  r  ri  )rC   r  r  r  r  rj  r  ri  settable_parserarg_namerg  r?   r  r  rD   rD   rE   complete_set_valuet  s&   
zCmd.complete_set_valuezSet a settable parameter or show current settings of parameters
Call without arguments for a list of all settable parameters with their values.
Call with just param to view that parameter's value.)rP  rX  z.include description of parameters when viewingr  zparameter to set or viewDescriptionr  r~  znew value for settable)r2  rt   r3  suppress_tab_hintc              
   C   s  | j s
| d dS |jrz| j |j }W n ty(   | d|j Y dS w |jrt|j|_zt	| |j}t
| |j||j t	| |j}W n tyk } zd|j|}| | W Y d}~dS d}~ww | d|j|| ||kr|jr||j|| dS |jg}nt| j  }d}t }	|D ]}
d|
t	| |
|	|
< t|t|	|
 }qt|	| jdD ]!}
|	|
 }|jr| d	tj||d
| j |
 j q| | qdS )z?Set a settable parameter or show current settings of parametersz There are no settable parametersNzAParameter '{}' not supported (type 'set' for list of parameters).zError setting {}: {}z{} - was: {!r}
now: {!r}r   z{}: {!r}r  z{} # {})r  )r   r$  r  rm  r  r   r~  r   r  r
  r%  val_typer  r  onchange_cbr  r  r   r[  r   r'  r  r   rp  
align_leftrP  )rC   r  ri  
orig_value	new_valuerc  r  to_showmax_lenresultsr  
result_strrD   rD   rE   do_set  sR   



z
Cmd.do_set(Execute a command as if at the OS promptzthe command to run)rt   r3  c                 C   s   ddl }|jg|j }t| d|}| j9 |j|t| j	tj
r&|jn| j	ttjtj
r2|jntjdd}t|| j	tj}|  |j| _W d   dS 1 sTw   Y  dS )r  r   Nr3  T)rk   r  r  )r  r  r1  r   expand_user_in_tokensr  r   r  r   rk   r  r  r   r  r  r  r  r   )rC   r  r  r  expanded_commandr  proc_readerrD   rD   rE   r    s   


"zCmd.do_shellc               	   C   sD   g d} | D ]}zt j|= W q ty   Y qw t jt _t jt _dS )a  
        Resets the dynamic objects in the sys module that the py and ipy consoles fight over.
        When a Python console starts it adopts certain display settings if they've already been set.
        If an ipy console has previously been run, then py uses its settings and ends up looking
        like an ipy console in terms of prompt and exception text. This method forces the Python
        console to create its own display settings since they won't exist.

        IPython does not have this problem since it always overwrites the display settings when it
        is run. Therefore this method only needs to be called before creating a Python console.
        )ps1ps2ps3N)r   __dict__rm  __displayhook__displayhook__excepthook__
excepthook)
attributescur_attrrD   rD   rE   _reset_py_display  s   zCmd._reset_py_displayinterpc                 C   sJ  t  }ttjkrtdt d D ]}|jt	| qt
  | jD ]}t| q$|  rttjkrZtttjj|j_tt_dtjv rZdtjv rRtjd |_tjd tjd< t |j_tt ttjkrptd n
ttjkrzt tj!j"_#t$ |j_%|&d |&d |&d | '  tj(|_)| j(t_(tj*|_+| j*t_*|S )zy
        Set up interactive Python shell environment
        :return: Class containing saved up cmd2 environment
        r   gnureadliner8   Nz!from rlcompleter import Completerzimport readlinez4readline.set_completer(Completer(locals()).complete)),rM   r1   r-   rx  ranger8   r  rQ   r   get_history_itemclear_historyr   add_historyry  r  r(  r  r:   r  r~  rO   rA   orig_rl_basic_quotesr   modulesrP   r  r@   r  orig_rl_delimsr  r  r1  r  r  r  r	  r?   runcoder  rk   rR   rj   rS   )rC   r  cmd2_enviitemrD   rD   rE   _set_up_py_shell_env  sF   











zCmd._set_up_py_shell_envr  c                 C   s   |j t_|jt_ttjkrj| j	  t
dt d D ]}| jt| qt  |jD ]}t| q.|  rlt|jj t|jj ttjkrn|jjt_dtjv rp|jdu rbtjd= dS |jtjd< dS dS dS dS dS )z
        Restore cmd2 environment after exiting an interactive Python shell

        :param cmd2_env: the environment settings to restore
        r   r  Nr8   )rR   r   rk   rS   rj   r1   r-   rx  r   r!  r  r8   r  r   r  r  rQ   r  ry  r
  rO   r?   r  r@   r  rA   r:   r~  r  rP   )rC   r  r  r  rD   rD   rE   _restore_cmd2_envU  s,   






zCmd._restore_cmd2_enva  Invoke Python command or shell

Note that, when invoking a command directly from the command line, this shell
has limited ability to parse Python statements into tokens. In particular,
there may be problems with whitespace and quotes depending on their placement.

If you see strange parsing behavior, it's best to just open the Python shell
by providing no arguments to py and run more complex statements there.zcommand to run)r2  rt   	remainderzremainder of commandpyscriptr  c                C   sh  dd }ddl m} || }d}|  r| d dS zwd| _d}t| j}||| j< ||d	< ||d
< | jr;| |d< |durt	j
|}	zt|	}
|
 }W d   n1 sYw   Y  W n; ty } z/| d|	| W Y d}~W | j |dur|t_
d| _W d   dS 1 sw   Y  dS d}~ww d|d< |	|d< ttj
}tj
dt	j
t	j
|	 nd|d< |jr|j}|jr|dd|j 7 }d|_t|d}|rz|| W n ty   Y nw d}d| j}d}zTz)| j | |}W d   n	1 s
w   Y  |jdtj tj!||d W n
 ty(   Y nw W | j |dur8| "| W d   n	1 sCw   Y  n&| j |dur^| "| W d   w W d   w 1 siw   Y  w W | j |dur||t_
d| _W d   |j#S 1 sw   Y  |j#S | j |dur|t_
d| _W d   w 1 sw   Y  w )a  
        Enter an interactive Python shell

        :param args: Namespace of args on the command line
        :param pyscript: optional path to a pyscript file to run. This is intended only to be used by run_pyscript
                         after it sets up sys.argv for the script. If populated, this takes precedence over all
                         other arguments. (Defaults to None)
        :return: True if running of commands should stop
        c                   S   s   t )zNFunction callable from the interactive Python console to exit that environment)r"   rD   rD   rD   rE   py_quit  s   zCmd.do_py.<locals>.py_quitr   PyBridgeN=Recursively entering interactive Python shells is not allowedTr>   quitexitrC   z"Error reading script file '{}': {}F__main__rH   __file__r   __console__r3  )localszFType "help", "copyright", "credits" or "license" for more information.z}End with `Ctrl-D` (Unix) / `Ctrl-Z` (Windows), `quit()`, `exit()`.
Non-Python commands can be issued with: {}("your command")zPython {} on {}
{}

{}
)banner)$	py_bridger  r  r  r   r   r   r   r   r   r   r   r  r  r  r  r   r   r   r  insertr  r   r  r  r  cmd_echor   r  BaseExceptionr  interactversionr   r  r  )rC   r  r  r  r  r  saved_sys_pathpy_code_to_run	localvarsexpanded_filenamefr  r  cprtinstructionssaved_cmd2_envrD   rD   rE   do_py  s   




>"
 



 
 


 z	Cmd.do_pyz+Run a Python script file inside the consolescript_pathzpath to the script filescript_argumentszarguments to pass to scriptc                 C   s   t j|j|_|jds#| d|j | dd}|dkr#dS tj	}z|jg|j
 t_	| jd|jd}W |t_	|S |t_	w )	zw
        Run a Python script file inside the console

        :return: True if running of commands should stop
        .pyz"'{}' does not have a .py extensionYes Noz.Continue to try to run it as a Python script? YesNr>   r  )r   r   r   r  endswithr$  r   r  r   r  r  r  )rC   r  	selection	orig_args	py_returnrD   rD   rE   do_run_pyscript  s   zCmd.do_run_pyscriptz"Enter an interactive IPython shellc                 C   sd   ddl m} dtd|fdd}|  r| d dS zd	| _|| }|| | |jW d
| _S d
| _w )zz
            Enter an interactive IPython shell

            :return: True if running of commands should stop
            r   r  cmd2_appr  c                 S   s>   t d| j | jrt d ~ ~tddtjd d dS )z
                Embed an IPython shell in an environment that is restricted to only the variables in this function

                :param cmd2_app: instance of the cmd2 app
                :param py_bridge: a PyBridge
                z{} = py_bridgezself = cmd2_appz}Entering an embedded IPython shell. Type quit or <Ctrl>-d to exit.
Run Python code from external files with: run filename.py
zLeaving IPython, back to {}r   )banner1exit_msgN)execr   r   r   r;   r   r  )r  r  rD   rD   rE   load_ipy5  s   
zCmd.do_ipy.<locals>.load_ipyr  NTF)r  r  rY   r  r  r   r  )rC   r  r  r  new_py_bridgerD   rD   rE   ry   +  s   

z
Cmd.do_ipyz;View, run, edit, save, or clear previously entered commandsz-rz--runzrun selected history itemsz-ez--editz(edit and then run selected history itemsz-oz--output_fileFILEz,output commands to a script file, implies -s)r'  rt   r3  rp   z--transcriptTRANSCRIPT_FILEz<output commands and results to a transcript file,
implies -sz-cz--clearzclear all history
formatting)titlez--scriptz>output commands in script format, i.e. without command
numbersz-xz
--expandedz\output fully parsed commands with any aliases and
macros expanded, instead of typed commandszSdisplay history and include expanded commands if they
differ from the typed commandzEdisplay all commands, including ones persisted from
previous sessionszempty               all history items
a                   one history item by number
a..b, a:b, a:, ..b  items by indices (inclusive)
string              items containing string
/regex/             items matching regular expressionr  c              
   C   sL  |j r'|js|js|js|js|js|js|jr'| d | | j	
  dS |js-|jrK|js<|js<|js<|js<|jrK| d | | j	
  dS |jr| j  | jrzt| j W n% tyg   Y n ty } z| d| j| W Y d}~dS d}~ww ttjkrt  dS | |}|jr|js| d | d dS | |S |jr
ddl}|jdd	d
\}}t|d$}|D ]}|jj r|!d|j q|!d|j" qW d   n1 sw   Y  z| #| | $t%&| W t| dS t| w |jrzGt'tj()|jd'}|D ]}	|	jj r.|!d|	j q|!d|	j" qW d   n	1 sDw   Y  t*|dkrRdnd}
W n tys } z| d|j| W Y d}~dS d}~ww | +dt*||
|j dS |jr| ,||j dS |D ]}| |j-|j|j|j d qdS )z
        View, run, edit, save, or clear previously entered commands

        :return: True if running of commands should stop
        z)-v can not be used with any other optionsNz4-s and -x can not be used with -c, -r, -e, -o, or -tz$Error removing history file '{}': {}z9Cowardly refusing to run all previously entered commands.zEIf this is what you want to do, specify '1:' as the range of history.r   z.txtT)r  r  r  r  r   sr>   zError saving {!r} - {}z{} command{} saved to {})scriptexpandedrp  ).rp  r!  editoutput_filerun
transcriptr  r  r  history_parserformat_usagerQ   r[   r   r  FileNotFoundErrorr  r  r   r1   r-   rx  r8   r  _get_historyr  r  r  r  mkstempfdopenrL  r  r  r  _run_editordo_run_scriptr   r   r  r   r   r   r  _generate_transcriptpr)rC   r  r  rQ   r  fdfnamefobjr  r  pluralrc  hirD   rD   rE   
do_history|  s   	








" zCmd.do_historyc                 C   s   |j rU|j }d}zt| d}W n	 ty   Y nw d|v s"d|v r,| j||j}|S |r7| j|g}|S |drK|drK| j	||j}|S | j
||j}|S | jd|j}|S )znIf an argument was supplied, then retrieve partial contents of the history; otherwise retrieve entire history.FTz..r  /)r  rt  r   rQ   spanrB  r   r   r  regex_search
str_search)rC   r  r  
arg_is_intrQ   rD   rD   rE   r    s,   
zCmd._get_historyc                 C   s  t  | _|s|| _dS tjtj|}tj|r'd}| |	| dS tj
|}z	tj|dd W n tyT } zd	||}| | W Y d}~dS d}~ww t  }zt|d}t|}W d   n1 snw   Y  W n/ ttttttttjfy   Y n ty } zd}| |	|| W Y d}~dS d}~ww || _| j  || _ttjkrd}|D ]}|j D ]}	|	|krt |	 |	}qqddl!}
|
"| j# dS )	a  Initialize history using history related attributes

        This function can determine whether history is saved in the prior text-based
        format (one line of input is stored as one line in the file), or the new-as-
        of-version 0.9.13 pickle based format.

        History created by versions <= 0.9.12 is in readline format, i.e. plain text files.

        Initializing history does not effect history files on disk, versions >= 0.9.13 always
        write history in the pickle format.
        Nz+Persistent history file '{}' is a directoryT)exist_okz9Error creating persistent history file directory '{}': {}rbz-Can not read persistent history file '{}': {}r   )$r&   rQ   r[   r   r   r   r   r  r  r   r  makedirsr  r  r  pickleloadrz   r  r  ImportErrorr]  rm  r   UnpicklingErrorstart_sessionr1   r-   rx  r  r  r8   r  atexitregister_persist_history)rC   	hist_filer  hist_file_dirr  rQ   r%  lastr  r  r6  rD   rD   rE   r     s`   





zCmd._initialize_historyc              
   C   s   | j sdS | j| j z"t| j d}t| j| W d   W dS 1 s'w   Y  W dS  tyM } zd}| |	| j | W Y d}~dS d}~ww )z%Write history out to the history fileNwbz.Can not write persistent history file '{}': {})
r[   rQ   truncater   r  r1  dumpr  r  r   )rC   r%  r  r  rD   rD   rE   r8  3  s   &"zCmd._persist_historyrQ   transcript_filec                 C   s  t jt j|}t j|}t j|rt |t js'| d	| dS d}z| j
 | j}| j}d| _W d   n1 sAw   Y  d}|D ]m}	d}
d}t|	trX|	j}	|	 D ]}|
rl|d	| j|7 }d}
q\|d	| j|7 }q\||7 }t| j| _z	| j|	dd}W n ty } z| | d}W Y d}~nd}~ww |d	7 }|| j d
d7 }|r nqJW | j
 || _|| _W d   n1 sw   Y  n| j
 || _|| _W d   w 1 sw   Y  w |t|k rd	|}| | zt|d}|| W d   n	1 sw   Y  W n ty6 } z| d	| W Y d}~dS d}~ww |d	kr?d}nd}d}| |	||| dS )z;Generate a transcript file from a given history of commandsz6{!r} is not a directory or you don't have write accessNr   Fr>   Tr  )r  r   r)  z\/zACommand {} triggered a stop and ended transcript generation earlyr  zFailed to save transcript: {}zcommands and their outputszcommand and its outputz#{} {} saved to transcript file {!r}) r   r   r   r   r  r  r  W_OKr  r   r   r   rk   r   r'   r  r  r|  r   r   r  r  r  r  r  r   r$  r  r  r  r  r  )rC   rQ   r?  transcript_pathtranscript_dircommands_run
saved_echosaved_stdoutr  history_itemfirstr  r  r  rc  r  foutr  r&  r  rD   rD   rE   r!  @  s   

 


zCmd._generate_transcriptzRun a text editor and optionally open a file with it

The editor used is determined by a settable parameter. To set it:

  set editor (program-name)	file_pathz)optional path to a file to open in editorc                 C   s   |  |j dS )z4Run a text editor and optionally open a file with itN)r  rI  )rC   r  rD   rD   rE   do_edit  s   zCmd.do_editc                 C   sN   | j stdttj| j }|r |dttj| 7 }| | dS )z
        Run a text editor and optionally open a file with it

        :param file_path: optional path of the file to edit
        :raises: EnvironmentError if self.editor is not set
        zGPlease use 'set editor' to specify your text editing program of choice.r3  N)r   EnvironmentErrorr   r   r   r   r   r  )rC   rI  r  rD   rD   rE   r    s   zCmd._run_editorc                 C   s   | j r| j d S dS )zMAccessor to get the current script directory from the _script_dir LIFO queue.r  N)r   rB   rD   rD   rE   rk    s   
zCmd._current_script_dira7  Run commands in script file that is encoded as either ASCII or UTF-8 text

Script should contain one command per line, just like the command would be
typed in the console.

If the -t/--transcript flag is used, this command instead records
the output of the script commands to a transcript for testing purposes.
z4record the output of the script as a transcript filec                 C   sp  t jt j|j}t j|s| d| dS t j|s+| d| dS t j	|dkr5dS t
|sD| d| dS |dr]| d| | dd	}|d
kr]dS zt|dd}|  }W d   n1 suw   Y  W n ty } z| d|| W Y d}~dS d}~ww t| j}zq| jt j| |jr| |t j|j n,| |W | j |t| jkr| j  W d   S W d   S 1 sw   Y  S W | j |t| jkr| j  W d   dS W d   dS 1 sw   Y  dS | j |t| jkr'| j  W d   w W d   w 1 s2w   Y  w )zRun commands in script file that is encoded as either ASCII or UTF-8 text.

        :return: True if running of commands should stop
        z)'{}' does not exist or cannot be accessedNz'{}' is not a filer   z/'{}' is not an ASCII or UTF-8 encoded text filer   z '{}' appears to be a Python filer  z,Continue to try to run it as a text script? r  r  r$  z&Problem accessing script from '{}': {})r   r   r   r   r  r   r  r   isfilegetsizer   is_text_filer  r$  r  r  r  r  r  r  r   r   r   r  r  r!  r  r   rE  )rC   r  r  r  r   script_commandsr  orig_script_dir_countrD   rD   rE   r     sf   



, zCmd.do_run_scriptz

If this is called from within an already-running script, the filename will be
interpreted relative to the already-running script's directory.zKNotes:
  This command is intended to only be used within text file scripts.z a file path pointing to a scriptc                 C   s*   |j }tj| jp
d|}| t|S )z
        Run commands in script file that is encoded as either ASCII or UTF-8 text

        :return: True if running of commands should stop
        r>   )rI  r   r   r  rk  r   r   r   )rC   r  rI  relative_pathrD   rD   rE   do__relative_run_script  s   zCmd.do__relative_run_scripttranscript_pathsc                    s  ddl }ddl}ddl}ddlm} G  fddd|}tj|tjd}|s0 	d d	 _
dS d
tttjdd }t|}	t|dkrIdnd}
 tjtjddddd  dtj||jt  dt   dtjd   tjd|	|
dd | j_tjd gt_| }ttj}|j|d}|  }| |}|  | }|! rt"tj|#  d|	|
|}t$tj|dd} | dS |# }|%d}||d %d}|| } 	||d  d	 _
dS )a#  Runs transcript tests for provided file(s).

        This is called when either -t is provided on the command line or the transcript_files argument is provided
        during construction of the cmd2.Cmd instance.

        :param transcript_paths: list of transcript test file paths
        r   Nr   )Cmd2TestCasec                       s   e Zd Z ZdS )z0Cmd._run_transcript_tests.<locals>.TestMyAppCaseN)rH   rI   rJ   cmdapprD   rB   rD   rE   TestMyAppCase/  s    rV  )r  z%No test files found - nothing to testr  .   r>   r  z cmd2 transcript test =)	fill_charT)boldz.platform {} -- Python {}, cmd2-{}, readline-{}zcwd: {}zcmd2 app: {}zcollected {} transcript{})streamz- {0} transcript{1} passed in {2:.3f} seconds zAssertionError:zFile )&timeunittestcmd2r  rT  r   files_from_glob_patternsr   R_OKr  r   r  maprY  r   version_infor   r  r   stylealign_centerr   r   __version__r1   r  r  r   	testfilesr  r  TextTestRunnerr  wasSuccessfulr  r  style_successr  )rC   rS  r]  r^  r_  rT  rV  transcripts_expandedverinfonum_transcriptsr&  testcaser\  runner
start_timetest_resultsexecution_time
finish_msg	error_strend_of_tracefile_offsetr[  rD   rB   rE   _run_transcript_tests"  sN   



zCmd._run_transcript_tests	alert_msg
new_promptc                 C   s   t r| jsdS | jjddrud}|r|d7 }d}|dur.|| jkr.|| _| js.t| j d}|rnddl}| jr:| jn| j}t	j
| j|t t |d}ttjkr^tj| tj  nttjkrktjjj| t  | j  dS td)	a  
        Display an important message to the user while they are at a command line prompt.
        To the user it appears as if an alert message is printed above the prompt and their current input
        text and cursor location is left alone.

        Raises a `RuntimeError` if called while another thread holds `terminal_lock`.

        IMPORTANT: This function will not print an alert unless it can acquire self.terminal_lock to ensure
                   a prompt is onscreen.  Therefore it is best to acquire the lock before calling this function
                   to guarantee the alert prints and to avoid raising a RuntimeError.

        :param alert_msg: the message to display to the user
        :param new_prompt: if you also want to change the prompt that is displayed, then include it here
                           see async_update_prompt() docstring for guidance on updating a prompt
        NFblockingr~  Tr   )terminal_columnsr|  r  cursor_offsetrx  "another thread holds terminal_lock)r3   rw  r   r  r|  r   r0   shutilr   r   async_alert_strget_terminal_sizecolumnsr8   rX  r.   r1   r-   r  r   r  r  r  r  r  r  r0  r7   r  r  )rC   rx  ry  update_terminalr  current_promptterminal_strrD   rD   rE   async_alert^  s6   



zCmd.async_alertc                 C   s   |  d| dS )a  
        Update the command line prompt while the user is still typing at it. This is good for alerting the user to
        system changes dynamically in between commands. For instance you could alter the color of the prompt to
        indicate a system status or increase a counter to report an event. If you do alter the actual text of the
        prompt, it is best to keep the prompt the same width as what's on screen. Otherwise the user's input text will
        be shifted and the update will not be seamless.

        Raises a `RuntimeError` if called while another thread holds `terminal_lock`.

        IMPORTANT: This function will not update the prompt unless it can acquire self.terminal_lock to ensure
                   a prompt is onscreen.  Therefore it is best to acquire the lock before calling this function
                   to guarantee the prompt changes and to avoid raising a RuntimeError.

                   If user is at a continuation prompt while entering a multiline command, the onscreen prompt will
                   not change. However self.prompt will still be updated and display immediately after the multiline
                   line command completes.

        :param new_prompt: what to change the prompt to
        r>   N)r  )rC   ry  rD   rD   rE   async_update_prompt  s   zCmd.async_update_promptr  c                 C   s   t sdS | jjddr<z*ztjt| tj  W n	 t	y%   Y n	w W | j
  dS W | j
  dS | j
  w td)a  Set the terminal window title.

        Raises a `RuntimeError` if called while another thread holds `terminal_lock`.

        IMPORTANT: This function will not set the title unless it can acquire self.terminal_lock to avoid writing
                   to stderr while a command is running. Therefore it is best to acquire the lock before calling
                   this function to guarantee the title changes and to avoid raising a RuntimeError.

        :param title: the new window title
        NFrz  r~  )r3   r   r  r   r  r  r   set_title_strr  rz   r  r  )rC   r  rD   rD   rE   set_window_title  s   zCmd.set_window_titlec                 C   s   || j vrdS tj| }tj| }| j | }t| | ||j |jdu r+t| | nt| ||j |j	du r=t| | nt| ||j	 | j |= dS )zp
        Enable a command by restoring its functions

        :param command: the command being enabled
        N)
r   r   r   r   r%  r  rV   rW   r  rX   )rC   r  r  r  dcrD   rD   rE   r.    s   





zCmd.enable_commandr  c                 C   s<   t | jD ]}| j| j}t|tjd|kr| | qdS )zh
        Enable an entire category of commands

        :param category: the category to enable
        N)r  r   rV   r
  r   r  r.  )rC   r  r(  rR  rD   rD   rE   enable_category  s   
zCmd.enable_categorymessage_to_printc                 C   s   ddl }|| jv rdS | |}|du rtd|tj| }tj| }t|t	| |dt	| |dd| j|< |j
| j|tj|d}t| | || t| || t| |dd  dS )a  
        Disable a command and overwrite its functions

        :param command: the command being disabled
        :param message_to_print: what to print when this command is run or help is called on it while disabled

                                 The variable COMMAND_NAME can be used as a placeholder for the name of the
                                 command being disabled.
                                 ex: message_to_print = "{} is currently disabled".format(COMMAND_NAME)
        r   Nz{} does not refer to a commandrU   )r  c                  _   s   g S rN   rD   r  rD   rD   rE   r     r  z%Cmd.disable_command.<locals>.<lambda>)rE  r   r8  rz   r   r   r   r   rT   r
  rF  _report_disabled_command_usager  COMMAND_NAMEr%  r  )rC   r  r  rE  rV   r  r  new_funcrD   rD   rE   disable_command  s$   





zCmd.disable_commandc                 C   s>   |   }|D ]}| |}t|tjd|kr| || qdS )a  Disable an entire category of commands.

        :param category: the category to disable
        :param message_to_print: what to print when anything in this category is run or help is called on it
                                 while disabled. The variable COMMAND_NAME can be used as a placeholder for the name
                                 of the command being disabled.
                                 ex: message_to_print = "{} is currently disabled".format(COMMAND_NAME)
        N)r   r8  r
  r   r  r  )rC   r  r  all_commandsr(  rR  rD   rD   rE   disable_category  s   	
zCmd.disable_categoryc                O   s   | j |dd dS )z
        Report when a disabled command has been run or had help called on it

        :param args: not used
        :param message_to_print: the message reporting that the command is disabled
        :param kwargs: not used
        Fr  N)r  )rC   r  _args_kwargsrD   rD   rE   r  .  s   	z"Cmd._report_disabled_command_usageintroc                 C   s   t  t  urtdddl}||j}||j| j | j	  | j
D ]}|  q&|   | jdurA| dd | jD  n|durH|| _| jdurS| | j |   | jD ]}|  qZ|   | j  ||j| | jS )a  This is an outer wrapper around _cmdloop() which deals with extra features provided by cmd2.

        _cmdloop() provides the main loop equivalent to cmd.cmdloop().  This is a wrapper around that which deals with
        the following extra features provided by cmd2:
        - transcript testing
        - intro banner
        - exit code

        :param intro: if provided this overrides self.intro and serves as the intro banner printed once at start
        z&cmdloop must be run in the main threadr   Nc                 S   s   g | ]}t j|qS rD   )r   r   r   )r   tfrD   rD   rE   r   X  r  zCmd.cmdloop.<locals>.<listcomp>)r   current_threadmain_threadr  signal	getsignalSIGINTr  r   r  _preloop_hooksr  r   rw  r  r  r#  _postloop_hooksr  r  r   )rC   r  r  original_sigint_handlerrR  rD   rD   rE   cmdloop9  s,   





zCmd.cmdloopc                 C   s(   g | _ g | _g | _g | _g | _g | _dS )zInitialize the plugin systemN)r  r  r  r  r  r  rB   rD   rD   rE   r{   x  s   
zCmd._initialize_plugin_systemrR  countc                 C   s4   t |}t|j}||krtd|j||dS )z5Ensure a function has the given number of parameters.z+{} has {} positional arguments, expected {}N)r   r   r   r   	TypeErrorr   rH   )clsrR  r  r   nparamrD   rD   rE   _validate_callable_param_count  s   

z"Cmd._validate_callable_param_countc                 C   s4   |  |d t|}|jdurtd|jdS )z@Check parameter and return types for preloop and postloop hooks.r   Nz.{} must declare return a return type of 'None')r  r   r   return_annotationr  r   rH   )r  rR  r   rD   rD   rE   _validate_prepostloop_callable  s   

z"Cmd._validate_prepostloop_callablec                 C      |  | | j| dS )zFRegister a function to be called at the beginning of the command loop.N)r  r  r   rC   rR  rD   rD   rE   register_preloop_hook     
zCmd.register_preloop_hookc                 C   r  )z@Register a function to be called at the end of the command loop.N)r  r  r   r  rD   rD   rE   register_postloop_hook  r  zCmd.register_postloop_hookc                 C   sh   |  |d t|}t|j d \}}|jtjkr$t	d
|j|jtjkr2t	d
|jdS )z6Check parameter and return types for postparsing hooksr   r   zK{} must have one parameter declared with type 'cmd2.plugin.PostparsingData'zE{} must declare return a return type of 'cmd2.plugin.PostparsingData'N)r  r   r   r  r   r  
annotationr   r  r  r   rH   r  r  rR  r   r  r  rD   rD   rE   _validate_postparsing_callable  s   
z"Cmd._validate_postparsing_callablec                 C   r  )zXRegister a function to be called after parsing user input but before running the commandN)r  r  r   r  rD   rD   rE   register_postparsing_hook  r  zCmd.register_postparsing_hook	data_typec                 C   s   t |}| |d t|j d }|j| }|j|kr)td|j	|j||j
|jkr8td|j	||j
|krHtd|j	|j
|dS )z@Check parameter and return types for pre and post command hooks.r   r   z6argument 1 of {} has incompatible type {}, expected {}z4{} does not have a declared return type, expected {}z/{} has incompatible return type {}, expected {}N)r   r   r  r  r   r  r  r  r   rH   r  empty)r  rR  r  r   	paramnamer  rD   rD   rE   _validate_prepostcmd_hook  s,   



zCmd._validate_prepostcmd_hookc                 C      |  |tj | j| dS )z9Register a hook to be called before the command function.N)r  r   r  r  r   r  rD   rD   rE   register_precmd_hook     zCmd.register_precmd_hookc                 C   r  )z8Register a hook to be called after the command function.N)r  r   r  r  r   r  rD   rD   rE   register_postcmd_hook  r  zCmd.register_postcmd_hookc                 C   sp   |  |d t|}t|j d \}}|jtjkr&t	d
|jtj|jtjkr6t	d
|jtjdS )z@Check parameter and return types for command finalization hooks.r   r   z0{} must have one parameter declared with type {}z*{} must declare return a return type of {}N)r  r   r   r  r   r  r  r   r  r  r   rH   r  r  rD   rD   rE   "_validate_cmdfinalization_callable  s   


z&Cmd._validate_cmdfinalization_callablec                 C   r  )zdRegister a hook to be called after a command is completed, whether it completes successfully or not.N)r  r  r   r  rD   rD   rE   register_cmdfinalization_hook  s   
z!Cmd.register_cmdfinalization_hookcmd_support_funccmd_selfc                 C   s   t |}|durDt|trDt||r|}|S d}g }| jD ]}t||kr)|} nt||r3|| q|du rBt|dkrB|d }|S | S )a  
        Attempt to resolve a candidate instance to pass as 'self' for an unbound class method that was
        used when defining command's argparse object. Since we restrict registration to only a single CommandSet
        instance of each type, using type is a reasonably safe way to resolve the correct object instance

        :param cmd_support_func: command support function. This could be a completer or namespace provider
        :param cmd_self: The `self` associated with the command or sub-command
        :return:
        Nr   r   )r6   
issubclassr   r   r   r   r   r   )rC   r  r  
func_class	func_selfcandidate_setsinstalled_cmd_setrD   rD   rE   _resolve_func_self  s$   
	


zCmd._resolve_func_self)rZ   NN)ri   N)r>   )F)r  rN   )rH   rI   rJ   rK   r   find_editorr   INTERNAL_COMMAND_EPILOG	norm_foldr   natural_keysNATURAL_SORT_KEYrY  rt  rs  r   r	   r   r   r   rF   r   r   r   r   r   r   r  r  r  r/  r,  r   r   r-  r5   rk  rn  r   propertyro  setterry  r}  r   r  r  r$  r  r  r  r  r   r  r  r  r
   r  r	  r  r  staticmethodr  r!  r  r  rU  rd  r   r   rG  r  r  r#  rn  r   rw  r   r{  r  r  r\  r  r  r*   r  r  r  r  r  r  r  r'   r  r  r  r  r  r  r  r8  r  r  r  r  r  r=   r  r   r#  alias_descriptionalias_epilogr   alias_parseradd_subparsersalias_subparsersrequiredr   	Namespacer-  alias_create_descriptionalias_create_epilogalias_create_parserr   	REMAINDERr   r  r<  alias_delete_helpalias_delete_descriptionalias_delete_parserZERO_OR_MORErE  alias_list_helpalias_list_descriptionalias_list_parserrP  macro_descriptionmacro_epilogmacro_parsermacro_subparsersrQ  macro_create_helpmacro_create_descriptionmacro_create_epilogmacro_create_parserrd  macro_delete_helpmacro_delete_descriptionmacro_delete_parserre  macro_list_helpmacro_list_descriptionmacro_list_parserrf  ri  rm  help_parserOPTIONALr
  cmdrY   r  rs  rq  ry  r{  shortcuts_parserr  
eof_parserr  quit_parserr  r  r  set_descriptionr  
set_parserr  shell_parserr  r  r   rM   r  r  py_description	py_parserr  run_pyscript_parserr  ipython_availableipython_parserry   history_descriptionr  add_mutually_exclusive_grouphistory_action_groupadd_argument_grouphistory_format_grouphistory_arg_helpr(  r  r   r8  r!  edit_descriptionedit_parserrJ  r  rk  run_script_descriptionrun_script_parserr   relative_run_script_descriptionrelative_run_script_epilogrelative_run_script_parserrR  rw  r  r  r  r.  r  r  r  r  r  r{   classmethodr  r  r  r  r   r  r  r  r  r  r  r  r  r  r  r  objectr  __classcell__rD   rD   r   rE   rY      s   




  $(;$g.	 
&&""=*?
?
,
.
 
&Q$
6
 #a




p
?.-e$
L#*

"(
#


Q&#	#&L*6
8
A&	
0v" ,SI*V:&<< ' ?	 $"
"(& &&
rY   )krK   r   r  r  r   r   r1  rt  rS  r   r   coder   collectionsr   
contextlibr   typingr   r   r   r   r	   r
   r   r   r   r   r>   r   r   r   r   argparse_customr   r   	clipboardr   r   r   command_definitionr   r   r   r   r   
decoratorsr   r   
exceptionsr    r!   r"   r#   r$   r%   rQ   r&   r'   parsingr(   r)   r*   r+   r,   rl_utilsr-   r.   r/   r0   r1   r2   r3   r4   r5   r6   rx  r  r  r  r7   r8   r  r  r  r  r  r  r1  r  r(  r9   r)  in_dllr:   r  r  r~  r  r  IPythonr;   r3  r=   rM   rT   rY   rD   rD   rD   rE   <module>   s^   0 $	

	