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

Windows / PowerShell Functionality #32

Closed
michaeltlombardi opened this issue Jul 29, 2022 · 23 comments
Closed

Windows / PowerShell Functionality #32

michaeltlombardi opened this issue Jul 29, 2022 · 23 comments
Labels
bug Something isn't working

Comments

@michaeltlombardi
Copy link

michaeltlombardi commented Jul 29, 2022

\o I started work last night to make a Chocolatey package for gum since there's a build for Windows. I've been able to get the package sorted out but I started running into problems when I tried writing some example use cases.

Error Examples

Example 1: No Redirection or Assignment

Calling a gum command without doing anything else seems to work exactly as expected.

gum-minimal

Example 2: Variable Assignment

Attempting to set assign a gum command's stdout to a variable seems to misbehave.

gum-var

  1. The prompt is munged with leading whitespace on the second line. I haven't run this down yet but I think this is related to the bubbletea model and some strange interaction when the console tries to go back to regular flow.

  2. The output has an error prepended.

    I expect to see:

    hello!
    

    but instead see (leading whitespace trimmed):

    failed to get console mode for stdout: the handle is invalid.
    hello!
    

    Note:
    I still see this behavior even without my prompt (starting PowerShell with the NoProfile flag). The problem does not appear to be connected to the prompt or to the specific terminal - I see it in the Windows Terminal, the VS Code terminal, and the built-in console host in both PowerShell (versions 5.1 and 7x) and CMD.

    Doing a little digging, this appears to come from containerd/console:

    https://github.com/containerd/console/blob/21ccd90b850f542a0b5a4fee0f5cb2e9b7bd7496/console_windows.go#L54

    It seems this has been a pain point for Windows users of docker compose:

    Though that issue is closed, there are re-reports from this year.

Example 3: Output Redirection

Attempting to redirect a gum command's stdout to a file has apparently identical behavior to assigning it to a variable.

gum-redir

Context

I'm a huge fan of your libraries and tools. I saw gum and immediately thought that it would be great for interactive scripts and would obviate a lot of work to get even an approximately similar UX for folks. I started thinking about a PowerShell module that wraps gum to provide a more familiar (to PowerShell developers) DevX.

If the captured output problem is intractable, I'm happy to write PowerShell handlers to hide away the implementation (strip the error message, etc). What that can't fix (I think) is the prompt munging.

I also noticed that there are completers for other shells and would love to see a completer for PowerShell (and be happy to try my hand at contributing one). I filed this all together as a single issue but if there's a desire to address these Windows-and-PowerShell-specific items, I'm also happy to file separate issues and link to them here as a pseudo-epic.

I'm also happy to help debug/troubleshoot, though my go skills are still nascent.

@volkerwestphal
Copy link

Windows 10 x64 user here: The problem also appears at the CMD prompt. It's not limited to Powershell.

@maaslalani
Copy link
Member

@michaeltlombardi Thank you so much for the really well-written issue and screen captures. It is very much appreciated.

Unfortunately, I do not have a windows machine so it is a little hard for me to debug and I have very little knowledge of how Powershell / Windows works, but I would really like for gum to be usable on Windows.

For what it's worth gum programs (interactive ones) run on stderr and then output to stdout.

Out of curiosity, does fzf work on Windows / Powershell?

@maaslalani
Copy link
Member

I imagine the prompt mangling could be an issue with the difference between line returns on windows vs unix maybe when the gum program returns it is not printing the correct new line and that is why the prompt looks like it is not properly reset.

@michaeltlombardi
Copy link
Author

@maaslalani it does!

fzf --version
fzf
$a = fzf
$a
0.32.0 (f7e7259)
gummy.txt

gummy.txt

shows fzf write its version, return output, and be used as a subexpression

I also tested whether fzf would handle being used in the pipeline:

(fzf) -replace '\.', '!'
(fzf) | ForEach-Object {
  $Parts = $_ -split '\.'
  [PSCustomObject]@{
    Name = $Parts[0]
    Extension = $Parts[1]
  }
} | Format-List
gummy!txt
Name      : gummy
Extension : txt

Shows fzf find gummy.txt and get used in the pipeline

fzf seems to work okay:

  • on its own (no prompt munging)
  • to store the output to a variable
  • to use in a subexpression ((fzf) -replace ...)
  • to use in the pipeline (fzf | ...)

Taking a peek into fzf's code to see if I can find anything obvious or special they're doing to handle output on Windows now.

@michaeltlombardi
Copy link
Author

