Skip to content

fix(gitbash): arrow-key selection and confirmation in mintty - #763

Merged
linghengqian merged 16 commits into
version-fox:mainfrom
linghengqian:fix/98-gitbash-select
Nov 15, 2026
Merged

linghengqian merged 16 commits into
version-fox:mainfrom
linghengqian:fix/98-gitbash-select

Conversation

@linghengqian

@linghengqian linghengqian commented Nov 14, 2026 •

Copy link
Copy Markdown
Member

Fixes #98.

Problem

vfox use and vfox search could not select a version in native Git Bash (mintty):

  • mintty gives a native program a pty that reaches it as a pipe, so util.IsTTY() reported no terminal. The commands then took their non-interactive branch: use failed with "Please specify a version to use in non-interactive environments", and search only printed the list. The y/n prompts (remove, link, install, add) took that branch too.
  • Where the interactive path ran, the key reader (atomicgo.dev/keyboard, which pterm's select and confirm printers use as well) cannot read a Windows pipe. Without a console it takes a mock branch and reads from a nil file, so Listen spins on empty keys and never reads the input.

The pterm issue linked from #98 (pterm/pterm#616) is about AreaPrinter.Update appending in Git Bash, not about key input.

Change

  • util.IsTTY() also accepts a Cygwin or MSYS2 pty: a pipe named \msys-<id>-pty<N>-(from|to)-master, with an optional -nat for native programs. Nothing else may follow the name. util.IsPtyInput() tells whether stdin is such a pty.
  • The prompts choose how they take their answer (printer.InputFor):
    • Keyboard: the keyboard library, where the console or a Unix terminal can deliver keys. This is the existing pterm path, unchanged.
    • RawKeys: a pty pipe in Git Bash. stty (which comes with Git for Windows) switches it to raw mode for the prompt: no line buffering, no echo, no signals from Ctrl-C. printer.KeySelect and confirmKeys read the keys: the up and down arrows move the highlight in the version list, typed text filters it, Enter chooses, Ctrl-C cancels, and y or n answers a confirmation. The mode is restored afterwards.
    • Line: a line from a pipe or a file, as before. It is the fallback when stty cannot be used.
  • printer.Prompt carries the input for the choice and the confirmation. The call sites of printer.Confirm are unchanged.
  • The FAQ (en and zh-hans) describes the arrow keys in native Git Bash, and the heading is now a question about how to select.

Behaviour change, limited to mintty, which was non-interactive before:

  • use, search, install without a version, and the confirmations now wait for input.
  • After an install, mintty also gets the "copied to clipboard" step that Windows consoles already had (sdk.go).

Testing

  • Linux: CI=true go test ./... passes on this branch, which includes main at c4f6275. GOOS=windows go vet ./... passes as well.
  • Real Git Bash in a real mintty window: the workflow Git Bash in mintty (.github/workflows/gitbash-mintty.yml, driver scripts/gitbash-mintty-test.ps1). On windows-latest the driver starts Git for Windows' mintty.exe running Git for Windows' bash.exe, which runs the test binary built from cmd/commands (TestGitBashMinttySelection). It presses the down arrow (posted WM_KEYDOWN/WM_KEYUP) and Enter, then y.
    • Classic pseudo terminal (MSYS=disable_pcon), which reaches the program as a pipe: IsTTY is true, the input is RawKeys, the down arrow chooses 20.19.0 in raw mode, and y confirms. Passes on this head: https://github.com/version-fox/vfox/actions/runs/43597156292
    • Default on the runner, where the program gets a pseudo console: the input is Keyboard, and the arrow key chooses 20.19.0 through pterm. Passes on this head (same run).
    • On the commit before the fix, the classic pseudo terminal reported IsTTY: false and the selection never returned (timed out waiting for confirm.ready). That is the reported failure: https://github.com/linghengqian/vfox/actions/runs/43594366283 (throwaway branch).
  • An arrow probe (throwaway branch, not in the PR) showed that the stty raw mode works on the classic pty, and that the down arrow reaches the program at once as ESC [ B without Enter: https://github.com/linghengqian/vfox/actions/runs/43596744947
  • Windows (windows-latest) and the other jobs on this head: https://github.com/version-fox/vfox/actions/runs/43597156308 (all pass, including the Windows CLI tests with VFOX_TEST_WINDOWS_REGISTRY=1).
  • Unit tests: the key decoding (arrow sequences of both cursor modes, Enter, Backspace, Ctrl-C, escapes), the key-driven selection and confirmation on byte input, the line selection and confirmation, the Windows pipe names (including the real -nat names and the rejected suffixes), and the choice of the input.

Not covered

  • The driver presses keys with posted window messages, not with a person's keystrokes. It does not test a person's key presses.
  • Off Windows and in consoles, nothing changed: the keyboard library reads the keys as before.

)

Git Bash in mintty gives native programs a pipe, not a console. Two
Windows tests pin the failure: IsTTY does not recognize a mintty pty
(an msys-named pipe), and selectFromOptions never reads the choice typed
into a pipe because the key reader cannot read from one.
Git Bash in mintty gives vfox a pty that reaches it as a pipe. IsTTY
therefore said no, so use, search and the prompts were skipped as
non-interactive. Where the prompts did run, the key reader
(atomicgo.dev/keyboard) cannot read a Windows pipe and spins on it.

- IsTTY also accepts a Cygwin or MSYS2 pty, recognized by its pipe name
  the way go-isatty does.
- CanReadKeys reports whether stdin is a console on Windows. Off
  Windows it stays true, as the key reader falls back to /dev/tty.
- Without key input, use and search pick a version with
  printer.LineSelect (a number, a version, or text to filter), and the
  y/n prompts go through printer.Confirm, which reads a line. Consoles
  keep the arrow-key selection and single-key prompts.
- The FAQ describes how native GitBash behaves now.
…sion-fox#98)

A version whose name is a number, such as "2", must choose that version
and not the second entry of the list, so keys are matched before
positions.
…ms (version-fox#98)

Seen on windows-latest under script(1): a native program on an MSYS2 pty
gets \msys-<id>-pty0-to-master-nat for stdout and ...-from-master-nat for
stdin. The name check already accepts them; these cases pin it.
Copilot AI lite review requested due to automatic review settings November 14, 2026 12:06
@linghengqian linghengqian added the bug Something isn't working label Nov 14, 2026
@linghengqian linghengqian added this to the 1.1.1 milestone Nov 14, 2026
@codecov

codecov Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.71642% with 78 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.45%. Comparing base (c4f6275) to head (7189418).

Files with missing lines Patch % Lines
internal/shared/printer/input.go 18.18% 27 Missing ⚠️
internal/shared/printer/keyselect.go 83.05% 13 Missing and 7 partials ⚠️
internal/shared/printer/keys.go 79.48% 4 Missing and 4 partials ⚠️
internal/shared/printer/rawtty_other.go 0.00% 4 Missing ⚠️
cmd/commands/install.go 0.00% 3 Missing ⚠️
cmd/commands/search.go 70.00% 3 Missing ⚠️
cmd/commands/use.go 81.25% 3 Missing ⚠️
cmd/commands/link.go 0.00% 2 Missing ⚠️
cmd/commands/remove.go 0.00% 2 Missing ⚠️
internal/manager.go 0.00% 2 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #763      +/-   ##
==========================================
+ Coverage   56.62%   57.45%   +0.83%     
==========================================
  Files         116      123       +7     
  Lines        8595     8916     +321     
==========================================
+ Hits         4867     5123     +256     
- Misses       3263     3317      +54     
- Partials      465      476      +11     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Approval is blocked by an active correctness issue where the Windows named-pipe matcher accepts unsupported suffixes and may incorrectly enable interactive mode, along with a documentation nit requiring rewording.

2 open issues
What changed in this PR

This pull request adds native Git Bash (mintty) support for interactive vfox commands by detecting MSYS2/Cygwin pseudo-terminals and falling back to line-based selection and confirmation when Windows key input is unavailable.

Changes:

  • Adds Windows PTY detection and key-reading capability checks.
  • Implements line-based version selection, filtering, and confirmation prompts.
  • Updates affected commands, tests, and English and Chinese FAQ documentation.
File Description
internal/​shared/​util/​tty.go Exposes helpers for detecting terminals and determining whether individual key input is available.
internal/​shared/​util/​tty_windows.go Detects Windows consoles and MSYS2/Cygwin pseudo-terminal named pipes.
internal/​shared/​util/​tty_windows_test.go Tests Windows PTY recognition and key-reading behavior.
internal/​shared/​util/​tty_notwindows.go Provides non-Windows implementations of the terminal capability helpers.
internal/​shared/​printer/​select_line.go Implements line-based version selection, filtering, cancellation, and disabled-option handling.
internal/​shared/​printer/​select_line_test.go Tests line-based selection behavior and edge cases.
internal/​shared/​printer/​confirm.go Adds line-based confirmation handling when key input is unavailable.
internal/​shared/​printer/​confirm_test.go Tests confirmation responses, defaults, and EOF behavior.
internal/​manager.go Routes plugin-install confirmations through the shared confirmation helper.
docs/​zh-hans/​guides/​faq.md Documents native Git Bash line-based interaction in Chinese.
docs/​guides/​faq.md Documents native Git Bash line-based interaction in English.
cmd/​commands/​use.go Uses line-based version selection when individual key input is unavailable.
cmd/​commands/​use_line_select_test.go Tests line-based version selection and cancellation for the use command.
cmd/​commands/​select_windows_test.go Verifies version selection from a Windows pipe.
cmd/​commands/​search.go Adds line-based version selection to the search command.
cmd/​commands/​remove.go Routes removal confirmations through the shared confirmation helper.
cmd/​commands/​link.go Routes link confirmations through the shared confirmation helper.
cmd/​commands/​install.go Routes installation confirmations through the shared confirmation helper.

Review effort: Lite

Comment thread internal/shared/util/tty_windows.go Resolved
Comment thread internal/shared/util/tty.go Resolved
…ersion-fox#98)

scripts/gitbash-mintty-test.ps1 starts Git for Windows' mintty.exe running
Git for Windows' bash.exe, which runs TestGitBashMinttySelection. The test
checks IsTTY and CanReadKeys in that window, then the script types "2" for
the selection and "y" for the confirmation with WM_CHAR messages.
…sion-fox#98)

MainWindowHandle stayed zero on windows-latest although the session was
interactive, so the driver now enumerates the top-level windows and takes
the one of class "mintty". On a timeout it prints the windows and the
mintty command lines, and it fails at once when mintty has exited.
…x#98)

The first run showed that the mintty window's default gives vfox a
pseudo console, where the arrow-key selection already works, so the
check did not reach the pipe case of the issue. The workflow now runs the
window twice: once with MSYS=disable_pcon, the classic pseudo terminal
that reaches the program as a pipe, and once with the default. The test
checks which one it got, and the driver types the full version, which
both selectors accept.
…ote lists (version-fox#98)

- search: the line selection of RunSearch moves into installByLine, which
  takes the installer as an interface, so the cancel, refusal, install and
  read-error paths run in unit tests.
- use, confirm: the choice between keys and a line is a parameter of
  chooseVersion and confirm, so the line paths run in unit tests on every
  platform; the wrappers that read util.CanReadKeys stay one line each.
- Read errors of LineSelect, lineConfirm and selectVersionByLine, shortAnswer,
  and the tty helpers off Windows are covered.
- On Windows, Confirm reads a line from a pipe.

What remains uncovered is interactive only: the confirmation calls in
install, link, remove and manager, and the key paths of RunSearch and
confirm. Those run only when stdout is a terminal.
Copilot review on version-fox#763: the matcher checked only the first five parts of
a pipe name, so \msys-<id>-pty0-to-master-not-a-pty counted as a terminal
and could switch a command into interactive mode. The name is now matched
as a whole: the documented forms, with -nat as the only suffix, and digits
after pty. The table adds names with anything else after the name.
…on-fox#98)

The comment read ambiguously ("a pipe, which isCygwinTerminal recognizes").
…rsion-fox#98)

In Git Bash in mintty, with the pseudo console off, the program gets its
terminal as a pipe, and the keyboard library cannot read it. The arrow keys
then arrived only with the line, so the selection fell back to typed lines.

Now such a terminal is switched with stty to raw mode (no line buffering, no
echo, no signals from Ctrl-C), which stty from Git for Windows does on the
pipe. The prompts read the keys themselves: the arrow keys move the highlight
in the version list, typed text filters it, Enter chooses, Ctrl-C cancels, and
y and n answer a confirmation. The mode is restored afterwards.

- printer.InputFor says how the prompts take their answers: the keyboard
  library where it can read keys, raw keys on a pty pipe where stty works, and
  a line otherwise. printer.Prompt takes it for choosing and confirming, and
  the existing call sites of the keyboard library are unchanged.
- printer.KeySelect is the key-driven selection; readKey decodes the keys,
  including the arrow sequences of both cursor modes.
- The version selection of use and search and the confirmations use the
  prompt; the line input stays the fallback.
- The mintty check drives the down arrow in both modes and checks that the
  pipe mode reads the keys raw.
)

The FAQ said the arrow keys did not work in native Git Bash (MinTTY). They do
now, through stty raw mode on the classic pty, and the line input is the
fallback. The heading becomes a question about how to select, and the links
to it follow.
@linghengqian linghengqian changed the title fix(gitbash): select and confirm by line in mintty fix(gitbash): arrow-key selection and confirmation in mintty Nov 14, 2026
Every job of the workflows now carries if: github.repository ==
'version-fox/vfox', so a push to a fork runs no job. The test summary keeps
its always() and joins the gate with &&. Pull requests from forks still run
the jobs, because a pull_request workflow runs in the base repository.
…version-fox#98)

mintty.exe does not always keep its window in the process it starts. The
driver treated that process exiting before the window showed as a failure, so
a launch that was still starting failed the step: the classic-pty run of
a71499f on the fork exited with code 0 at 0.7 seconds, while the same commit
passed upstream. In every run that found a window, the window belonged to a
different process than the one started.

The window is now looked for by its class for 30 seconds, whatever became of
the process started. A launch that shows no window is tried once more, after
the mintty, bash and test processes of the first are stopped and its leftover
files are removed. A bash that starts writes started.txt, which the message for
a failed launch reports. The test and its assertions are unchanged.

@linghengqian linghengqian left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CC @version-fox/vfox-maintainers @version-fox/vfox-committers . Could you please take a look and provide a review?

@linghengqian
linghengqian merged commit bf79246 into version-fox:main Nov 15, 2026
13 checks passed
@linghengqian
linghengqian deleted the fix/98-gitbash-select branch November 15, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Unable to select when using on GitBash

3 participants