Zsh提示只显示一次上一个错误代码

时间:2018-03-18 11:49:31

标签: zsh

当前一个命令失败时,我希望我的提示显示交叉(✘)。我使用以下代码:

export PROMPT=$'%(?..✘\n)\n› '

这给了我以下输出:

› echo Hello
Hello

› asjdfiasdf
zsh: command not found: asjdfiasdf
✘

› 
✘

我想修改提示,以便在 Enter 之后重新绘制提示时不重复交叉(上例中的第三种情况)。

有可能吗?

2 个答案:

答案 0 :(得分:6)

我想我明白了。如果你发现了一个错误,请告诉我......

preexec() {
    preexec_called=1
}
precmd() {
    if [ "$?" != 0 ] && [ "$preexec_called" = 1 ]
    then echo ✘; unset preexec_called; fi
}
PROMPT=$'\n› '

结果:

› ofaoisfsaoifoisafas
zsh: command not found: ofaoisfsaoifoisafas
✘  

› 

› echo $? # (not overwritten)
127

答案 1 :(得分:2)

我在zsh中执行此操作,但使用的是颜色而不是unicode字符。这是相同的原则。

首先,我设置了我的颜色,确保它们仅在受支持时使用:

case $TERM in

( rxvt* | vt100* | xterm* | linux | dtterm* | screen )
  function PSC() { echo -n "%{\e[${*}m%}"; } # insert color-specifying chars
  ERR="%(0?,`PSC '0;32'`,`PSC '1;31'`)"      # if last cmd!=err, hash=green, else red
  ;;

( * )
  function PSC() { true; }   # no color support? no problem!
  ERR=
  ;;

esac

接下来,我设置了一个魔术输入功能(感谢this post about an empty command(忽略这个问题,看看我在这里如何调整它):

function magic-enter() {    # from https://superuser.com/a/625663
  if [[ -n $BUFFER ]]
    then unset Z_EMPTY_CMD  # Enter was pressed on an empty line
    else Z_EMPTY_CMD=1      # The line was NOT empty when Enter was pressed
  fi
  zle accept-line           # still perform the standard binding for Enter
}
zle -N magic-enter          # define magic-enter as a widget
bindkey "^M" magic-enter    # Backup: use ^J

现在是时候解释捕获命令并使用其返回码来设置提示颜色:

setopt prompt_subst # allow variable substitution

function preexec() { # just after cmd has been read, right before execution
  Z_LAST_CMD="$1"   # since $_ is unreliable in the prompt
  #Z_LAST_CMD="${1[(wr)^(*=*|sudo|-*)]}"    # avoid sudo prefix & options
  Z_LAST_CMD_START="$(print -Pn '%D{%s.%.}')"
  Z_LAST_CMD_START="${Z_LAST_CMD_START%.}" # zsh <= 5.1.1 makes %. a literal dot
  Z_LAST_CMD_START="${Z_LAST_CMD_START%[%]}" # zsh <= 4.3.11 makes %. literal
}

function precmd() { # just before the prompt is rendered
  local Z_LAST_RETVAL=$?                  # $? only works on the first line here
  Z_PROMPT_EPOCH="$(print -Pn '%D{%s.%.}')"  # nanoseconds, like date +%s.%N
  Z_PROMPT_EPOCH="${Z_PROMPT_EPOCH%.}"    # zsh <= 5.1.1 makes %. a literal dot
  Z_PROMPT_EPOCH="${Z_PROMPT_EPOCH%[%]}"  # zsh <= 4.3.11 makes %. a literal %.
  if [ -n "$Z_LAST_CMD_START" ]; then
    Z_LAST_CMD_ELAPSED="$(( $Z_PROMPT_EPOCH - $Z_LAST_CMD_START ))"
    Z_LAST_CMD_ELAPSED="$(printf %.3f "$Z_LAST_CMD_ELAPSED")s"
  else
    Z_LAST_CMD_ELAPSED="unknown time"
  fi

  # full line for error if we JUST got one (not after hitting <enter>)
  if [ -z "$Z_EMPTY_CMD" ] && [ $Z_LAST_RETVAL != 0 ]; then
    N=$'\n'  # set $N to a literal line break
    LERR="$N$(PSC '1;0')[$(PSC '1;31')%D{%Y/%m/%d %T}$(PSC '1;0')]"
    LERR="$LERR$(PSC '0;0') code $(PSC '1;31')$Z_LAST_RETVAL"
    LERR="$LERR$(PSC '0;0') returned by last command"
    LERR="$LERR (run in \$Z_LAST_CMD_ELAPSED):$N"
    LERR="$LERR$(PSC '1;31')\$Z_LAST_CMD$(PSC '0;0')$N$N"
    print -PR "$LERR"
  fi
}

最后,设置提示符:

PROMPT="$(PSC '0;33')[$(PSC '0;32')%n@%m$(PSC '0;33') %~$PR]$ERR%#$(PSC '0;0') "

以下是它的外观:

screenshot

根据上述内容改编的问题更直接的答案:

function magic-enter() {    # from https://superuser.com/a/625663
  if [[ -n $BUFFER ]]
    then unset Z_EMPTY_CMD  # Enter was pressed on an empty line
    else Z_EMPTY_CMD=1      # The line was NOT empty when Enter was pressed
  fi
  zle accept-line           # still perform the standard binding for Enter
}
zle -N magic-enter          # define magic-enter as a widget
bindkey "^M" magic-enter    # Backup: use ^J

function precmd() { # just before the prompt is rendered
  local Z_LAST_RETVAL=$?                  # $? only works on the first line here

  # full line for error if we JUST got one (not after hitting <enter>)
  if [ -z "$Z_EMPTY_CMD" ] && [ $Z_LAST_RETVAL != 0 ]; then
    echo '✘'
  fi
}

PROMPT=$'\n› '

使用屏幕截图:

simpler screenshot