Hacker News new | past | comments | ask | show | jobs | submit login
Writing Programs with Ncurses (invisible-island.net)
280 points by ComradeUlyanov 28 days ago | hide | past | favorite | 89 comments

I love TUIs. They are clear, quick and easy to use. Probably because they require straightforward design.

I just read the following links to build up foundation of knowledge first - low-level:




Other libraries:

# C, C++, Python and Rust


# Python, more polished presentation - but I cannot judge the technical foundation


True, i worked in a insurance company, the main CRM was a TUI with a Mainframe in the background, fast and reliable as hell/heaven.

Then everyone (Management) wanted to go away from mainframe (because it's 60's technology and expensive), so we developed a Java application with a GUI and Oracle in the background..and i was just ashamed about the whole project when it was finished.

It was slower for the user, less reliable and counting the dev-cost would gave us 10years of "free" mainframe-time.

I did such a migration. End results :

- user security massively increased (they need hardware tokens)

- user management is now part of a globalized management system where control access are much stricter than (let's call the dev to add somebody)

- it is muuuch easier to find new Java devs; development is now shared between the company (for business knowledge) and another company for the development, diminishing the train factor by a huge amount.

- code has been modernized and so is much more easy to audit

- SQL database can be queried by armies of cheap data analysis tools

- some of the consultants have now much less power to negotiate their salary (less than they were only 3 managing the application :-) )

That were for the positives. Negattives:

- Java UI needs much more time to get polished or much better dev's.

- Security is now much more administrative. Gone the days of the quick fix in production.

- hardware token for security is not vey well handled, incurring a heavy toll on data access (a limitation of our security token, which was unfortunately not seen during project planning)

- we had to reproduce all the TUI shortcuts for people to stay productive. Yes, you read that correctly :-)

It sounds you had a much bigger budget than we had ;)

BTW, the Mainframe had a sql-database (DB2) and was attached to Active-Directory already, the Reports/Print-jobs where send to a Linux Machine, it was actively maintained and not some old crusty 70's System.

The only sad part here is that you didn’t get your own 3278 with beam spring keyboard ;-)

People often equate a later fad with “modernisation” when a well architected app can be easy to manage even if written in COBOL and running under CICS.

If a person can learn Java, they can learn to read COBOL.

>The only sad part here is that you didn’t get your own 3278 with beam spring keyboard ;-)

Hey! I have my beloved HHKB Professional 2 since years :-)

>If a person can learn Java, they can learn to read COBOL.

Well...well yes! That's true especially the modern one's.

> Hey! I have my beloved HHKB Professional 2 since years :-)

Doesn’t come even close. ;-)

Don't you dare to say anything more!!!

But i believe you ;)

You don't need to trust me. Trust the almost physiological reaction they provoke on an unprepared human: https://www.youtube.com/watch?v=hNRH1ULmbNA

Similar experience (as a user) at a medium-sized college.

The information system (class registration, bursar, etc) could be accessed via a TUI over telnet/ssh. It was amazingly fast, and all the older professors could move around that thing fast as hell, since all the shortcuts were in muscle memory. Force-adding a student to a class could literally take <5s if they had all the numbers.

Students could use it, too. And those of us who knew about it would do so, since it was so much better.

Then the web frontend came out…

Hehe, we also had similar system in university. It was usually accessed over telnet, but in some places at the school, you could still find the real electron tube green (or orange?) text teletype terminal, where the student could sit and access just this system.

It was fast in normal times, but you'd still have trouble using it when the class registrations opened, and thousands of students tried to use it at the same time.

> It was fast in normal times, but you'd still have trouble using it when the class registrations opened, and thousands of students tried to use it at the same time.

Often the way these things work, the old terminals go slow (sometimes very slow) but work, and the new way times out often making it impossible to make changes, but sometimes you still can, but won't know if they worked.

Wanted to hear this. This had been my experience too. But no one on the net seem to talk about it. It was always "we are stuck with mainframe due to politics..."

But this isn't about mainframe vs Java. I have a feeling it's about Terminal user interface vs GUI.

A modern terminal app, will be just as much fast as those old mainframe apps, is my feeling.

