Skip to content

Commit a79863f

Browse files
committed
fix: Recover PS1 before command execution.
Before this change, when doing completion in the same process PS1 was modified to be able to detect the end of the completion command output and it was recovered later on from PROMPT_COMMAND, just *after* executing the user command, before building the next prompt. The effect was not visible, unless the user command included $PS1, so if you did: > echo $PS1 and ran completion while editing that command, the PS1 that would be output would be the one from bash-completion. This change switches to another approach for recovering the prompt that allows recovering it before executing the user command: a DEBUG trap is registered which restores PS1 and PROMPT_COMMAND if the previous command included __ebrcet. This change also adds __ebcret after the last command issued by completion. This way, the last command issued by completion uses the fake prompt, but the command run just after that sees the real prompt in its variable. issue #77
1 parent a4c8fbc commit a79863f

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

bash-completion.el

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ Return the status code of the command, as a number."
15331533
((not define-functions)
15341534
(concat
15351535
"if type __ebcpre &>/dev/null; then "
1536-
" __ebcpre; %s; "
1536+
" __ebcpre; %s; __ebcret $?; "
15371537
"else "
15381538
" echo ==emacs==nopre=${BASH_VERSION}==.; "
15391539
" __ebcp=(\"$PS1\" \"$PROMPT_COMMAND\");"
@@ -1548,28 +1548,26 @@ Return the status code of the command, as a number."
15481548
" c=$((c+1));"
15491549
" fi;"
15501550
" history -d $c &>/dev/null || true;"
1551-
"}; function __ebcpre {"
1551+
"} ; function __ebcret {"
1552+
" __ebcret=t;"
1553+
" return $1;"
1554+
"} ; function __ebctrap {"
1555+
" if [[ \"$__ebcret\" = \"t\" && ${#__ebcp[@]} -gt 0 ]]; then"
1556+
" PS1=\"${__ebcp[0]}\";"
1557+
" PROMPT_COMMAND=\"${__ebcp[1]}\";"
1558+
" unset __ebcp;"
1559+
" unset __ebcret;"
1560+
" fi;"
1561+
"} ; trap __ebctrap DEBUG ; function __ebcpre {"
15521562
" set +x; set +o emacs; set +o vi;"
15531563
" echo \"==emacs==bash=${BASH_VERSION}==.\";"
15541564
" if [[ ${#__ebcp[@]} = 0 ]]; then "
15551565
" __ebcp=(\"$PS1\" \"$PROMPT_COMMAND\");"
15561566
" fi;"
1557-
" PROMPT_COMMAND=" ;; set a temporary prompt
1558-
(bash-completion-quote
1559-
(concat "PS1=" bash-completion--ps1 ";"
1560-
"PROMPT_COMMAND=" ;; recover prompt
1561-
(bash-completion-quote
1562-
(concat
1563-
"__ebcr=$?;"
1564-
"PS1=\"${__ebcp[0]}\";"
1565-
"PROMPT_COMMAND=\"${__ebcp[1]}\";"
1566-
"unset __ebcp;"
1567-
"if [[ -n \"$PROMPT_COMMAND\" ]]; then"
1568-
" (exit $__ebcr); eval \"$PROMPT_COMMAND\";"
1569-
"fi;"))))
1570-
";"
1567+
" PS1=" bash-completion--ps1 ";"
1568+
" unset PROMPT_COMMAND;"
15711569
" __ebcnohistory 1;"
1572-
"} && { __ebcpre; %s; }\n")))
1570+
"} ; { __ebcpre; %s; __ebcret $?; }\n")))
15731571
commandline)))
15741572
(setq bash-completion--debug-info
15751573
(list (cons 'commandline complete-command)
@@ -1591,7 +1589,7 @@ Return the status code of the command, as a number."
15911589
;; common initialization, then retry.
15921590
(bash-completion-send "__ebcnohistory" process timeout debug-context 'define-functions)
15931591
(bash-completion--setup-bash-common process)
1594-
(funcall send-string process (concat "__ebcpre; " commandline ";\n"))
1592+
(funcall send-string process (concat "__ebcpre; " commandline "; __ebcret $?\n"))
15951593
(bash-completion--wait-for-regexp
15961594
"short-timeout" process "==emacs==bash=[0-9].*?==."
15971595
bash-completion-short-command-timeout))

test/bash-completion-integration-test.el

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,4 +900,30 @@ $ ")))))
900900
"dummy moretestfile "
901901
(bash-completion_test-complete "dummy moret")))))
902902

903+
(ert-deftest bash-completion-integration-recover-status-ps1 ()
904+
(bash-completion_test-with-shell-harness
905+
(concat ; .bashrc
906+
"function dummy { echo --$PS1--; }\n"
907+
"function _dummy {\n"
908+
" COMPREPLY=( dummy )\n"
909+
"}\n"
910+
"complete -F _dummy dummy\n"
911+
"PS1='$ '")
912+
nil
913+
;; The first time initializes completion, the second time executes
914+
;; an already initialized completion. The two cases behave very
915+
;; differently, so we test both.
916+
(dotimes (i 2)
917+
(should (equal
918+
"dummy dummy "
919+
(bash-completion_test-complete "dummy dum")))
920+
(let ((start (line-beginning-position)))
921+
(comint-send-input)
922+
(bash-completion_test-wait-for-prompt start)))
923+
924+
;; The PS1 printed by the dummy function should be the one set in
925+
;; the init section, and not the one set by bash completion.
926+
(should (equal (bash-completion_test-buffer-string)
927+
"$ dummy dummy\n--$ --\n$ dummy dummy\n--$ --\n$ "))))
928+
903929
;;; bash-completion-integration-test.el ends here

0 commit comments

Comments
 (0)