How to create scrollable console application that support ANSI escape code sequences
Asked Answered
M

1

1

I am making some assumptions here on technology based on what I know, but other technology recommendations are welcome.

My goal: Write an ANSI Art viewer that as closely as possible resembles viewing on a DOS machine as possible, preferably without the overhead of running dosbox. This will run on a Raspberry Pi.

I have gotten my console to properly cat an ANSI with proper characters, colors, etc. The catch with the "viewer" is that I would like to be able to use the arrow keys to scroll up and down through the document, much like, say, the "less" command does.

From what I have been able to research, curses is a perfect candidate for this. The problem is that curses does not support ANSI escape code sequences. There is an ANSI editor written in C++ that uses curses, but it builds its own support for parsing the escape code sequences. Right now this is my last resort.

So my question is: Is there a better route to creating a scrollable console-mode application for viewing ANSI Art (Code Page 437 + ANSI escape code sequences) in python on linux?

Mcdaniel answered 21/8, 2013 at 22:30 Comment(1)
What does it mean to "scroll up" in a document that contains cursor-movement sequences? If you only want to handle the subset of ANSI art that doesn't move the cursor around, that's a lot easier… but then you don't need curses in the first place (assuming your terminal happens to handle ANSI color, etc. sequences, that is, but you've apparently already dealt with that, given the cat example).Eventempered
E
0

There are really only two possibilities: Parse the ANSI sequences into something curses can accept, or use the ANSI sequences as-is.

At first, the latter may seem more attractive. Most of the limitations are either irrelevant to you, or easy to deal with:

  • It only works for static ANSI art, not animated files. Which is pretty reasonable, because it wouldn't make much sense to "scroll up" in an animated file. (You could of course render it on the fly to a canvas and then scroll a window up and down within that, but once you start thinking about what that rendering and windowing means… you're parsing ANSI art.) But it sounds like you only need static ANSI art.
  • It only works if your terminal is (close enough to) ANSI compatible… but it is (or can be made so) or your cat command wouldn't work. (You may still have a problem with the color settings, but I assume you know how to work around that too.)
  • It only works if your terminal is cp437, which may be more of a problem… but that's trivial to work around; just decode('cp437') then encode as appropriately in your code; the escape sequences are going to pass through unchanged.
  • You probably want raw keyboard input. But this is as easy as tty.setraw(sys.stdin.fileno()) and just reading stdin as an unbuffered file. (Well, you may want to stash the original tcgetattr so you can restore it later, but that's not much harder.)
  • You'll have to parse keyboard input escape sequences yourself. This is a lot of work to do generally… but just handling the up and down arrows for ANSI-art-compatible terminals is easy.
  • You'll have to know how to map the ANS file to actual lines.

That last one sounds like the easy part, but it's not. For example, I grabbed a random file, GR-BANT; it's only 33 lines long, but it's got 154 newlines in it. And that's going to be pretty common. In many cases, it's just going to be "overlay lines" that start with esc-[-A, that you have to treat as part of the previous line, which is not hard to do, but there will be plenty of cases that require something more than that.

So, you're going to have to do at least some ANSI parsing, no matter what.

And once you start on that, I think you'll find an easier time with your "last resort" of doing a full parse and drawing manually to a curses pad. (And of course this has the side effects of making it possible to handle animated files, working on non-ANSI terminals, handling "keypad" keys more easily and on all terminals, …)

But if you want to go the second way, here is a quick hack that should get you started.

Eventempered answered 22/8, 2013 at 0:13 Comment(3)
To answer your question above: I want to take a static ANSI image and move the 25 line "window" that is visible as you look at it. So if an ANSI is 200 lines long, as I press the down arrow, I move down that 200 lines seeing only 25 lines at a time. If I press the up arrow, I will start to see the lines above that I have passed, adding one line to the top, removing one from below essentially. I will check out your proposed solutions.Mcdaniel
@lordscarlet: Right, that's what I assumed you wanted. The problem is that even "static" ANSI-art files typically aren't really static. Look at the example I linked to—154 lines of text to draw a static 33-line image. So, you have to render it before you can scroll it. For that particular image, you only need to deal with the "up 1" code, which is pretty easy to work around (my sample code does it in a hacky but successful way), and "left" codes, which you can ignore. But if you want to handle files where that isn't true, you need to parse and render.Eventempered
Yeah, I got distracted and haven't been able to work on it, I'm working on porting my ruby port of the perl code we use to parse ANSI. I probably should just try to get the ruby code to work on the pi, but I guess that's neither here nor there. FWIW, I run the site that you linked to for the example.Mcdaniel

© 2022 - 2024 — McMap. All rights reserved.