Show HN: A modular Python TUI framework with a fast and pretty markup language(github.com)
github.com
Show HN: A modular Python TUI framework with a fast and pretty markup language
https://github.com/bczsalba/pytermgui
7 comments
What are good examples of well known TUI applications that would be a good fit using frameworks like this?
Most TUI apps I use do no involve space consuming borders, buttons, interactive dragging/resizing etc. That's also precisely why I prefer TUIs for some apps, to not be dependent on those features and navigate by shortcut keys instead.
Most TUI apps I use do no involve space consuming borders, buttons, interactive dragging/resizing etc. That's also precisely why I prefer TUIs for some apps, to not be dependent on those features and navigate by shortcut keys instead.
I use something similar for the presenter view in It's A Live, for example:
https://gitlab.com/stavros/itsalive
https://gitlab.com/stavros/itsalive
At the moment not many, but full-screen layout support is planned. The eventual "end-state" of the framework would be something along the lines of MC, where there is a main, fullscreen display that contains a bunch of inner elements. These inner elements would then create modal windows, allows user input and display data as needed. Only difference from MC and the like is in this case the windows aren't just things that look like windows, but they actually act and behave like it too.
Fair question though! WindowManager honestly started off as a joke with my friend, and just so happened to end up being the main "entry point" to the library. In the future pre-defined (or even dynamic) layouts should allow the above mentioned to happen when needed, but also keep all the optional mouse input shenanigans working as intended.
Edit: One thing that I think can showcase some of the upsides an architecture like this has is an ongoing project of mine based on PTG, https://github.com/bczsalba/Pagoda. It is primarily a frontend for a WIP messaging protocol me an my friend are creating, but the main idea behind it is the chat functionality is all confined within an "application", and that the user can write and install their own applications to be run from within Pagoda. This kind of makes the system feel like a proper desktop WM, and I think is a really cool idea. As the project is still very early the only available app is the messaging one, but I do have high hopes for it, if nothing else as a tech-demo for what PTG can do.
Fair question though! WindowManager honestly started off as a joke with my friend, and just so happened to end up being the main "entry point" to the library. In the future pre-defined (or even dynamic) layouts should allow the above mentioned to happen when needed, but also keep all the optional mouse input shenanigans working as intended.
Edit: One thing that I think can showcase some of the upsides an architecture like this has is an ongoing project of mine based on PTG, https://github.com/bczsalba/Pagoda. It is primarily a frontend for a WIP messaging protocol me an my friend are creating, but the main idea behind it is the chat functionality is all confined within an "application", and that the user can write and install their own applications to be run from within Pagoda. This kind of makes the system feel like a proper desktop WM, and I think is a really cool idea. As the project is still very early the only available app is the messaging one, but I do have high hopes for it, if nothing else as a tech-demo for what PTG can do.
I'm really impressed by the resizing and dragging. Works fine with my relatively vanilla terminal when a lot of advanced things don't. I've never seen an app make use of this feature so far.
Thank you! As long as the terminal supports the xterm-256 colors everything should work alright, and even below that the colors might look a bit off but nothing should break, per se.
The resizing bit was a bit of a mess to implement properly, but the current system does things like calculate the predicted minimum width of a window and not letting you minimize further, among other things.
The resizing bit was a bit of a mess to implement properly, but the current system does things like calculate the predicted minimum width of a window and not letting you minimize further, among other things.
On the Linux console, I couldn't see anything until striking a key. This was also the case for xterm; Emacs ansi-term; screen on urxvt; and SSH via SyncTERM. In all cases, hitting anything was sufficient to bring ptg to its senses. Still, this sort of behavior is worth shaking out, especially for remote applications.
Could you elaborate on this on more? I tried on xterm and it worked the way it should've. If you could raise an issue on GH I can look into it further, as it definitely seems like behaviour that should be fixed.
Thank you so much for checking it out!
Thank you so much for checking it out!
I’m curious how this compares to Textual?
I’ve been using Rich and Im about to try Textual for the gui of some scripts.
I’ve been using Rich and Im about to try Textual for the gui of some scripts.
It's similar but different in a lot of ways.
In PyTermGUI there is a large focus on the underlying terminal APIs and their implementations. This is because there are no external libraries to help us with them, so everything is hand-coded, and as an extension available to anyone from the outside. While the flashy part of PTG is the WindowManager class, the library is just as well suited for minimal applications such as converting your scripts' boring output to colored text or a nice looking Container. This is not advertised as much as it doesn't look that cool compared to everything else, but there is real value in it.
There is also some conceptual differences: Rich and Textual are very web-based in how they work and their syntacies, while PTG is very much not. This doesn't show up in many places, but for example in Rich, expressing an xterm-256 color would be like:
Other than that it's a lot of minor things. Most ideas can be created with either, though depending on your needs one might be more suitable than the other. For example, Textual does not support windowing in any way, while PyTermGUI does support full-screening, so if you want to create a modal popup on top of a larger background screen my version should be a bit easier to achieve it with.
Also, PTG code tends to be a bit shorter and usually easier to read, and IMO our markup syntax is much nicer (and as a fact, our parser significantly faster) and our Widget system is a bit easier to manage and extend.
In PyTermGUI there is a large focus on the underlying terminal APIs and their implementations. This is because there are no external libraries to help us with them, so everything is hand-coded, and as an extension available to anyone from the outside. While the flashy part of PTG is the WindowManager class, the library is just as well suited for minimal applications such as converting your scripts' boring output to colored text or a nice looking Container. This is not advertised as much as it doesn't look that cool compared to everything else, but there is real value in it.
There is also some conceptual differences: Rich and Textual are very web-based in how they work and their syntacies, while PTG is very much not. This doesn't show up in many places, but for example in Rich, expressing an xterm-256 color would be like:
[color(141)]This is lavender
While PTG lets you just use [141]This is lavender
...or with RGB: [rgb(111, 222, 333)]I have no idea what this color is
vs: [111;222;333]I have no idea what this color is
I suppose the biggest difference is that Textual is async-based and PTG is synchronous. Both can be run from the other paradigm, but converting async-sync or vice-versa in a decent sized project is pretty difficult.Other than that it's a lot of minor things. Most ideas can be created with either, though depending on your needs one might be more suitable than the other. For example, Textual does not support windowing in any way, while PyTermGUI does support full-screening, so if you want to create a modal popup on top of a larger background screen my version should be a bit easier to achieve it with.
Also, PTG code tends to be a bit shorter and usually easier to read, and IMO our markup syntax is much nicer (and as a fact, our parser significantly faster) and our Widget system is a bit easier to manage and extend.
Very impressive! Congratulations, it looks great and pretty complete.
Any idea why the getch demo does not report the Escape key?
Any idea why the getch demo does not report the Escape key?
Thank you!
IIRC it used to work just fine, but it hasn't for a minute. There is some weird handling with ESC, as most of the time it is the start of a longer sequence, so I probably just messed something up in that while refactoring.
Will look into it when I have the time, thank you!
IIRC it used to work just fine, but it hasn't for a minute. There is some weird handling with ESC, as most of the time it is the start of a longer sequence, so I probably just messed something up in that while refactoring.
Will look into it when I have the time, thank you!
No mneonics... All of this Python TUI stuff wastes pixels with 80's technology screen rendering and yet it doesn't have the only thing that still makes TUIs good: fast keyboard navigation. And I don't mean Tab-ing and arrow-ing your way to the button, let alone mouse clicking. I that C or Alt-C presses button with label "[C]ancel". Try to play with Midnight Commander to see. Also not saying that it's not possible in GUI but usually GUIs are not designed with keyboard in mind, while TUIs should be.
EDIT: GUIs had tradition of having mnemonics in menus and sometimes even on buttons. That is until smart people started removing it in the name of the design.
EDIT: Still, will check it out, though I will try to hack my way into adding mnemonics to buttons. Because arrow/tab navigation is f-ing stupid.
EDIT: GUIs had tradition of having mnemonics in menus and sometimes even on buttons. That is until smart people started removing it in the name of the design.
EDIT: Still, will check it out, though I will try to hack my way into adding mnemonics to buttons. Because arrow/tab navigation is f-ing stupid.
There is a pretty in-depth binding system that allows for the exact behaviour you are describing. This library is generally a framework with a loose implementation in the name of WindowManager. Most of these behaviours can and should be implemented in applications using this framework.
About "wasting pixels"... What if I (and many others) like the aesthetic and simplicity? There is a sort of magic in never having to leave your terminal emulator. Most frameworks are still keyboard-centered, as many of them don't even have mouse support to replace it with.
Edit: Thank you for your interest though! If you have a syntactically neat way to do the things you talked about feel free to raise an issue and I'll get to it as it comes up.
About "wasting pixels"... What if I (and many others) like the aesthetic and simplicity? There is a sort of magic in never having to leave your terminal emulator. Most frameworks are still keyboard-centered, as many of them don't even have mouse support to replace it with.
Edit: Thank you for your interest though! If you have a syntactically neat way to do the things you talked about feel free to raise an issue and I'll get to it as it comes up.
I'm with you. As beautiful as it is IMHO it's too reliant on the mouse and has no obvious keyboard-only navigation. But, also, it seems like the mnemonics are there, just buried. I would like to see that stuff front and centre and on by default if not obligatory.
After thinking about it overnight, I'm thinking about adding a button type that automatically binds its onclick method to either a given or automatically generated binding.
So something like
So something like
ptg.KeyboardButton("Help")
or ptg.KeyboardButton("Action", binding=ptg.keys.CTRL_B)
These would create a button with a label such as "[H]elp" and "[B] Action", and pressing `CTRL_` + their button would activate them. If idea is fine implementation should really not take much time.Perfect! Usually mnemonics are activated by Meta-$letter, e.g. Meta-C (or Alt-C) for "[C]ancel" or Meta-M for "I[m]port". That has long tradition. I've just found the I[m]port example in Evolution's (mail client) [F]ile menu. It also works that way in console twin-panel file managers Midnight Commander and almost all menu-like GUI panels in Windows applications.
So I'm midway through implmementing it all, and I'm finding that a lot of both meta and alt keys have behaviours that block them from working on my Mac. I know on Linux it probably isn't like that, but a lot of people will have Meta- bindings for some actions in the UI. Would it be a huge issue if it defaulted to CTRL? ATM I'm having issues even recording the value of my meta keypresses as too many of them are default bindings in MacOS.
Edit: Regardless, it is now pushed on GH. Will be included in next version, thank you both for the suggestion!
Edit: Regardless, it is now pushed on GH. Will be included in next version, thank you both for the suggestion!
Alright, I'll keep that in mind! Thank you for the suggestion :D
That sounds really nice!
[deleted]
[deleted]
The markup language is another great feature of the library, and is used by practically all elements of it. It is based on Rich's implementation, but uses a more concise and easier to humanly parse syntax, while being over 10 times faster at parsing due to a long list of optimizations.
There is a full Window Manager API included as well, allowing the user to move, resize and otherwise manipulate windows and inner contents using either their mouse of keyboard.
All of the "guts" of the library are also exposed and usable from the outside within the `ansi_interface` submodule.
Thank you for your time, and I hope the library may be of some use!