Mac Terminal doesn't obey ANSI "Show Cursor" Escape Sequence; Can't Regain Cursor Visibility, suspect State issue

System:

I'm writing a Python 3 script using ANSI escape sequences on an Intel iMac Pro running up-to-date Monterey.

Problem:

I hide the cursor when printing a lot of ASCII animations to the screen. When I'm all done I like to reset the screen as the last action.

But sending "\033[?25h" to the screen after a script has ran for a while doesn't bring the cursor back. If I send the hide code, then just sleep for 3 seconds, then send the show-cursor sequence, it DOES seem to work.

Research / Attempts:

I also had the idea to "save cursor state", and then later restore cursor state, but that didn't work either. I tried both the ANSI settings (ESC[7 and ESC[8) and the VT commands (ESC[s and ESC[u)

I also tried using curses.curs_set(0) and then later curses.curs_set(1), also didn't work. Not only does this leave the cursor invisible, but echo of characters is also then disabled, and I think maybe the linefeed gets messed up too.

I also tried the unix commands "reset ; stty sane ; clear", but that still won't reset it either. This really surprised me; the only workaround left is to open up a fresh terminal tab.

I saw one post (which I can't find now) which said there was maybe some stateful issue with the Mac Terminal program, that sometimes it doesn't work, but other times it does, depending on what's been previously sent. This would seem to be consistent with my experience (that if I restore right away it works, but after lots of traffic, it doesn't. With that in mind, I tried sending the visibility command a bunch of times, that didn't help.

I've also tried entering the escape strings into the Python code a couple different ways, as in "\e[?25h" and "\033[?25h"; of course that didn't help.


Solution 1:

I think what we need here is the Curses library. They have the intricacies of common terminal emulators all figured out. You can hide the cursor with curses.curs_set(0), and show it again with curses.curs_set(1).

https://docs.python.org/3/howto/curses.html