diff --git a/dash-passion.zsh-theme b/dash-passion.zsh-theme index d41c0c9..ee7cb48 100644 --- a/dash-passion.zsh-theme +++ b/dash-passion.zsh-theme @@ -1,64 +1,3 @@ -# gdate for macOS -# REF: https://apple.stackexchange.com/questions/135742/time-in-milliseconds-since-epoch-in-the-terminal -if [[ "$OSTYPE" == "darwin"* ]]; then - { - gdate - } || { - echo "\n$fg_bold[yellow]passsion.zsh-theme depends on cmd [gdate] to get current time in milliseconds$reset_color" - echo "$fg_bold[yellow][gdate] is not installed by default in macOS$reset_color" - echo "$fg_bold[yellow]to get [gdate] by running:$reset_color" - echo "$fg_bold[green]brew install coreutils;$reset_color"; - echo "$fg_bold[yellow]\nREF: https://github.com/ChesterYue/ohmyzsh-theme-passion#macos\n$reset_color" - } -fi - - -# time -function real_time() { - local color="%{$fg_no_bold[cyan]%}"; # color in PROMPT need format in %{XXX%} which is not same with echo - local time="[$(date +%H:%M:%S)]"; - local color_reset="%{$reset_color%}"; - echo "${color}${time}${color_reset}"; -} - -# login_info -function login_info() { - local color="%{$fg_no_bold[cyan]%}"; # color in PROMPT need format in %{XXX%} which is not same with echo - local ip - if [[ "$OSTYPE" == "linux-gnu" ]]; then - # Linux - ip="$(ifconfig | grep ^eth1 -A 1 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -1)"; - elif [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - ip="$(ifconfig | grep ^en1 -A 4 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -1)"; - elif [[ "$OSTYPE" == "cygwin" ]]; then - # POSIX compatibility layer and Linux environment emulation for Windows - elif [[ "$OSTYPE" == "msys" ]]; then - # Lightweight shell and GNU utilities compiled for Windows (part of MinGW) - elif [[ "$OSTYPE" == "win32" ]]; then - # I'm not sure this can happen. - elif [[ "$OSTYPE" == "freebsd"* ]]; then - # ... - else - # Unknown. - fi - local color_reset="%{$reset_color%}"; - echo "${color}[%n@${ip}]${color_reset}"; -} - - -# directory -function directory() { - # local color="%{$fg_no_bold[cyan]%}"; - local color="$FG[111]"; - # REF: https://stackoverflow.com/questions/25944006/bash-current-working-directory-with-replacing-path-to-home-folder - local directory="${PWD/#$HOME/~}"; - local color_reset="%{$reset_color%}"; - echo "${color}[${directory}]${color_reset}"; -} - - -# git ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_no_bold[blue]%}❮%{$fg_no_bold[red]%}"; ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%}"; ZSH_THEME_GIT_PROMPT_END_SUFFIX="%{$fg_no_bold[blue]%}❯%{$reset_color%}"; @@ -76,11 +15,43 @@ ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg_bold[red]%}⬢%{$reset_color%}" ZSH_THEME_GIT_PROMPT_UNMERGED="%{$fg_bold[red]%}!%{$reset_color%}" +ZSH_THEME_GIT_FETCH_STATUS=0 +ZSH_THEME_GIT_FETCH_STATUS_INTERVAL=60 + +function strf_real_time() { + local time_str; + local format=${1:='%Y-%m-%d {%u} %H:%M:%S'} + strftime -s time_str ${format} $EPOCHSECONDS + # strftime -s time_str "%Y-%m-%d {%u} %H:%M:%S" $EPOCHSECONDS + local time="[${time_str}]"; + echo -e ${time} +} + +# time +function real_time() { + local color="%{$fg_no_bold[cyan]%}"; # color in PROMPT need format in %{XXX%} which is not same with echo + # local time_str; + # strftime -s time_str "%Y-%m-%d {%u} %H:%M:%S" $EPOCHSECONDS + # local time="[${time_str}]"; + local _time="$(strf_real_time '%H:%M:%S')" + local color_reset="%{$reset_color%}"; + echo "${color}${_time}${color_reset}"; +} + +# directory +function directory() { + # local color="%{$fg_no_bold[cyan]%}"; + local color="$FG[111]"; + # REF: https://stackoverflow.com/questions/25944006/bash-current-working-directory-with-replacing-path-to-home-folder + local directory="${PWD/#$HOME/~}"; + local color_reset="%{$reset_color%}"; + echo "${color}[${directory}]${color_reset}"; +} function __git_branch() { local ref - ref=$(command git symbolic-ref HEAD 2> /dev/null) || \ - ref=$(command git rev-parse --short HEAD 2> /dev/null) || return + ref=$(__git_prompt_git symbolic-ref HEAD 2> /dev/null) || \ + ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref#refs/heads/}${ZSH_THEME_GIT_PROMPT_SUFFIX}" } @@ -91,55 +62,40 @@ function vscode_git_status() { # This cannot use the prompt constants, as they may be empty local -A prefix_constant_map prefix_constant_map=( - '\?\? ' 'UNTRACKED' - '[MTARC][ MTD] ' 'STAGED' - 'D ' 'STAGED' - ' [AMTD] ' 'UNSTAGED' - '[MTARC][MTD] ' 'UNSTAGED' - '[DAU][DAU] ' 'UNMERGED' - 'ahead' 'AHEAD' - 'behind' 'BEHIND' - 'diverged' 'DIVERGED' - 'stashed' 'STASHED' + '\?\? ' 'UNTRACKED' + '[MTARC][ MTD] ' 'STAGED' + 'D ' 'STAGED' + ' [AMTD] ' 'UNSTAGED' + '[MTARC][MTD] ' 'UNSTAGED' + '[DAU][DAU] ' 'UNMERGED' + 'ahead' 'AHEAD' + 'behind' 'BEHIND' + 'diverged' 'DIVERGED' + 'stashed' 'STASHED' ) - # '(?![DAU][DAU])[MTARCD][AMTD ] ' 'STAGED' # exclude the `[DAU][DAU]` - # '(?![DAU][DAU])[MTARCD ][AMTD] ' 'UNSTAGED' -# prefix_constant_map=( -# '\?\? ' 'UNTRACKED' -# '[MTARC][MTD] ' 'STAGEDUNSTAGED' -# '[MTARC] ' 'STAGED' -# 'D ' 'STAGED' -# ' [AMD] ' 'UNSTAGED' -# '[DAU][DAU] ' 'UNMERGED' -# 'ahead' 'AHEAD' -# 'behind' 'BEHIND' -# 'diverged' 'DIVERGED' -# 'stashed' 'STASHED' -# ) - # Maps the internal constant to the prompt theme local -A constant_prompt_map constant_prompt_map=( - 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" - 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" - 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" - 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" - 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" - 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" - 'AHEAD' "$(git_commits_ahead)" - 'BEHIND' "$(git_commits_behind)" - 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" - 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" - 'STAGED' "$ZSH_THEME_GIT_PROMPT_STAGED" - 'UNSTAGED' "$ZSH_THEME_GIT_PROMPT_UNSTAGED" + 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" + 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" + 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" + 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" + 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" + 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" + 'AHEAD' "$(git_commits_ahead)" + 'BEHIND' "$(git_commits_behind)" + 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" + 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" + 'STAGED' "$ZSH_THEME_GIT_PROMPT_STAGED" + 'UNSTAGED' "$ZSH_THEME_GIT_PROMPT_UNSTAGED" ) # The order that the prompt displays should be added to the prompt local status_constants status_constants=( - UNTRACKED ADDED MODIFIED RENAMED DELETED - STASHED UNMERGED AHEAD BEHIND DIVERGED STAGED UNSTAGED + UNTRACKED ADDED MODIFIED RENAMED DELETED + STASHED UNMERGED AHEAD BEHIND DIVERGED STAGED UNSTAGED ) local status_text @@ -147,14 +103,14 @@ function vscode_git_status() { # Don't continue on a catastrophic failure if [[ $? -eq 128 ]]; then - return 1 + return 1 fi # A lookup table of each git status encountered local -A statuses_seen if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then - statuses_seen[STASHED]=1 + statuses_seen[STASHED]=1 fi local status_lines @@ -162,80 +118,76 @@ function vscode_git_status() { # If the tracking line exists, get and parse it if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then - local branch_statuses - local match - local branch_status - branch_statuses=("${(@s/,/)match}") - for branch_status in $branch_statuses; do - if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then - continue - fi - local last_parsed_status=$prefix_constant_map[$match[1]] - statuses_seen[$last_parsed_status]=$match[2] - done + local branch_statuses + branch_statuses=("${(@s/,/)match}") + for branch_status in $branch_statuses; do + if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then + continue + fi + local last_parsed_status=$prefix_constant_map[$match[1]] + statuses_seen[$last_parsed_status]=$match[2] + done fi - local status_prefix # For each status prefix, do a regex comparison for status_prefix in ${(k)prefix_constant_map}; do - local status_constant="${prefix_constant_map[$status_prefix]}" - local status_regex=$'(^|\n)'"$status_prefix" + local status_constant="${prefix_constant_map[$status_prefix]}" + local status_regex=$'(^|\n)'"$status_prefix" - if [[ "$status_text" =~ $status_regex ]]; then - statuses_seen[$status_constant]=1 - fi + if [[ "$status_text" =~ $status_regex ]]; then + statuses_seen[$status_constant]=1 + fi done # Display the seen statuses in the order specified local status_prompt for status_constant in $status_constants; do - if (( ${+statuses_seen[$status_constant]} )); then - local next_display=$constant_prompt_map[$status_constant] - status_prompt="$next_display$status_prompt" - fi + if (( ${+statuses_seen[$status_constant]} )); then + local next_display=$constant_prompt_map[$status_constant] + status_prompt="$next_display$status_prompt" + fi done echo $status_prompt } function update_git_status() { - if __git_prompt_git rev-parse --git-dir &>/dev/null; then - GIT_STATUS=$(__git_branch); - local git_status="$(vscode_git_status)" - if [[ $git_status != "" ]]; then - GIT_STATUS+=" ${git_status}"; - fi - GIT_STATUS+=${ZSH_THEME_GIT_PROMPT_END_SUFFIX}; - else - GIT_STATUS="" - fi + if __git_prompt_git rev-parse --git-dir &>/dev/null; then + GIT_STATUS=$(__git_branch); + local git_status="$(vscode_git_status)" + if [[ $git_status != "" ]]; then + GIT_STATUS+=" ${git_status}"; + fi + GIT_STATUS+=${ZSH_THEME_GIT_PROMPT_END_SUFFIX}; + else + GIT_STATUS="" + fi } function git_status() { - update_git_status; - echo "${GIT_STATUS}" + update_git_status; + echo "${GIT_STATUS}" } - # command function update_command_status() { - local arrow=""; - local color_reset="%{$reset_color%}"; - local reset_font="%{$fg_no_bold[white]%}"; - COMMAND_RESULT=$1; - export COMMAND_RESULT=$COMMAND_RESULT - if $COMMAND_RESULT; - then - arrow="%{$fg_bold[red]%}❱%{$fg_bold[yellow]%}❱%{$fg_bold[green]%}❱"; - else - arrow="%{$fg_bold[red]%}❱❱❱"; - fi - COMMAND_STATUS="${arrow}${reset_font}${color_reset}"; + local arrow=""; + local color_reset="%{$reset_color%}"; + local reset_font="%{$fg_no_bold[white]%}"; + COMMAND_RESULT=$1; + export COMMAND_RESULT=$COMMAND_RESULT + if $COMMAND_RESULT; + then + arrow="%{$fg_bold[red]%}❱%{$fg_bold[yellow]%}❱%{$fg_bold[green]%}❱"; + else + arrow="%{$fg_bold[red]%}❱❱❱"; + fi + COMMAND_STATUS="${arrow}${reset_font}${color_reset}"; } update_command_status true; function command_status() { - echo "${COMMAND_STATUS}" + echo "${COMMAND_STATUS}" } # settings @@ -245,123 +197,140 @@ typeset +H my_orange="$FG[214]" # separator dashes size function afmagic_dashes { - local ratio=1 - echo $((COLUMNS * ratio)) + local ratio=1 + echo $((COLUMNS * ratio)) } +current_time_millis() { + local time_millis; + time_millis=$EPOCHREALTIME + echo $time_millis; +} + + # output command execute after output_command_execute_after() { - if [ "$COMMAND_TIME_BEIGIN" = "-20200325" ] || [ "$COMMAND_TIME_BEIGIN" = "" ]; - then - return 1; - fi + if [ "$COMMAND_TIME_BEIGIN" = "-20200325" ] || [ "$COMMAND_TIME_BEIGIN" = "" ]; + then + return 1; + fi - # cmd - local cmd="${$(fc -l | tail -1)#* }"; - local color_cmd=""; - if $1; - then - color_cmd="$fg_no_bold[green]"; - else - color_cmd="$fg_bold[red]"; - fi - local color_reset="$reset_color"; - cmd="${color_cmd}${cmd}${color_reset}" + # cmd + local cmd="${$(fc -l | tail -1)#* }"; + local color_cmd=""; + if $1; + then + color_cmd="$fg_no_bold[green]"; + else + color_cmd="$fg_bold[red]"; + fi + local color_reset="$reset_color"; + cmd="${color_cmd}${cmd}${color_reset}" - # time - local time="[$(date +%H:%M:%S)]" - local color_time="$fg_no_bold[cyan]"; - time="${color_time}${time}${color_reset}"; + # time + # you can use the real_time command to replace + local color_time="$fg_no_bold[cyan]"; + local _time="${color_time}$(strf_real_time)${color_reset}"; - # cost - local time_end="$(current_time_millis)"; - local cost=$(bc -l <<<"${time_end}-${COMMAND_TIME_BEIGIN}"); - COMMAND_TIME_BEIGIN="-20200325" - local length_cost=${#cost}; - if [ "$length_cost" = "4" ]; - then - cost="0${cost}" - fi - cost="[cost ${cost}s]" - local color_cost="$fg_no_bold[yellow]"; - cost="${color_cost}${cost}${color_reset}"; + # cost + local time_end="$(current_time_millis)"; + local cost=$(bc -l <<<"${time_end}-${COMMAND_TIME_BEIGIN}"); + COMMAND_TIME_BEIGIN="-20200325" + local length_cost=${#cost}; + if [ "$length_cost" = "11" ]; # 11 means the length of cost + then + cost="0${cost}" + fi + cost="[cost ${cost}s]" + local color_cost="$fg_no_bold[yellow]"; + cost="${color_cost}${cost}${color_reset}"; - echo -e "${time} ${cost} ${cmd}"; - echo -e ""; - local echo_dark_gray="\033[2;49;39m" + echo -e "${_time} ${cost} ${cmd}"; - echo -e "$echo_dark_gray${(l.$(afmagic_dashes)..-.)}${color_reset}" + echo -e ""; + local echo_dark_gray="\033[2;49;39m" + echo -e "$echo_dark_gray${(l.$(afmagic_dashes)..-.)}${color_reset}" } # command execute before # REF: http://zsh.sourceforge.net/Doc/Release/Functions.html preexec() { - COMMAND_TIME_BEIGIN="$(current_time_millis)"; + COMMAND_TIME_BEIGIN="$(current_time_millis)"; } -current_time_millis() { - local time_millis; - if [[ "$OSTYPE" == "linux-gnu" ]]; then - # Linux - time_millis="$(date +%s.%3N)"; - elif [[ "$OSTYPE" == "darwin"* ]]; then - # macOS - time_millis="$(gdate +%s.%3N)"; - elif [[ "$OSTYPE" == "cygwin" ]]; then - # POSIX compatibility layer and Linux environment emulation for Windows - elif [[ "$OSTYPE" == "msys" ]]; then - # Lightweight shell and GNU utilities compiled for Windows (part of MinGW) - elif [[ "$OSTYPE" == "win32" ]]; then - # I'm not sure this can happen. - elif [[ "$OSTYPE" == "freebsd"* ]]; then - # ... - else - # Unknown. - fi - echo $time_millis; -} - - # command execute after # REF: http://zsh.sourceforge.net/Doc/Release/Functions.html dash_passion_precmd() { - # last_cmd - local last_cmd_return_code=$?; - local last_cmd_result=true; - if [ "$last_cmd_return_code" = "0" ]; - then - last_cmd_result=true; - else - last_cmd_result=false; - fi + # last_cmd + local last_cmd_return_code=$?; + local last_cmd_result=true; + if [ "$last_cmd_return_code" = "0" ]; + then + last_cmd_result=true; + else + last_cmd_result=false; + fi - # update_git_status - update_git_status + # update_git_status + update_git_status - # update_command_status - update_command_status $last_cmd_result; + # update_command_status + update_command_status $last_cmd_result; - # output command execute after - output_command_execute_after $last_cmd_result; + # output command execute after + output_command_execute_after $last_cmd_result; } -TMOUT=1; - -TRAPALRM() { - # $(git_prompt_info) cost too much time which will raise stutters when inputting. so we need to disable it in this occurence. - # if [ "$WIDGET" != "expand-or-complete" ] && [ "$WIDGET" != "self-insert" ] && [ "$WIDGET" != "backward-delete-char" ]; then - # black list will not enum it completely. even some pipe broken will appear. - # so we just put a white list here. - if [ "$WIDGET" = "" ] || [ "$WIDGET" = "accept-line" ] ; then - zle reset-prompt; - fi +function git_fetch_status() { + [ ${ZSH_THEME_GIT_FETCH_STATUS} != "0" ] && return 0 + ZSH_THEME_GIT_FETCH_STATUS=1 + __git_prompt_git rev-parse --is-inside-work-tree &>/dev/null || return 0 + __git_prompt_git fetch -q --all 2>/dev/null + __git_prompt_git status 12>/dev/null + ZSH_THEME_GIT_FETCH_STATUS=0 } +function chpwd() { + __git_prompt_git rev-parse --is-inside-work-tree &>/dev/null || return 0 + __git_prompt_git status 12>/dev/null +} + +# real time clock for zsh. +# https://stackoverflow.com/questions/2187829/constantly-updated-clock-in-zsh-prompt +schedprompt() { + emulate -L zsh + zmodload -i zsh/sched + + integer i=${"${(@)zsh_scheduled_events#*:*:}"[(I)git_fetch_status]} + # git_fetch_all periodically. + (( i )) || sched +${ZSH_THEME_GIT_FETCH_STATUS_INTERVAL} git_fetch_status + + # Remove existing event, so that multiple calls to + # "schedprompt" work OK. (You could put one in precmd to push + # the timer 30 seconds into the future, for example.) + integer i=${"${(@)zsh_scheduled_events#*:*:}"[(I)schedprompt]} + (( i )) && sched -$i + + # Test that zle is running before calling the widget (recommended + # to avoid error messages). + # Otherwise it updates on entry to zle, so there's no loss. + if [ "$WIDGET" = "" ] || [ "$WIDGET" = "accept-line" ] ; then + zle && zle reset-prompt; + fi + + # This ensures we're not too far off the start of the minute + # update zle for every second. + sched +1 schedprompt +} + +zmodload -i zsh/datetime + setopt prompt_subst PROMPT='$(real_time) $(directory) $(git_status) $(command_status) '; RPROMPT='%{$FG[242]%}%n@%m $(battery_pct_prompt)${color_reset}'; autoload -Uz add-zsh-hook -add-zsh-hook precmd dash_passion_precmd \ No newline at end of file +add-zsh-hook precmd dash_passion_precmd +schedprompt