# atom's .zshrc # atom's .zshrc # atom.smasher.org # atom @ # smasher.org # suspicious.org # gpg key = 762A 3B98 A3C3 96C9 C6B7 582A B88D 52E4 D9F5 7808 # first public release late 2007 # last updated 12 jun 2011 - under regular development, check back for updates ZSHRC='public release v0.157 - http://smasher.org/zsh/' # let me know if there's a problem with this zshrc. ## this is enabled by default zshrc_wiggle=y ## these are not enabled by default. see the functions for details. enable_sudo_hack=n # linux specific. see "show_mach_type" function. enable_outline=n # set to "y" to enable some extra line drawings on startup. enable_color_err=n # see "color_err" function. # if you find this useful, please consider: # my wish list: http://amzn.com/w/164X0LDU2Z390 # or a donation to these (or similar?) organizations: # Electronic Frontier Foundation - http://www.eff.org/ # FreeBSD Foundation - http://www.freebsdfoundation.org/ # Free Software Foundation - http://www.fsf.org/ # Creative Commons - http://creativecommons.org/ # Center for Democracy and Technology - http://www.cdt.org/ # Public Knowledge - http://www.publicknowledge.org/ # Open Source Initiative - http://www.opensource.org/ # New Zealand Open Source Society - http://nzoss.org.nz/ # !! this is not intended to be a universal zshrc file !! # what's here works for me. i like it. the reason i'm # releasing this is for others to learn from it. if you # want to copy from it, good luck. for best results, roll # up your sleeves and make it your own. # # original code released under GNU General Public License. # http://www.gnu.org/licenses/gpl-3.0.txt # other licenses may be available on request. # to the best of my knowledge code from others has been # properly attributed, but in most (all?) cases modified enough # that i can claim copyright over it as it appears here. # # thanks to everyone who posted something that's attributed below!! # and thanks to everyone who helped make this zshrc better. # this file would never have gotten so far if not for all of you. ## if ~/.hushlogin exists & this is a "login" shell... ## display motd only if it's something i haven't seen before [[ 'on' == ${options[login]} && /etc/motd -nt ~/.hushlogin ]] && { cat /etc/motd && :> ~/.hushlogin } umask 022 export HOME TERM \ GZIP="${GZIP} -9" \ KDEDIR=${KDEDIR:-/usr/local} \ OGLE_USE_XV=0 \ TZ=Pacific/Auckland TTY_LINE=$(print -P '%l') ## this bit makes this zshrc more portable. ## the TZ setting above is a default if none is specified with a ~/.TZ file. ## on a server on the US east coast my ~/.TZ contains "America/New_York" ## this way i don't have to set the TZ every time i update my zshrc. [[ -f ~/.TZ ]] && read TZ < ~/.TZ ## this feature may be deprecated; see - http://www.smasher.org/zsh/ ## overall, that's a better way to include your local/preferred settings # after this zshrc file is run you can type: TZ= # and see a list of time zones ;) WORDCHARS=':*?_-.[]~&;!#$%^(){}<>|' HISTSIZE=250 ## turn on colors for ls if { ls --color=auto -- ${HOME} &> /dev/null } then ## looks like gnu-ls ls () { command ls --color=auto ${@} } else [[ ${OSTYPE} == freebsd* || ${OSTYPE} == darwin* ]] && export CLICOLOR=yes LSCOLORS=ExGxFxdxCxDxDxhbadacec fi ## (re)set defaults. useful if the zshrc needs to be re-sourced emulate -LR zsh ## enable: setopt PROMPT_SUBST \ EXTENDED_GLOB \ AUTO_CD \ CORRECT \ CORRECT_ALL \ INTERACTIVE_COMMENTS \ 2> /dev/null ## load some modules that i find useful zmodload zsh/terminfo zsh/zselect zsh/system zsh/datetime autoload is-at-least ## zsh/termcap needs to be handled specially or else the shell ## may die as soon as this file is parsed (eg; during login) ## http://www.zsh.org/mla/users/2009/msg00921.html zsh -c "zmodload zsh/termcap" && zmodload zsh/termcap ## figure out what the PATH should be typeset -U common_paths common_paths=( ${path} ${=$(command -p getconf PATH 2> /dev/null)//:/ } # what the system thinks PATH should be /bin /sbin /usr/bin /usr/sbin # good places to look /usr/local/bin /usr/local/sbin # freeBSD /usr/X11R6/bin # X11 /usr/pkg/bin /usr/pkg/sbin # ??? /usr/ucb # solaris - BSD /usr/sfw/bin /usr/sfw/sbin # solaris - sun free-ware /usr/xpg4/bin /usr/xpg6/bin # solaris - X/Open Portability Guide /opt/local/bin /opt/local/sbin /opt/SUNWspro/bin # solaris /usr/ccs/bin # solaris - C Compilation System /usr/platform/$(uname -i)/sbin # solaris - hardware dependent #/var/qmail/bin # qmail - uncomment if desired /usr/games # fun stuff ${HOME}/bin # personal stuff ) 2> /dev/null unset PATH_tmp unsetopt NOMATCH for temp_path in ${common_paths} do if [[ ${OSTYPE} == solaris* ]] then ## solaris may have some of these directories owned by "bin:bin" (uid 2) ## observed on: SunOS 5.10 Generic_120011-14 sparc, core install test -d "${temp_path}"(u0r^IWt,u2r^IWt,Ur^IWt) && PATH_tmp="${PATH_tmp}${temp_path}:" elif [[ ${OSTYPE} == *freebsd* && 1 == "$(/sbin/sysctl -n security.jail.jailed)" ]] 2> /dev/null then ## in a bsd jail, look for symlinks, not just directories test -e "${temp_path}"(-/u0r^IWt,-/Ur^IWt) && PATH_tmp="${PATH_tmp}${temp_path}:" elif [[ ${OSTYPE} == 'cygwin' ]] then ## f**king windoze - trying to enforce reasonable security here will just break things test -e "${temp_path}"(/F) && PATH_tmp="${PATH_tmp}${temp_path}:" else ## this is the normal case test -d "${temp_path}"(u0r^IWt,Ur^IWt) && PATH_tmp="${PATH_tmp}${temp_path}:" fi done setopt NOMATCH export PATH=${PATH_tmp/%:/} unset common_paths temp_path PATH_tmp ## cygwin only: commands that auto-complete with and without .exe or .dll suffixes are annoying. ## thanks Thorsten Kampe & Bart Schaefer ## http://www.zsh.org/mla/users/2009/threads.html#00391 [[ ${OSTYPE} == 'cygwin' ]] && { setopt EXTENDED_GLOB LOCAL_OPTIONS zstyle ':completion:*:-command-:*' ignored-patterns '(#i)*.exe' '(#i)*.dll' } ## quoting from FreeBSD's man logname(1) page: "The logname utility explicitly ## ignores the LOGNAME and USER environment variables because the environment ## cannot be trusted." ## ain't that the truth. Linux and sudo crap all over it. as tested on linux, this fixes the problem. LOGNAME="${$(logname 2> /dev/null):-$LOGNAME}" ## solaris grep is lacking [[ ${OSTYPE} == solaris* ]] && { ## solaris-10 will likely have these, except core install [[ -x $(whence -p ggrep) ]] && alias grep=$(whence -p ggrep) [[ -x $(whence -p gegrep) ]] && alias egrep=$(whence -p gegrep) [[ -x $(whence -p gfgrep) ]] && alias fgrep=$(whence -p gfgrep) } ## not all systems have `less`, but it sure beats `more` [[ -x $(whence -p less) ]] && export PAGER=$(whence -p less) ## ## not all systems have `most`, but i like it better than `less` ## except on a dumb TERM [[ -x $(whence -p most) && ${TERM} != 'dumb' ]] && export PAGER=$(whence -p most) ## not all systems (solaris) have a userland stat [[ -x $(whence -p stat) ]] || { zmodload zsh/stat && alias stat="stat -ronL" } ## after setting the PAGER, above... READNULLCMD=${PAGER} ## not all systems have `emacs`, but i like it when they do [[ -x $(whence -p emacs) ]] && export EDITOR=$(whence -p emacs) ## if there's a `manpath` command, use it [[ -x $(whence -p manpath) ]] && export MANPATH=$(manpath 2> /dev/null) ## old (and/or crappy) versions of `grep` choke on this - make it safe { print test_for_color | grep -q --color test && \ export GREP_OPTIONS="${GREP_OPTIONS} --color=auto" GREP_COLOR='1;33;4' } 2> /dev/null ####################################################### ## set up an array to help facilitate the PROMPT tricks ## the array "PR_STUFF" contains things to be used in the prompt typeset -A PR_STUFF ###################### ## aliases & functions alias mv='nocorrect mv' # no spelling correction on mv (zsh FAQ 3.4) alias cp='nocorrect cp' # no spelling correction on cp (zsh FAQ 3.4) alias mkdir='nocorrect mkdir' # no spelling correction on mkdir (zsh FAQ 3.4) ## look for rsync - if it's found create a "cpv" function [[ -x $(whence -p rsync) ]] && cpv () { { unsetopt XTRACE } 2> /dev/null ## verbose copy ## rsync, but neutered rsync -Ih --inplace --progress -e /dev/null -- ${@} } cd () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh ## cd to a file (cd to the directory that a file is in). ## this _might_ break some zsh specific features of 'cd', but none that i use. ## as of 23 oct 2007 i can't see that it breaks anything. if [[ 1 == "${#}" && '-' != "${1}" && ! -d "${1}" && -d "${1:h}" && "${1}" != (+|-)<-> ]] then PR_STUFF[cd_color]=file builtin cd "${1:h}" else [[ "${*}" == '-' ]] && PR_STUFF[cd_color]=dash builtin cd "${@}" fi } cdmkdir () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh ## create a new directory and cd into it mkdir -p "${1}" cd "${1}" } fortune () { { unsetopt XTRACE } 2> /dev/null ## include all fortunes in the database ## freebsd - /usr/share/games/fortune ## ubuntu - /usr/share/games/fortunes command fortune -a ${@} /usr/share/games/{fortune,fortunes}(N) } shellname () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh ## a *very* simple command to set the SHELL_NAME variable. ## used to explicitly set a name for the shell, as displayed in ## title bars, icons, `screen` lists, etc ## with no arguments the name returns to normal (dynamic) operation SHELL_NAME="${*}" } shellprefix () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh ## like shellname, but just a prefix SHELL_PREFIX="${*}" } command_title () { ### this function sets the current command name in title bars, tabs, and screen lists ## inspired by: http://www.semicomplete.com/blog/2006/Jun/29 if [[ -n ${SHELL_NAME} ]] then # allow the $cmnd_name to be set manually and override automatic values # to set the shell's title to "foo"; export SHELL_NAME=foo # to return to normal operation; unset SHELL_NAME cmnd_name="${SHELL_NAME}" elif [[ 'fg' == "${${(Qz)@}[1]}" ]] then # this is a poor hack to replace 'fg' with a more sensical command # it really only works properly if only one job is suspended cmnd_name="${(qvV)jobtexts}" else # get the $cmnd_name from the current command being executed local cmnd_name="${1}" fi # make nonprintables visible # convert literal newline into "; " & literal tab into space cmnd_name="${(QV)${cmnd_name//$'\t'/ }//$'\n'/; }" # truncate the $cmnd_name cmnd_name="%80>...>${cmnd_name//\%/\%\%}%<<" [[ "${USERNAME}" != "${LOGNAME}" ]] && cmnd_name="${USERNAME}: ${cmnd_name}" # if the shell is running on an ssh connection, prefix the command with "$HOST: " [[ -n "${SSH_CONNECTION}" ]] && cmnd_name="${HOST}: ${cmnd_name}" ## add prefix, if defined [[ -n "${SHELL_PREFIX}" ]] && cmnd_name="${SHELL_PREFIX}: ${cmnd_name}" PR_STUFF[prev_cmnd_name]="${(q)cmnd_name}" # don't confuse the display any more than required # we'll put this back, if required, below setopt NO_PROMPT_SUBST LOCAL_OPTIONS case ${TERM} in xterm*) print -Pn "\e]0;[${COLORTERM:-${TERM}}] ${(q)cmnd_name}\a" > ${TTY} # plain xterm title & icon name ;; screen) print -Pn "\ek${(q)cmnd_name}\e\\" > ${TTY} # screen title ## for best results, see: http://smasher.org/zsh/screenrc ## and modify to suit ;; rxvt*) print -Pn "\e]62;[${COLORTERM:-${TERM}}] ${(q)cmnd_name}\a" > ${TTY} # (m)rxvt title & icon name print -Pn "\e]61;${(q)cmnd_name}\a" > ${TTY} # mrxvt tab name ## there's no good way for the shell to know if it's running in rxvt or mrxvt. ## this assumes mrxvt, but shouldn't hurt anything in rxvt. ;; esac } ############################## ## enable completion functions autoload -U compinit if [[ ${OSTYPE} == 'cygwin' ]] then compinit -u ; compaudit ## (in)security workaround for windoze else compinit ## normal case fi ############################################################### ## uncomment these lines to make the completion widgets verbose ## useful for learning more about the secret art of zsh's completion system ## thanks John Beppu - http://www.linux-mag.com/id/1106 #zstyle ':completion:*' verbose yes #zstyle ':completion:*:descriptions' format '%B%d%b' #zstyle ':completion:*:messages' format '%d' #zstyle ':completion:*:warnings' format 'No matches for: %d' #zstyle ':completion:*' group-name '' ## enable zargs autoload -U zargs ## these are fall-backs if the TERM doesn't handle colors ## if the TERM supports color TIMEFMT will be overwritten below # worst case: TERM supports nothing special TIMEFMT=" ## %J ## %*U user, %*S system, %P cpu, %*E total" # next best: TERM supports underline - better than nothing [[ -n ${terminfo[smul]} ]] && TIMEFMT=" ## ${terminfo[smul]}%J${terminfo[rmul]} ## ${terminfo[smul]}%*U user, %*S system, %P cpu, %*E total${terminfo[rmul]}" # next best: TERM supports reverse - better than underline [[ -n ${terminfo[rev]} ]] && TIMEFMT=" ## ${terminfo[rev]}%J${terminfo[sgr0]} ## ${terminfo[rev]}%*U user, %*S system, %P cpu, %*E total${terminfo[sgr0]}" # my favorite: TERM supports colors - handled below ########################## # See if we can use colors # inspired by: http://www.aperiodic.net/phil/prompt/ autoload colors [[ "${terminfo[colors]}" -ge 8 ]] && { colors ## color support! TIMEFMT=" ${fg_bold[yellow]}## ${terminfo[smul]}%J${terminfo[rmul]} ## ${terminfo[smul]}%*U user, %*S system, %P cpu, %*E total${terminfo[sgr0]}" } for color in CYAN WHITE YELLOW MAGENTA BLACK BLUE RED DEFAULT GREY GREEN do PR_STUFF[${color}]="%{${fg_bold[${(L)color}]}%}" PR_STUFF[LIGHT_${color}]="%{${fg[${(L)color}]}%}" PR_STUFF[BG_${color}]="%{${bg_bold[${(L)color}]}%}" PR_STUFF[BG_LIGHT_${color}]="%{${bg[${(L)color}]}%}" done ################################## ## print fortune in reverse video [[ -x $(whence -p fortune) ]] && \ print "${terminfo[bold]}${fg[cyan]}${terminfo[rev]}$(fortune)${terminfo[sgr0]}" ###################### #### prompt tricks ### ## not all tricks are available on all terminals ###################### ## property start end ## bold %B %b ## underline %U %u ## standout %S %s PR_STUFF[ITALIC]="%{${terminfo[sitm]}%}" # enter_italics_mode PR_STUFF[END_ITALIC]="%{${terminfo[ritm]}%}" # exit_italics_mode PR_STUFF[DIM]="%{${terminfo[dim]}%}" # enter_dim_mode PR_STUFF[BLINK]="%{${terminfo[blink]}%}" # enter_blink_mode PR_STUFF[NO_COLOR]="%{${terminfo[sgr0]}%}" # exit_attribute_mode (turn off all attributes) ##################################################### # See if we can use extended characters to look nicer # more info on all of this funky stuff: "man 5 terminfo" typeset -A altchar set -A altchar ${(s..)terminfo[acsc]} PR_STUFF[SET_CHARSET]="%{${terminfo[enacs]}%}" # enable_alternate_character_set PR_STUFF[SHIFT_IN]="%{${terminfo[smacs]}%}" # enter_alt_charset_mode PR_STUFF[SHIFT_OUT]="%{${terminfo[rmacs]}%}" # end_alternate_character_set typeset -A ACS ACS[STERLING]=${altchar[\}]:- } # UK pound sign ACS[DARROW]=${altchar[.]:- } # arrow pointing down ACS[LARROW]=${altchar[,]:-<} # arrow pointing left ACS[RARROW]=${altchar[+]:->} # arrow pointing right ACS[UARROW]=${altchar[-]:-^} # arrow pointing up ACS[BOARD]=${altchar[h]:-#} # board of squares ACS[BULLET]=${altchar[~]:-#} # bullet ACS[CKBOARD]=${altchar[a]:-#} # checker board (stipple) ACS[DEGREE]=${altchar[f]:-#} # degree symbol ACS[DIAMOND]=${altchar[\`]:-+} # diamond ACS[GEQUAL]=${altchar[z]:->} # greater-than-or-equal-to ACS[PI]=${altchar['{']:-#} # greek pi ACS[HLINE]=${altchar[q]:--} # horizontal line ACS[LANTERN]=${altchar[i]:-#} # lantern symbol ACS[PLUS]=${altchar[n]:-+} # large plus or crossover ACS[LEQUAL]=${altchar[y]:-<} # less-than-or-equal-to ACS[LLCORNER]=${altchar[m]:-+} # lower left corner ACS[LRCORNER]=${altchar[j]:-+} # lower right corner ACS[NEQUAL]=${altchar[|]:-!} # not-equal ACS[PLMINUS]=${altchar[g]:-#} # plus/minus ACS[S1]=${altchar[o]:-_} # scan line 1 ACS[S3]=${altchar[p]:-_} # scan line 3 ACS[S7]=${altchar[r]:-_} # scan line 7 ACS[S9]=${altchar[s]:-_} # scan line 9 ACS[BLOCK]=${altchar[0]:-#} # solid square block ACS[TTEE]=${altchar[w]:-+} # tee pointing down ACS[RTEE]=${altchar[u]:- } # tee pointing left ACS[LTEE]=${altchar[t]:- } # tee pointing right ACS[BTEE]=${altchar[v]:-+} # tee pointing up ACS[ULCORNER]=${altchar[l]:-+} # upper left corner ACS[URCORNER]=${altchar[k]:-+} # upper right corner ACS[VLINE]=${altchar[x]:-#} # vertical line ## this makes `less` much more friendly export LESS_TERMCAP_md="${terminfo[bold]}${fg_bold[white]}" # bold/ bright export LESS_TERMCAP_mh="${fg[white]}" # dim/ half export LESS_TERMCAP_me="${terminfo[sgr0]}" # normal (turn off all attributes) export LESS_TERMCAP_mr="${terminfo[rev]}" # reverse export LESS_TERMCAP_mp="${fg[white]}" # protected export LESS_TERMCAP_mk="${fg[white]}" # blank/ invisible export LESS_TERMCAP_se="${terminfo[sgr0]}" # standout end export LESS_TERMCAP_so="${terminfo[rev]}" # standout export LESS_TERMCAP_ue="${terminfo[sgr0]}" # end underline export LESS_TERMCAP_us="${fg_bold[cyan]}" # underline export LESS='MiRJw -z-5 -j15' ## outline startup info if the TERM does fancy alt-chars [[ ${enable_outline} == 'y' && ( -n "${${terminfo[enacs]}}" || "${#${(V)ACS[HLINE]}}" -gt 1 ) ]] && { PR_STUFF[start_bar]="\${(r:$[${COLUMNS}/3]::${ACS[HLINE]}:)}" print -P "${terminfo[enacs]}${terminfo[smacs]}${fg_bold[white]}${ACS[ULCORNER]}${PR_STUFF[start_bar]}${terminfo[rmacs]}${terminfo[sgr0]}" PR_STUFF[bar_vline]="${terminfo[enacs]}${terminfo[smacs]}${fg_bold[white]}${ACS[VLINE]}${terminfo[rmacs]}${terminfo[sgr0]}" print -n "${PR_STUFF[bar_vline]}" } how_many_cpu () { { unsetopt XTRACE } 2> /dev/null ## try to figure out how many CPUs are in the system local cpu_count=0 ## linux [[ ${OSTYPE} == linux* ]] && { while read proc_cpu_count do [[ ${proc_cpu_count} == processor* ]] && cpu_count=$[${cpu_count}+1] done < /proc/cpuinfo print "Found ${cpu_count} CPUs in /proc/cpuinfo" 1>&2 print "${cpu_count}" return 0 } ## cygwin [[ 'cygwin' == ${OSTYPE} && -n ${NUMBER_OF_PROCESSORS} ]] && { ## if there's one thing i like about windoze, this is it. it couldn't be simpler. ## of course it would be nice if it was accurate more often... and without a way ## of knowing the system load this number doesn't mean anything :( cpu_count=${NUMBER_OF_PROCESSORS} print "Found ${cpu_count} CPUs with \$NUMBER_OF_PROCESSORS environment variable" 1>&2 print "${cpu_count}" return 0 } ## FreeBSD, OpenBSD... (and darwin? not tested) { sysctl -n hw.ncpu 2> /dev/null | read cpu_count } && { print "Found ${cpu_count} CPUs with sysctl" 1>&2 print "${cpu_count}" return 0 } ## solaris... [[ ${OSTYPE} == solaris* && -x $(whence -p psrinfo) ]] && { local psrinfo_count psrinfo | while read psrinfo_count do [[ -z "${psrinfo_count##*on-line*}" ]] && cpu_count=$[${cpu_count}+1] ## is there a justification to re-check this as part is TRAPALRM? maybe...? ## should i be counting physical or virtual processors? ## apparently solaris doesn't have a standard interface for counting cores ## or even virtual CPUs. it seems i'll have to settle for physical CPUs. ## i think the line above can be simplified, or at least made easier ## to read. will test when i have access to a solaris box. ## i'm also not sure how far back these commands are useful on solaris. ## [[ ${psrinfo_count} == *on-line* ]] && cpu_count=$[${cpu_count}+1] ## ?? ## cpu_count=$(psrinfo -p) ## ?? done print "Found ${cpu_count} \"on-line\" physical CPUs with psrinfo" 1>&2 print "${cpu_count}" return 0 } ## if all else fails, assume 1 CPU print 'Assuming 1 CPU' 1>&2 print 1 ## to do, when i have access to these machines for testing ## darwin: sysctl hw.logicalcpu ?? ## solaris: as noted above } ################################################################################### ## before we colorize the system load figure out how many CPUs are sharing the load ######################################### ## if the load is less then #CPUs - green ## if the load is more than twice #CPUs - red ## if the load is in between - yellow PR_STUFF[cpu_count]=$(how_many_cpu) load_color () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh setopt NO_SH_WORDSPLIT load_color=${1} ## if the same color is used two (or more) times it only has ## to be specified once if [[ ${load_color} == ${this_load_color} ]] then color_loads="${color_loads}${each_load}" else color_loads="${color_loads}${PR_STUFF[UPTIME_LOAD_${load_color}]}${each_load}" this_load_color=${load_color} fi } ## // unfortunately, this chokes on interactive prompts to STDERR, eg, "rm -i file" ## Colorize STDERR ## based on - http://gentoo-wiki.com/TIP_Advanced_zsh_Completion#Colorize_STDERR ## // the only way really make this work properly is to implement it in the terminal #exec 2>>( #while read stderr #do # print "${fg[red]}"${(q)stderr}"${terminfo[sgr0]}" 1>&2 #done) ## see below... i think i've got it... almost. ## colorize STDERR ## this mostly works, but can suffer from race conditions when output is also on STDOUT. ## and other bugs and weirdness. color_err () { ## sysread & syswrite are part of zsh/system emulate -LR zsh while sysread do syswrite -o 2 "${fg_bold[red]}${REPLY}${terminfo[sgr0]}" done } ## i'm not sure exactly how far back it's safe to go with this ## 4.3.4 works; 4.2.1 hangs. is-at-least 4.3.4 && [[ ${enable_color_err} == 'y' ]] && exec 2> >( color_err ) set_up_prompt () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh setopt PROMPT_SUBST NO_SH_WORDSPLIT EXTENDED_GLOB ## set up for PROMPT local TERMWIDTH=$[${COLUMNS}-2] ## figure out the load averages local uptime_load uptime_load_size color_loads each_load this_load_color load_color ## stderr from `uptime` is redirected to /dev/null to cope with a bug observed in OS-X ## 10.5.1 and likely exists in other OS-X releases; if an xterm is opened in X11 ## the output of `uptime` gets hosed in *all* terminals uptime_load="${(@)${=$(uptime 2> /dev/null)}[-3,-1]:-?, ?, ?}" # the load averages ## i'd rather see question marks than zeros, if the zeros are not accurate [[ 'cygwin' == ${OSTYPE} && '0.00, 0.00, 0.00' == ${uptime_load} ]] && uptime_load='?, ?, ?' ## i just found two reasons today for including a default uptime of "?, ?, ?". one is cygwin. ## the other is that a SIGINT at the wrong instant can kill uptime before it produces output. ## this deals gracefully with both of those conditions. uptime_load_size=$[ ${#uptime_load} + 2] # how many characters in the load averages ## colorize the load averages for each_load in ${${=uptime_load}[1]}\ ${${=uptime_load}[2]}\ ${${=uptime_load}[3]} do ## this looks weird: ${each_load/%${~:-,*}/} ## it's doing a pattern substitution on ',*' to get rid of everything after a comma, if there is one ## the leading '~' allows substitution for a pattern, instead of a string ## the ':' tells it to substitute what follows, instead of using the preceding null string ## different LOCALEs, and different OSes do weird things with commas in the load ## averages, and this seems to deal with them all if [[ "${PR_STUFF[cpu_count]:-1}" -gt "${each_load/%${~:-,*}/}" ]] then load_color LOW elif [[ $[${PR_STUFF[cpu_count]:-1}*2] -le "${each_load/%${~:-,*}/}" ]] then load_color HI else load_color MED fi done uptime_load="${PR_STUFF[SHIFT_OUT]}${color_loads}${PR_STUFF[SHIFT_IN]}" ## time zone stuff - a linux system with a half-broken strftime(3) showed me that i like seeing ## the city name of the time zone i'm in. if that's not available then show the short version ## if you just want the short version use this: PR_STUFF[TZ]=$(print -P '%D{%Z}') [[ ${TZ} != ${PR_STUFF[TZ_LAST]} ]] && { ## sanity check if the TZ file exists ## only do this when the TZ env variable changed ## the reason for this is to not display nonsense if TZ=foo/bar ## and set TZ to something useful instead of leaving it undefined local tz_file ## thanks: Peter Stephenson - zsh-users mailing list 09 Jan 2008 tz_file=(/usr/{share,lib,share/lib}/{zoneinfo,locale/TZ}/${TZ}(.N)) (( ${#tz_file} )) || export TZ=Etc/UTC PR_STUFF[TZ_LAST]=${TZ} PR_STUFF[TZ]=${${TZ:t}:-$(print -P '%D{%Z}')} } ## how much space will the time take up local time_space="${#${(%):-$(print -P '%D{%H:%M} '${PR_STUFF[TZ]})}}" ## if there's battery info, get it. otherwise don't (but fail gracefully) ## the battery info comes from "/root/bin/bat-mon" ## check that /tmp/battery-status is a plain file ## and owned either by root or current UID setopt NO_NOMATCH LOCAL_OPTIONS if test -f /tmp/battery-status(u0R^IW,UR^IW) then setopt NOMATCH ## return that to normal read BATT_STAT < /tmp/battery-status local batt_stat_size=${#${(%S)BATT_STAT//\$\{*\}}} [[ -n "${BATT_STAT}" ]] && BATT_STAT="${ACS[RTEE]}${BATT_STAT}${PR_STUFF[PS1_LINE]}${PR_STUFF[NO_COLOR]}${PR_STUFF[PS1_LINE]}${PR_STUFF[SHIFT_IN]}${ACS[LTEE]}" local promptsize=$[${#${(%):-xx%n@%M:}} + ${batt_stat_size} + 2 + ${uptime_load_size} + time_space + 2] else setopt NOMATCH ## return that to normal local promptsize=$[${#${(%):-xx%n@%M:}} + ${uptime_load_size} + time_space + 2] fi ## count up the width of the things that are on the prompt local pwdsize=${#${(%):-%(1/.%~/.%~)}} local termwidth_minus_promptsize_minus_pwdsize=$[${TERMWIDTH} - ${promptsize} - ${pwdsize}] [[ 0 -gt ${termwidth_minus_promptsize_minus_pwdsize} ]] && termwidth_minus_promptsize_minus_pwdsize='0' PR_STUFF[PWDLEN]=$[${TERMWIDTH} - ${promptsize}] [[ 0 -gt $PR_STUFF[PWDLEN] ]] && PR_STUFF[PWDLEN]=1 ## ending the line with a null fixes some weird problems observed when TERM=linux ## and it shouldn't hurt anything to just leave it there. it may fix the same weird ## problems on other TERMs. the crazy thing is that if the line ends with ACS_LTEE ## it causes problems, but ACS_RTEE is fine. truly bizarre. PR_STUFF[FILLBAR]="\${(r:${termwidth_minus_promptsize_minus_pwdsize}::${ACS[HLINE]}:)}\ ${ACS[RTEE]}${PR_STUFF[TIME]}${PR_STUFF[SHIFT_OUT]}%D{%H:%M} ${PR_STUFF[TIME_TZ]}${PR_STUFF[TZ]}${PR_STUFF[SHIFT_IN]}${PR_STUFF[PS1_LINE]}${ACS[LTEE]}${ACS[RTEE]}\ ${uptime_load}${PR_STUFF[PS1_LINE]}${ACS[LTEE]}${BATT_STAT}" ## linux console TERM hack [[ ${TERM} == linux ]] && PR_STUFF[FILLBAR]="$PR_STUFF[FILLBAR]"$'\0' PR_STUFF[COLUMNS]=${COLUMNS} } chpwd () { { unsetopt XTRACE } 2> /dev/null [[ -z "${PR_STUFF[cd_color]}" ]] && PR_STUFF[cd_color]=new } ## use colors from the 256 color palate if they're available ## ## to set a background color behind the prompt, ## uncomment the lines starting with: PR_STUFF[BG_PS] if [[ 256 -eq "${terminfo[colors]}" ]] then ## if the TERM supports 256 colors # PR_STUFF[BG_PS]="$PR_STUFF[BG_BLACK]" ## prompt bg color PR_STUFF[PWD_NEW]="%b${PR_STUFF[BG_PS]}%{$(echoti setaf 226)%}" PR_STUFF[PWD_NEW_FILE]="%b%U${PR_STUFF[BG_PS]}%{$(echoti setaf 226)%}" PR_STUFF[PWD_NEW_DASH]="%b${PR_STUFF[BG_PS]}%{$(echoti setaf 178)%}" PR_STUFF[PWD_OLD]="%b${PR_STUFF[BG_PS]}%{$(echoti setaf 33)%}" PR_STUFF[TIME]="%b%{$(echoti setaf 147)%}${PR_STUFF[SHIFT_OUT]}${PR_STUFF[BG_PS]}" PR_STUFF[TIME_TZ]="%{$(echoti setaf 62)%}" PR_STUFF[UPTIME_LOAD_LOW]="%{$(echoti setaf 40)%}${PR_STUFF[BG_PS]}" PR_STUFF[UPTIME_LOAD_MED]="%{$(echoti setaf 226)%}${PR_STUFF[BG_PS]}" PR_STUFF[UPTIME_LOAD_HI]="%{$(echoti setaf 196)%}${PR_STUFF[BG_PS]}" PR_STUFF[PS1_LINE]="${PR_STUFF[BG_PS]}%{$(echoti setaf 231)%}" [[ 0 -eq ${UID} ]] && PR_STUFF[PS1_LINE]="${PR_STUFF[BG_PS]}%{$(echoti setaf 196)%}" PR_STUFF[ROOT_BG]="%{$(echoti setab 196)%}" else ## if the term doesn't support 256 colors # PR_STUFF[BG_PS]="$PR_STUFF[BG_BLACK]" ## prompt bg color PR_STUFF[PWD_NEW]="%b${PR_STUFF[BG_PS]}${PR_STUFF[YELLOW]}" PR_STUFF[PWD_NEW_FILE]="%b%U${PR_STUFF[BG_PS]}${PR_STUFF[YELLOW]}" PR_STUFF[PWD_NEW_DASH]="%b${PR_STUFF[BG_PS]}${PR_STUFF[GREEN]}" PR_STUFF[PWD_OLD]="%b${PR_STUFF[BG_PS]}${PR_STUFF[BLUE]}" PR_STUFF[TIME]="%b${PR_STUFF[LIGHT_CYAN]}${PR_STUFF[BG_PS]}" PR_STUFF[UPTIME_LOAD_LOW]="${PR_STUFF[BG_PS]}${PR_STUFF[LIGHT_GREEN]}" PR_STUFF[UPTIME_LOAD_MED]="${PR_STUFF[BG_PS]}${PR_STUFF[LIGHT_YELLOW]}" PR_STUFF[UPTIME_LOAD_HI]="${PR_STUFF[BG_PS]}${PR_STUFF[LIGHT_RED]}" PR_STUFF[PS1_LINE]="${PR_STUFF[BG_PS]}${PR_STUFF[WHITE]}" [[ 0 -eq ${UID} ]] && PR_STUFF[PS1_LINE]="${PR_STUFF[BG_PS]}${PR_STUFF[RED]}" PR_STUFF[ROOT_BG]="$PR_STUFF[BG_LIGHT_RED]" fi chpwd_color () { { unsetopt XTRACE } 2> /dev/null ## change the color of the PWD in the prompt ## if we just changed directories if [[ -z "${PR_STUFF[cd_color]}" ]] then PR_STUFF[PWD_COLOR]="${PR_STUFF[PWD_OLD]}${PR_STUFF[BG_PS]}" else ## we just changed to to a new directory ## the color of the new dir depends on how we got here case ${PR_STUFF[cd_color]} in dash) PR_STUFF[PWD_COLOR]="${PR_STUFF[PWD_NEW_DASH]}${PR_STUFF[BG_PS]}" ;; file) PR_STUFF[PWD_COLOR]="${PR_STUFF[PWD_NEW_FILE]}${PR_STUFF[BG_PS]}" ;; *) PR_STUFF[PWD_COLOR]="${PR_STUFF[PWD_NEW]}${PR_STUFF[BG_PS]}" ;; esac unset 'PR_STUFF[cd_color]' fi } wiggle_on_error () { ## this draws attention to terminal windows that have a non-zero exit status ## note that output is explicitly directed to the TTY to avoid problems with redirection ## if you have annoying non-fixed fonts you may want to comment out ## the lines that are marked "pipe" and "dash". also consider halving ## the wiggle speed, as in xterm, when only using slash and backslash { unsetopt XTRACE } 2> /dev/null jobs -Z "wiggle_on_error ${TTY_LINE}" cd ${HOME} ## move the process to place that won't need to be unmounted wiggle_speed=10 ## default wiggle speed. higher number = slower speed ## slow down the wiggle speed if BAUD is slow. ## consider putting something like this in .zlogin on remote machines, if ## BAUD is not calculated auto-magically: ## [[ -n "${SSH_CONNECTION}" && -z "${BAUD}" ]] && export BAUD=10000 ## see "zshparam" for more info about $BAUD [[ -n ${BAUD} && 38400 -gt ${BAUD} ]] && wiggle_speed=$[ 614400 / $[BAUD] ] wiggle_on_error_pause () { zselect -t $[${1:-1} * ${wiggle_speed}] } setopt NO_PROMPT_SUBST LOCAL_OPTIONS case ${TERM} in xterm*) while [[ 1 != $sysparams[ppid] ]] ; do print -Pn "\e]0;\\\\${1}\\\\ ${2} \\\\ ${3}\a" ; wiggle_on_error_pause 2 ## backslash print -Pn "\e]0;/${1}/ ${2} / ${3}\a" ; wiggle_on_error_pause 2 ## slash done ;; screen) while [[ 1 != $sysparams[ppid] ]] ; do print -Pn "\ek\\\\${1}\\\\ ${2} \\\\ ${3}\e\\" ; wiggle_on_error_pause ## backslash print -Pn "\ek|${1}| ${2} | ${3}\e\\" ; wiggle_on_error_pause ## pipe print -Pn "\ek/${1}/ ${2} / ${3}\e\\" ; wiggle_on_error_pause ## slash print -Pn "\ek-${1}- ${2} - ${3}\e\\" ; wiggle_on_error_pause ## dash done ;; rxvt*) ## 62 is the escape sequence for the mrxvt title bar & tab title ## 61 is the escape sequence for the mrxvt tab title only while [[ 1 != $sysparams[ppid] ]] ; do print -Pn "\e]62;\\\\${1}\\\\ ${2} \\\\ ${3}\a" ; wiggle_on_error_pause ## backslash print -Pn "\e]61;|${1}| ${2} | ${3}\a" ; wiggle_on_error_pause ## pipe print -Pn "\e]62;/${1}/ ${2} / ${3}\a" ; wiggle_on_error_pause ## slash print -Pn "\e]61;-${1}- ${2} - ${3}\a" ; wiggle_on_error_pause ## dash done ;; *) ## this seems like a decent way to do nothing, indefinately, untill killed ## which makes it safe to kill a command that's been backgrounded read ;; esac } kill_wiggle_on_error () { [[ 'y' != ${zshrc_wiggle} ]] && return 0 ## if "tostop" is set, the wiggle_job will hang and require a "kill -KILL" to really kill it ## since there isn't a good & portable way to detect tostop use "-KILL" here kill -KILL ${PR_STUFF[wiggle_job]} unset 'PR_STUFF[wiggle_job]' } precmd () { # this displays nifty stuff about commands that exit non-zero # 1) Look at exit status of last command - attach appropriate signal # if it was a signal that caused it. It's safest to do this first # before $?'s value gets screwed up. # http://zsh.dotsrc.org/Contrib/startup/users/debbiep/dot.zshrc # 2) make it more feasible to control how/when it's displayed # idea from zsh-users mailing list; # Matthew Wozniski , Sep 29 2007 { local exit_and_pipe_status="${?} ${pipestatus[-1]}" } 2> /dev/null ## the "unsetopt XTRACE" below (also called in most of the functions) and the way the ## line above is enclosed in curly braces with stderr redirected, allows the shell to use ## xtrace without causing a *LOT* of noise every time it prints a prompt { unsetopt XTRACE } 2> /dev/null emulate -LR zsh local precmd_exitstatus="${${=exit_and_pipe_status}[1]}" local precmd_pipe_status="${${=exit_and_pipe_status}[-1]}" if [[ 0 -ne "${precmd_exitstatus}" && -z "${shownexterr}" ]] then PR_STUFF[exitstuff]="${precmd_exitstatus}" shownexterr=y # see also preexec: unset shownexterr if [[ ${precmd_exitstatus} -ge 128 && $precmd_exitstatus -le (127+${#signals}) ]] then # Last process was (most likely) killed by a signal PR_STUFF[exitstuff]="${PR_STUFF[exitstuff]}:${signals[${precmd_exitstatus}-127]}" elif [[ ${precmd_exitstatus} != ${precmd_pipe_status} ]] then ## check for other signals that don't terminate, and don't return signal# + 128 ## the pipe_status hack is explained here - http://www.zsh.org/mla/users/2009/msg00377.html case ${signals[${precmd_exitstatus}+1]} in TSTP) ## in all likelihood, this is the only stop signal that you'll ever see on a command line PR_STUFF[exitstuff]="${PR_STUFF[exitstuff]}:TSTP" ;; STOP) PR_STUFF[exitstuff]="${PR_STUFF[exitstuff]}:STOP" ;; TTIN) PR_STUFF[exitstuff]="${PR_STUFF[exitstuff]}:TTIN" ;; TTOU) PR_STUFF[exitstuff]="${PR_STUFF[exitstuff]}:TTOU" ;; esac fi ## wiggle on error ## first; kill the previous wiggle, if there is one (done in several places, as needed) ## second; start the wiggle process and disown it ## third; save the PID of the wiggle process so it can be killed later [[ -n ${PR_STUFF[wiggle_job]} ]] && kill_wiggle_on_error [[ 'y' == ${zshrc_wiggle} ]] && { wiggle_on_error "${PR_STUFF[exitstuff]}" "${PR_STUFF[prev_cmnd_name]}" "${ZSH_NAME} (${TTY_LINE})" > ${TTY} &! PR_STUFF[wiggle_job]="${!}" } ## if wiggle_on_error isn't working, check if stty tostop is set else [[ -n ${PR_STUFF[wiggle_job]} ]] && kill_wiggle_on_error unset 'PR_STUFF[exitstuff]' fi ## if the most recent command returned non-zero, display the exit status in the prompt ## if the most recent command was killed with a signal, show that too [[ -n "${PR_STUFF[exitstuff]}" ]] && { PR_STUFF[exitstuff]="${PR_STUFF[SHIFT_IN]}${ACS[RTEE]}${PR_STUFF[BG_RED]}${PR_STUFF[WHITE]}\ ${PR_STUFF[SHIFT_OUT]}${PR_STUFF[exitstuff]}${PR_STUFF[NO_COLOR]}${PR_STUFF[WHITE]}${PR_STUFF[BG_PS]}\ ${PR_STUFF[PS1_LINE]}${PR_STUFF[SHIFT_IN]}${ACS[LTEE]}" } ## underline the USERNAME in the prompt if it's different than the LOGNAME PR_STUFF[ps1_name]=$([[ ${LOGNAME} != ${USERNAME} ]] && print '%U%n%u' || print '%n') ## the default title for this terminal, when no command is being executed command_title "${ZSH_NAME} (${TTY_LINE})" set_up_prompt chpwd_color ## reset a sane tty print -n "${terminfo[rmacs]}" } preexec () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh unset shownexterr print -n ${terminfo[sgr0]} ## reset colors, etc ## kill of any wigglers, if any. here, it serves the purpose of getting ## rid of wigglers if a subsequent command doesn't return immediately. [[ -n ${PR_STUFF[wiggle_job]} ]] && kill_wiggle_on_error ## set the command_title command_title "${(qqq)1}" } ## colored completion listings [[ "${terminfo[colors]}" -ge 8 ]] && zstyle ':completion:*:default' list-colors \ 'no=1;36;4:fi=1;36:di=0;34:ln=0;35:pi=0;31:so=0;32:bd=44;37:cd=44;37:ex=0;31:tc=0;0:sp=0;0:ec=' ############################### ## custom widgets & key-bindings bindkey -e ## emacs key-bindings ## SHIFT-TAB can do a reverse-menu-complete! ## may not work on all TERMs? bindkey '^[[Z' reverse-menu-complete ## this is a nice compliment to ^K bindkey '^[k' backward-kill-line execute-prev-command () { { unsetopt XTRACE } 2> /dev/null ## kind of like "accept-and-hold" but this doesn't require forethought ## it can be used after the previous command is executed with zle && zle .up-line-or-history && zle .accept-line } zle -N execute-prev-command ## note that this replaces the default key-binding for "execute-last-named-cmd" ## which i find not as useful as this bindkey "^[z" execute-prev-command move-to-bottom () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh setopt PROMPT_SUBST ## because sometimes i feel like moving to the bottom of the screen echoti cup $[${LINES}-1] 0 2> /dev/null zle && zle reset-prompt } zle -N move-to-bottom bindkey "^X^L" move-to-bottom copy-prev-word () { { unsetopt XTRACE } 2> /dev/null ## for most command line editing i like to use "/" as a word separator ## but when using "copy-prev-word" i want the whole path local WORDCHARS="'${WORDCHARS}/'" zle .copy-prev-word } zle -N copy-prev-word backward-word-with-slash () { { unsetopt XTRACE } 2> /dev/null ## SHIFT-ALT-B can do backward-word, with slashes local WORDCHARS="'${WORDCHARS}/'" zle .backward-word } zle -N backward-word-with-slash bindkey "^[B" backward-word-with-slash forward-word-with-slash () { { unsetopt XTRACE } 2> /dev/null ## SHIFT-ALT-F can do forward-word, with slashes local WORDCHARS="'${WORDCHARS}/'" zle .forward-word } zle -N forward-word-with-slash bindkey "^[F" forward-word-with-slash transpose-words () { { unsetopt XTRACE } 2> /dev/null ## definitely include the "/" as part of words to transpose local WORDCHARS="'${WORDCHARS}/'" zle .transpose-words } zle -N transpose-words ## not needed with zle_highlight is-at-least 4.3.9 || { accept-line () { { unsetopt XTRACE } 2> /dev/null ## this may not be the most efficient way to do this... ## redraw the edit buffer before executing the command ## the real reason this is here is to re-color the edit buffer ## if completion messed it up zle .redisplay zle .accept-line } zle -N accept-line } expand-or-complete-with-color () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh print -n ${fg_bold[cyan]} _main_complete } zle -C expand-or-complete .expand-or-complete expand-or-complete-with-color expand-or-complete-prefix-with-color () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh print -n ${fg_bold[cyan]} _main_complete } zle -C expand-or-complete-prefix .expand-or-complete-prefix expand-or-complete-prefix-with-color ## if i do "^A" and go to the beginning of the line, and i want to insert a command ## at the beginning of the line, i can start typing the command and CTRL-SPACE to complete bindkey "^ " expand-or-complete-prefix ################################################# ## redraw the prompt when the window size changes TRAPWINCH () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh setopt PROMPT_SUBST zle || return 0 [[ ${PR_STUFF[COLUMNS]} -gt ${COLUMNS} ]] && echoti cud1 set_up_prompt zle reset-prompt } ## cygwin + xterm = don't do it [[ 'cygwin' == ${OSTYPE} && 'xterm' == ${TERM} ]] && { unset -f TRAPWINCH } ################################## ## update the prompt auto-magically. update ~about~ every 30 seconds. ## this can be invoked manually with a "kill -ALRM" to the shell. TMOUT=$[(${RANDOM}%15)+25] TRAPALRM () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh setopt PROMPT_SUBST ## reset-prompt - this will update the prompt zle && set_up_prompt && zle reset-prompt TMOUT=$[(${RANDOM}%15)+25] } ## some things just don't work well with dumb TERMs. there are probably other ## TERM types that are just as dumb, but i haven't come across any. yet. [[ 'dumb' == ${TERM} ]] && { unset -f TRAPWINCH TRAPALRM unset TMOUT } ########## ## prompts PS1='${PR_STUFF[SET_CHARSET]}${PR_STUFF[PS1_LINE]}\ ${PR_STUFF[SHIFT_IN]}${ACS[ULCORNER]}${ACS[RTEE]}${PR_STUFF[SHIFT_OUT]}\ %(0#.${PR_STUFF[WHITE]}${PR_STUFF[ps1_name]}@%M.${PR_STUFF[MAGENTA]}${PR_STUFF[ps1_name]}${PR_STUFF[PWD_OLD]}@${PR_STUFF[MAGENTA]}%M)\ ${PR_STUFF[WHITE]}:${PR_STUFF[PWD_COLOR]}%${PR_STUFF[PWDLEN]}<...<%(1/.%~/.%~)%<<%u\ ${PR_STUFF[NO_COLOR]}\ ${PR_STUFF[BG_PS]}${PR_STUFF[PS1_LINE]}\ ${PR_STUFF[SHIFT_IN]}${ACS[LTEE]}\ ${(e)PR_STUFF[FILLBAR]}\ ${PR_STUFF[SHIFT_IN]}${ACS[LLCORNER]}${PR_STUFF[exitstuff]}\ %#${PR_STUFF[NO_COLOR]}${PR_STUFF[SHIFT_OUT]} ' ## set colors and related attributes for the command line text if is-at-least 4.3.9 then zle_highlight=( \ region:standout \ special:standout \ isearch:bg=blue,fg=cyan,bold \ default:bold,fg=cyan ) else PS1="${PS1}\${PR_STUFF[CYAN]}" fi PS2='${PR_STUFF[BLUE]}>${PR_STUFF[NO_COLOR]} ${PR_STUFF[CYAN]}' RPS2='${PR_STUFF[BLUE]}${PR_STUFF[BG_PS]}${PR_STUFF[SHIFT_IN]}\ ${ACS[HLINE]}${PR_STUFF[WHITE]}${ACS[RTEE]}${PR_STUFF[SHIFT_OUT]}\ %_\ ${PR_STUFF[SHIFT_IN]}${ACS[VLINE]}${PR_STUFF[SHIFT_OUT]}${PR_STUFF[NO_COLOR]}${PR_STUFF[CYAN]}' ## spelling prompt SPROMPT="${PR_STUFF[YELLOW]}zsh: correct '%U%R%u' to '%U%r%u' ${PR_STUFF[NO_COLOR]}\ ${PR_STUFF[LIGHT_YELLOW]}[Nyae]?${PR_STUFF[NO_COLOR]} " ########################################### ## display some useful stuff when the shell starts show_os_distro () { ## this function is somewhat dependant on the flavor of *nix. i think Linux(tm) is the only ## OS that will give less than useful information from "uname -sr". exec 2> /dev/null ## suppress errors generated in this function [[ ${OSTYPE} == linux* ]] && { ## try to figure out the distro with lsb_release. if that fails, look at /proc/version lsb_release -sd || { read < /proc/version ; print ${${REPLY//*\(/}//[0-9]*} } } | read 'PR_STUFF[os_name]' ## most linux distros should produce useful output from above. for everything else use uname. [[ -z "${PR_STUFF[os_name]}" ]] && PR_STUFF[os_name]=$(uname -sr) [[ -n "${PR_STUFF[os_name]}" ]] && print -n "(${fg_bold[white]}${${=PR_STUFF[os_name]}[*]}${${terminfo[sgr0]}})" } show_mach_type () { ## this function is very dependant on the flavor of *nix. i can only test ## what i have access to. if there's something missing i'll get to it sooner ## if you can provide access. (aix, hp-ux, solaris, darwin, etc) exec 2> /dev/null ## suppress errors generated in this function [[ ${OSTYPE} == freebsd* ]] && { kenv | while read do [[ ${REPLY} == smbios.planar.maker=* ]] && mobo_maker=${${=${(Q)REPLY/*=/}}} [[ ${REPLY} == smbios.planar.product=* ]] && mobo_product=${${=${(Q)REPLY/*=/}}} [[ ${REPLY} == smbios.system.maker=* ]] && system_maker=${${=${(Q)REPLY/*=/}}} [[ ${REPLY} == smbios.system.product=* ]] && system_product=${${=${(Q)REPLY/*=/}}} ## thinkpad hack [[ ${REPLY} == smbios.system.version=* ]] && product_version=${${=${(Q)REPLY/*=/}}} done } [[ ${OSTYPE} == openbsd* ]] && { ## tested only on "OpenBSD 4.7 macppc" - 24 mar 2010 ## i'd like to test this on more openbsd/macppc systems sysctl -a | while read do [[ ${REPLY} == hw.vendor=* ]] && system_maker=${${=${(Q)REPLY/*=/}}} [[ ${REPLY} == hw.product=* ]] && system_product=${${=${(Q)REPLY/*=/}}} done } [[ ${OSTYPE} == linux* ]] && { ## try the simple method first read mobo_maker < /sys/class/dmi/id/board_vendor || read mobo_maker < /sys/devices/virtual/dmi/id/board_vendor read mobo_product < /sys/class/dmi/id/board_name || read mobo_maker < /sys/devices/virtual/dmi/id/board_name read system_maker < /sys/class/dmi/id/sys_vendor || read mobo_maker < /sys/devices/virtual/dmi/id/sys_vendor read system_product < /sys/class/dmi/id/product_name || read mobo_maker < /sys/devices/virtual/dmi/id/product_name ## thinkpad hack read product_version < /sys/class/dmi/id/product_version || read product_version < /sys/devices/virtual/dmi/id/product_version ## if that's done, there's no need to try what's next [[ -n ${mobo_maker} && -n ${mobo_product} && -n ${system_maker} && -n ${system_product} ]] && { skip_root_dmidecode=y } ## dmidecode only works for root - so try it last ## dmidecode isn't really machine parsable, so it needs to be executed once per parameter :( [[ ( ${UID} == 0 || ${enable_sudo_hack} == 'y' ) && ${skip_root_dmidecode} != 'y' ]] && { unset prefix_cmnd [[ ${enable_sudo_hack} == 'y' && ${UID} != 0 ]] && prefix_cmnd='sudo -n' mobo_maker=$( ${=prefix_cmnd} dmidecode -s baseboard-manufacturer ) mobo_product=$( ${=prefix_cmnd} dmidecode -s baseboard-product-name ) system_maker=$( ${=prefix_cmnd} dmidecode -s system-manufacturer ) system_product=$( ${=prefix_cmnd} dmidecode -s system-product-name ) ## thinkpad hack product_version=$( ${=prefix_cmnd} dmidecode -s system-version ) ## it's possible to preface the dmidecode commands with "sudo -n", but that ## depends on the sudo config and is likely to pollute the auth.log. on some ## systems that will attract unwanted attention from security admins. in any ## case, if UID == 0 then there's no need to use sudo. ## note that erros from sudo, if any, will be directed to /dev/null. } } ## thinkpad hack [[ ${system_product} == ${mobo_product} ]] && system_product=${product_version} ## if these two values are the same, they're both noise [[ ${system_maker} == ${system_product} ]] && unset system_maker system_product ## if these two values are the same, one of them is noise [[ ${system_maker} == ${mobo_maker} ]] && unset system_maker ## if these two values are the same, one of them is noise [[ ${system_product} == ${mobo_product} ]] && unset mobo_product ## get rid of garbage. some "American Megatrends" BIOSes contain "System manufacturer" ## or "System Product Name". at least one BIOS contains the typo "stem manufacturer". ## all other garbage cleanup i've seen (so far) can be handled above. ## make an array, then join the elements with ", ". ## EXTENDED_GLOB should be set at the the top, but if someone unsets it, make sure it works here. setopt EXTENDED_GLOB LOCAL_OPTIONS mach_type_array=( ${mobo_maker} ${mobo_product} ${system_maker/*(#i)manufacturer*/} ${system_product/*(#i)product*/} ) PR_STUFF[mach_type]="${(j:, :)mach_type_array}" ## if all else fails, fallback to "uname -m" [[ -z "${PR_STUFF[mach_type]}" ]] && PR_STUFF[mach_type]=$(uname -m) [[ -n "${PR_STUFF[mach_type]}" ]] && print -n "(${fg_bold[white]}${${=PR_STUFF[mach_type]}[*]}${terminfo[sgr0]})" } show_cpu_type () { ## like the function above, this function is very dependant on the flavor of *nix. ## i can only test what i have access to. if there's something missing i'll get to ## it sooner if you can provide access. (aix, hp-ux, solaris, darwin, etc) exec 2> /dev/null ## suppress errors generated in this function PR_STUFF[cpu_type]=$(uname -p) ## on modern linux, we can do better than "unknown" # [[ 'unknown' == "${PR_STUFF[cpu_type]}" && -r /proc/cpuinfo ]] && { ## somehwere between 2.6.35 and 2.6.38-7 the output from uname changed from "unknown" ## to something just as useless - just test for /proc/cpuinfo [[ -r /proc/cpuinfo ]] && { while read do ## this will only report the first CPU found. ## like anything else, let me know if that turns into a problem. [[ ${REPLY} == model\ name*:* ]] && { print ${REPLY/*:/} ; return } done < /proc/cpuinfo } | read 'PR_STUFF[cpu_type]' ## on freebsd this seems to give better results (than uname) every time [[ ${OSTYPE} == freebsd* ]] && PR_STUFF[cpu_type]=$(sysctl -n hw.model) [[ -n "${PR_STUFF[cpu_type]}" ]] && print -n "(${fg_bold[white]}${${=PR_STUFF[cpu_type]}[*]}${${terminfo[sgr0]}})" } ## this displays hardware and OS info when the shell starts print -n "${PR_STUFF[bar_vline]}OS: ${terminfo[smul]}$OSTYPE${terminfo[rmul]} $(show_os_distro) ${PR_STUFF[bar_vline]}MACH: ${terminfo[smul]}$MACHTYPE${terminfo[rmul]} $(show_mach_type) ${PR_STUFF[bar_vline]}CPU: ${terminfo[smul]}$CPUTYPE${terminfo[rmul]} $(show_cpu_type) ${PR_STUFF[bar_vline]}TTY: ${fg[white]}${TTY%%${TTY_LINE}}${terminfo[sgr0]}${terminfo[smul]}${TTY_LINE}${terminfo[rmul]} ${PR_STUFF[bar_vline]}SHLVL: ${terminfo[smul]}" unset -f show_os_distro show_mach_type show_cpu_type if [[ ${SHLVL} -gt 1 ]] then ## only attempt to display SHLVL in color if it's >1 print "${fg_bold[yellow]}${SHLVL}${terminfo[sgr0]}" else print "${SHLVL}${terminfo[sgr0]}" fi ## wrap up the excessive visuals, if enabled. [[ -n ${PR_STUFF[start_bar]} ]] && { print -P "${terminfo[enacs]}${terminfo[smacs]}${fg_bold[white]}${ACS[LLCORNER]}${PR_STUFF[start_bar]}${terminfo[rmacs]}${terminfo[sgr0]}" unset 'PR_STUFF[start_bar]' 'PR_STUFF[bar_vline]' } ## when exiting a forked interactive shell, display what level we're returning to zshexit () { { unsetopt XTRACE } 2> /dev/null emulate -LR zsh ## really, is there any need to use the "-L" option there? i guess it's good form. setopt EXTENDED_GLOB [[ ${SHLVL} -gt 1 && 'on' == ${options[interactive]} ]] && { exec 2> /dev/null ## suppress errors generated in this function print " ${fg_bold[yellow]}## ${terminfo[smul]}Returning to SHLVL $[${SHLVL}-1]${terminfo[sgr0]}" ## not entirely portable below here... but on bsd with procfs and on linux, ## display the parent process name of the shell we're returning to. read -A < {/compat/linux/proc,/proc}/${PPID}/stat(N) || return 0 read -A < {/compat/linux/proc,/proc}/${reply[4]}/stat(N) ## the color of the next message depends on the parent process [[ "(${ZSH_NAME})" != "${reply[2]}" ]] && PR_STUFF[exit_color]=red print " ${fg_bold[${PR_STUFF[exit_color]:-yellow}]}## Parent process: ${terminfo[smul]}${${reply[2]}[2,-2]}${terminfo[sgr0]}" } print -n ${terminfo[sgr0]} ## reset colors, etc } :