Skip to content
New issue

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

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

Already on GitHub? # to your account

On fzf.vim opening in new cmd Window in Git Bash #3809

Closed
5 of 10 tasks
ykhan21 opened this issue May 21, 2024 · 42 comments
Closed
5 of 10 tasks

On fzf.vim opening in new cmd Window in Git Bash #3809

ykhan21 opened this issue May 21, 2024 · 42 comments
Labels

Comments

@ykhan21
Copy link

ykhan21 commented May 21, 2024

Checklist

  • I have read through the manual page (man fzf)
  • I have searched through the existing issues
  • For bug reports, I have checked if the bug is reproducible in the latest version of fzf

Output of fzf --version

0.52.1 (6432f00)

OS

  • Linux
  • macOS
  • Windows
  • Etc.

Shell

  • bash
  • zsh
  • fish

Problem / Steps to reproduce

This PR made by @Konfekt allows fzf.vim to work in Git Bash.
However, I found that by commenting the following part of the if-branch allows fzf.vim with the stock vim in Git Bash to run normally.

fzf/plugin/fzf.vim

Lines 711 to 716 in daa6024

elseif has('win32unix') && $TERM !=# 'cygwin'
let shellscript = s:fzf_tempname()
call s:writefile([command], shellscript)
let command = 'cmd.exe //C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript)
let a:temps.shellscript = shellscript
endif

In Git Bash's vim, :echo has('unix') returns 1, :echo has('win32unix') returns 1, :echo has('win32') returns 0, and :echo has('win64') returns 0.

What is has('win32unix') used for? It seems like it can be removed in a few cases.

@Konfekt
Copy link
Contributor

Konfekt commented May 21, 2024

This checks for the Win32 version of Vim, using Unix files (Cygwin), according to :help feature-list, but Cygwin nowadays rather refers to MSYS2.
One striking difference is that it expects Unix paths.

As vim in Git Bash is the default Vim, we looked no further.
By has('win32unix') being true, we know not only that this is most likely Git Bash vim, but also that the Git Bash executable exists, used by line 714.

