summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJared Crapo <jared@kotfu.net>2017-08-23 15:40:57 -0600
committerJared Crapo <jared@kotfu.net>2017-08-23 15:40:57 -0600
commitdde0b697b15cda29538251467c0f384c819778af (patch)
treee59dcce6a9bd4afc95725057ebeed52f0b89f885
parent64e19334cf6aac8edeecf8e7f8725d00da758ee5 (diff)
downloadcmd2-git-dde0b697b15cda29538251467c0f384c819778af.tar.gz
Prompt and line now properly echoed on tty and pipe
if we are on a pipe, we have to echo the prompt only after we read and are not at EOF.
-rwxr-xr-xcmd2.py38
-rw-r--r--tests/test_cmd2.py51
2 files changed, 79 insertions, 10 deletions
diff --git a/cmd2.py b/cmd2.py
index 2b99a7ab..7fde6d14 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -970,25 +970,45 @@ class Cmd(cmd.Cmd):
return result
def pseudo_raw_input(self, prompt):
- """copied from cmd's cmdloop; like raw_input, but accounts for changed stdin, stdout"""
+ """
+ began life as a copy of cmd's cmdloop; like raw_input but
+
+ - accounts for changed stdin, stdout
+ - if input is a pipe (instead of a tty), look at self.echo
+ to decide whether to print the prompt and the input
+ """
# Deal with the vagaries of readline and ANSI escape codes
safe_prompt = self._surround_ansi_escapes(prompt)
if self.use_rawinput:
try:
- line = sm.input(safe_prompt)
+ if sys.stdin.isatty():
+ sys.stdout.write(safe_prompt)
+ line = sm.input()
+ else:
+ line = sm.input()
+ if self.echo:
+ sys.stdout.write('{}{}\n'.format(safe_prompt,line))
except EOFError:
line = 'eof'
else:
- self.poutput(safe_prompt, end='')
- self.stdout.flush()
- line = self.stdin.readline()
- if not len(line):
- line = 'eof'
+ if self.stdin.isatty():
+ # on a tty, print the prompt first, then read the line
+ self.poutput(safe_prompt, end='')
+ self.stdout.flush()
+ line = self.stdin.readline()
else:
- line = line.rstrip('\r\n')
-
+ # we are reading from a pipe, read the line to see if there is
+ # anything there, if so, then decide whether to print the
+ # prompt or not
+ line = self.stdin.readline()
+ if len(line):
+ # we read something, output the prompt and the something
+ if self.echo:
+ self.poutput('{}{}'.format(safe_prompt, line))
+ else:
+ line = 'eof'
return line.strip()
def _cmdloop(self):
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index dcbb99f7..16a86530 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -7,6 +7,7 @@ Released under MIT license, see LICENSE file
"""
import os
import sys
+import io
import tempfile
import mock
@@ -849,6 +850,7 @@ def test_cmdloop_without_rawinput():
# Create a cmd2.Cmd() instance and make sure basic settings are like we want for test
app = cmd2.Cmd()
app.use_rawinput = False
+ app.echo = False
app.intro = 'Hello World, this is an intro ...'
app.stdout = StdOut()
@@ -858,7 +860,7 @@ def test_cmdloop_without_rawinput():
# Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args
testargs = ["prog"]
- expected = app.intro + '\n{}'.format(app.prompt)
+ expected = app.intro + '\n'
with mock.patch.object(sys, 'argv', testargs):
# Run the command loop
app.cmdloop()
@@ -1388,7 +1390,54 @@ def test_echo(capsys):
assert app._current_script_dir is None
assert out.startswith('{}{}\n'.format(app.prompt, command) + 'history [arg]: lists past commands issued')
+#@pytest.mark.parametrize('rawinput', [True, False])
+def test_piped_input_echo_false(capsys):
+ command = 'set'
+
+ # hack up stdin
+ fakein = io.StringIO(command)
+ #realin = sys.stdin
+ #sys.stdin = fakein
+
+ # run the cmdloop, which should pull input from stdin
+ app = cmd2.Cmd(stdin=fakein)
+ app.use_rawinput = False
+ app.echo = False
+ app.abbrev = False
+ app._cmdloop()
+ out, err = capsys.readouterr()
+
+ # put stdin back
+ #sys.stdin = realin
+
+ firstline = out.splitlines()[0]
+ assert firstline == 'abbrev: False'
+ assert not '{}{}'.format(app.prompt, command) in out
+
+#@pytest.mark.parametrize('rawinput', [True, False])
+def test_piped_input_echo_true(capsys):
+ command = 'set'
+
+ # hack up stdin
+ fakein = io.StringIO(command)
+ # realin = sys.stdin
+ # sys.stdin = fakein
+
+ # run the cmdloop, which should pull input from stdin
+ app = cmd2.Cmd(stdin=fakein)
+ app.use_rawinput = False
+ app.echo = True
+ app.abbrev = False
+ app._cmdloop()
+ out, err = capsys.readouterr()
+
+ # put stdin back
+ # sys.stdin = realin
+ out = out.splitlines()
+ assert out[0] == '{}{}'.format(app.prompt, command)
+ assert out[1] == 'abbrev: False'
+
def test_raw_input(base_app):
base_app.use_raw_input = True
fake_input = 'quit'