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

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
While an example full-screen program is running
After
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.

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.

Related

terminal command is overwritten on itself

sometimes in terminal when I type a long command, instead of continuing in the next line it starts to write at the same line and I cannot see what I am typing. What is the reason and how should I make it fine?
Sometimes if you resize a terminal window while in a fullscreen command (say inside "vim" or "less"), when you exit back to the shell it will assume your terminal has the old dimensions, and will show the behavior you are describing. See this question: https://unix.stackexchange.com/questions/61584/how-to-solve-the-issue-that-a-terminal-screen-is-messed-up-usually-after-a-res
Also, please in the future post this kind of questions in unix.stackexchange.com as this one is not strictly a programming question.

How to keep terminal input always at bottom in Golang?

I am trying to create a program which will have live updates from some data source. And I also want to wait for user input just like a normal terminal. Right now, whenever there is update, I will print the content and print the prompt message for input again which create something like this:
Enter command >
This is a live update message
Enter command >
This is a multi-line li......
......ve update message
Enter command > quit
Bye bye!
The problem is that for every live message I received, I will print it and the "Enter command >" will be displayed again again and again, which is not desired. I want the live update to be update on the main part of the terminal, while the "Enter command >" always stay at the bottom
The closest package I can found on Github is https://github.com/gizak/termui but most of the examples inside is trying to display text, gauge and graphs. So I am not quite sure how to get started.
Is there any package or example of the termui package to achieve this? Thank you.
With github.com/gizak/termui you're heading in the correct direction.
To understand why you can't get that
I want the live update to be update on the main part of the terminal, while the "Enter command >" always stay at the bottom
part sorted out, a little excursion to the history of computing is due. ;-)
The thing is, the mode your teminal emulator¹ works by default originated
in how computers would communicate to the operator in the era which predated
alphanumeric displays — they would print their responses using a line printer. Now think of it: a line printer works like this: it prints whatever is sent to it on a roll of paper. What was output, was output.
The new output always appears physically below the older.
When alphanumeric displays (screens) came into existence they
naturally continued to support this mode:
the line text to be output was rendered at the bottom of the screen
with the text above it scrolled upwards.
That's what you see in your typical terminal emulator all the time when you're working in the command line of a shell (such as bash) running by the emulator window.
This, default, work mode of a terminal is called "canonical" or "cooked".
Then came more advanced displays, for which it was possible to change
individual positions on the screen — identified by their column and
row numbers.
This changed the paradigm of how the information was output: the concept
of a so-called "full-screen application" was born.
Typical examples of them are text editors such as Vim and Emacs.
To support full-screen text output, terminals (and terminal emulators)
were adapted by implementing certain extensions to their protocols.
A full-screen application first requests the terminal to switch into another
mode called "raw", in which the terminal sends most of what is input by the
user directly to the program running on the terminal.
The program handles this input and orders the terminal where and what
to draw.
You can read this good summary
of the distinction between the both modes.
As you are supposedly suspecting by now, to be able to keep some block
of information at a certain fixed place of the terminal's text screen,
you want your program to be a full-screen program and use the terminal's
raw mode and its special commands allowing you to directly modify
text at certain character cells.
Now the problem is that different terminals (and terminal emulators)
have different commands to do that, so there exist libraries to isolate
the programs from these gory details. They rely on the special "terminal
information databases" to figure out what capabilities a terminal has
and how to make it do what the program asks.
See man terminfo for more background.
The most widely known such library (written in C) is called ncurses,
and there exist native solutions for Go with supposedly the most visible
one being github.com/nsf/termbox-go.
The github.com/gizak/termui makes use of termbox-go but for you it might
suffice to use the latter directly.
¹ Chances are very high you're not sitting at
a real hardware terminal
connected to a UNIX® machine but are rather working in a GUI application
such as GNOME Terminal or xterm or Termial.app etc.
These are not "terminals" per se but are rather
terminal emulators —
that is, pieces of software emulating a hardware terminal.

Which editor is used to open man pages in macOS? Is it even an editor?

I am using macOS Sierra(unfortunately), and for example when I typed man curl to see what the -LSso flag does, it opens the man page in a editor which resembles vim slightly. I know its not Vim since it doesn't have :syntax on and you can't use :wq and so on.
The heading of the page says man(less).
I can't find what editor this might be and I'm learning vim and emacs configurations. Or maybe it's just a man page and no editor is used?
Less is a program similar to more (1), but which allows backward movement in the file as well as forward movement. Also, less does not have to read the entire input file before starting, so with large
input files it starts up faster than text editors like vi (1). Less uses termcap (or terminfo on some systems), so it can run on a variety of terminals. There is even limited support for hardcopy
terminals. (On a hardcopy terminal, lines which should be printed at the top of the screen are prefixed with a caret.)
Commands are based on both more and vi. Commands may be preceded by a decimal number, called N in the descriptions below. The number is used by some commands, as indicated.
-- Copied from less man page