Mainframes do have a more sensible way to build a TUI than something like curses. A 3270 TUI is very similar to using html forms. The fields are named, have attributes, validation, and a so on. The mainframe sends the form, the user interacts with the form, and nothing is sent back to the server until either a field validation is needed or the "Enter" key is pressed.

More detail: http://bitsavers.trailing-edge.com/pdf/ibm/3270/GA23-0059-4_...

Did you mean to link to a 380 page PDF book? Sure, it fits with the literal meaning of "more detail", but it doesn't feel helpful in a discussion context like this...

I clicked on that link hoping to see one or two pages of info that made it clear how the whole system worked with more detail than you gave, but not a whole book of minutia that I don't have enough reason to care about at this point in the discussion.

You can <ctrl-f> and search for "Overview and Concepts".

I'm not aware of a summarized 2 pager as a standalone html page.

There is no 2 page manual at IBM ;)

Few things would make me as happy as the Django admin module ported to a TUI. In the mainframe days, how much did application developers need to worry about the displayed field length, or was that handled by the OS?

That approach is good enough for simple forms ala HTML, but it's not effective for the sorts of full-featured TUI's with character-based graphics, drop-down menus, widgets, panes/windows etc. that are expected nowadays. Even writing a simple interactive text editor would be problematic using that model.

You can do all that as well. Screenshot of a fairly complex 3270 TUI: https://davideellis.files.wordpress.com/2012/08/1-samplee327...

Or a video, skip forward to about 8:00 https://higherlogicdownload.s3.amazonaws.com/IMWUC/UploadedI...

I don't think it is exactly TUI vs GUI, but more keyboard-first vs mouse-first, i.e. how you interact with it. Granted, Desktop GUI are usually developed mouse-first, but it doesn't have to be that way: if you take windows 98 / windows 2000, you could get everything done more efficiently with a keyboard than with a mouse.

Just think about the difference between an app developed specifically for the desktop (mouse) or for mobile (touch): same GUI but completely different programs and experience


Plus responsiveness. Terminal apps have faster response time than GUIs. And when someone is typing like 10 chars per seconds it matters.

The usecase is different between terminal vs GUI. Where in GUI you look - choose - decide and click. And in terminal you blindly storm on the keyboard as fast as you can.

Terminal apps are running under a GUI terminal for at least two decades now, there isn't really a reason for a GUI application to not be as responsive as a terminal application, it is just that "modern" GUI toolkits being slow.

IMO a reason is because nobody seems to bat an eye when faced with a "TUI" made out of lines, boxes and garish colors but if a GUI is made like that it is suddenly ugly so toolkit developers put a ton of effort into shiny looks.

But try a GUI made with Win32, Motif, Tk (not Ttk) or even Gtk1 and it'll be as responsive as any terminal application (of course it also depends on the application, there isn't much the GUI can do if the application abuses it or is sluggish for other reasons ).

A bit of that is also related to different UX design, with many of the venerated old TUIs actually having better UX, not due to being TUI, but because they avoided certain popular (anti-)patterns of GUI programming.

A top example, from discussing with non-techies who had the tools change from TUI to GUI, is the drop-down menu bar at the top of the window (or top of the screen, for mac). What used to be few keys at worst, turned out to multiple long trips by mouse to select an option 3+ levels of nesting deep, because the job was just that complex - but there was no contextual shortcut available.

