Is there an option or extension to restrict command output in Emacs shell or eshell to just few lines and show the rest either when pressing a special key or showing full output in a separated window?
I can redirect the output to a new buffer, but that requires to know in advance that the output is big. What would be nice instead is to restrict output to, for example, half widow height so unexpectedly long output does not clatter the shell window.
Related
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.
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
When typing a (long) command in the bash shell, if you were to make a mistake early in the line, is there a way to correct that mistake without having to navigate back to it? For example, lets say you have just entered something like this, but not yet pressed return:
git commit =m 'Some really long commit message, perhaps spanning multiple lines'
where you have accidentally typed = instead of -, would it be possible to append something to the end of the command before you press enter that would perform an in-line substitution to correct the mistake? This would be really handy to avoid having to do something annoying like
Pressing Ctrl+C and then rebuilding the command using a combination of copy and paste.
Pressing the left arrow a huge bunch of times so that it can be corrected before pressing enter.
One solution (in theory) would be to pipe the contents of the whole command through sed, however I am not sure how to capture the command as a string of text that could then be used in this manner.
What I would do : ctrl+a
then move the cursor after the =, then hit ctrl+w.
The latest delete the previous word.
Multiple shortcuts can help here:
Use ctrl+a to go to the beginning of the line
Use alt+b and alt+f to move forward and backward one word at a time
Use alt+e to open an editor ($EDITOR) containing your current command, edit it, then close your editor.
As it is right now, it has become rather annoying having to wade through old result texts through iTerm trying to distinguish where my command line was and what the resulting text is.
Is there a way to make it easier for me to clearly identify my command line?
I was thinking I could set it a different color than my result text.
You can setup your shell prompt in a different color please have a look at following two links, one for bash and the other for zsh.
Remember if you ssh to a different host you most likely will lose the color unless you have exactly same settings on that host.
on-my-zsh
crazy bash prompt
I have been reading a lot of the questions here on vim. I can't locate something that I want to do with vim but I am sure its possible.
I like vim(I am still new at it) using tabs and I have adjusted my vimrc so that H & L keys take me back and forth between tabs.
I was hoping to find a way to be able to use tab commands to open up a tab as output, so that if I am writing something in my case Ruby and I want to test it I could run it and flip to a new tab with the output. Or flip a tab to an interactive console to test code. This is possible?
As an aside is it possible to expand tabs to views so if I had two tabs open say script and output I could :spx or similar and have tabs come to split screen.
You can load the ruby output into a vim window in a couple of ways. One way would be to open a new split window and then load output of command:
" vimscript command to open new split window
wincmd n
" run ruby command and insert output at line 1
1,1!ruby foo.rb
alternatively you could get view the output on a new tab with a single window:
tabnew
1,1!ruby foo.rb
I know it's not the answer you want, but use buffers and ditch the tabs. I have a screencast going over how to use splits to manage your window.
http://lococast.net/archives/111
As for the ruby output, that seems like it might be covered here:
https://superuser.com/questions/133886/vim-displaying-code-output-in-a-new-window-a-la-textmate
In answer to your question about opening up a tab as output, I don't think there's any built in way to do this. There's the RunView plugin (see my answers to this question and this one), but I don't think that it supports using a separate tab (it works with a split window: what I think you refer to when you say 'view').
Regarding an interactive console: no, this is not possible. See :help design-not.
As for general use of Vim, try to get used to the idea of buffers and the fact that each 'view' (my term), whether it be a split window, a tab or whatever is just a means of looking at a particular buffer. You can have multiple views on a single buffer, so you can have a source file vertical split with two headers in one tab and the same source file vertically split with another header and a different bit of the same source file in another tab. This is very powerful once you get used to it. The Ctrl-W keyboard shortcuts are your friend (e.g. Ctrl-W, h to go left one window).
As for changing a tab into a split window, I don't think there's a direct way to do this (how would Vim know which tabs you wanted to join?). You can break a split into a tab with Ctrl-W + T, but to go back you'd have to create a couple of mappings. This is off the top of my head but something like this might work:
command! TakeThis let takebufnr = bufnr("")<CR>
command! SplitTaken exe 'split #' . takebufnr<CR>
nmap ,t :TakeThis<CR>
nmap ,s :SplitTaken<CR>
Then press ,t on the buffer you want to grab and ,s on the one you want to split with the 'taken' buffer.