Is it possible to replicate the effect of vim's `zz` in bash?

In Vim, executing zz in normal mode will take the line the cursor is currently on, and move that line, together with the cursor, to the vertical center of the current window.
Is there a way to replicate this behavior in bash, to move the current command prompt to the vertical center of the screen, and scroll the command buffer along with it?
I am posting on StackOverflow instead of Unix/Linux because I am open to solutions that require writing custom code if bash does not natively support this.
Vim controls the entire area of the screen. Bash is only responsible for the input line. It has no idea about the contents of the rest of the screen, which is/was under control of other programs, and cannot reposition it.
Note that the contents of the screen nornally cannot be read by a program running on it. The only way to know what's on the screen is to start from a clean state and account for every single character and terminal command printed. Vim does just that; Bash does not and can not.
n.m. has already explained that bash itself cannot do it. However, you still might be able to send commands directly to the underlying terminal to achieve an effect similar to what you want. For example, assuming that your bash input line is somewhere below the middle of the screen, the following will scroll down by sending a couple of empty lines and then putting you into the middle of the screen:
declare -i L; declare -i M; L=`tput lines`/2; M=$L-1; for (( c=1; c<=$L; c++ )); do echo; done; tput cup $M
Note that this doesn't work when your somewhere in the upper half of the screen (it will put you into the middle of the screen, but will not scroll back).
For more info see man tput and man terminfo.

Cygwin 'less' command makes bash forget screen buffer history

I'm having some issues with my Cygwin terminal when I run 'less'. 'less' works fine, but when I come out of it, all the screen buffer history of the terminal is lost. Any suggestions?
I'm running Cygwin on WinXP.
Try running as less -X, or set the LESS environment variable to -X.
It has nothing to do with bash. What's being erased is the text displayed by your terminal emulator.
Like other full-screen programs, less saves the terminal state (including any displayed text and the cursor position) when it starts, and restores it on exit.
It does this by printing the strings defined by the smcup and rmcup terminfo entries.
These depend on the value of the $TERM environment variable.
If these strings aren't printed, or if they're configured to something that doesn't save and restore your terminal state, then less will replace whatever was on your screen by the contents of the file you want to view, and then not restore it.
Using the -X option to less (as suggested by the answer you accepted tells less not to print the smcup and rmcup strings -- which I would expect to cause the problem you're trying to solve.
If you want to save and restore your terminal state (which means that the output produced by less will vanish when you quit), you need to make sure that your $TERM environment variable is set to something with proper smcup and rmcup settings. I find that setting it to xterm usually works.
If you're ambitious, you can create your own terminfo entry and use the tic command to "compile" it to the binary format used by the system.
Dawid Ferenczy's answer suggests another possible cause for the problem; it's not something I've ever run into myself.
(Opinions differ widely on whether saving and restoring the terminal state is a good thing. This blog entry was written by someone who intensely dislikes it. Personally, I like it; if I want to run a full-screen command and keep its output visible while I'm doing something else, I just launch it in another window.)
(The original poster hasn't been on the site in about 2½ years, so we shouldn't expect any feedback, but these answers are likely to be useful to others.)
I had the same issue on my new laptop. I have been using Cygwin on the 64bit Windows 7 for a long time and I never experienced this problem. But on the new fresh system (also 64bit Windows 7) the same Cygwin with the same configuration cleared the screen buffer whenever I quit LESS, MAN, VIM etc. And it bothered me very much. Because I'm using Cygwin inside ConEmu terminal emulator, I suspected ConEmu. After a lot of hours comparing everything what potentially could be the cause (environment variables, configurations, software versions etc.), I had a conversation with the ConEmu's author (and he was really great, exemplary support for the free software!). And we finally found the cause.
The only difference (or one of few) was in the display size. The old laptop has a screen resolution of 1366 x 768 pixels, while the new one has 1920 x 1080. And I'm using the whole screen for the terminal window. It's really strange, but if the terminal window height is greater than cca 62 lines, the screen buffer is cleared after quitting the LESS, VIM etc. No matters if Cygwin is executed inside the ConEMu or plain cmd.exe. Making the terminal window smaller solved the problem. Window height of 62 lines seems to be fine for me. Also, with some of greater height values, the LESS process sometimes crashed.
It seems that it's a problem of the Cygwin.
The whole story you can read here.
Maybe it could help somebody. It took me really a lot of time to solve that. While the solution (or rather workaround) is such damn stupid :)

Resources