Many old TUIs (and we're talking divergent brother of S/370 with random other stuff in the mix old) tended to have ways to reach pretty deep in the navigation structure pretty fast (sometimes even direct - for example airline reservation systems, where you often can make a CLI command go straight to a completely different context).

> The usecase is different between terminal vs GUI. Where in GUI you look - choose - decide and click. And in terminal you blindly storm on the keyboard as fast as you can.

Actually I think it is more nuanced than that.

Some GUI programs are well optimized for fast keyboard only usage even if you can use point and click. NetBeans, Eclipse, IntelliJ, Sublime Text and VS Code are on top of my mind but even some old web applications used to be quite usable I think.

I had a similar experience. And it would have been simple to pay attention to tab traversal, field highlighting, key bindings, etc, to have made the new application more familiar and faster. Wasn't to be though.

For C++, there is also ImTui that I wrote sometime ago:


I made a few sample apps with it, such as HN client and a WTF configuration tool. They are both linked in the repo if you are interested.

I still want to make some other cool terminal app with it, but haven't found a nice idea yet.

This library looks really fun!

Thanks for sharing the link.

So, does that actually work in a proper terminal? Or is it only when you have a framebuffer available?

> does that actually work in a proper terminal?

Yes - all of the examples in the linked repo run in the terminal and are also ported to the Web using Emscripten.

> Or is it only when you have a framebuffer available?

ImTui creates a framebuffer and renders the scene using ASCII characters into the framebuffer. To create the scene, you can use the entire API of Dear ImGui [0] - it has various options for creating windows, buttons, sliders, tables, checkboxes, colors, etc.

You now need to display this framebuffer somehow and also provide input from the keyboard and the mouse. ImTui provides an ncurses interface for this. It uses the ncurses API to render the characters in the terminal and also to grab input from the keyboard and the mouse.

Technically, ncurses is an overkill for this application, since ImTui only uses only a very small subset of the ncurses functions. But this was the easiest way to make it work.

ImTui can be extended with more interfaces. For example, I made a second one which I call "Emscripten" interface. It's purpose is to provide an API to easily export the framebuffer to the JS layer and to easily grab input back from the JS layer. This way, I can have a single application code that builds and runs both in the terminal and on the web.

[0] https://github.com/ocornut/imgui

It feels like we live in a pretty good time for writing TUIs, CLIs and also small self-contained tools (thanks to languages like Go, which have a lot of libraries, are easy to use, but also compile to statically linked executables).

What stuck with me was using the Typer library for a Python tool that i wrote: https://typer.tiangolo.com/

It made regular shell scripts into a fully fledged CLI with nested commands thanks to just a few decorators that were sprinkled in the source files, as well as the occasional slight signature alteration.

Developing a GUI feels awfully complicated in comparison and i'm amazed that there don't seem to be all that many (if any) frameworks for creating GUIs in a similar way - by annotating method calls as actions that correspond to the actual GUI elements and letting some smart parsing logic handle the rest for you.

I feel like perhaps the world would be a slightly better place if desktop software could also be distributed as libraries of callable code, where you could automate button presses programmatically and there would be a 1:1 link between what you can do in code and manually.

> Developing a GUI feels awfully complicated

It’s kind of a language thing. When Visual Basic came out, it’s UI builder was ahead of anything I’ve ever seen on a GUI and more versatile than HyperCard (and much faster).

A decent GUI builder attached to an IDE and some nice language support goes a long way.

That’s the opposite of the experience you get when using, say, Flutter or React Native. The language is better than BASIC, though.

Sadly it seems a thing of the times, perhaps due to the direction the industry has gone in.

I recall creating GUIs in Lazarus/FreePascal was really easy and an enjoyable experience, however there are so few libraries and integrations for it, that it's a non starter for new projects.

There is Swing for Java which had a really nice GUI builder in NetBeans, but the other IDEs are somewhat lacking in comparison and then JavaFX/OpenJFX came out, which didn't integrate quite as nicely and complicated things further.

As for .NET, it has always had lovely GUI options, especially with WinForms/WPF in Visual Studio, yet it has always lacked cross platform options for the most part.

How we got from being able to drag and drop components to create fully functional GUIs to embedding browsers and creating apps with full webdev stacks locally never ceases to surprise me in a bad way.

> I recall creating GUIs in Lazarus/FreePascal was really easy and an enjoyable experience, however there are so few libraries and integrations for it, that it's a non starter for new projects.

Lazarus and Free Pascal are used for new projects all the time, if anything judging from the mailing lists, they are more popular than they've ever been (hell, unlike only just 5-6 years ago, i rarely see people mention that they remember using Turbo Pascal back in their school years whenever a new release is made nowadays :-P).

Free Pascal comes with a ton of bindings out of the box, but making new ones for C should be simple with the included h2pas tool (i think there is also a frontend for Lazarus though i never used it myself). There should also be already made bindings for stuff that aren't distributed with Free Pascal. You should also be able to use Rust libraries by going via cbindgen -> h2pas, as well as any other language that can "export" C header files for FFI. Beyond that you can do it manually, which can be a pain, but that is the case with pretty much any language.

Of course using libraries from scripting languages and managed languages like Python, JavaScript, Java and C# is harder but not impossible (and not really that much harder than using them from any other native language, C included).

It wouldn't be too difficult to build on Glade or QtDesigner and better integrate it with code generation. Both Glade and QtDesigner output language-neutral UI descriptions that could be used to build any sort of app.

Lazarus already saves the forms into text-based files that you can read, however this is really missing the point and reducing an advanced RAD tool to nothing more than 80s-circa resource editor for Windows. There are tons of tools like that.

The big feature of Lazarus (and Delphi and C++ Builder, etc) is how integrated the entire thing is - not just the form designer but also the framework being itself designed around its use inside Lazarus' form designer, object inspector, etc and the language having features (e.g. published properties) explicitly for such use and the IDE knows about the framework so it can automatically plug things, generate code (not in the Glade style of unidirectional generation but in that the IDE understands the code and can modify it). Hell, even C++ Builder actually feels a bit "alien" to VCL (which was originally made for Delphi and Borland had to add several extensions to C++ for it to work, which only really worked because they had their own compiler, linker, etc to work with).

The closest you could get to that elsewhere is QtCreator but you quickly realize (assuming you were used to Lazarus-like tools, most developers actually do not realize that) you are working with something that was meant to be coded against instead of used with visual designers (which is kinda backwards IMO considering the "G" in GUIs and kinda remind me a quip about Motif back in the day about how its documentation was a bunch of volumes almost without any screenshot :-P).

But if you want to do it right, you can't really work around the need for all these to be integrated with a unifying vision. Even Lazarus and Free Pascal, which are technically different projects, largely managed it because they basically did what Delphi already had done - and most of the warts when using Lazarus come from not being a truly integrated project like Delphi was, like issues with different FPC versions or relying on GDB as a debugger (which is the #1 source of debugging issues, fortunately there is a new debugger in works which can work as part of the IDE itself and personally find it to work fine, though it isn't enabled by default).

