VT100 Escape Codes in Command-Line MiniScript

MiniScript is most commonly used either in the Mini Micro virtual computer, or embedded within some other game or application. However it is also available on the command line. A command-line MiniScript user asked me the other day: is there a way to clear the terminal window from code?

The answer is, yes and no. There is no built-in API for it, but in most cases, it can be done with an ancient set of tricks known as VT100 escape codes.

The VT100 was a terminal (a keyboard and display used to communicate with a mainframe computer) made by Digital Equipment Corporation (DEC). It actually referred to a whole series of related models, made in the 1978-1983 era (things moved fast in those days!). These terminals were among the first to go much beyond what a paper-based teletype could do: they could clear the screen, move the cursor, draw in inverse mode, and more. And yet the only way the mainframe (think "cloud server" in modern terms) could tell it a terminal to do anything was by sending it characters to display.

So the good people at DEC defined a system of "escape codes" — short sequences of characters that begin with the Escape character (ASCII 27). The terminal would watch for these special character sequences, and perform the indicated function of clearing the screen, moving the cursor, etc. This system was so simple and powerful that it was an instant success, and is still imitated even in modern terminal programs today, half a century later!

So with no further ado, consider the following MiniScript code.

esc = char(27)

// character styles
bold = esc+"[1m"
underline = esc+"[4m"  
inverse = esc+"[7m"
invisible = esc+"[8m"
normal = esc+"[m"

The first assignment above, esc = char(27), just defines a convenient shortcut for the Escape character. All the VT100 codes begin with this. The rest of the definitions in the above listing have to do with styling the text. You use them by simply printing them wherever you want to change the style. For example:

print "This is a " + bold + "bold" + normal + " step!"

which prints: This is a bold step!

Now let's consider some escape sequences for moving the cursor. Some of these have arguments, so are defined below as functions. Because there are so many cursor-moving functions, I've put them into a little cursor map.

// cursor movement
cursor = {}
cursor.up = function(n=1); return esc + "[" + n + "A"; end function
cursor.down = function(n=1); return esc + "[" + n + "B"; end function
cursor.left = function(n=1); return esc + "[" + n + "C"; end function
cursor.right = function(n=1); return esc + "[" + n + "D"; end function
cursor.goto = function(row,col); return esc + "[" + row + ";" + col + "H"; end function
cursor.home = esc + "[f"
cursor.save = esc + "7"
cursor.restore = esc + "8"

You use these in the same way. For example, suppose you want to print a countdown, but without filling the screen up with a new line every time you update the count. You can now do:

print; for i in range(20); print cursor.up + i + " "; wait; end for

This moves the cursor up and overdraws the previous number, making a nice neat countdown. You can also print something like cursor.right(10) to move the cursor to the right ten spaces, or even cursor.goto(1,40) to move the cursor instantly to row 1, column 40. If you print cursor.save, the terminal will remember the current cursor position; and then when you later print cursor.restore, it will put it back.

Finally, here are some escape sequences for clearing various parts of the screen.

// clearing part or all of the screen
clear = esc + "[2J"
clearLineToRight = esc + "[K"
clearLineToLeft = esc + "[1K"
clearLine = esc + "[2K"
clearBelow = esc + "[J"
clearAbove = esc + "[1J"
reset = esc + "c"  // (clear, plus also resets all state)

These all do what you would expect. Printing clear clears the whole screen; reset does the same, but also resets other state (such as character styles). The other codes above allow you to clear some part of the screen, relative to the cursor: just the line the cursor is on, or the left or right part of that line (relative to the cursor), or the whole screen above or below the cursor.

With these escape sequences, your command-line terminal programs can be much more interactive and interesting — almost as good as using Mini Micro!