microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
164.1k stars 29.26k forks source link

Integrated Terminal with remote SSH and bash clobbers exit code to zero #221393

Closed aguakandra closed 2 months ago

aguakandra commented 4 months ago

Type: Bug

The issue shows up if I have a custom PS1 prompt that looks at the exit code of the previous command (using $?). Here's a minimal configuration in the .bashrc file on my remote Linux host:

function set_prompt_exitcode() {
  local exit_status=$?
  PS1="last exit = $exit_status\n> "
}
export PROMPT_COMMAND=set_prompt_exitcode

Expected results: When I run in a terminal outside vscode or disable automatic script injection in the integrated terminal, I get this:

last exit = 0
> true
last exit = 0
> false
last exit = 1
> 

Actual results: when I enable integrated terminal shell injection, I instead see this output running the same commands:

last exit = 0
> true
last exit = 0
> false
last exit = 0
> 

That is, the exit code is now always 0.

I tried manually injecting the scripts using the command from https://code.visualstudio.com/docs/terminal/shell-integration#_installation . "$(code --locate-shell-integration-path bash)"; no change in behavior.

Looking at the script that gets loaded (.../server/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh), I see these lines:

__vsc_prompt_cmd_original() {
    __vsc_status="$?"
    __vsc_restore_exit_code "${__vsc_status}"
    # Evaluate the original PROMPT_COMMAND similarly to how bash would normally
    # See https://unix.stackexchange.com/a/672843 for technique
    local cmd
    for cmd in "${__vsc_original_prompt_command[@]}"; do
        eval "${cmd:-}"
    done
    __vsc_precmd
}

As an experiment, I tried moving the __vsc_restore_exit_code call later and opening a new terminal, which fixed the issue for me:

__vsc_prompt_cmd_original() {
    __vsc_status="$?"
    # Evaluate the original PROMPT_COMMAND similarly to how bash would normally
    # See https://unix.stackexchange.com/a/672843 for technique
    local cmd
    __vsc_restore_exit_code "${__vsc_status}"
    for cmd in "${__vsc_original_prompt_command[@]}"; do
        eval "${cmd:-}"
    done
    __vsc_precmd
}

So it looks like the step that clobbers the exit code is the local cmd step.

Remote OS: RHEL 8.10, bash 4.4.20

VS Code version: Code 1.91.0 (ea1445cc7016315d0f5728f8e8b12a45dc0a7286, 2024-07-01T18:52:22.949Z) OS version: Windows_NT x64 10.0.19045 Modes: Remote OS version: Linux x64 4.18.0-553.5.1.el8_10.x86_64 Remote OS version: Linux x64 4.18.0-553.5.1.el8_10.x86_64 Remote OS version: Linux x64 4.18.0-553.5.1.el8_10.x86_64

A/B Experiments ``` vsliv368:30146709 vspor879:30202332 vspor708:30202333 vspor363:30204092 vscod805:30301674 binariesv615:30325510 vsaa593:30376534 py29gd2263:31024239 c4g48928:30535728 azure-dev_surveyone:30548225 962ge761:30959799 pythongtdpath:30769146 welcomedialogc:30910334 pythonnoceb:30805159 asynctok:30898717 pythonregdiag2:30936856 pythonmypyd1:30879173 2e7ec940:31000449 pythontbext0:30879054 accentitlementsc:30995553 dsvsc016:30899300 dsvsc017:30899301 dsvsc018:30899302 cppperfnew:31000557 dsvsc020:30976470 pythonait:31006305 jchc7451:31067544 chatpanelc:31048052 dsvsc021:30996838 0ee40948:31013168 pythoncenvpt:31062603 a69g1124:31058053 dvdeprecation:31068756 dwnewjupytercf:31046870 impr_priority:31082723 ```
aguakandra commented 3 months ago

In VS Code version 1.92.0, I still see this issue.

In this version I now see that the __vsc_prompt_cmd_original method calls builtin local cmd instead of just local cmd, but running this after the __vsc_restore_exit_code function still clobbers out the return code to zero.

https://ss64.com/bash/local.html says this about running local:

The return status is zero unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.