There is something kind of similar-ish in the GUI space that takes any commandline program and turns it into a simple GUI.


I recently came across YAD (https://sourceforge.net/projects/yad-dialog/), which is a improved version of dialog. Allows you to create a simple GUI, where all the entries are written to STDOUT. So, you can interface with your favorite language. For examples, see this page: http://smokey01.com/yad/

Note that the project hasn't been contributed to since 2017, and contains unfixed bugs from six years ago.

Might be worth a fork or a rewrite.

It's active. Seems to have been moved to https://github.com/v1cont/yad

I installed via AUR (which uses the right github link) and didn't notice that I was bookmarking the old version of the project. Thanks!

Gooey is a similar tool to Typer that I have bookmarked for such cases, but never had the opportunity to use it.


> http://%CA%9E.cc/irl/term.html

Link is broken (malformed); should be (I think) http://xn--rpa.cc/irl/term.html.

I have looked into this in the past, and have always felt discouraged by the lack of good support for modern keyboards and mice. With ncurses and similar, you can only detect (a subset of) keys modified by Ctrl and Alt; I would like a portable way of finding about multiple combinations of modifiers, with any key in the keyboard, including function keys, home, end, up, down, etc. Ideally, I would also like to detect mouse events (including "window" clicked position) and even mouse events when holding Ctrl, Alt, etc. And I would like to do all this without having to parse multiple escape codes, implement timers or whatnot.

https://sw.kovidgoyal.net/kitty/keyboard-protocol/ is a very promising step on this direction. Maybe next time I have to work on a TUI I will look into it.

I think part of it is that what good is your TUI if it doesn't work with, you know, a terminal, hooked up on a serial port? Where you will be unable to have anything but "shifted" and "control" characters easily recognisable. Some terminals did have a "meta"-equivalent key that simply forced the highest bit on, making them INSTANTLY incompatible with anything but US ASCII.

Sure, you can write a TUI library that allows you to interact with "idealised terminal of choice", but I'd prefer one that works with one of the serial terminals I actually have, somewhere, around the place.

While discussing ncurses, has anyone ever seen any attempt to make accessible interfaces?

Nowadays when making a quick interface I tend to use a web-based interface -- while they are much heavier it's fairly easy to make fully blind accessible interfaces, I (very briefly) looked to see if any terminal based libraries supported anything similar, and the only thing which seems to be trying is emacs, with emacsspeak (which I've heard good things about but haven't tried, as I'm not an emacs user).

