clear terminal screen but keep visual spacing - unix

When I want to provide a visual break after a long list of output lines from a command I normally run clear so that the terminal will clear the screen, put my prompt back at 0,0 while also keeping the history (vs reset).
The problem is that when I scroll up, the terminal is now back to the long lines of output, without any kind of break in history.
I had the idea of "echo'ing a screen's worth of empty lines" by doing yes '' | head -n $(tput lines), but then my cursor is at the bottom of the screen. So I try to run clear but it seems to remove the empty lines. I also tried tput cup 0 0 but that also removes the empty lines (I guess by "reverting" my screen's worth of empty lines).
I can force the empty lines by printing any character with yes instead of the empty string, or I can print some character/message at the end of the empty lines. But now I'm adding garbage.
The only thing I've been able to get to work is:
yes '' | head -n $(($(tput lines) * 2))
tput cup 0 0
Is there another way or is this my only option?

Essentially yes - you can express the script in various ways, but most terminals don't allow one aspect which could be used to improve your script: when scrolling up, they don't move blank lines into the scrollbar. So you can't (for example) do it like this:
tput cup $(tput lines)
tput indn $(($(tput lines) * 2))
tput cup 0 0
tput ed
since the blank lines that you would expect from indn (index) are ignored.

Related

Can't edit command in Zsh

I have a custom prompt in Zsh. At the end of it, I colour the last character red or green depending on if the last command succeeded or failed. However, when I do this, I can't go back and edit previous commands.
This is the prompt code:
%{%F%(?.$fg[green].$fg[red])>%f%}
An example workflow:
I enter a command that wraps onto a new line:
> printf "%s\n" "This is a very long printf. How long is it? It's so very very long that it wraps onto the next line."
After this runs, I hit up arrow and modify the command by deleting and retyping "is it". Now, the command line shows:
> printf "%s\n" "This is a very long printf. How long is it It's so very very long that it wraps onto the next line."
This prints out:
This is a very long printf. How long iis it It's so very very long that it wraps onto the next line.
I assume that I'm not terminating the color codes somehow so that the prompt is spilling over into the actual commands I'm trying to enter. It only misbehaves when the prompt wraps around to a new line. Can anyone see what's wrong with my prompt?
I've verified that, without this snippet of code, the rest of the prompt is fine and behaves as you'd expect.
zsh is confused about how long the prompt actually is. The shell already knows that its own %F escape doesn't contribute to the on-screen length of the prompt; you don't need to wrap it in %{...%} like you would similarly do in bash.
PS1="%F%(?.$fg[green].$fg[red])>%f"
If fg contains actual terminal-specific escape sequences, then you would need %{...%}, but you wouldn't use %F at all, as this isn't how you use it. So you might actually need something like
PS1="%(?.%{$fg[green]%}.%{$fg[red]}%})>%f"
But, you don't need a separate array of colors; zsh has them built in as well.
PS1='%(?.%F{green}.%F{red})>%f '

how to move Tmux panes

I like to work with 3 tmux panes. one horizontal pane at the upper half of the screen and two more panes at the bottom half. These panes are split vertically.
There are cases where I would like to take the last pane and make it go from top to bottom. like this:
How can I achieve this? using [ctrl+b ctrl+o] and [ctrl+b space] did not reach the desired position and is cumbersome.
There is probably an easier way, but what you can do is arrange the panes manually in each of the two configurations, noting each layout in a variable with e.g.:
layout1=$(tmux list-windows -F '#{window_layout}')
This holds a string something like:
5f2f,80x23,0,0[80x11,0,0,0,80x11,0,12{39x11,0,12,1,40x11,40,12,2}]
which you must not alter in any way as the first number is a checksum of the rest of the string.
Once you have the two strings you can set a binding to set that layout using select-layout, or by giving the command from the shell where you have the variables:
tmux select-layout "$layout1"
You might find it easier to write a small helper script, say mtmux to toggle between the layouts:
#!/usr/bin/bash
# https://stackoverflow.com/q/56343223/5008284
# toggle between 2 layouts, previously saved
layout1='5f2f,80x23,0,0[80x11,0,0,0,80x11,0,12{39x11,0,12,1,40x11,40,12,2}]'
layout2='093c,80x23,0,0{39x23,0,0[39x11,0,0,0,39x11,0,12,4],40x23,40,0,3}'
layout="$(tmux list-windows -F '#{window_layout}')"
case "$layout" in
*80x11*) new=$layout2 ;;
*) new=$layout1 ;;
esac
tmux select-layout "$new"
tmux display-panes
exit 0
and have a binding, say control-L, to run this shell:
bind-key -n C-l run-shell 'mtmux'

Narrow centered single frame in tmux

