What mechanism allows ViM to temporarily overwrite the entire console? - vim

When you enter vim, it "clears" the screen. Upon exiting, it "restores" the original contents.
I understand one can use \x1b[2J to clear the console and reset the cursor position, but this will overwrite terminal contents.
I assume Vim uses ncurses under the hood, in which case I suppose the better question is how ncurses does this, but how is it done?

Regarding the answer by #Keith Thompson — not exactly:
vim does not use the screen optimization of ncurses which sends smcup and rmcup automatically. Rather, it is a termcap application. It follows a convention used by most (not all) termcap applications. There are some implementations of vi which do not for instance (on IRIX64 perhaps).
as for "most terminals" — actually, xterm look-alikes are a small part of the terminal database (even counting variations, less than 10%). Rephrase that to something like "the most common terminal emulators on Linux.
the terminal does not save and restore the screen contents. Instead, it switches between two screens (in xterm's documentation "normal" and "alternate"). In xterm for instance, one can always switch between the two using a menu entry. The xterm FAQ Why doesn't the screen clear when running vi? gives more detail.
for better context, note that smcup is an (obscure) abbreviation for set-mode-cursor-positioning, or start cursor-positioning mode. (also cursor-addressing). The r in rmcup means "reset" (and m means "mode"). set/reset have different connotations from save/restore; with the latter the user is led to believe that the values can be stacked up.

Most terminal emulators are able to save and restore the contents of the screen.
The terminfo codes for this are smcup to enter full-screen mode and rmcup to leave it. (The older termcap codes are ti and te.)
If these capabilities are enabled in the terminfo database, any program that uses ncurses will print the smcup string on entry, and the rmcup string on exit.
On the system I'm using at the moment, the strings are (with \E representing the Escape character):
smcup: \E7\E[?1;47h
rmcup: \E[2J\E[?1;47l\E8
This restores the previous contents of the screen as well as the cursor position.
The specific meanings of the sequences (for xterm) are documented here:
smcup:
\E7 Save Cursor
\E[?1;47h Application Cursor Keys; Use Alternate Screen Buffer
rmcup:
\E[2J Erase screen
\E[?1;47l Application Cursor Keys; Use Normal Screen Buffer
\E8 Restore Cursor
(This assumes I'm understanding the use of the semicolon correctly; I'm not 100% sure of that.)

Related

Is there a way to view the current input source in vim?

When using vim in a non-English language environment, mistakes in mis-entering command often occur.
To prevent this, is there a way to view the current input source on the statusline?
For example, EN or JP.
like MS word bottom bar
Vim doesn't have that information so it can't expose it, which is not exactly a problem since your desktop environment already does.
If you really want to duplicate that information in your Vim status line, then you will have to find what external command to call, and then find a way to consume the information that doesn't slow Vim to a crawl because the status line is refreshed several times per second.
Now, your question is really two questions:
How to get the information?
How to show it in the statusline?
The answer to the first question depends on your desktop environment, which you didn't disclose. You will have to look around on your own, on more specialised forums.
The answer to the second question is irrelevant without an answer to the first one but you can look up :help 'statusline' and :help system() if you are curious.
Anyway, you already have the information in your desktop environment's menu bar/task bar/whatever, so why bother?
Vim has modes. In Normal mode where it is supposed to stay most of the time all commands consist of latin letters by default. Therefore, using OS level keyboard layout switch cannot be recommended. Instead, Vim has a feature called "keymap". Vim keymap is only active in Insert or Command-line mode never affecting the Normal mode.
So, Vim never cares what is your active keyboard layout on OS level and you won't expect an easy way showing it. On the other side, Vim keymap name is accessible either as b:keymap_name variable or %k format specifier for the statusline option. So it is pretty easy to add it.

How to scroll within vim's shell command output?

When I enter a shell command via vim -- e.g., :!rake routes -- I'll get some output and then:
Press ENTER or type command to continue
If I press anything at that point, I am always taken back to the main vim UI. How do I stay in that shell mode for a bit longer, specifically I can scroll back to see all the output of the command?
For terminal vim scrolling is provided by terminal emulator (or terminal multiplexer like tmux/screen if you use it). I.e. if your terminal scrolls when using <S-PageUp> it must also scroll with Vim’s !. Same for mouse wheel (it works for me even if vim was configured to handle mouse on its own).
If have terminal vim and you need to view output after you pressed <CR> then you can use <C-z>/:susp. Both these capabilities will be spoiled with incorrect configuration of either vim or terminal (terminal multiplexer) (i.e. terminal configured not to support alternate screens (which is normally issue for terminal multiplexers rather then terminal emulators: screen requires altscreen on in .screenrc) or vim setting telling vim what to output to the terminal on startup/resume and shutdown/suspend was spoiled).
If you have GUI vim your options are very limited. It is better to follow link provided by #glts or #EricAndres advice in this case as I do not use GUI vim.
:r! [shell command] will read the output from the command into the buffer. So if you open a new buffer then use that command, you can search and scroll through it all you like. See Vimcasts episode 57 for more information.

Return focus to vim when using screens plugin after ScreenShellFocus?

The screens plugin turns vim into a kind of dreampie, only its a whole lot better because you have more control over what gets send even when you have multiple buffers and specific text within those buffers.
To follow my environment setup, merely install screens with vim, and then at the command line, do screen, reach the shell, then type vim in. Edit a shell script of some kind with it, then do :ScreenShell *shell type here, eg python/bash/irb* which spawns a shell below. You can use :ScreenShellSend to send the visually selected text to the shell or all of the file if none is selected.
My problem is, say I want to restart the shell that I'm running using this plugin and sending it some text. I need to do :ScreenShellFocus, call exit, and then start it up again. But then I need to be able to return to the same vim session that is directly above the shell that I'm affecting. I realize that I can use screen to just reach the vim session, but the only way I can do that now is to select it with ^a 1, which really only replaces the lower portion, the one that supposed to be the shell, with the vim buffer being edited. This is stupid because now you have vim buffer on top of vim buffer.
So my question is, how do I return the cursor to the vim session above after doing :ScreenShellFocus?
(yes I know my example of killing and restarting a shell may be circumvented by other logic, but I'm not that acquainted with the GNU screen util, and I think there's a way to do it like this, which I think preserves the workflow of the programmer)
<C-a><Tab>
is the mapping used in screen to cycle through "regions". Since you have only two, it moves the focus to the other region.
Since you are effectively using screen, you should learn how to use it to make this plugin really useful.
$ man screen

xterm keep page from less in terminal after exit

I often view files using less and want to remember what i have just seen in the file. However when I quit less by pressing the q key my xterm window removes the page of less showing the file and only shows my command prompt.
How do I keep the less output on my terminal when I quit?
less -X
Use the -X option from the less man page described below:
-X or --no-init
Disables sending the termcap initialization and deinitialization strings to the terminal.
This is sometimes desirable if the deinitialization string does something unnecessary, like
clearing the screen.
Actually, if you are using xterm (rather than some other program), the choice of whether to honor alternate-screen escape sequences can be done readily using a menu selection Enable Alternate Screen Switching (or resource setting). The less option does not apply to other programs such as vi.
In the manual, this is the titeInhibit, named after the termcap settings
ti (terminal initialization)
te (terminal ending)
and in the FAQ, this is Why doesn't the screen clear when running vi?.

How does VIM display to the terminal and then take it back?

How is it that VIM (when running) can display the contents of a file to the terminal, then (when closed) can take what was displayed back? There have been several applications I have made where I would have liked to implement this functionality... like when making a program with terminal graphics where the entire screen typically has to be updated when a single "object" moves.
It's your terminal that stores the old buffer, not Vim.
If you use XTerm emulation, Vim switches to the "alternate" terminal screen on startup. On exit, Vim switches back to the normal screen.
Terminfo strings at startup:
\E7 saves the cursor's position
\E[?47h switches to the alternate screen
Terminfo strings at exit:
\E[2J clears the screen (assumed to be the alternate screen)
\E[?47l switches back to the normal screen
\E8 restores the cursor's position.

Resources