It would be nice if curses programs all had a standard keymapping or signal that would invoke one of curses screen dump functions. Lacking that, a screenreader would have to jump through a lot of hoops to even know what's on the screen. I suppose you could use tmux instead...it seems to be able to dump the current screen. Either way, still a lot of work to do after you have the raw data.

You don't need to dump the screen, the screen reader takes care of letting you explore the screen by line, word, character, etc.

Some curses programs work reasonably well with screen readers (e.g. Mutt and WeeChat). One useful way to make them more accessible is to put the hardware cursor somewhere useful, even if hidden. Mutt puts it on the same line as the currently-selected message, and if braille_friendly is set, onto the first line of message content when opening one.

WeeChat puts it on the input line. Where this goes wrong is when trying to use fset, where I have no way to move it to the list of options.

> One useful way to make them more accessible is to put the hardware cursor somewhere useful, even if hidden.

You should be doing this anyway to account for hardware terminals where the cursor is always visible, including the traditional VGA/VESA text console that still gets used by default on PC hardware.

Can you give any more guidance on what might constitute "somewhere useful"?

Is the hardware cursor position the default place to start reading from?

Somewhere useful depends on the app. In an editor, it's the line of text I'm editing. In a file manager, it's the currently focused file.

The hardware cursor is where it will start reading when I press read current line, word, etc.

That makes sense. It's a little harder to determine where it should go for something like a chat client where the UI changes asynchronously.

I have met some blind users who were using terminal-based IRC clients. I believe they were using the scripting interface to assist in integrating it with their input/output hardware.

Plain old HTML + forms can go a long way when accessed through the Lynx or w3 web browsers. I think the first time I encountered a system where this was the preferred path was in Kannel [0].


I've never thought about this! I tried to write a simple TUI with ncurses, but it turned anything but simple real quick!

I don't think that this is inherent to ncurses but to any UI programming. Keeping state on the UI can be "simple" until is not.

Thanks for the idea, I'll give it a try!

That's funny, I had this tab open this weekend while I was trying to make a silly terminal game, where each sprite is an ncurses window. I didn't really make much progress, but got the physics and sprite drawing working.


why merely write programs with NCURSES when you can hack the planet with notcurses? enjoy the free book:


I can't access the site...

Access Denied - Sucuri Website Firewall Block reason: Access from your Country was disabled by the administrator.

In case someone else experience the same and wants an alternate link: http://web.archive.org/web/20210531163620/https://invisible-...

I don't know why that WAF is in front of it, but there seems to be an intentionally maintained mirror that doesn't have the Securi headers: https://invisible-mirror.net/

So, the mirrored copy of this article would be: https://invisible-mirror.net/ncurses/ncurses-intro.html

> Block reason: Access from your Country was disabled by the administrator.

Thanks for that mirror, I occasionally use the lynx web browser that is also hosted there and being blocked has always been a problem.

Thomas Dickey has been maintaining this code by himself for years (decades?). Along with the timezone database, the terminal info database is a huge SPOF. It's too bad that this effort is mostly unrecognised.

One really nice thing about ncurses (which I used in python to make an email user agent) —- you can run ncurses apps in an ssh session.

I had always wanted to write something in this and got my chance last year when I finally decided to write a utility for Safari tab management:


Since then, however, I’ve switched to the Min browser. But it was super empowering to make a console-based interface and I’m looking forward to trying it again soon.

Any examples of modern apps with rich terminal GUI?

Take a look at the latest Notcurses demo video to see what that library makes possible:



not sure how you define modern but things like neovim, neomutt and ranger come to mind.