Writing prose in a console environment I like to have my editor in a narrow centered pane. I can achieve this with this .screenrc:
focusminsize 75 25
split -v
focus
only
split -v
split -v
focus
caption string "%{= dd} "
sorendition "="
Then $screen emacs gives me the desired layout.
How do I achieve something similar in tmux 1.8?
Bonus: how to I bind toggling 'default layout' / 'narrow centered single pane' to a key?

Piping program output to less does not display beginning of the output

I am trying to make a bunch of files in my directory, but the files are generating ~200 lines of errors, so they fly past my terminal screen too quickly and I have to scroll up to read them.
I'd like to pipe the output that displays on the screen to a pager that will let me read the errors starting at the beginning. But when I try
make | less
less does not display the beginning of the output - it displays the end of the output that's usually piped to the screen, and then tells me the output is 1 line long. When I try typing Gg, the only line on the screen is the line of the makefile that executed, and the regular screen output disappears.
Am I using less incorrectly? I haven't really ever used it before, and I'm having similar problems with something like, sh myscript.sh | less where it doesn't immediately display the beginning of the output file.
The errors from make appear on the standard error stream (stderr in C), which is not redirected by normal pipes. If you want to have it redirected to less as well, you need either make |& less (csh, etc.) or make 2>&1 | less (sh, bash, etc.).
Error output is sent to a slightly different place which isn't caught by normal pipelines, since you often want to see errors but not have them intermixed with data you're going to process further. For things like this you use a redirection:
$ make 2>&1 | less
In bash and zsh (and csh/tcsh, which is where they borrowed it from) this can be shortened to
$ make |& less
With things like make which are prone to produce lots of errors I will want to inspect later, I generally capture the output to a file and then less that file later:
$ make |& tee make.log
$ less make.log

Delete newline in Vim

Is there a way to delete the newline at the end of a line in Vim, so that the next line is appended to the current line?
For example:
Evaluator<T>():
_bestPos(){
}
I'd like to put this all on one line without copying lines and pasting them into the previous one. It seems like I should be able to put my cursor to the end of each line, press a key, and have the next line jump onto the same one the cursor is on.
End result:
Evaluator<T>(): _bestPos(){ }
Is this possible in Vim?
If you are on the first line, pressing (upper case) J will join that line and the next line together, removing the newline. You can also combine this with a count, so pressing 3J will combine all 3 lines together.
Certainly. Vim recognizes the \n character as a newline, so you can just search and replace.
In command mode type:
:%s/\n/
While on the upper line in normal mode, hit Shift+j.
You can prepend a count too, so 3J on the top line would join all those lines together.
As other answers mentioned, (upper case) J and search + replace for \n can be used generally to strip newline characters and to concatenate lines.
But in order to get rid of the trailing newline character in the last line, you need to do this in Vim:
:set noendofline binary
:w
J deletes extra leading spacing (if any), joining lines with a single space. (With some exceptions: after /[.!?]$/, two spaces may be inserted; before /^\s*)/, no spaces are inserted.)
If you don't want that behavior, gJ simply removes the newline and doesn't do anything clever with spaces at all.
set backspace=indent,eol,start
in your .vimrc will allow you to use backspace and delete on \n (newline) in insert mode.
set whichwrap+=<,>,h,l,[,]
will allow you to delete the previous LF in normal mode with X (when in col 1).
All of the following assume that your cursor is on the first line:
Using normal mappings:
3Shift+J
Using Ex commands:
:,+2j
Which is an abbreviation of
:.,.+2 join
Which can also be entered by the following shortcut:
3:j
An even shorter Ex command:
:j3
It probably depends on your settings, but I usually do this with A<delete>
Where A is append at the end of the line. It probably requires nocompatible mode :)
I would just press A (append to end of line, puts you into insert mode) on the line where you want to remove the newline and then press delete.
<CURSOR>Evaluator<T>():
_bestPos(){
}
cursor in first line
NOW, in NORMAL MODE do
shift+v
2j
shift+j
or
V2jJ
:normal V2jJ
if you don't mind using other shell tools,
tr -d "\n" < file >t && mv -f t file
sed -i.bak -e :a -e 'N;s/\n//;ba' file
awk '{printf "%s",$0 }' file >t && mv -f t file
The problem is that multiples char 0A (\n) that are invisible may accumulate.
Supose you want to clean up from line 100 to the end:
Typing ESC and : (terminal commander)
:110,$s/^\n//
In a vim script:
execute '110,$s/^\n//'
Explanation: from 110 till the end
search for lines that start with new line (are blank)
and remove them
A very slight improvement to TinkerTank's solution if you're just looking to quickly concatenate all the lines in a text file is to have something like this in your .vimrc:
nnoremap <leader>j :%s/\n/\ /g<CR>
This globally substitutes newlines with a space meaning you don't end up with the last word of a line being joined onto the first word of the next line. This works perfectly for my typical use-case.
If you're wanting to maintain deliberate paragraph breaks, V):join is probably the easiest solution.

Resources