Skip to content

Commit 23824e8

Browse files
committed
Fix transcript generate to close #385
1 parent bf72952 commit 23824e8

File tree

3 files changed

+41
-18
lines changed

3 files changed

+41
-18
lines changed

cmd2/cmd2.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3002,45 +3002,65 @@ def do_history(self, args):
30023002
except Exception as e:
30033003
self.perror('Saving {!r} - {}'.format(args.output_file, e), traceback_war=False)
30043004
elif args.transcript:
3005-
membuf = io.StringIO()
3006-
3007-
# Make sure echo is on so commands print to standard out
3005+
# Save the current echo state, and turn it off. We inject commands into the
3006+
# output using a different mechanism
30083007
saved_echo = self.echo
30093008
self.echo = False
30103009

30113010
# Redirect stdout to the transcript file
30123011
saved_self_stdout = self.stdout
3013-
self.stdout = membuf
30143012

3015-
# Run all of the commands in the history with output redirected to transcript and echo on
3013+
# The problem with supporting regular expressions in transcripts
3014+
# is that they shouldn't be processed in the command, just the output.
3015+
# In addition, when we generate a transcript, any slashes in the output
3016+
# are not really intended to indicate regular expressions, so they should
3017+
# be escaped.
3018+
#
3019+
# We have to jump through some hoops here in order to catch the commands
3020+
# separately from the output and escape the slashes in the output.
3021+
transcript = ''
30163022
for history_item in history:
3017-
# write the command to the output stream
3023+
# build the command, complete with prompts. When we replay
3024+
# the transcript, it looks for the prompts to separate
3025+
# the command from the output
30183026
first = True
3027+
command = ''
30193028
for line in history_item.splitlines():
30203029
if first:
3021-
self.stdout.write('{}{}\n'.format(self.prompt, line))
3030+
command += '{}{}\n'.format(self.prompt, line)
30223031
first = False
30233032
else:
3024-
self.stdout.write('{}{}\n'.format(self.continuation_prompt, line))
3033+
command += '{}{}\n'.format(self.continuation_prompt, line)
3034+
transcript += command
3035+
# create a new string buffer and set it to stdout to catch the output
3036+
# of the command
3037+
membuf = io.StringIO()
3038+
self.stdout = membuf
3039+
# then run the command and let the output go into our buffer
30253040
self.onecmd_plus_hooks(history_item)
3041+
# rewind the buffer to the beginning
3042+
membuf.seek(0)
3043+
# get the output out of the buffer
3044+
output = membuf.read()
3045+
# and add the regex-escaped output to the transcript
3046+
transcript += output.replace('/', '\/')
30263047

30273048
# Restore stdout to its original state
3028-
#self.stdout.close()
30293049
self.stdout = saved_self_stdout
3030-
30313050
# Set echo back to its original state
30323051
self.echo = saved_echo
30333052

3034-
# Post-process the file to escape un-escaped "/" regex escapes
3035-
membuf.seek(0)
3036-
data = membuf.read()
3037-
post_processed_data = data.replace('/', '\/')
3053+
# finally, we can write the transcript out to the file
30383054
with open(args.transcript, 'w') as fout:
3039-
fout.write(post_processed_data)
3055+
fout.write(transcript)
30403056

3041-
plural = 's' if len(history) > 1 else ''
3042-
self.pfeedback('{} command{} and outputs saved to transcript file {!r}'.format(len(history), plural,
3043-
args.transcript))
3057+
# and let the user know what we did
3058+
if len(history) > 1:
3059+
plural = 'commands and their outputs'
3060+
else:
3061+
plural = 'command and its output'
3062+
msg = '{} {} saved to transcript file {!r}'
3063+
self.pfeedback(msg.format(len(history), plural, args.transcript))
30443064
else:
30453065
# Display the history items retrieved
30463066
for hi in history:

tests/test_transcript.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ def test_history_transcript(request, capsys):
131131
app.stdout = StdOut()
132132
run_cmd(app, 'help')
133133
run_cmd(app, 'orate this is\na multiline\ncommand;\n')
134+
run_cmd(app, 'speak /tmp/file.txt is not a regex')
134135

135136
# Get location of the expected transcript
136137
test_dir = os.path.dirname(request.module.__file__)

tests/transcripts/expected_history.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ edit history mumble py quit set shortcuts unalias
1616
> a multiline
1717
> command;
1818
this is a multiline command
19+
(Cmd) speak /tmp/file.txt is not a regex
20+
\/tmp\/file.txt is not a regex

0 commit comments

Comments
 (0)