I enjoy r/unixporn (it's actually sfw), they LOVE console apps there, everything from music to email to file manager to everything console!

There are also a few modern terminal emulators that are doing some pretty fun stuff with the terminal, some examples are alacritty, kitty and hyper

My personal favorite is musikcube: https://musikcube.com/

The mouse support is excellent, assuming your terminal emulator supports the features it needs. (Alacritty does, but iTerm2 doesn't seem to send right clicks to the program.) Pretty much everything can be clicked and right-clicked, you can even scroll (although I find it scrolls too fast to be useful).

I listen to most of my music through musikcube and ncspot https://github.com/hrkfdn/ncspot these days.

I don't know if it counts as rich, but I rolled my own terminal UI in my email client meli [0]. There's a web demo here: https://meli.delivery/wasm2.html that is the client compiled to webassembly and the ANSI escape codes translated to equivalent SVG drawing so that you can try it on your browser. [0] https://github.com/meli/meli/

take a look at growlight: https://github.com/dankamongmen/growlight

VisiData is one of my favorite TUI apps. It's a handy tool for working with tabular data, like CSVs:


I love mu4e. I don't know if running in Emacs qualifies as "terminal GUI" though.


It certainly qualifies. TUI stands for text UI not terminal UI

The most modern terminal GUI (as for 2021) would have to use React: https://github.com/vadimdemedes/ink

The "n" in "ncurses" is for new. Its not so new any more ;)

This naming problem is not specific to programming. The name "Carthage," for example, is derivative of Phoenician for "new city."

For whatever reason, my country is banned from accessing this website.


I checked your country, very odd to me. Maybe try this link


For a low-mental-overhead alternative to curses, I just discovered this lovely little library:


I don't like text UIs. They try to emulate GUI but do it poorly. You should either make a classic console program, that can be scripted, piped, etc., or a real GUI.

> They try to emulate GUI but do it poorly

I dispute that point. Firstly, because TUIs and GUIs were developed pretty much in parallel, as far as I‘m aware. But secondly (and more importantly), because TUIs fill a different niche and follow a different philosophy to GUIs.

TUIs are primarily intended for environments where GUIs are either not available (e.g. SSH), unnecessary (e.g. servers), or overkill (e.g. very old computers). In terms of design and UX philosophy, they are much more concentrated on keybased rather than mousebased interaction, and bring their own set of conventions that are markedly different from GUI design philosophy.

So, while you are entitled not to like TUIs (they can be difficult to work with), calling them a bad emulation of GUIs really misses the point.

> TUIs are primarily intended for environments where GUIs are either not [...] or overkill (e.g. very old computers).

You'd have to be using a very old computer considering Windows 3.0 worked even on an original IBM PC. Though granted, you needed at least a 386 for it to be usable.

Chances are your GUI toolkit is too bloated, but that is the fault of the toolkit you chose, not GUIs themselves - use a more lightweight toolkit.

> In terms of design and UX philosophy, they are much more concentrated on keybased rather than mousebased interaction

This is up to the application, there is nothing that forbids GUIs to be fully keyboard controlled (in addition to mouse of course).

> and bring their own set of conventions that are markedly different from GUI design philosophy.

Pretty much every TUI either has its own set of conventions or mimics established GUIs or a mix of both, so not really.

Hard disagree. What’s wrong with htop? Do you propose installing a full desktop environment on your servers and then using X forwarding just to monitor live CPU usage? It’s just a live-refreshing ps. With colors to make it easier to grok at a glance. Then making it slightly interactive so you can click on column headers with the mouse to sort accordingly?

Same here. Never liked using console text editors, in particular. When editing remote files, I always prefer using something like sshfs/WinSCP + Sublime Text.

Eh there is plenty room for all gray areas of tui. You are talking about CLI and not TUI, completely different world. TUI is great if you work remote and can present a lot of information quickly in such situations. Plus some people prefer them and that's all it really requires for there to be some awesome TUI programs. All you really have to do is ignore them if you don't like them.

Hearing the word ncurses brings back memories of second year computer science for me. Once upon a time. In a galaxy far far away

I wish there was a list of all the quirkiness of ncurses back when I wrote a win32 port of it for a game.

curses are awesome, there is also a react wrapper that makes it easier to implement

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact