From 07387603671300edd4495c48d73e60755f6d84d4 Mon Sep 17 00:00:00 2001 From: step Date: Fri, 26 Dec 2025 15:33:02 +0100 Subject: [PATCH 1/3] fix head -1 hanging **Issue** Dispatch within tmux can leave `head -1` hanging. **Reproducible test** Linux target. In tmux start vim and `:let b:dispatch=./maker.sh`, write maker.sh as follows: ```sh echo "Press Enter to continue or Ctrl+C to abort ..." read x echo "Making ..." echo "DONE" exit 0 ``` and set maker.sh executable. Then `:Dispatch`, and switch input focus to the compiler's output tmux pane, which shows "Press Enter to continue or...". Here you can either press Enter to simulate a full make or press Ctrl+C to abort. If you press Ctrl+C and check the process list afterwards, you should notice a `head -1 /tmp/xyz.complete` process under the vim parent process. `head -1` is blocked on a fifo that will never receive input because Ctrl+C killed the process that was supposed to write to the fifo. **Proposed fix** This PR unblocks `head -1` through a shell trap handler that writes to the fifo upon receiving the INT signal. If INT is handled, maker.sh exists 129 otherwise the value of `$?`. --- autoload/dispatch.vim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/autoload/dispatch.vim b/autoload/dispatch.vim index a78ea34..c3ff1d3 100644 --- a/autoload/dispatch.vim +++ b/autoload/dispatch.vim @@ -308,6 +308,7 @@ function! dispatch#prepare_start(request, ...) abort else let exec .= 'sleep 1; ' endif + let exec .= 'trap "trap \"\" INT; (exit 129); '. dispatch#complete_make(a:request) . '" INT; ' let exec .= a:0 ? a:1 : a:request.expanded let wait = a:0 > 1 ? a:2 : get(a:request, 'wait', 'error') let pause = s:subshell("printf '\e[1m--- Press ENTER to continue ---\e[0m\\n'; exec head -1") @@ -325,12 +326,16 @@ function! dispatch#prepare_start(request, ...) abort endfunction function! dispatch#prepare_make(request, ...) abort - let exec = a:0 ? a:1 : s:subshell(a:request.expanded . '; echo ' . - \ dispatch#status_var() . ' > ' . a:request.file . '.complete') . + let exec = a:0 ? a:1 : s:subshell(a:request.expanded . '; ' . + \ dispatch#complete_make(a:request)) . \ dispatch#shellpipe(a:request.file) return dispatch#prepare_start(a:request, exec, 'make') endfunction +function! dispatch#complete_make(request, ...) abort + return 'echo ' . dispatch#status_var() . ' > ' . a:request.file . '.complete' +endfunction + function! dispatch#set_title(request) abort return dispatch#shellescape('printf', \ '\033]1;%s\007\033]2;%s\007', From b7e87e0914c0b88e74a5a4223daa486dfead0427 Mon Sep 17 00:00:00 2001 From: step Date: Fri, 26 Dec 2025 22:28:16 +0100 Subject: [PATCH 2/3] fix exterior quotes and exit 130 --- autoload/dispatch.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoload/dispatch.vim b/autoload/dispatch.vim index c3ff1d3..1d2b056 100644 --- a/autoload/dispatch.vim +++ b/autoload/dispatch.vim @@ -308,7 +308,8 @@ function! dispatch#prepare_start(request, ...) abort else let exec .= 'sleep 1; ' endif - let exec .= 'trap "trap \"\" INT; (exit 129); '. dispatch#complete_make(a:request) . '" INT; ' + let exec .= "trap 'trap \"\" INT; (exit 130); ". dispatch#complete_make(a:request) . "' INT; " + let exec .= a:0 ? a:1 : a:request.expanded let wait = a:0 > 1 ? a:2 : get(a:request, 'wait', 'error') let pause = s:subshell("printf '\e[1m--- Press ENTER to continue ---\e[0m\\n'; exec head -1") From 1cd9a55afef0d56e09dc0adcd06f8a5745a22ee6 Mon Sep 17 00:00:00 2001 From: step Date: Sun, 28 Dec 2025 09:43:52 +0100 Subject: [PATCH 3/3] fix: "(exit 130)" does not work with fish shell --- autoload/dispatch.vim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/autoload/dispatch.vim b/autoload/dispatch.vim index 1d2b056..9f1b7a5 100644 --- a/autoload/dispatch.vim +++ b/autoload/dispatch.vim @@ -308,8 +308,7 @@ function! dispatch#prepare_start(request, ...) abort else let exec .= 'sleep 1; ' endif - let exec .= "trap 'trap \"\" INT; (exit 130); ". dispatch#complete_make(a:request) . "' INT; " - + let exec .= "trap 'trap \"\" INT; ". dispatch#complete_make(a:request, '130') . "' INT; " let exec .= a:0 ? a:1 : a:request.expanded let wait = a:0 > 1 ? a:2 : get(a:request, 'wait', 'error') let pause = s:subshell("printf '\e[1m--- Press ENTER to continue ---\e[0m\\n'; exec head -1") @@ -328,13 +327,13 @@ endfunction function! dispatch#prepare_make(request, ...) abort let exec = a:0 ? a:1 : s:subshell(a:request.expanded . '; ' . - \ dispatch#complete_make(a:request)) . + \ dispatch#complete_make(a:request, dispatch#status_var())) . \ dispatch#shellpipe(a:request.file) return dispatch#prepare_start(a:request, exec, 'make') endfunction -function! dispatch#complete_make(request, ...) abort - return 'echo ' . dispatch#status_var() . ' > ' . a:request.file . '.complete' +function! dispatch#complete_make(request, status, ...) abort + return 'echo ' . a:status . ' > ' . a:request.file . '.complete' endfunction function! dispatch#set_title(request) abort