Looking around, I'm not seeing too many places where they're doing Windows-specific handling.

  1. func (r *Reader) feed(src io.Reader)

    Here they are chomping the CRLF instead of the LF when reading from stdin/stdout

  2. func quoteEntry(entry string) string

    Here they're handling escaping strings a little differently (which I don't think is related to our issue).

  3. consoleFlagsInput and consoleFlagsOutput

    It looks like they have some flag handling for Windows specifically. This gets used in func (r *LightRenderer) setupTerminal() error and func (r *LightRenderer) restoreTerminal() error which might be a clue, but I'm not super clear on how that changes things yet.

  4. This line might be important at some point as it interacts with the virtual terminal input for PSReadLine which will almost always be loaded in a modern interactive PowerShell session. Though looking at the PR it was added (back) in I don't think the issue it was resolving is one bubbletea or this project has.

@hay-kot
Copy link

hay-kot commented Aug 4, 2022

Wanted to let you know that this isn't isolated to gum. I am experiencing an identical issue with a program I wrote using the bubbletea library.

https://github.com/hay-kot/gofind

Notable Things...

  • I'm writing to stderr in interactive mode like fzf and returning the result to stdout
  • I'm also experiencing the "failed to get console mode for stdout: The handle is invalid" as well
  • Prompt is also mangled as a result
  • Works fine on Mac OS

182470286-7b99145b-2231-473b-bb71-176d1b4b69fc

Happy to help troubleshoot on windows as well.

@immersivegamer
Copy link

immersivegamer commented Aug 8, 2022

  1. consoleFlagsInput and consoleFlagsOutput

    It looks like they have some flag handling for Windows specifically. This gets used in func (r *LightRenderer) setupTerminal() error and func (r *LightRenderer) restoreTerminal() error which might be a clue, but I'm not super clear on how that changes things yet.

  2. This line might be important at some point as it interacts with the virtual terminal input for PSReadLine which will almost always be loaded in a modern interactive PowerShell session. Though looking at Restore VT hack for Windows junegunn/fzf#2580 I don't think the issue it was resolving is one bubbletea or this project has.

Just to add to these. When using gum and then doing a tail using Get-Content I am unable to use Ctrl-C or Ctrl-Break to stop the running process, I have to shut down the PowerShell process. This seems to point to an issue with the SetConsoleMode that was seen in num. 4 and the combination of flags in num. 3. I am guessing something in gum changes the console mode when reading input and doesn't revert it.

Reading input is the key to the above. If I do:

gum style "Hello"
> Hello
Get-Content -Tail 0 -Wait C:\temp\log.txt
> # can succesfully use ctrl-c (^C) to stop

However, if I use choose, input, or filter before the tail I cannot quit:

$path = (Get-ChildItem C:\temp\ -File -Filter *.txt).Fullname | gum filter
> chose item
$path = $path[1].Trim() # hack for the extra error as commented already by the original poster
Get-Content -Tail 0 -Wait $path
> # cannot use ctrl-c to stop

I tested with a different program that keeps on running instead of running Get-Content, I was able to use Ctrl-C to exit it. So my guess it is something to do with ENABLE_VIRTUAL_TERMINAL_INPUT flag when running in the context of PowerShell.

I tested this on Windows PowerShell v5.1 and PowerShell v7 on Windows 10. I may try testing gum with PowerShell on a non-windows machine.

@bfqrst
Copy link

bfqrst commented Aug 9, 2022

I can't say I know the first thing about this topic and I apologize if this is just noise, but I remember that Taskfile uses https://pkg.go.dev/mvdan.cc/sh/v3 under the hood to smooth out variances between OSes and shells. Of course it introduces at least another dependency and I'm not sure if this aligns with the intentions of the authors...

@immersivegamer
Copy link

This was way harder than I would have thought to figure out. Had to bang my head against how to get the console stream input on Windows. Couldn't just use stdin since it can sometimes be a pipe (e.g. when using gum filter). This change is at least working for me personally on PowerShell v7 on Windows 10. It solves my problem of not being able to use Ctrl-C after certain gum UI runs. I'll be using my personal forked version. I would clean it up for integration but I'm tapped out for a while. Maybe someone else can pickup where I left off: immersivegamer@6577304

@hay-kot
Copy link

hay-kot commented Aug 18, 2022

I pulled down @immersivegamer fork and am still having the same issue with Gum described in the original issue. It looks like your fix implements what is more or less suggested here

