How can I reset my terminal in a GNU screen session after accidentally printing binary garbage? - terminal

Sometimes I accidentally print binary garbage on the screen, for example I have printed a binary hash value or nonce instead of the hex hash value.
Sometimes the terminal is messed up in various ways after this, because the binary data contained escape sequences which reconfigure the terminal, rendering it almost useless.
When in a normal shell (locally or via ssh) it is usually sufficient to blindly type reset and press enter. (Often the typing is not visible due to the messed up terminal configuration.)
But when in a shell which is inside a GNU screen session this is sometimes not sufficient and the shell is still unresponsive.
How can I revive my terminal without destroying it and re-creating it?

The GNU screen terminals maintain part of the terminal state, too. To reset that in GNU screen do:
Press Ctrl-A.
Enter :reset and press enter.
Done. You may also need to enter reset in the terminal itself as well as usual.

Related

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
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.

Change the behaviour of cooked mode

On a terminal, the cooked (canonical) mode allows the user to input in text, and the text is sent to the program when the user hits enter. While in cooked mode, the arrow keys don't work, and they just appear as ^[[A and similar, but backspace does.
So is it possible to allow arrow keys in the terminal? Ideally, I would be able to even specify my own default 'cooker' to use.
And if it is not possible, then why are all terminals like this?
If it helps, I use suckless terminal, but I would prefer a solution that works on all terminals.
As a workaround, you can run your commands with rlwrap, which provides readline's line editing, including arrow key movement.

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.

Keyboard characters in script record

I am using script to record a terminal session. However, inside my recorded text file, the text input and output is interlaced with strange characters that look like:
^M^[[K^[[A^[[C^ $vim session ^M
^[[?1049h^[[?1h^[=^[[1;21r^[[?12;25h^[[?12l^[[?25h^[[27m^[[m^[[H^[[2J^[[?25l^[[21;1H"session"
[noeol] 3L, 855C^
I think these correspond to return keys and other keyboard commands. Is there a way to not record these during a script session?
In the example given,
^M^[[K^[[A^[[C^ $vim session ^M
^[[?1049h^[[?1h^[=^[[1;21r^[[?12;25h^[[?12l^[[?25h^[[27m^[[m^[[H^[[2J^[[?25l^[[21;1H"session"
[noeol] 3L, 855C^
you have a mixture of cursor-movement and other escape-sequences. The ^[ is the escape character, and ^M is carriage return. As noted, script records everything sent to the terminal, and full-screen programs such as vim will always use these escape sequences. For instance, picking it apart
^[[K
clears the line,
^[[C
moves the cursor,
^[[?1049h
switches the terminal to the alternate screen,
^[[1;21r
sets scrolling margins
^[[?12;25h
sets modes (12 for blinking cursor, 25 to ensure the cursor is visible). Oddly, vim next stops blinking the cursor, resets video attributes with
^[[27m
^[[m
^[[H
before moving the cursor to the upper left
^[[J
and clearing the screen, and then hides the cursor again before
^[[21;1H"session"
[noeol] 3L, 855C
jumping to the lower left of the screen and printing a message (for reference, XTerm Control Sequences). So there is a lot going on, and it is not simply printing the screen left-to-right and top-to-bottom.
Since you are using script, it captures the output into a "typescript" file. If you want to filter those into readable form, a pager such as less using its -R option works passably well—but it misses things. The terminal emulator (with the same screensize) is the best way I know to filter the results, e.g, using a program which sends the characters to the terminal slowly. If you want plain text, select/paste from a replay (using ^S and ^Q to stop/resume) might be a way to go.
A UNIX terminal has two modes, canonical and non-canonical (also known as 'cooked' and 'raw').
The script program works by inserting itself into the message queue stack between the terminal driver and the shell (that's simplified).
The shell thinks it is talking to a terminal when it is talking with script. So what you see is what the shell sees, the raw terminal characters.
Try strings typescript

Full screen terminal application with ruby (or other languages)

Have you ever used cli tools like vim or htop? All these will maximize inside the terminal and have no scrollback but when you exit, they disappear and you can see what you typed in before.
Example:
(terminal window with scrollback)
(maximized vim without scrollback)
(back in shell with scrollback and vim gone)
How can I do this in my own application, preferably ruby?
This is a mode supported by most terminals through the XTerm control sequence specifications.
The specific screen-switching mode that can be activated using those specs is called the alternate screen buffer.
When you send the correct XTerm control sequence to the terminal then the terminal will switch into an alternate screen buffer. Once whatever program exits, it usually sends the commands to switch back to the original screen buffer. This way you get the effect of the application restoring your original terminal display.
The sequence for activating the alternate buffer is CSI ? 47 h. CSI stands for Control Sequence Initiator, and it's usually ESC + [. So by sending ESC [ ? 47 h (without spaces) to the terminal it will switch to the alternate buffer.
You can test this by running the cat command in your shell, hitting ESC and typing [?47h and hitting enter. You should see the screen clear (or switch to the other buffer).
The sequence to switch back to the normal screen buffer is CSI ? 47 l, and you can test this the same way running the cat command and typing the keys ESC [ ? 47 l and hitting enter.
When programming complex terminal screen-based applications however, most people tend to use a library like curses or ncurses, which will take care of all the terminal handling stuff for you. See these for example:
Learning Ruby Curses
http://www.ruby-doc.org/stdlib-2.0.0/libdoc/curses/rdoc/Curses.html
I suspect a program like htop probably uses curses or ncurses too.

Resources