The wonderful world of TUI's

The wonderful world of TUI's

How to solve a need in a very fancy (and retro) way

At a time when the fledgling WEB3 is starting to permeate everything, be it blockchains, smart contracts, NFT's (Lol, no) or a hefty chunk of AI and Neural Networks doing whatever you want them to do (or whatever they want to do themselves, you know) I feel more and more nostalgic every time. And very often I remember how I started in this world in a "serious" way, not counting the 8-bit era that was little less than experimenting without a clear objective .

I remember when in my first year in the university I was given about 3 floppy disks with a suspicious “BORLAND TURBOC ARJ” label on them without being very clear what any of that meant. The next thing I remember is how I was programming a video store management application in an interface like this:

image.png

And yes, it was mouse compatible. And yes, It worked in windows98. But I had the urgent need to shoot it full screen so that absolutely everything that was seen was pure and simple terminal. I put so many hours into it that , even today, being able to do all my daily work - or almost everything - on a terminal still fascinates me.

And it was also at university when I met a fellow student who was an absolute genious: master and commander of the Shell, he was a specialist in putting together some scripts that I would barely dream of. And this is when he introduced me to the wonderful world of ncurses.

nCurses and the TUIs

TUIS (Text based User Interfaces) are the ancestors of what we know today as GUI's and they are still a way to embellish and improve the experience of a program that runs on a console or terminal beyond pure plain text. The magic of these interfaces lies in the fact that everything you see on the screen are characters: there is no "pixels" as we can understand it today to shape lines, curves, shadows, etc... but we only have the UNICODE character set of the terminal that we are using to shape user elements such as containers, buttons, forms, etc... A clear example of this type of application is the Vim editor...

image.png

... or the file manager MidnightCommander...

image.png

Within this universe we must mention nCurses , a library that allowed the development of TUIs. With this library, a little ingenuity and a lot of patience, spectacular things could be done.

Without going any further (behold: another old story incoming...) one of the practical exercises we had to do in Object Oriented Programming subject was to develop a "BattleShip" game but in console. The most stupid of us went to the basics: whether to paint an “X”, whether to insert tabs to draw a board, whether to clear the screen and redraw the board every time there was an event, etc... My amazing friend , obviously, couldn't stop at that and what we saw, apart from getting a 10 in practice, made us crack our heads: home screen, cursor movements, background colors, font colors, ASCII drawings, text effects... Mind blowing.

So we plant ourselves in 2022 with a specific need at work with no apparent solution. What do we do if we do not find any tool to help us solve it? Well, you have to create it, right?

Scenario

Let's put ourselves in a situation: in my day to day I have to manage the work of a few people; this work is reflected in a task management system that, in our particular case, is Redmine.

Redmine is very powerful and configurable but it has certain limitations. In my case I saw myself with the constant need to switch between views to see the workload of each of my colleagues, which wasted precious time. I needed some way to see everything globally, and the solution of opening a bunch of browser tabs with each view just didn't seem feasible. Redmine's custom views also didn't work for me because they got extremely long and I kept losing focus.

So after thinking about it for a bit, I realized that maybe using the API that Redmine offers, and a bit of development, maybe I could set up my own management tool. So that's what I did.

Research

The first thing I thought of was building an application based on React (i'm a React developer) for the front and Node for the back. Bad idea to do something that I wanted to keep simple: only the fact of having to set up a backend as a Proxy (to avoid CORS) and having to set it up to be able to make requests to the Redmine API every time I wanted to check fresh data seemed excessive to me . At the end of the day, all I want is to make my life easier... So discarded.

My next thought was to build an app via Electron that could maybe keep it all embedded in one package. With that I could save myself the issue of having to launch two executables separately and, in addition, I could make it totally portable in case any of my colleagues wanted to use it in the future. But again I found myself with the same feeling: it was something too "heavy" for something that I wanted to keep light.

So I dedicated myself to investigate how I could do something "simple" and that hardly required any effort to assemble. And it was when I found the second life that "ncurses" had had and of which I was unaware. And it was called blessed

Blessed

v0.1.0-3.gif

'' A curses-like library with a high level terminal interface API for node.js. ''

This can be read onthe project's github page. Blessed was born as a reinvention of ncurses for current technologies. The number of options and resources that this library offers is immense and allows us to do everything from simple text coloring to interfaces that can be handled with the mouse, passing through complex forms and decorations of all kinds.

The way of mounting interfaces using Blessed (or one of its many forks since the original project seems abandoned. I personally use neo-blessed) is extremely declarative and closely resembles the way of mounting the DOM on a web page. : starting from a root node (screen) the different elements of our interface are created. E.g:

image.png

This allows us to navigate between them and access their properties, referring to them as "ancestors", "descendants", "children", etc. Modifying their values, we just need to re-render the "root" node again so that the changes are reflected. make them visible on the terminal screen.

With a little investment of time to finish understanding how the library works we can achieve extremely cool things, and this is an (obfuscated, you know) example: this is how my little terminal app looks like right now: at last, on a single screen, all the information I need.

2022-04-28 22_48_07-.png

2022-04-28 22_46_00-.png

In addition to drawing on the screen, the library itself offers us methods to capture keyboard events and thus be able to navigate between sections. In fact, since everything ends up working on top of NodeJS, we can use any library available for it and thus, for example, format dates with "moment" or open the selected issue directly in the browser just by pressing enter. The possibilities are endless.

But the party doesn't end here...

Ink

image.png

Recently, while looking for information about how to implement a functionality that neo-blessed doesn't seem to offer natively, I came across something that I thought was wonderful: INK. This library is like mixing the best of two worlds: the design of TUI's with REACT. Yes, with React. Do not ask me how they achieve it, but the developers of this project have managed to use the terminal as if it were the DOM of a browser and render the same components that we would define for a React application in a browser. And this involves using things like styles, dynamic component rendering... even responsive elements!

What's next

My closest goal is to develop a parallel version of my issue tracker using INK because React is something that I'm pretty good at and i think I can build something cool with it. I have some very basic first conceptual tests and being able to program with React in the terminal is a joy.

Anyway, in the next posts I promise to explain in more detail how both blessed and INK libraries work and a little "how-to" use them for those who dare to develop TUIs.

Until next time! 👋