@@ -1052,7 +1052,9 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, persistent_histor
10521052
10531053 # If a startup script is provided, then add it in the queue to load
10541054 if startup_script is not None :
1055- self .cmdqueue .append ('load {}' .format (startup_script ))
1055+ startup_script = os .path .expanduser (startup_script )
1056+ if os .path .exists (startup_script ) and os .path .getsize (startup_script ) > 0 :
1057+ self .cmdqueue .append ('load {}' .format (startup_script ))
10561058
10571059 ############################################################################################################
10581060 # The following variables are used by tab-completion functions. They are reset each time complete() is run
@@ -2105,9 +2107,9 @@ def complete(self, text, state):
21052107
21062108 else :
21072109 # Complete token against aliases and command names
2108- alias_names = list (self .aliases .keys ())
2109- visible_commands = self .get_visible_commands ()
2110- strs_to_match = alias_names + visible_commands
2110+ alias_names = set (self .aliases .keys ())
2111+ visible_commands = set ( self .get_visible_commands () )
2112+ strs_to_match = list ( alias_names | visible_commands )
21112113 self .completion_matches = self .basic_complete (text , line , begidx , endidx , strs_to_match )
21122114
21132115 # Handle single result
@@ -2305,13 +2307,24 @@ def parseline(self, line):
23052307 # Deal with empty line or all whitespace line
23062308 return None , None , line
23072309
2308- # Handle aliases
2309- for cur_alias in self .aliases :
2310- if line == cur_alias or line .startswith (cur_alias + ' ' ):
2311- line = line .replace (cur_alias , self .aliases [cur_alias ], 1 )
2312- break
2310+ # Make a copy of aliases so we can edit it
2311+ tmp_aliases = list (self .aliases .keys ())
2312+ keep_expanding = len (tmp_aliases ) > 0
2313+
2314+ # Expand aliases
2315+ while keep_expanding :
2316+ for cur_alias in tmp_aliases :
2317+ keep_expanding = False
23132318
2314- # Expand command shortcuts to the full command name
2319+ if line == cur_alias or line .startswith (cur_alias + ' ' ):
2320+ line = line .replace (cur_alias , self .aliases [cur_alias ], 1 )
2321+
2322+ # Do not expand the same alias more than once
2323+ tmp_aliases .remove (cur_alias )
2324+ keep_expanding = len (tmp_aliases ) > 0
2325+ break
2326+
2327+ # Expand command shortcut to its full command name
23152328 for (shortcut , expansion ) in self .shortcuts :
23162329 if line .startswith (shortcut ):
23172330 # If the next character after the shortcut isn't a space, then insert one
@@ -2734,33 +2747,48 @@ def _cmdloop(self):
27342747 def do_alias (self , arglist ):
27352748 """Define or display aliases
27362749
2737- Usage: Usage: alias [<name> <value>]
2750+ Usage: Usage: alias [name] | [ <name> <value>]
27382751 Where:
2739- name - name of the alias being added or edited
2740- value - what the alias will be resolved to
2752+ name - name of the alias being looked up, added, or replaced
2753+ value - what the alias will be resolved to (if adding or replacing)
27412754 this can contain spaces and does not need to be quoted
27422755
27432756 Without arguments, 'alias' prints a list of all aliases in a reusable form which
27442757 can be outputted to a startup_script to preserve aliases across sessions.
27452758
2759+ With one argument, 'alias' shows the value of the specified alias.
2760+ Example: alias ls (Prints the value of the alias called 'ls' if it exists)
2761+
2762+ With two or more arguments, 'alias' creates or replaces an alias.
2763+
27462764 Example: alias ls !ls -lF
2765+
2766+ If you want to use redirection or pipes in the alias, then either quote the tokens with these
2767+ characters or quote the entire alias value.
2768+
2769+ Examples:
2770+ alias save_results print_results ">" out.txt
2771+ alias save_results print_results "> out.txt"
2772+ alias save_results "print_results > out.txt"
27472773"""
27482774 # If no args were given, then print a list of current aliases
27492775 if len (arglist ) == 0 :
27502776 for cur_alias in self .aliases :
27512777 self .poutput ("alias {} {}" .format (cur_alias , self .aliases [cur_alias ]))
27522778
2779+ # The user is looking up an alias
2780+ elif len (arglist ) == 1 :
2781+ name = arglist [0 ]
2782+ if name in self .aliases :
2783+ self .poutput ("alias {} {}" .format (name , self .aliases [name ]))
2784+ else :
2785+ self .perror ("Alias {!r} not found" .format (name ), traceback_war = False )
2786+
27532787 # The user is creating an alias
2754- elif len ( arglist ) >= 2 :
2788+ else :
27552789 name = arglist [0 ]
27562790 value = ' ' .join (arglist [1 :])
27572791
2758- # Make sure the alias does not match an existing command
2759- cmd_func = self ._func_named (name )
2760- if cmd_func is not None :
2761- self .perror ("Alias names cannot match an existing command: {!r}" .format (name ), traceback_war = False )
2762- return
2763-
27642792 # Check for a valid name
27652793 for cur_char in name :
27662794 if cur_char not in self .identchars :
@@ -2770,10 +2798,7 @@ def do_alias(self, arglist):
27702798
27712799 # Set the alias
27722800 self .aliases [name ] = value
2773- self .poutput ("Alias created" )
2774-
2775- else :
2776- self .do_help ('alias' )
2801+ self .poutput ("Alias {!r} created" .format (name ))
27772802
27782803 def complete_alias (self , text , line , begidx , endidx ):
27792804 """ Tab completion for alias """
@@ -3698,16 +3723,35 @@ def parsed(self, raw):
36983723 s = self .input_source_parser .transformString (s .lstrip ())
36993724 s = self .commentGrammars .transformString (s )
37003725
3701- # Handle aliases
3702- for cur_alias in self .aliases :
3703- if s == cur_alias or s .startswith (cur_alias + ' ' ):
3704- s = s .replace (cur_alias , self .aliases [cur_alias ], 1 )
3705- break
3726+ # Make a copy of aliases so we can edit it
3727+ tmp_aliases = list (self .aliases .keys ())
3728+ keep_expanding = len (tmp_aliases ) > 0
37063729
3730+ # Expand aliases
3731+ while keep_expanding :
3732+ for cur_alias in tmp_aliases :
3733+ keep_expanding = False
3734+
3735+ if s == cur_alias or s .startswith (cur_alias + ' ' ):
3736+ s = s .replace (cur_alias , self .aliases [cur_alias ], 1 )
3737+
3738+ # Do not expand the same alias more than once
3739+ tmp_aliases .remove (cur_alias )
3740+ keep_expanding = len (tmp_aliases ) > 0
3741+ break
3742+
3743+ # Expand command shortcut to its full command name
37073744 for (shortcut , expansion ) in self .shortcuts :
37083745 if s .startswith (shortcut ):
3709- s = s .replace (shortcut , expansion + ' ' , 1 )
3746+ # If the next character after the shortcut isn't a space, then insert one
3747+ shortcut_len = len (shortcut )
3748+ if len (s ) == shortcut_len or s [shortcut_len ] != ' ' :
3749+ expansion += ' '
3750+
3751+ # Expand the shortcut
3752+ s = s .replace (shortcut , expansion , 1 )
37103753 break
3754+
37113755 try :
37123756 result = self .main_parser .parseString (s )
37133757 except pyparsing .ParseException :
0 commit comments