From 5ba21cd29085003a33e1cf3508a76b55d963f550 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Fri, 19 Apr 2024 11:25:05 +0200 Subject: [PATCH] Send repaint requests through the input queue again Another consequence of a583fe723 ("commandline -f foo" to skip queue and execute immediately, 2024-04-08) is that "commandline -f repaint" will paint the prompt with the current value of $status which might be set from a shell command in a the currently executing binding, instead of waiting for the top-level status. This is wrong, at least historically. It surfaces in bindings like alt-w which always paint a status value of [1] when on single-lines commandlines. Another regression is that a redundant repaint in a signal handler outputs an extra prompt. Fix both by making repaint commands go over the input queue again. This way, they are always run with a good commandline state. There is no need to repaint immediately because I don't think anyone has a data dependency on it (we currently don't expose the prompt string), it's only for rendering. --- src/reader.rs | 13 +++++++++++++ tests/checks/tmux-prompt.fish | 24 +++++++++++++++++++++--- tests/checks/tmux-signal.fish | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/checks/tmux-signal.fish diff --git a/src/reader.rs b/src/reader.rs index 2dd358ac4..f35c55796 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -903,6 +903,19 @@ pub fn reader_schedule_prompt_repaint() { pub fn reader_execute_readline_cmd(ch: CharEvent) { if let Some(data) = current_data() { + let CharEvent::Readline(readline_cmd_evt) = &ch else { + panic!() + }; + if matches!( + readline_cmd_evt.cmd, + ReadlineCmd::ClearScreenAndRepaint + | ReadlineCmd::RepaintMode + | ReadlineCmd::Repaint + | ReadlineCmd::ForceRepaint + ) { + data.inputter.queue_char(ch); + return; + } if data.rls.is_none() { data.rls = Some(ReadlineLoopState::new()); } diff --git a/tests/checks/tmux-prompt.fish b/tests/checks/tmux-prompt.fish index e1f129e56..12802d46e 100644 --- a/tests/checks/tmux-prompt.fish +++ b/tests/checks/tmux-prompt.fish @@ -2,19 +2,37 @@ #REQUIRES: command -v tmux set -g isolated_tmux_fish_extra_args -C ' - function fish_prompt; printf "prompt $status_generation> <$prompt_var> "; end + function fish_prompt + printf "prompt $status_generation> <$prompt_var> " + set prompt_var '' + end function on_prompt_var --on-variable prompt_var commandline -f repaint end + function token-info + __fish_echo echo "current token is <$(commandline -t)>" + end + bind ctrl-g token-info ' isolated-tmux-start isolated-tmux capture-pane -p -# CHECK: prompt 0> <> +# CHECK: prompt 0> <> set -q CI && set sleep sleep 10 set -U prompt_var changed tmux-sleep +isolated-tmux send-keys Enter +# CHECK: prompt 0> + +isolated-tmux send-keys echo Space 123 +tmux-sleep +isolated-tmux send-keys C-g + +# CHECK: prompt 0> <> echo 123 +# CHECK: current token is <123> +# CHECK: prompt 0> <> echo 123 +tmux-sleep + isolated-tmux capture-pane -p -# CHECK: prompt 0> diff --git a/tests/checks/tmux-signal.fish b/tests/checks/tmux-signal.fish new file mode 100644 index 000000000..90a2d31e8 --- /dev/null +++ b/tests/checks/tmux-signal.fish @@ -0,0 +1,18 @@ +#RUN: %fish %s +#REQUIRES: command -v tmux + +isolated-tmux-start + +isolated-tmux send-keys ' + function usr1_handler --on-signal SIGUSR1 + echo Got SIGUSR1 + # This repaint is not needed but make sure it is coalesced. + commandline -f repaint + end +' Enter +isolated-tmux send-keys C-l 'kill -SIGUSR1 $fish_pid' Enter +tmux-sleep +isolated-tmux capture-pane -p +# CHECK: prompt 1> kill -SIGUSR1 $fish_pid +# CHECK: Got SIGUSR1 +# CHECK: prompt 2>