I've tried modifying the code to explicitly use the handle and flag as specified in the python example in the issue, but still get the same results no matter what I've tried. Will continue to work on a fix, but I'm not super familiar with the windows APIs so It will probably take me a while.

@muesli muesli added the bug Something isn't working label Oct 5, 2022
@muesli
Copy link
Member

muesli commented Oct 20, 2022

charmbracelet/bubbletea#565 will improve the situation somewhat, as soon as we merge & bump the bubbletea dependency in gum. The redirection issues need to be addressed separately however.

@muesli
Copy link
Member

muesli commented Oct 21, 2022

I've also figured out the redirection problem and realized it's an issue with the upstream console package printing to stdout when encountering a redirected handle. I've opened a PR here: containerd/console#66

@muesli
Copy link
Member

muesli commented Oct 21, 2022

One more upstream fix required to correctly reset stderr on shutdown: containerd/console#67

@lwbt
Copy link

lwbt commented Nov 13, 2022

Unfortunately, I do not have a windows machine so it is a little hard for me to debug and I have very little knowledge of how Powershell / Windows works, but I would really like for gum to be usable on Windows.

Just in case nobody was aware:

You can run the latest version of PowerShell on Linux and Mac because Microsoft made it portable a while ago. Note that Windows still ships older versions of PowerShell and the terminal program (the one with the blue background which came before Windows Terminal, it's called "something host" or so), so it's up to developers and users to teach narrow minded people who deem the bare Windows OS as a sufficient OS solution that it's actually like running a recent Linux kernel with bash 2.x and KDE 3.0.x or Gnome 2.x. When you look around in the PowerShell Github organization you will find some pretty interesting things which only work with recent versions of PowerShell.

I'm just a Linux admin passing by who wrote his first few lines of PowerShell scripts to customize the OOTB experience of Windows 11 with winget and a few settings (Registry, Windows features) a few weeks ago.

@antonmedv
Copy link

Will removing console dep completely help with powershell issues?

@Jonathan-Zollinger
Copy link

came here to say I'm finding the same issue when piping variable assignments from gum filter on powershell 7 on windows 11

@JGJP
Copy link

JGJP commented Apr 25, 2023

Any solution? Quite a downer to not have this

@muesli
Copy link
Member

muesli commented Apr 25, 2023

My upstream fixes have been merged, so pretty much all of this is working fine now.

@maaslalani
Copy link
Member

maaslalani commented Apr 25, 2023

Latest release does include Windows support now (thanks to @muesli): https://github.com/charmbracelet/gum/releases/tag/v0.10.0

I believe we can close this issue 😄

@JGJP
Copy link

JGJP commented Apr 27, 2023

@maaslalani I hate to be that guy.. but it does not work in Cygwin 😭😭😭

image

Powershell confirmed working

@alexn-s
Copy link

alexn-s commented May 5, 2023

@maaslalani the issue still perists for me in PowerShell 7.2.11

image

and the error failed to get console mode for stdout: The handle is invalid. remains.
do you have any ideas why or tipps for me?

appreciate your help

@Jonathan-Zollinger
Copy link

Jonathan-Zollinger commented May 5, 2023

@alexn-s if you're experiencing the same thing as i am, the the value returned is actually multiple strings. see my gif below - I've thought about how I'd go about this between now and when I first ran into it in february (prior to the fix in build 0f0f8e9).

to show what I'm seeing when I use gum input as you showed, I'm calling gum input then piping it to a foreach ternary which then uses an expression to print the returned strings wrapped with green text to emphasize the string separations.

gum input \
  --placeholder "Tell me something nice." | % { echo "$(gum style --foreground="#00fff" "String in series of strings ->") $_ $(gum style --foreground="#00fff" "<-- end of String")" }

This is what I see:

WindowsTerminal_5doXbc9eqi

if you're experiencing the same thing, then maybe you could add an eleement to your script to remove any Strings that match the error message?

that being said, ultimately the best case would be to update to v0.10.0 - that fixed it on my end (if you used scoop, it's just scoop update charm-gum)

image

@alexn-s
Copy link

alexn-s commented May 6, 2023

@Jonathan-Zollinger thanks for your response and the snippet

i just noticed that i had gum 0.10 & 0.8 installed

WARN  'charm-gum' (0.10.0) is already installed.
Use 'scoop update charm-gum' to install a new version.
2023-05_hot-script > gum --version
gum version v0.8.0 (dfa412f)

that is why i was confused that it was not working for me.

thank you

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

No branches or pull requests