Skip to content

Commit fd60e40

Browse files
authored
Merge pull request #434 from python-cmd2/fix_redirection
Fix unexpected redirection behavior
2 parents eb8181e + 5aa4eb1 commit fd60e40

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

cmd2/cmd2.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import cmd
3434
import collections
3535
from colorama import Fore
36-
import copy
3736
import glob
3837
import os
3938
import platform
@@ -498,10 +497,11 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, persistent_histor
498497
# An optional header that prints above the tab-completion suggestions
499498
self.completion_header = ''
500499

501-
# If the tab-completion suggestions should be displayed in a way that is different than the actual match values,
502-
# then place those results in this list. The full matches still must be returned from your completer function.
503-
# For an example, look at path_complete() which uses this to show only the basename of paths as the
504-
# suggestions. delimiter_complete() also populates this list.
500+
# Use this list if you are completing strings that contain a common delimiter and you only want to
501+
# display the final portion of the matches as the tab-completion suggestions. The full matches
502+
# still must be returned from your completer function. For an example, look at path_complete()
503+
# which uses this to show only the basename of paths as the suggestions. delimiter_complete() also
504+
# populates this list.
505505
self.display_matches = []
506506

507507
# Used by functions like path_complete() and delimiter_complete() to properly
@@ -692,6 +692,7 @@ def tokens_for_completion(self, line, begidx, endidx):
692692
On Failure
693693
Both items are None
694694
"""
695+
import copy
695696
unclosed_quote = ''
696697
quotes_to_try = copy.copy(constants.QUOTES)
697698

@@ -1330,7 +1331,7 @@ def complete(self, text, state):
13301331
# from text and update the indexes. This only applies if we are at the the beginning of the line.
13311332
shortcut_to_restore = ''
13321333
if begidx == 0:
1333-
for (shortcut, expansion) in self.shortcuts:
1334+
for (shortcut, _) in self.shortcuts:
13341335
if text.startswith(shortcut):
13351336
# Save the shortcut to restore later
13361337
shortcut_to_restore = shortcut
@@ -1439,6 +1440,7 @@ def complete(self, text, state):
14391440
# Since self.display_matches is empty, set it to self.completion_matches
14401441
# before we alter them. That way the suggestions will reflect how we parsed
14411442
# the token being completed and not how readline did.
1443+
import copy
14421444
self.display_matches = copy.copy(self.completion_matches)
14431445

14441446
# Check if we need to add an opening quote
@@ -1855,7 +1857,7 @@ def _redirect_output(self, statement):
18551857
if statement.output == constants.REDIRECTION_APPEND:
18561858
mode = 'a'
18571859
try:
1858-
sys.stdout = self.stdout = open(os.path.expanduser(statement.output_to), mode)
1860+
sys.stdout = self.stdout = open(statement.output_to, mode)
18591861
except OSError as ex:
18601862
self.perror('Not Redirecting because - {}'.format(ex), traceback_war=False)
18611863
self.redirecting = False
@@ -2384,7 +2386,7 @@ def select(self, opts, prompt='Your choice? '):
23842386
fulloptions.append((opt[0], opt[1]))
23852387
except IndexError:
23862388
fulloptions.append((opt[0], opt[0]))
2387-
for (idx, (value, text)) in enumerate(fulloptions):
2389+
for (idx, (_, text)) in enumerate(fulloptions):
23882390
self.poutput(' %2d. %s\n' % (idx + 1, text))
23892391
while True:
23902392
response = input(prompt)

cmd2/parsing.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33
"""Statement parsing classes for cmd2"""
44

5+
import os
56
import re
67
import shlex
78
from typing import List, Tuple
@@ -38,7 +39,7 @@ class Statement(str):
3839
from the elements of the list, and aliases and shortcuts
3940
are expanded
4041
:type argv: list
41-
:var terminator: the charater which terminated the multiline command, if
42+
:var terminator: the character which terminated the multiline command, if
4243
there was one
4344
:type terminator: str or None
4445
:var suffix: characters appearing after the terminator but before output
@@ -49,7 +50,7 @@ class Statement(str):
4950
:type pipe_to: list
5051
:var output: if output was redirected, the redirection token, i.e. '>>'
5152
:type output: str or None
52-
:var output_to: if output was redirected, the destination, usually a filename
53+
:var output_to: if output was redirected, the destination file
5354
:type output_to: str or None
5455
5556
"""
@@ -297,6 +298,11 @@ def parse(self, rawinput: str) -> Statement:
297298
pipe_pos = tokens.index(constants.REDIRECTION_PIPE)
298299
# save everything after the first pipe as tokens
299300
pipe_to = tokens[pipe_pos+1:]
301+
302+
for pos, cur_token in enumerate(pipe_to):
303+
unquoted_token = utils.strip_quotes(cur_token)
304+
pipe_to[pos] = os.path.expanduser(unquoted_token)
305+
300306
# remove all the tokens after the pipe
301307
tokens = tokens[:pipe_pos]
302308
except ValueError:
@@ -309,7 +315,12 @@ def parse(self, rawinput: str) -> Statement:
309315
try:
310316
output_pos = tokens.index(constants.REDIRECTION_OUTPUT)
311317
output = constants.REDIRECTION_OUTPUT
312-
output_to = ' '.join(tokens[output_pos+1:])
318+
319+
# Check if we are redirecting to a file
320+
if len(tokens) > output_pos + 1:
321+
unquoted_path = utils.strip_quotes(tokens[output_pos + 1])
322+
output_to = os.path.expanduser(unquoted_path)
323+
313324
# remove all the tokens after the output redirect
314325
tokens = tokens[:output_pos]
315326
except ValueError:
@@ -318,7 +329,12 @@ def parse(self, rawinput: str) -> Statement:
318329
try:
319330
output_pos = tokens.index(constants.REDIRECTION_APPEND)
320331
output = constants.REDIRECTION_APPEND
321-
output_to = ' '.join(tokens[output_pos+1:])
332+
333+
# Check if we are redirecting to a file
334+
if len(tokens) > output_pos + 1:
335+
unquoted_path = utils.strip_quotes(tokens[output_pos + 1])
336+
output_to = os.path.expanduser(unquoted_path)
337+
322338
# remove all tokens after the output redirect
323339
tokens = tokens[:output_pos]
324340
except ValueError:

0 commit comments

Comments
 (0)