Reputation: 6365
I have a zsh
prompt I rather like: it evaluates the current time in precmd
and displays that on the right side of the prompt:
[Floatie:~] ^_^
cbowns% [9:28:31 on 2012-10-29]
However, this isn't exactly what I want: as you can see below, this time is actually the time the previous command exited, not the time the command was started:
[Floatie:~] ^_^
cbowns% date [9:28:26 on 2012-10-29]
Mon Oct 29 09:28:31 PDT 2012
[Floatie:~] ^_^
cbowns% date [9:28:31 on 2012-10-29]
Mon Oct 29 09:28:37 PDT 2012
[Floatie:~] ^_^
cbowns% [9:28:37 on 2012-10-29]
Is there a hook in zsh
to run a command just before the shell starts a new command so I can update the prompt timestamp then? (I saw Constantly updated clock in zsh prompt?, but I don't need it constantly updated, just updated when I hit enter.)
(The ^_^
is based on the previous command's return code. It shows ;_;
in red when there's a nonzero exit status.)
Upvotes: 44
Views: 17678
Reputation: 8056
Building off @vitaŭt-bajaryn's cool ZSH style answer:
I think overriding the accept-line function is probably the most idiomatic zsh solution:
function _reset-prompt-and-accept-line {
zle reset-prompt
zle .accept-line # Note the . meaning the built-in accept-line.
}
zle -N accept-line _reset-prompt-and-accept-line
Upvotes: 12
Reputation: 159
You can remap the Return
key to reset the prompt before accepting the line:
reset-prompt-and-accept-line() {
zle reset-prompt
zle accept-line
}
zle -N reset-prompt-and-accept-line
bindkey '^m' reset-prompt-and-accept-line
Upvotes: 15
Reputation: 2234
I had a struggle to make this:
It displays the date on the right side when the command has been executed. It does not overwrite the command shown. Warning: it may overwrite the current RPROMPT.
strlen () {
FOO=$1
local zero='%([BSUbfksu]|([FB]|){*})'
LEN=${#${(S%%)FOO//$~zero/}}
echo $LEN
}
# show right prompt with date ONLY when command is executed
preexec () {
DATE=$( date +"[%H:%M:%S]" )
local len_right=$( strlen "$DATE" )
len_right=$(( $len_right+1 ))
local right_start=$(($COLUMNS - $len_right))
local len_cmd=$( strlen "$@" )
local len_prompt=$(strlen "$PROMPT" )
local len_left=$(($len_cmd+$len_prompt))
RDATE="\033[${right_start}C ${DATE}"
if [ $len_left -lt $right_start ]; then
# command does not overwrite right prompt
# ok to move up one line
echo -e "\033[1A${RDATE}"
else
echo -e "${RDATE}"
fi
}
Sources:
Upvotes: 20
Reputation: 1501
This is in fact possible without resorting to strange hacks. I've got this in my .zshrc
RPROMPT='[%D{%L:%M:%S %p}]'
TMOUT=1
TRAPALRM() {
zle reset-prompt
}
The TRAPALRM function gets called every TMOUT seconds (in this case 1), and here it performs a prompt refresh, and does so until a command starts execution (and it doesn't interfere with anything you type on the prompt before hitting enter). I know you don't need it constantly refreshed but it still gets the job done without needing a line for itself!
Source: http://www.zsh.org/mla/users/2007/msg00944.html (It's from 2007!)
Upvotes: 44
Reputation: 7194
You can use ANSI escape sequences to write over the previous line, like this:
preexec () {
DATE=`date +"%H:%M:%S on %Y-%m-%d"`
C=$(($COLUMNS-24))
echo -e "\033[1A\033[${C}C ${DATE} "
}
Upvotes: 8
Reputation: 19475
zsh
will run the preexec
function just before executing a line. It would be simple to have that output the current time, a simple version would be just:
preexec() { date }
Modifying an existing prompt would be much more challenging.
Upvotes: 14