It seems to me very strange that zig, by default, doesn’t appear to have an out-of-the-box cross-platform terminal capability that is useful for TUI for ANSI encoded outputs: stdout.write does not appear up to snuff.
OSX and Linux look great where stock terminals “just work.”
However, MS WIN seems to be a wholly different beast, appearing to require WriteConsoleA or WriteConsoleN API and lots of prep work for Microsoft’s solutions - CMD, PowerShell, etc.
What are our thoughts?
It is kinda driving me crazy that to write cross-platform zig TUI, it appears as if we need numerous if (builtin.os.tag == .windows) { conditionals…this level of detail gates zig’s cross-platform utility…a shift from pythons “write once, run anywhere” to more of a C-style “yeah, but…that’s a you problem.”
My 2 cents are that supporting that is up to TUI libraries and whether they want to spend time on supporting windows.
I think that is why a lot of people will just settle with using that and being fine with it not working everywhere. Sure you can be critical and say it should run properly on windows too, but in the end it is up to whoever writes the thing and whether they want to deal with that or not.
I don’t think we can expect batteries included in the standard library for everything (or a lot) until the language develops further, so I think having support for additional things as community libraries is fine.
I also don’t agree with the whole “the standard library should have everything”, there are multiple different TUI libraries (that probably have different approaches and goals), seems difficult to pick one in particular over another and the standard library isn’t focused on “being organized for 1.0” (for that I might agree that it would be nice to add some basic compatibility shims that work for the simple cases).
Sure you can be critical and say it should run properly on windows too,
We def agree here – stdout.write for MS WIN does not work the way it is intended. It is broken.
In the event you haven’t tried, it is not a question of choice. There is no other option but link to the Win32 API, which is something that SHOULD be in the standard library.
Secondly, the value of cross-architecture compilation is limited. Who cares? I can already write bespoke code for bespoke platforms without zig.
The value of cross-platform – such as stdout.write, write once, run everywhere - is limitless.
For latest windows 10 or windows 11 you can use escape sequences for anything, including setting color.
You must call SetConsoleMode to enable output escape sequences.
Write once, run anywhere…if zig code works in OSX and Linux, and on a Microsoft architecture, if could, but doesn’t, would we agree it’s nott a Microsoft problem, but a zig std one?
Just seems crazy to me to do some basic console output I have to wire into WinAPI and all the fun that entails.
No, at least not always, because someone might don’t want the unix way but the windows way.
Well, I was thinking this is where writers would have branching, to help resolve ambiguity!
var stdout: std.fs.File.Writer = std.io.getStdOut().writer();
const tty = stdout.context.handle; // appropriate to Windows -or- MacOS -or- Linux
stdout.write(...) // If windows && ( cmd || ps) ; UF8 enabled, ANSi sequence activated,
So the invoking function doesn’t have to care, but stdout write would a great deal, and could mature over time. It would also help clarify, I am unsure if the handle in windows is accurate or not; because I can’t invoke stdout w/ANSI codes, I have to worry about such things.
There is also the lldb use case as well, which appears to need a tty sourced from the device.
stdout.write should write bytes to stdout, unmodified from what you pass to it.
On Windows, you have to tell stdout that you are sending ansi escape sequences. You might even have to tell it you have UTF-8.
On POSIX, you have to set a bunch of IOCTLs so that ‘\n’ doesn’t move the cursor to column 0. You don’t have to do this on Windows.
Both platforms require a level of normalization to something that you want. But in all cases: write performs the same. It’s the underlying handle that has the state.
According to getOrEnableAnsiEscapeSupport docs (and my experience on Windows), ANSI escape codes are enabled by default when using the Windows Terminal. It’s not as great as the better terminals on other platforms, but still better than the old command prompt.
vaxis is wonderful! Thank you for this lib. I was wishing the cfg/setup portion of vaxis was part of std when writing this post.
For my specific use case, i must use no dependencies, so that the source repo can be cloned + built with no, other requirements; in every other TUI project, I use vaxis lol!
My next stop was evaluating vaxis source to see how I could improve my solution.
Awesome, thank you thank you. I will try getOrEnableAnsiEscapeSupport next.
For Windows to emit ANSI properly, I believed I had to abandon the stdout writer altogether, as CMD.EXE rendered the ANSI codes directly to screen unless invoked direct via Win API. The linux path also needed a tty handle fallback for lldb use-cases, and i just feel like these should…work.