Search code examples
shellterminaltput

How do programs like man, screen, and vim create temporary overlays?


Several *NIX commands, such as screen, man, vim and others, create a temporary canvas/screen/overlay in a shell environment. When such programs execute, they cover or hide whatever content was displayed in the terminal before — almost like a "full screen" mode, within the terminal window. When they terminate, however, they reveal or restore whatever had been on the terminal before.

In the example below, I create some filler text on the screen, then invoke man bash. The man page opens up and covers all other characters on the terminal display. When I close the man page, the characters that had been covered up are again shown.

Before

terminal screen capture before running <code>man bash</code>

While an example full-screen program is running

Screencap of the man page for Bash

After

Screencap of the terminal after running <code>man bash</code>

I would expect that programs writing to stdout/stderr could accomplish the first step (replacing the content of the terminal with program-specific content), but then it would produce a ton of text that I could scroll through, and therefore couldn't do the second step: restoring the contents of the terminal. That means that somehow either the program memorizes the previous contents of the screen and re-outputs them (I doubt it?), or it creates some sort of sub-window within a terminal and something else keeps track of the previous contents of the terminal.

My Question

How can I accomplish that behavior in my own program and/or script?

Perhaps I should use curses/ncurses, tput, termcap/terminfo, or ANSI escape sequences?

Update:

This revised question is essentially the same as https://unix.stackexchange.com/questions/27941/show-output-on-another-screen-and-return-to-normal-when-done. (I hadn't found it when I had written this question despite lots of searching.) The difference is that my question is more general (any language) whereas that question is specific to Bash. The answers to both questions are essentially the same. If it's too similar to a question on another site, feel free to close it here for that reason.


Solution

  • How do these programs accomplish that behavior?

    ANSI escape sequences. Try running this script:

    #/bin/bash -
    tput smcup
    echo 'Hello world!'
    sleep 3
    tput rmcup
    

    Using infocmp, you can see underlying sequences that create this overlaying effect, e.g:

    $ infocmp -1 | grep 'rmcup\|smcup'
            rmcup=\E[?1049l\E[23;0;0t,
            smcup=\E[?1049h\E[22;0;0t,
    

    is this behavior shell-dependent or system-dependent?

    None, it depends on whether the terminal emulator supports save/restore operations.