zshpromptzsh-zle

zsh: update prompt with current time when a command is started


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.)


Solution

  • 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: