Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document usage as the Terminal within JetBrains IDEs - "Process Terminal local Is Running" error #207

Open
jacob-pro opened this issue May 27, 2022 · 4 comments

Comments

@jacob-pro
Copy link

jacob-pro commented May 27, 2022

So I'm trying to use MSYS as my terminal within IntelliJ, PyCharm and CLion, and thought I would open this issue here in case anyone else has similar difficulties:

I started off copying the command documented here for Windows Terminal: https://www.msys2.org/docs/terminals/, i.e. invoking msys2_shell.cmd.

image

This does work, however it leads to an incorrect warning when closing the terminal, the IDE incorrectly thinks that 'Process
Terminal local Is Running' when it is not:

image

I'm 99% certain the reason for this (after doing some testing) is because the IDE is looking to see if the terminal process has any child processes running. So it thinks msys2_shell.cmd is the terminal process, and that bash.exe is an active child process:

image

I was able to work around this by setting the ide to invoke "C:\msys64\usr\bin\bash.exe" --login directly:

image

However this requires manually setting all the environment variables that would have been applied by the msys2_shell.cmd script.

Unfortunately the JetBrains Terminal environment variables are scoped locally to the individual project, there is no way to set them globally - so I have had to set them at the Windows level - which isn't ideal :(

image

I now have MSYS working as my terminal in CLion/IntelliJ, and it correctly detects if there is a process running or not when closing the terminal tab.

@jacob-pro jacob-pro changed the title Document usage as the Terminal within JetBrains IDEs Document usage as the Terminal within JetBrains IDEs - "Process Terminal local Is Running" error May 27, 2022
@lazka
Copy link
Member

lazka commented May 27, 2022

What about C:\msys64\usr\bin\env.exe MSYSTEM=MINGW64 CHERE_INVOKING=1 /usr/bin/bash.exe --login ?

@jacob-pro
Copy link
Author

Thanks @lazka , but unfortunately I still get incorrect "Process Terminal Local Is Running" prompt in my IDE,
I believe this is because it is still a child process:

image

I think this is because env doesn't behave the same way on Windows, I can see the Linux version tries to use execvp which should replace the running process - but clearly the MSYS/Cygwin implementation spawns a child process instead?

@jacob-pro
Copy link
Author

jacob-pro commented May 27, 2022

I guess the possible solutions to this whole issue could be:

  1. We find a way to do proper process replacement to invoke bash.exe within a single process (unlikely?)
  2. JetBrains adds an option to set Terminal environment variables globally for all projects.
  3. JetBrains adds an option to check if subprocesses are running based on an extra step down the process tree (ugly?)
  4. We patch bash.exe to support setting these environment variables via its CLI interface?

I had a go at #1 myself but haven't been successful...

The following code seems to launch when I open the exe directly, but opening it in within JetBrains causes STATUS_ACCESS_VIOLATION errors - not sure if this is my fault, or I have a feeling that process replacement is really not properly supported on Windows:

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null;
use windows::Win32::Foundation::GetLastError;

extern "C" {
    fn _wexecve(
        cmdname: *const u16,
        argv: *const *const u16,
        argp: *const *const u16,
    ) -> cty::intptr_t;
}

fn execve(cmdname: &str, parameters: &[String], environment: &[String]) {
    let cmdname = wide_string(cmdname);
    let parameters = parameters.iter().map(wide_string).collect::<Vec<_>>();
    let p_ref = parameters
        .iter()
        .map(|p| p.as_ptr())
        .chain(once(null()))
        .collect::<Vec<_>>();
    let environment = environment.iter().map(wide_string).collect::<Vec<_>>();
    let env_ref = environment
        .iter()
        .map(|p| p.as_ptr())
        .chain(once(null()))
        .collect::<Vec<_>>();
    let retval = unsafe { _wexecve(cmdname.as_ptr(), p_ref.as_ptr(), env_ref.as_ptr()) };
    let last_error = unsafe { GetLastError() };
    println!("retval {}, error: {}", retval, last_error.to_hresult().message());
}

fn wide_string<T: AsRef<str>>(value: T) -> Vec<u16> {
    OsStr::new(value.as_ref())
        .encode_wide()
        .chain(once(0))
        .collect()
}

fn main() {
    execve(
        r"C:\msys64\usr\bin\bash.exe",
        &vec![r"C:\msys64\usr\bin\bash.exe".to_string(), "-l".to_string()],
        &vec!["MSYSTEM=MINGW64".to_string(), "MSYS2_PATH_TYPE=inherit".to_string()],
    );
}

@amanteaux
Copy link

What @lazka suggested worked fine for me. I just adapted it to my settings: "C:\dev\msys2\usr\bin\env.exe" MSYSTEM=MINGW64 CHERE_INVOKING=1 /usr/bin/zsh.exe --login

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@lazka @amanteaux @jacob-pro and others