So yes, one could likely check for something like has('win32unix') || (has('win32') && &shell =~# '\v<(ba)?sh>') instead of has('win32unix')

Likely only its original author @janlazo can tell us why $TERM !=# 'cygwin' must be ensured.

@ykhan21
Copy link
Author

ykhan21 commented May 21, 2024

Why does it need to be run as a cmd.exe process?

Removing this branch lets Git Bash's vim use the unix branches and most importantly does not cause a separate cmd.exe Window to appear.

@Konfekt
Copy link
Contributor

Konfekt commented May 21, 2024

Removing this branch lets Git Bash's vim use the unix branches and most importantly does not cause a separate cmd.exe Window to appear.

Is it? What does branch refer to? If you mean spawning cmd.exe, that would be great.
Again, this code was added in #933 whose authors know better. The Wiki says

On Cygwin, install script will download the prebuilt fzf binary for Windows platform. It does not run on mintty, the default terminal emulator shipped with Cygwin, but it works fine on ConEmu or the default Command Prompt (cmd.exe).

The Vim plugin of fzf also works with the Windows binary. It will start an extra cmd.exe window on mintty to circumvent the aforementioned limitation.

but seems somewhat outdated, since now the dev branch already supports Fzf in Git Bash default Mintty term.

Mind that #3804 asks similarly if the spawning of cmd.exe could be removed.
Maybe with the latest changes this is indeed possible.
For starters, does

let command = 'start /WAIT sh -c '.shellscript 

suffice?

@Konfekt
Copy link
Contributor

Konfekt commented May 21, 2024

If I understand correctly, in latest Git Bash simply

execute 'silent !'.command

instead of the involved cmd.exe shell script execution suffices.
Did you check :FZF to work as expected for all kind of paths, namely with spaces?

@ykhan21
Copy link
Author

ykhan21 commented May 21, 2024

Yes, see the image below:

image

However, it executes it in full screen. Is this is normal behavior on a unix system or is this an artifact of some other has('win32unix') check?

@Konfekt
Copy link
Contributor

Konfekt commented May 22, 2024

For me :FZF $path without the above shown if-branch worked out-of-the-box in Windows Terminal, but not in Git Bash's default Mintty terminal.
However, it did with the exe from the dev branch using winpty.
Therefore I suspect that this if-branch was needed to make fzf work in Git Bash without winpty (which maybe wasn't included in Git bash from the start?) and we can drop it together with the next release.

If you could confirm that all commands work as expected under the Git Bash Terminal as well?

@Konfekt
Copy link
Contributor

Konfekt commented May 22, 2024

@junegunn

Therefore I suspect that this if-branch was needed to make fzf work without winpty in Git Bash (which maybe wasn't included in Git bash from the start?) and we can drop it together with the next release.

Maybe that could be part of the next release since it yet improves again on the Git Bash experience

@Konfekt
Copy link
Contributor

Konfekt commented May 22, 2024

Since 573df52 (#3807) seems to call winpty directly, the check for win32unix could be replaced by executable('winpty').

This would also make it clearer, if guessed correctly, why all the convolution

fzf/plugin/fzf.vim

Lines 711 to 716 in daa6024

elseif has('win32unix') && $TERM !=# 'cygwin'
let shellscript = s:fzf_tempname()
call s:writefile([command], shellscript)
let command = 'cmd.exe //C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript)
let a:temps.shellscript = shellscript
endif
had to be added in the first place, when likely neither winpty was an option nor Windows Terminal was widely used.

@junegunn
Copy link
Owner

@Konfekt Can you open a pull request against devel branch?

@ykhan21
Copy link
Author

ykhan21 commented May 22, 2024

Interestingly, I can use fzf in Git Bash without winpty. I don't know why that is.
image
0.52.1 (6432f00)

fzf also works for me with no ~/.bashrc.

@Konfekt
Copy link
Contributor

Konfekt commented May 22, 2024

Phew, to confirm: that might be because this terminal is from MSYS2 itself, not the somewhat more restricted Git Bash MSYS2? For most users, Vim in MSYS2 will be Vim in Git Bash, so that's a case to be accounted for.

@ykhan21
Copy link
Author

ykhan21 commented May 22, 2024

This is the Git Bash terminal from Git for Windows. It is from scoop install git.

@Konfekt
Copy link
Contributor

Konfekt commented May 22, 2024

I can confirm that fzf.exe 0.52.1 works in Git Bash Mintty under Windows 11; it does not under Window 10.

@Konfekt
Copy link
Contributor

Konfekt commented May 22, 2024

Maybe it's solved in Windows 11, and winpty only needs to be used after a check for Windows 10 in fzf.exe, such as

    var osvi OSVERSIONINFOEXW
    osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))

    mod := syscall.NewLazyDLL("kernel32.dll")
    proc := mod.NewProc("GetVersionExW")
    ret, _, _ := proc.Call(uintptr(unsafe.Pointer(&osvi)))

    if ret != 0 {
        if osvi.dwMajorVersion == 10 {
        ...

junegunn pushed a commit that referenced this issue May 23, 2024
* Git Bash Mintty: only use cmd.exe if winpty missing

Addresses #3809

* preferably use term in Git Bash for popup window

See #3811 (comment)
@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

No, this was not about the OS versions. It was rather about the difference between git 2.42.0 and 2.45.1.
@junegunn Fzf in latest Git Bash Mintty no longer seems to need the winpty workaround.
Here's where were at: #3809 (comment)

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

@ykhan21 You may check with an older Git Bash, confirming #3809 (comment)

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

I am not sure what might have changed regarding winpty in Git Bash, from crawling their repo there's nothing striking and the release notes https://github.com/git-for-windows/build-extra/blob/main/ReleaseNotes.md#known-issues still state that winpty is often needed. A comment two month ago by its maintainer reinstating it

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

Here we go, this might have tickled down from mintty to Git Bash: https://github.com/mintty/mintty/wiki/Tips#inputoutput-interaction-with-alien-programs

When interacting with programs that use a native Windows API for command-line user interaction (“console mode”), a number of undesirable effects used to be observed; this is the pty incompatibility problem and the character encoding incompatibility problem. This would basically affect all programs not compiled in a cygwin or msys environment (and note that MinGW is not msys in this context), and would occur in all pty-based terminals (like xterm, rxvt etc).

Cygwin 3.1.0 compensates for this issue via the ConPTY API of Windows 10. On MSYS2, its usage can be enabled by setting the environment variable MSYS=enable_pcon (or selecting this setting when installing an older version). You can also later set MSYS=enable_pcon in file /etc/git-bash.config. MSYS2 releases since 2022-10-28 enable ConPTY by default. You can also set mintty option ConPTY=true to override the MSYS2 setting.

As a workaround on older versions of Cygwin or Windows, you can use winpty as a wrapper to invoke the Windows program.

Indeed MSYS=enable_pcon makes fzf work even on older Git Bash terms

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

So Fzf could suggest

Once settled how fzf handles this, the Wiki entry https://github.com/junegunn/fzf/wiki/Cygwin can be updated

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

Good thing: Mintty provides the environment variable $TERM_PROGRAM_VERSION to check for these.
So how about something similar to

func main() {
  termProgramVersion := os.Getenv("TERM_PROGRAM_VERSION")
  if compareVersions(termProgramVersion, "3.7.0") >= 0 {
    return
  } else if compareVersions(termProgramVersion, "3.4.5") >= 0 {
    originalMSYS := os.Getenv("MSYS")
    os.Setenv("MSYS", "enable_pcon")
    defer os.Setenv("MSYS", originalMSYS)
  } else {
    if isWinptyAvailable() {
      // Use fzf-0.52.1-dev code ...
    } else {
      // Use fzf-0.52.1     code ...
    }
  }
}

func compareVersions(v1, v2 string) int {
  parts1 := strings.Split(v1, ".")
  parts2 := strings.Split(v2, ".")
  for i := 0; i < len(parts1) && i < len(parts2); i++ {
    if parts1[i] > parts2[i] {
      return 1
    } else if parts1[i] < parts2[i] {
      return -1
    }
  }
  return 0
}

func isWinptyAvailable() bool {
  _, err := exec.LookPath("winpty")
  return err == nil
}

@junegunn
Copy link
Owner

junegunn commented May 23, 2024

@Konfekt Thanks, but my Git bash reports 3.7.1 but fzf doesn't run without winpty.

image

MSYS=enable_pcon ./fzf --no-winpty works great, and it gives accurate colors and border.

  • enable_pcon
    • image
  • winpty
    • image

@junegunn
Copy link
Owner

However, even with MSYS=enable_pcon, --height doesn't work.

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

my Git bash reports 3.7.1 but fzf doesn't run without winpty.

Hm... 3.7.0 was a guess; supposedly 3.6.4 should have worked, but neither did for me.
3.7.1. is used in latest https://github.com/git-for-windows/build-extra/blob/34a82b52c89920c425b691e8ae61a8eed47152dd/versions/package-versions-2.45.1.txt and it worked for me in Scoop;
according to their (install script](https://github.com/ScoopInstaller/Main/blob/master/bucket/git.json) they don't seem to make many adaptions.

even with MSYS=enable_pcon, --height doesn't work.

Was this ever addressed? In 573df52 (#3807) it seemed like rather not

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

For what it's worth, I also content myself with

func main() {
  termProgramVersion := os.Getenv("TERM_PROGRAM_VERSION")
  if compareVersions(termProgramVersion, "3.4.5") >= 0 {
    originalMSYS := os.Getenv("MSYS")
    os.Setenv("MSYS", "enable_pcon")
    defer os.Setenv("MSYS", originalMSYS)
  } else {
    if isWinptyAvailable() {
      // Use fzf-0.52.1-dev code ...
    } else {
      // Use fzf-0.52.1     code ...
    }
  }
}

@junegunn
Copy link
Owner

@Konfekt Please review and test d4216b0

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

Would you mind attaching the exe? I did not find a devel mingw compile action https://github.com/junegunn/fzf/actions

@junegunn
Copy link
Owner

@Konfekt
fzf.exe.zip

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

It works fine in Git Bash 2.42.0.
Mintty < 3.4.5 is three years old, so maybe it's not worth to rack one's brain too much about it,
even less so for Mintty < 3.4.5 without winpty.

For the Vim plugin, the condition has become

elseif has('win32unix') && $TERM_PROGRAM ==# 'mintty' && $TERM_PROGRAM_VERSION =~# '\v^[0-2]\.|3\.[0-3]|3\.4\.[0-4]' && !executable('winpty')

@junegunn
Copy link
Owner

@Konfekt Thanks. See c36b846

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

Nice, a moment's thought would have suggested to me that there's already a s:compare_versions for such a long-lived versatile program.

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

Maybe time has come to update the wiki

@sledgehammer999
Copy link

Has anyone tested with Windows Terminal(different from the builtin cmd console) as an alternative terminal to mintty?
And there might be other terminals on windows that load git-bash... (how about the builtin terminal of VSCode ?)

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

Windows Terminal was never a trouble-maker to begin with, fzf worked fine in it and then also :FZF in vim in it. Has it become one now?

@ykhan21
Copy link
Author

ykhan21 commented May 23, 2024

I had MSYS=winsymlinks:nativestrict in my .bashrc, which allowed fzf to work. MSYS= causes fzf to hang, as expected.

(MSYS=winsymlinks:nativestrict allows ln to create symlinks in Windows.)
https://stackoverflow.com/a/40914277/8917573

@ykhan21
Copy link
Author

ykhan21 commented May 23, 2024

There is this old issue with fzf+Git Bash. I wonder if the new changes fixes it.
#3346

@Konfekt
Copy link
Contributor

Konfekt commented May 23, 2024

I had MSYS=winsymlinks:nativestrict in my .bashrc, which allowed fzf to work. MSYS= causes fzf to hang, as expected.

Thanks for pointing that out, so it's indeed a list of options. There are some doubts on their separators, though.

I found MSYS on Git Bash 2.42. to default to MSYS=disable_pcon.
@junegunn : That should explain why fzf kept not working on mintty 3.6.4 since Git Bash explicitly sets MSYS=disable_pcon, so the new default of mintty never came into play. (You need to check the "enable experimental support for pseudo consoles" checkbox when installing Git Bash.)

To complicate Portable Git now enables pcon, whereas the classic install not.

@Konfekt
Copy link
Contributor

Konfekt commented May 24, 2024

@Konfekt fzf.exe.zip

Somehow I'd trouble with Ctrl-T in the Fzf plug-ins for cmd and powershell with this version; just a reminder to check that the fixes on the Git Bash end do not cause regressions on the former two ends.

@junegunn
Copy link
Owner

junegunn commented Jun 1, 2024

@Konfekt

Somehow I'd trouble with Ctrl-T in the Fzf plug-ins for cmd and powershell with this version;

Which "Fzf plug-ins" do you mean? Are you referring to the shell integration scripts in this repo? I don't think they're supposed to work on cmd or powershell.

@junegunn
Copy link
Owner

junegunn commented Jun 1, 2024

Hmm, --height seems to be broken, let me look into it.

@junegunn
Copy link
Owner

junegunn commented Jun 1, 2024

@Konfekt

With a series of fixes, now everything seems to work nicely.

  • --height options works on Git bash, cmd, and powershell
  • Shell integration works on Git bash (eval "$(fzf --bash)")
image

You can test this binary:
fzf.exe.zip

@Konfekt
Copy link
Contributor

Konfekt commented Jun 1, 2024

Which "Fzf plug-ins" do you mean?

I checked with https://github.com/chrisant996/clink-fzf and https://github.com/kelleyma49/PSFzf on cmd and powershell. It's working fine now. Good work!

@ykhan21
Copy link
Author

ykhan21 commented Jun 7, 2024

Thanks for the fix.
@Konfekt, a minor thing on mintty: with export MSYS=disable_pcon, the selection of ls | fzf (the output) gets cleared. cd "$(ls | fzf)" works, however.

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

No branches or pull requests

4 participants