mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-11-04 07:21:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			95 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
# Add `autoload promptnl' to your .zshrc, and include a call to promptnl
 | 
						|
# near the end of your precmd function.
 | 
						|
#
 | 
						|
# When promptnl runs, it asks the terminal to send back the current
 | 
						|
# position of the cursor.  If the cursor is in column 1, it does nothing;
 | 
						|
# otherwise it prints a newline.  Thus you get a newline exactly when one
 | 
						|
# is needed.
 | 
						|
#
 | 
						|
# Of course this can make it appear that `print -n' and friends have
 | 
						|
# failed to suppress the final newline; so promptnl outputs the value
 | 
						|
# of the EOLMARK parameter before the newline, with prompt sequences
 | 
						|
# expanded.  So you can for example use EOLMARK='%B!%b' to put a bold
 | 
						|
# exclamation point at the end of the actual output.
 | 
						|
 | 
						|
# There's another way to accomplish the equivalent, without reading the
 | 
						|
# cursor position from the terminal.  Skip to the end of the file to see
 | 
						|
# that other way.
 | 
						|
 | 
						|
emulate -L zsh
 | 
						|
 | 
						|
# VT100 and ANSI terminals will report the cursor position when sent
 | 
						|
# the sequence ESC [ 6 n -- it comes back as ESC [ column ; line R
 | 
						|
# with of course no trailing newline.  Column and line are 1-based.
 | 
						|
 | 
						|
local RECV='' SEND='\e[6n' REPLY=X
 | 
						|
 | 
						|
# If you are on a very slow tty, you may need to increase WAIT here.
 | 
						|
integer WAIT=1
 | 
						|
 | 
						|
# Make sure there's no typeahead, or it'll confuse things.  Remove
 | 
						|
# this block entirely to use this function in 3.0.x at your own risk.
 | 
						|
while read -t -k 1
 | 
						|
do
 | 
						|
    RECV=$RECV$REPLY
 | 
						|
done
 | 
						|
if [[ -n $RECV ]]
 | 
						|
then
 | 
						|
    print -z -r -- $RECV
 | 
						|
    RECV=''
 | 
						|
    REPLY=X
 | 
						|
fi
 | 
						|
 | 
						|
# This is annoying, but zsh immediately resets it properly, so ...
 | 
						|
stty -echo
 | 
						|
 | 
						|
# Output the SEND sequence and read back into RECV.  In case this is
 | 
						|
# not a terminal that understands SEND, do a non-blocking read and
 | 
						|
# retry for at most WAIT seconds before giving up.  Requires 3.1.9.
 | 
						|
# For 3.0.x, remove "-t" but don't call this on the wrong terminal!
 | 
						|
 | 
						|
print -n $SEND
 | 
						|
 | 
						|
integer N=$SECONDS
 | 
						|
while [[ $REPLY != R ]] && ((SECONDS - N <= WAIT))
 | 
						|
do
 | 
						|
    if read -t -k 1
 | 
						|
    then
 | 
						|
	((N=SECONDS))
 | 
						|
	RECV=$RECV$REPLY
 | 
						|
    fi
 | 
						|
done
 | 
						|
 | 
						|
# If the cursor is not in the first column, emit EOLMARK and newline.
 | 
						|
 | 
						|
(( ${${RECV#*\;}%R} > 1 )) && print -P -- $EOLMARK
 | 
						|
 | 
						|
return 0
 | 
						|
 | 
						|
# OK, now here's the other way.  Works on any auto-margin terminal, which
 | 
						|
# includes most terminals that respond to ESC [ 6 n as far as I know.  It
 | 
						|
# prints a line of spaces exactly as wide as the terminal, then prints a
 | 
						|
# carriage return.  If there are any characters already on the line, this
 | 
						|
# will cause the line to wrap, otherwise it won't.
 | 
						|
 | 
						|
: setopt nopromptcr
 | 
						|
: PS1="%{${(pl:COLUMNS+1:: ::\r:)}%}$PS1"
 | 
						|
 | 
						|
# On a very slow connection, you might be able to see the spaces getting
 | 
						|
# drawn and then overwritten, so reading the cursor position might work
 | 
						|
# better in that circumstance because it transmits fewer characters.  It
 | 
						|
# also doesn't work if you resize the terminal.
 | 
						|
 | 
						|
# To get the EOLMARK behavior, simply adjust the COLUMNS+1 expression to
 | 
						|
# account for the width of the mark, and include it.  For example:
 | 
						|
 | 
						|
: setopt nopromptcr
 | 
						|
: PS1="%{%S<EOL>%s${(pl:COLUMNS-4:: ::\r:)}%}$PS1"
 | 
						|
 | 
						|
# The important bit is that the total width of the string inside %{...%}
 | 
						|
# has to be COLUMNS+1, where the extra character is the \r.  However, I
 | 
						|
# recommend using a one-character EOLMARK to avoid having the line wrap
 | 
						|
# in the middle of the marker string:
 | 
						|
 | 
						|
setopt nopromptcr
 | 
						|
PS1="%{%S#%s${(pl:COLUMNS:: ::\r:)}%}$PS1"
 |