Skip to content

Commit 7ef96d3

Browse files
committed
Do not asynchronously update continuation prompts
1 parent 11bc029 commit 7ef96d3

File tree

1 file changed

+26
-16
lines changed

1 file changed

+26
-16
lines changed

cmd2/cmd2.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,9 @@ def __init__(self, completekey: str='tab', stdin=None, stdout=None, persistent_h
457457
# Used to keep track of whether we are redirecting or piping output
458458
self.redirecting = False
459459

460+
# Used to keep track of whether a continuation prompt is being displayed
461+
self.at_continuation_prompt = False
462+
460463
# If this string is non-empty, then this warning message will print if a broken pipe error occurs while printing
461464
self.broken_pipe_warning = ''
462465

@@ -1845,6 +1848,7 @@ def _complete_statement(self, line: str) -> Statement:
18451848
# - a multiline command with unclosed quotation marks
18461849
if not self.quit_on_sigint:
18471850
try:
1851+
self.at_continuation_prompt = True
18481852
newline = self.pseudo_raw_input(self.continuation_prompt)
18491853
if newline == 'eof':
18501854
# they entered either a blank line, or we hit an EOF
@@ -1858,8 +1862,13 @@ def _complete_statement(self, line: str) -> Statement:
18581862
self.poutput('^C')
18591863
statement = self.statement_parser.parse('')
18601864
break
1865+
finally:
1866+
self.at_continuation_prompt = False
18611867
else:
1868+
self.at_continuation_prompt = True
18621869
newline = self.pseudo_raw_input(self.continuation_prompt)
1870+
self.at_continuation_prompt = False
1871+
18631872
if newline == 'eof':
18641873
# they entered either a blank line, or we hit an EOF
18651874
# for some other reason. Turn the literal 'eof'
@@ -2074,11 +2083,6 @@ def pseudo_raw_input(self, prompt: str) -> str:
20742083
- if input is a pipe (instead of a tty), look at self.echo
20752084
to decide whether to print the prompt and the input
20762085
"""
2077-
2078-
# Temporarily save over self.prompt to reflect what will be on screen
2079-
orig_prompt = self.prompt
2080-
self.prompt = prompt
2081-
20822086
if self.use_rawinput:
20832087
try:
20842088
if sys.stdin.isatty():
@@ -2122,9 +2126,6 @@ def pseudo_raw_input(self, prompt: str) -> str:
21222126
else:
21232127
line = 'eof'
21242128

2125-
# Restore prompt
2126-
self.prompt = orig_prompt
2127-
21282129
return line.strip()
21292130

21302131
def _cmdloop(self) -> bool:
@@ -3500,24 +3501,30 @@ def async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None:
35003501
# Sanity check that can't fail if self.terminal_lock was acquired before calling this function
35013502
if self.terminal_lock.acquire(blocking=False):
35023503

3504+
# Only update if there are changes
3505+
do_update = False
3506+
35033507
# Generate a string to clear the prompt and input lines and replace with the alert
35043508
terminal_str = self._clear_input_lines_str()
35053509
if alert_msg:
35063510
terminal_str += alert_msg + '\n'
3511+
do_update = True
35073512

35083513
# Set the new prompt now that _clear_input_lines_str is done using the old prompt
3509-
if new_prompt is not None:
3514+
if new_prompt is not None and not self.at_continuation_prompt:
35103515
self.prompt = new_prompt
35113516
rl_set_prompt(self.prompt)
3517+
do_update = True
35123518

3513-
# Print terminal_str to erase the lines
3514-
if rl_type == RlType.GNU:
3515-
sys.stderr.write(terminal_str)
3516-
elif rl_type == RlType.PYREADLINE:
3517-
readline.rl.mode.console.write(terminal_str)
3519+
if do_update:
3520+
# Print terminal_str to erase the lines
3521+
if rl_type == RlType.GNU:
3522+
sys.stderr.write(terminal_str)
3523+
elif rl_type == RlType.PYREADLINE:
3524+
readline.rl.mode.console.write(terminal_str)
35183525

3519-
# Redraw the prompt and input lines
3520-
rl_force_redisplay()
3526+
# Redraw the prompt and input lines
3527+
rl_force_redisplay()
35213528

35223529
self.terminal_lock.release()
35233530

@@ -3536,6 +3543,9 @@ def async_update_prompt(self, new_prompt: str) -> None: # pragma: no cover
35363543
a prompt is onscreen. Therefore it is best to acquire the lock before calling this function
35373544
to guarantee the prompt changes.
35383545
3546+
The prompt will not update if a continuation prompt is being displayed
3547+
while entering a multiline command.
3548+
35393549
:param new_prompt: what to change the prompt to
35403550
:raises RuntimeError if called while another thread holds terminal_lock
35413551
"""

0 commit comments

Comments
 (0)