Reputation: 405
(Disclaimer: I am using fish, but this should apply equally to bash)
My current shell prints a newline before the prompt so I can easily find it between command outputs.
# [...]
echo # newline before prompt
echo -s $arrow ' ' $cwd $git_info
echo -n -s '❯ '
However, the newline is also printed when there is no previous output, e.g. after clearing the terminal with printf "\033c"
(or when the terminal is first opened):
<--- bad newline: no previous output
➜ /some/dir
❯ command1
output...
<--- good newline
➜ /some/dir
❯ command2
Question: is there any way I can get rid of this small aesthetic annoyance?
Edit #1:
For clarification: By "no previous output" I meant the contents of my console are empty, i.e. after (re-)initializing the terminal (because that's all printf "\033c"
does).
Upvotes: 6
Views: 2596
Reputation: 66
exec events were merged into fish-shell a few years ago. I think you can use these here. They work like event lifecycle hooks in other languages. https://github.com/fish-shell/fish-shell/pull/1666
As a test I made a file called postexec-newline.fish with the following:
function postexec_test --on-event fish_postexec
echo
end
After issuing source postexec-newline.fish
, the behavior you are describing is observed. The newline is also not visible when the screen is cleared with C-l, which I think is how such a feature should behave.
This function can live in config.fish if you want the change permanently.
Upvotes: 5
Reputation: 15934
Stock fish already handles this (and has for years), there is no need for the prompt to do it.
When the output didn't end in a newline, you'll see a "missing newline symbol" like "¶" or "⏎", followed by a newline, and only then your prompt.
Upvotes: 1
Reputation: 6058
EDIT: post edited to be more portable.
Here's how I do it in bash:
__PROMPT_NEWLINE=$'\nVVV '
__set_missing_newline_fix()
{
local CURPOS
echo -en "\033[6n" # ANSI DSR
read -s -d R CURPOS
CURPOS=${CURPOS#*;}
if [ $CURPOS -eq 1 ]; then
__MISSING_NEWLINE_FIX=""
else
__MISSING_NEWLINE_FIX="$__PROMPT_NEWLINE"
fi
}
PROMPT_COMMAND=__set_missing_newline_fix
PS1="\${__MISSING_NEWLINE_FIX}\w > "
Note that it's configured to prefix my prompt with VVV
to let me know that the last command did not end with a newline.
Demo:
$ source bashrc.sh
/tmp/so/newline > echo hello
hello
/tmp/so/newline > echo -n hello
hello
VVV /tmp/so/newline >
The schtick:
ANSI DSR will cause the terminal to write its current cursor position as input. Since we're an interactive shell, that input is available to the shell's stdin, so we just read -s
it (with no echoing).
In the above link you'll see that the response is of the form CSI Pl; Pc R
, so we tell read
to read up to and including the R
with -d R
.
Then we extract that Pc
part using bash' "remove matching prefix" syntax ${CURPOS#*;}
which removes everything up to and including the semicolon ;
.
Then, if the cursor position is not 1, i.e. we're not at the beginning of a newline, we manually add a newline to the prompt.
ANSI DSR should work with every terminal that is ANSI compatible, but if you follow the link you'll see that it doesn't literally say \033[6n
, but rather CSI 6 n
. CSI is the beginning of an escape sequence. Escape sequences begin with ASCII 27 ESC character (octal 033).
In my original answer I used \E
, which bash' built-in echo -e
command parses the same as \033
, hence the edit above.
Upvotes: 1