Also refresh TTY timestamps after external commands from bindings

Commit ba67d20b7 (Refresh TTY timestamps after nextd/prevd, 2024-10-13)
wasn't quite right because it also needs to fix it for arbitrary commands.

While at it, do this only when needed:
1. It seems to be only relevant for multiline prompts.
   Note that we can wait until after evaluation to check if the prompt is
   multiline, because repaint events go through the queue, see 5ba21cd29
   (Send repaint requests through the input queue again, 2024-04-19).
2. When the binding doesn't execute any external command, we probably don't
   need to fix up whatever the user printed. If they actually wanted to show
   output and print another prompt, they should currently use  "__fish_echo",
   to properly support multiline prompts. Bindings should produce no other
   output. What distinguishes external programs is that they can trigger this
   issue even if they don't  produce any output that remains visible in fish,
   namely by using the terminal's alternate screen.
   Would be nice if we could get rid of __fish_echo; I'm not yet sure how.

Fixes #10800
This commit is contained in:
Johannes Altmanninger 2024-10-21 10:25:13 +02:00
parent 30cba03bf9
commit 2dbaf10c36
4 changed files with 24 additions and 2 deletions

View file

@ -1320,6 +1320,7 @@ fn exec_process_in_job(
piped_output_needs_buffering,
),
ProcessType::external => {
parser.libdata_mut().exec_external_count += 1;
exec_external_command(parser, j, p, &process_net_io_chain)?;
// It's possible (though unlikely) that this is a background process which recycled a
// pid from another, previous background process. Forget any such old process.

View file

@ -236,6 +236,9 @@ pub struct LibraryData {
/// A counter incremented every time a command executes.
pub exec_count: u64,
/// A counter incremented every time an external command executes.
pub exec_external_count: u64,
/// A counter incremented every time a command produces a $status.
pub status_count: u64,

View file

@ -1996,8 +1996,14 @@ impl<'a> Reader<'a> {
fn eval_bind_cmd(&mut self, cmd: &wstr) {
let last_statuses = self.parser.vars().get_last_statuses();
let prev_exec_external_count = self.parser.libdata().exec_external_count;
self.parser.eval(cmd, &IoChain::new());
self.parser.set_last_statuses(last_statuses);
if self.parser.libdata().exec_external_count != prev_exec_external_count
&& self.data.left_prompt_buff.contains('\n')
{
self.save_screen_state();
}
}
/// Run a sequence of commands from an input binding.
@ -2862,7 +2868,6 @@ impl<'a> Reader<'a> {
self.force_exec_prompt_and_repaint = true;
self.input_data
.queue_char(CharEvent::from_readline(ReadlineCmd::Repaint));
self.save_screen_state();
return;
}
@ -2885,7 +2890,6 @@ impl<'a> Reader<'a> {
self.force_exec_prompt_and_repaint = true;
self.input_data
.queue_char(CharEvent::from_readline(ReadlineCmd::Repaint));
self.save_screen_state();
return;
}

View file

@ -1,5 +1,6 @@
#RUN: %fish %s
#REQUIRES: command -v tmux && ! tmux -V | grep -qE '^tmux (next-3.4|3\.[0123][a-z]*($|[.-]))'
#REQUIRES: command -v less
isolated-tmux-start
@ -45,3 +46,16 @@ isolated-tmux capture-pane -p | tail -n 5
# CHECK: prompt-line-2>
# CHECK:
# CHECK:
# Test repainint after running an external program that uses the alternate screen.
isolated-tmux send-keys 'bind ctrl-r "echo | less +q; commandline \'echo Hello World\'"' Enter C-l \
isolated-tmux send-keys C-r
tmux-sleep
isolated-tmux send-keys Enter
tmux-sleep
isolated-tmux capture-pane -p
# CHECK: prompt-line-1
# CHECK: prompt-line-2> echo Hello World
# CHECK: Hello World
# CHECK: prompt-line-1
# CHECK: prompt-line-2>