jj-lib 0.46.0

Library for Jujutsu - an experimental version control system
Documentation
// Copyright 2026 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Common helpers for configuring subprocesses

use std::process::Command;

/// Keeps a console window from popping up when `jj` is used from a GUI
/// application on Windows.
///
/// The flag is only set if the current process has no console. When `jj` runs
/// in a terminal, its console is passed down to the child instead. That
/// matters for programs that prompt the user, such as `ssh` asking for a key
/// passphrase or for confirmation of an unknown host key: those prompts are
/// written to the console, not to the inherited standard streams.
///
/// Setting `CREATE_NO_WINDOW` unconditionally gives the child an *invisible*
/// console, which the child then happily prompts on, leaving `jj` waiting
/// forever for input that the user can neither see nor provide.
#[cfg(windows)]
pub fn suppress_console_window(command: &mut Command) {
    use std::os::windows::process::CommandExt as _;

    // Note that `DETACHED_PROCESS` is not used here, even though that's how Git
    // hides the window (see `compat/mingw.c`). It leaves the child without a
    // console at all, and Win32-OpenSSH then busy-loops in `readpassphrase()`
    // when it has to prompt, flooding stderr instead of failing.
    const CREATE_NO_WINDOW: u32 = 0x0800_0000;

    if !has_console() {
        command.creation_flags(CREATE_NO_WINDOW);
    }
}

/// Does nothing on platforms other than Windows.
#[cfg(not(windows))]
pub fn suppress_console_window(_command: &mut Command) {}

/// Returns whether the current process has a console window.
///
/// [`std::io::IsTerminal`] can't be used for this: it is false whenever the
/// standard streams are redirected, even though a console is still attached
/// and usable for prompting.
#[cfg(windows)]
#[allow(unsafe_code)]
fn has_console() -> bool {
    use windows_sys::Win32::System::Console::GetConsoleWindow;

    // SAFETY: `GetConsoleWindow()` takes no arguments, has no preconditions,
    // and only returns a window handle (or null) without touching any memory
    // we own.
    let hwnd = unsafe { GetConsoleWindow() };
    !hwnd.is_null()
}