diff options
author | Todd Leonhardt <todd.leonhardt@gmail.com> | 2018-06-07 17:14:54 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-07 17:14:54 -0700 |
commit | fd60e40bf96e06ff9410f71acbadfb43e3527dfd (patch) | |
tree | 4feb462ba0ca571b6c24427dd7d1b7f5554ddd71 | |
parent | eb8181e7d3f900cecd1455efd75f3b5c5f6918cd (diff) | |
parent | 5aa4eb17954f046a284fb2a81d5d5abd6adc11df (diff) | |
download | cmd2-git-fd60e40bf96e06ff9410f71acbadfb43e3527dfd.tar.gz |
Merge pull request #434 from python-cmd2/fix_redirection
Fix unexpected redirection behavior
-rw-r--r-- | cmd2/cmd2.py | 18 | ||||
-rw-r--r-- | cmd2/parsing.py | 24 |
2 files changed, 30 insertions, 12 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index bb4ac4ad..d0d8352c 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -33,7 +33,6 @@ import argparse import cmd import collections from colorama import Fore -import copy import glob import os import platform @@ -498,10 +497,11 @@ class Cmd(cmd.Cmd): # An optional header that prints above the tab-completion suggestions self.completion_header = '' - # If the tab-completion suggestions should be displayed in a way that is different than the actual match values, - # then place those results in this list. The full matches still must be returned from your completer function. - # For an example, look at path_complete() which uses this to show only the basename of paths as the - # suggestions. delimiter_complete() also populates this list. + # Use this list if you are completing strings that contain a common delimiter and you only want to + # display the final portion of the matches as the tab-completion suggestions. The full matches + # still must be returned from your completer function. For an example, look at path_complete() + # which uses this to show only the basename of paths as the suggestions. delimiter_complete() also + # populates this list. self.display_matches = [] # Used by functions like path_complete() and delimiter_complete() to properly @@ -692,6 +692,7 @@ class Cmd(cmd.Cmd): On Failure Both items are None """ + import copy unclosed_quote = '' quotes_to_try = copy.copy(constants.QUOTES) @@ -1330,7 +1331,7 @@ class Cmd(cmd.Cmd): # from text and update the indexes. This only applies if we are at the the beginning of the line. shortcut_to_restore = '' if begidx == 0: - for (shortcut, expansion) in self.shortcuts: + for (shortcut, _) in self.shortcuts: if text.startswith(shortcut): # Save the shortcut to restore later shortcut_to_restore = shortcut @@ -1439,6 +1440,7 @@ class Cmd(cmd.Cmd): # Since self.display_matches is empty, set it to self.completion_matches # before we alter them. That way the suggestions will reflect how we parsed # the token being completed and not how readline did. + import copy self.display_matches = copy.copy(self.completion_matches) # Check if we need to add an opening quote @@ -1855,7 +1857,7 @@ class Cmd(cmd.Cmd): if statement.output == constants.REDIRECTION_APPEND: mode = 'a' try: - sys.stdout = self.stdout = open(os.path.expanduser(statement.output_to), mode) + sys.stdout = self.stdout = open(statement.output_to, mode) except OSError as ex: self.perror('Not Redirecting because - {}'.format(ex), traceback_war=False) self.redirecting = False @@ -2384,7 +2386,7 @@ Usage: Usage: unalias [-a] name [name ...] fulloptions.append((opt[0], opt[1])) except IndexError: fulloptions.append((opt[0], opt[0])) - for (idx, (value, text)) in enumerate(fulloptions): + for (idx, (_, text)) in enumerate(fulloptions): self.poutput(' %2d. %s\n' % (idx + 1, text)) while True: response = input(prompt) diff --git a/cmd2/parsing.py b/cmd2/parsing.py index 655e0c58..8d59aedb 100644 --- a/cmd2/parsing.py +++ b/cmd2/parsing.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- """Statement parsing classes for cmd2""" +import os import re import shlex from typing import List, Tuple @@ -38,7 +39,7 @@ class Statement(str): from the elements of the list, and aliases and shortcuts are expanded :type argv: list - :var terminator: the charater which terminated the multiline command, if + :var terminator: the character which terminated the multiline command, if there was one :type terminator: str or None :var suffix: characters appearing after the terminator but before output @@ -49,7 +50,7 @@ class Statement(str): :type pipe_to: list :var output: if output was redirected, the redirection token, i.e. '>>' :type output: str or None - :var output_to: if output was redirected, the destination, usually a filename + :var output_to: if output was redirected, the destination file :type output_to: str or None """ @@ -297,6 +298,11 @@ class StatementParser: pipe_pos = tokens.index(constants.REDIRECTION_PIPE) # save everything after the first pipe as tokens pipe_to = tokens[pipe_pos+1:] + + for pos, cur_token in enumerate(pipe_to): + unquoted_token = utils.strip_quotes(cur_token) + pipe_to[pos] = os.path.expanduser(unquoted_token) + # remove all the tokens after the pipe tokens = tokens[:pipe_pos] except ValueError: @@ -309,7 +315,12 @@ class StatementParser: try: output_pos = tokens.index(constants.REDIRECTION_OUTPUT) output = constants.REDIRECTION_OUTPUT - output_to = ' '.join(tokens[output_pos+1:]) + + # Check if we are redirecting to a file + if len(tokens) > output_pos + 1: + unquoted_path = utils.strip_quotes(tokens[output_pos + 1]) + output_to = os.path.expanduser(unquoted_path) + # remove all the tokens after the output redirect tokens = tokens[:output_pos] except ValueError: @@ -318,7 +329,12 @@ class StatementParser: try: output_pos = tokens.index(constants.REDIRECTION_APPEND) output = constants.REDIRECTION_APPEND - output_to = ' '.join(tokens[output_pos+1:]) + + # Check if we are redirecting to a file + if len(tokens) > output_pos + 1: + unquoted_path = utils.strip_quotes(tokens[output_pos + 1]) + output_to = os.path.expanduser(unquoted_path) + # remove all tokens after the output redirect tokens = tokens[:output_pos] except ValueError: |