Repository: atuinsh/atuin (language: rust)

Issue:
`enter_accept` breaks liquidprompt with bash-preexec
"breaks" as in:

after interactively selecting-and-running a command from atuin's TUI the previous `PS1` is shown, and there are leftover characters right of the cursor if that previous `PS1` happened to be shorter than the current one (if that formulation even makes sense?  LP does the seemingly-normal thing of putting logic in `${pre{cmd,exec}_functions[@]}` that does stuff and sets `PS1` to something).

I tried flipping atuin & LP inits around in `.bashrc` to see if that's some sort of an order issue, but that didn't help.  no idea what else to try or if this is even a tractable problem; suggestions welcome!


Discussion / hints:
I don't have a good solution, but here I just describe what is happening there.

This is related to the timing of when the prompt content is updated using `PS1`. Bash updates the prompt content only after the execution of the user command from the command line. For example, even if `PS1` is changed, its content will not be reflected in the prompt until the user presses <kbd>Enter</kbd> to run the current command line.

With `enter_accept`, Atuin tries to emulate the execution of the user command, and update the prompt content by the new `PS1` in the following line:

https://github.com/atuinsh/atuin/blob/374255dd5856465b30d4c90d5882b150fa6c47de/atuin/src/shell/atuin.bash#L157-L161

However, the prompt content that Bash internally holds is not yet updated because `enter_accept` is not an authentic command execution that Bash recognizes. Here, inconsistency between "*the prompt content from the new PS1 rendered by Atuin*" and "*the one from the previous PS1 held by Bash*" arises.

----

One solution is to erase the last line of the prompt drawn by Atuin so that Bash totally redraws the last line. In this case, the prompt content would be the old one. For example, even if `cd xxx` is performed by `enter_accept`, the prompt still shows the previous directory (if the current directory is shown in the last line of the prompt). I think this is confusing and not a very good solution.

Another possibility could be to combine a readline keyboard macro with dynamic `bind` to conditionally induce an authentic command execution by Bash. However, I've never tried that, and I'm not sure if it is actually possible.

> In this case, the prompt content would be the old one. For example, even if `cd xxx` is performed by `enter_accept`, the prompt still shows the previous directory (if the current directory is shown in the last line of the prompt). I think this is confusing and not a very good solution.

Ah, wait. This also applies to the current implementation, so I think there is no drawback in erasing the last line.


Fix patch:
diff --git a/atuin/src/shell/atuin.bash b/atuin/src/shell/atuin.bash
index 5feb6d12599..c632cf9dc2b 100644
--- a/atuin/src/shell/atuin.bash
+++ b/atuin/src/shell/atuin.bash
@@ -106,10 +106,16 @@ __atuin_accept_line() {
     # Reprint the prompt, accounting for multiple lines
     local __atuin_prompt __atuin_prompt_offset
     __atuin_evaluate_prompt
+    local __atuin_clear_prompt
+    __atuin_clear_prompt=$'\r'$(tput el)
     if ((__atuin_prompt_offset > 0)); then
-        tput cuu "$__atuin_prompt_offset"
+        __atuin_clear_prompt+=$(
+            tput cuu "$__atuin_prompt_offset"
+            tput dl "$__atuin_prompt_offset"
+            tput il "$__atuin_prompt_offset"
+        )
     fi
-    printf '%s\n' "$__atuin_prompt$__atuin_command"
+    printf '%s\n' "$__atuin_clear_prompt$__atuin_prompt$__atuin_command"
 
     # Add it to the bash history
     history -s "$__atuin_command"
@@ -158,7 +164,7 @@ __atuin_accept_line() {
     # so to work for a multiline prompt we need to print it ourselves,
     # then go to the beginning of the last line.
     __atuin_evaluate_prompt
-    printf '%s\r' "$__atuin_prompt"
+    printf '%s\r%s' "$__atuin_prompt" "$(tput el)"
 }
 
 __atuin_history() {


Test patch: