Created
January 22, 2019 10:32
-
-
Save andurilan/fafab6a5771375d7eca2ad8fe5f681a5 to your computer and use it in GitHub Desktop.
Korn Shell Environment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*-sh-*- | |
# | |
# .kshrc - Korn shell 93 startup file | |
umask 0077 | |
set -o emacs | |
set +o multiline | |
# Taken from bash completion support core Git. | Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> | | |
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). | Distributed under the GNU General Public License, version 2.0. | |
# __gitdir accepts 0 or 1 arguments (i.e., location) | |
# returns location of .git repo | |
function __gitdir | |
{ | |
if [ -z "${1-}" ]; then | |
if [ -n "${__git_dir-}" ]; then | |
echo "$__git_dir" | |
elif [ -d .git ]; then | |
echo .git | |
else | |
git rev-parse --git-dir 2>/dev/null | |
fi | |
elif [ -d "$1/.git" ]; then | |
echo "$1/.git" | |
else | |
echo "$1" | |
fi | |
} | |
# | |
# __git_ps1 accepts 0 or 1 arguments (i.e., format string) | |
# returns text to add to bash PS1 prompt (includes branch name) | |
function __git_ps1 | |
{ | |
typeset g="$(__gitdir)" | |
if [ -n "$g" ]; then | |
typeset r | |
typeset b | |
if [ -f "$g/rebase-merge/interactive" ]; then | |
r="|REBASE-i" | |
b="$(cat "$g/rebase-merge/head-name")" | |
elif [ -d "$g/rebase-merge" ]; then | |
r="|REBASE-m" | |
b="$(cat "$g/rebase-merge/head-name")" | |
else | |
if [ -d "$g/rebase-apply" ]; then | |
if [ -f "$g/rebase-apply/rebasing" ]; then | |
r="|REBASE" | |
elif [ -f "$g/rebase-apply/applying" ]; then | |
r="|AM" | |
else | |
r="|AM/REBASE" | |
fi | |
elif [ -f "$g/MERGE_HEAD" ]; then | |
r="|MERGING" | |
elif [ -f "$g/BISECT_LOG" ]; then | |
r="|BISECTING" | |
fi | |
b="$(git symbolic-ref HEAD 2>/dev/null)" || { | |
b="$( | |
case "${GIT_PS1_DESCRIBE_STYLE-}" in | |
(contains) | |
git describe --contains HEAD ;; | |
(branch) | |
git describe --contains --all HEAD ;; | |
(describe) | |
git describe HEAD ;; | |
(* | default) | |
git describe --exact-match HEAD ;; | |
esac 2>/dev/null)" || | |
b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || | |
b="unknown" | |
b="($b)" | |
} | |
fi | |
typeset w | |
typeset i | |
typeset s | |
typeset u | |
typeset c | |
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then | |
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then | |
c="BARE:" | |
else | |
b="GIT_DIR" | |
fi | |
elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then | |
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then | |
if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then | |
git diff --no-ext-diff --ignore-submodules \ | |
--quiet --exit-code || w="*" | |
if git rev-parse --quiet --verify HEAD >/dev/null; then | |
git diff-index --cached --quiet \ | |
--ignore-submodules HEAD -- || i="+" | |
else | |
i="#" | |
fi | |
fi | |
fi | |
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then | |
git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" | |
fi | |
if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then | |
if [ -n "$(git ls-files --others --exclude-standard)" ]; then | |
u="%" | |
fi | |
fi | |
fi | |
if [ -n "${1-}" ]; then | |
printf "$1%s" "$c${b##refs/heads/}$w$i$s$u$r" | |
else | |
printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r" | |
fi | |
fi | |
} | |
# | |
# DIRECTORY MANIPULATION FUNCTION, REPLACES CD | |
# Uses global parameters _push_max _push_top _push_stack | |
# | |
# Change directory and put directory on front of stack | |
function _cd | |
{ | |
typeset dir= | |
integer n=0 type=4 | |
case $1 in | |
-|-1|2) # \cd - | |
n=_push_top type=1 | |
;; | |
-[1-9]*([0-9])) # \cd -n | |
n=_push_top+${1#-}-1 type=2 | |
;; | |
1) # keep present directory | |
print -r - "$PWD" | |
return | |
;; | |
[1-9]*([0-9])) # \cd n | |
n=_push_top+${1}-2 type=2 | |
;; | |
*) if ((_push_top <= 0)) | |
then type=3 n=_push_max | |
fi | |
esac | |
if ((type<3)) | |
then if ((n >= _push_max+1)) | |
then print -u2 cd: Directory stack not that deep. | |
return 1 | |
else dir=${_push_stack[n]} | |
fi | |
fi | |
case $dir in | |
\~*) dir=$HOME${dir#\~} | |
esac | |
\cd "${dir:-$@}" >| /dev/null || return 1 | |
dir=${OLDPWD#$HOME/} | |
case $TERM in | |
630) | |
print "\033[?${#PWD};2v$PWD\c" | |
;; | |
esac | |
case $dir in | |
$HOME) | |
dir=\~ | |
;; | |
/*) ;; | |
*) dir=\~/$dir | |
esac | |
case $type in | |
1) # swap first two elements | |
_push_stack[_push_top]=$dir | |
;; | |
2|3) # put $dir on top and shift down by one until top | |
integer i=_push_top | |
for dir in "$dir" "${_push_stack[@]}" | |
do ((i > n)) && break | |
_push_stack[i]=$dir | |
i=i+1 | |
done | |
;; | |
4) # push name | |
_push_stack[_push_top=_push_top-1]=$dir | |
;; | |
esac | |
# print -r - "$PWD" | |
} | |
# Uses global parameter _push_stack | |
# Display directory stack -- $HOME displayed as ~ | |
function dirs | |
{ | |
typeset dir="${PWD#$HOME/}" | |
case $dir in | |
$HOME) | |
dir=\~ | |
;; | |
/*) ;; | |
*) dir=\~/$dir | |
esac | |
PS3= | |
select i in "$dir" "${_push_stack[@]}" | |
do : | |
done < /dev/null | |
} | |
# Uses global parameter _push_stack | |
# Menu driven change directory command | |
function mcd | |
{ | |
typeset dir="${PWD#$HOME/}" | |
case $dir in | |
$HOME) | |
dir=\~ | |
;; | |
/*) ;; | |
*) dir=\~/$dir | |
esac | |
PS3='Select by number or enter a name: ' | |
select dir in "$dir" "${_push_stack[@]}" | |
do if _cd $REPLY | |
then return | |
fi | |
done | |
} | |
# Uses global parameters _push_max _push_top _push_stack | |
# Pops the top directory | |
function popd | |
{ | |
typeset dir | |
if ((_push_top >= _push_max)) | |
then print popd: Nothing to pop. | |
return 1 | |
fi | |
case $1 in | |
"") | |
dir=${_push_stack[_push_top]} | |
case $dir in | |
\~*) dir=$HOME${dir#\~} | |
esac | |
\cd "$dir" || return 1 | |
;; | |
+[1-9]|+[1-9][0-9]) | |
typeset savedir | |
integer i=_push_top$1-1 | |
if ((i >= _push_max)) | |
then print pushd: Directory stack not that deep. | |
return 1 | |
fi | |
while ((i > _push_top)) | |
do _push_stack[i]=${_push_stack[i-1]} | |
i=i-1 | |
done | |
;; | |
*) print pushd: Bad directory. | |
return 1 | |
esac | |
unset '_push_stack[_push_top]' | |
_push_top=_push_top+1 | |
dirs | |
} | |
# Uses global parameters _push_max _push_top _push_stack | |
# Change directory and put directory on front of stack | |
function pushd | |
{ | |
typeset dir= type=0 | |
integer i | |
case $1 in | |
"") # pushd | |
if ((_push_top >= _push_max)) | |
then print pushd: No other directory. | |
return 1 | |
fi | |
type=1 dir=${_push_stack[_push_top]} | |
;; | |
+[1-9]|+[1-9][0-9]) # pushd +n | |
integer i=_push_top$1-1 | |
if ((i >= _push_max)) | |
then print pushd: Directory stack not that deep. | |
return 1 | |
fi | |
type=2 dir=${_push_stack[i]} | |
;; | |
*) if ((_push_top <= 0)) | |
then print pushd: Directory stack overflow. | |
return 1 | |
fi | |
esac | |
case $dir in | |
\~*) dir=$HOME${dir#\~} | |
esac | |
\cd "${dir:-$1}" > /dev/null || return 1 | |
dir=${OLDPWD#$HOME/} | |
case $dir in | |
$HOME) | |
dir=\~ | |
;; | |
/*) ;; | |
*) dir=\~/$dir | |
esac | |
case $type in | |
0) # pushd name | |
_push_stack[_push_top=_push_top-1]=$dir | |
;; | |
1) # pushd | |
_push_stack[_push_top]=$dir | |
;; | |
2) # push +n | |
type=${1#+} i=_push_top-1 | |
set -- "${_push_stack[@]}" "$dir" "${_push_stack[@]}" | |
shift $type | |
for dir | |
do (((i=i+1) < _push_max)) || break | |
_push_stack[i]=$dir | |
done | |
esac | |
dirs | |
} | |
# History file. | |
export HISTFILE=~/.hist$$ | |
trap 'rm -f $HISTFILE' EXIT | |
export CDSTACK=32 | |
export FPATH=$HOME/.funcs | |
integer _push_max=${CDSTACK} _push_top=${CDSTACK} | |
# Directory manipulation functions. | |
unalias cd | |
alias cd=_cd | |
alias pu=pushd | |
alias po=popd | |
alias d=dirs | |
alias h=history | |
alias j=jobs | |
alias m=$PAGER | |
alias ll='ls -laFo' | |
alias l='ls -l' | |
alias g='fgrep -i' | |
alias c=clear | |
alias ec=emacsclient | |
alias mutt='TERM=rxvt-256color mutt' | |
# Don't get fancy if we have a dumb terminal. This happens for | |
# example if we're accessing files remotely through tramp in emacs. | |
[[ $TERM == 'dumb' ]] && return 0 | |
# Generate an associative array containing the alternative characters | |
# set for the terminal. See termcap (5) for more details. | |
eval typeset -A altchar=\($(tput acsc | sed -E "s/(.)(.)/['\1']='\2' /g")\) | |
# Generate two associative arrays containing the background | |
# and foreground colors. | |
typeset -A fg bg | |
function cleanhist | |
{ | |
maxtime=1 | |
find -E ~ -maxdepth 1 -regex '.*/\.hist[0-9]+' -Btime +${maxtime} -delete | |
} | |
function load_colors | |
{ | |
typeset color | |
integer i=0 | |
for color in black red green brown blue magenta cyan white; do | |
fg+=([$color]=$(tput setaf $i)) | |
bg+=([$color]=$(tput setab $i)) | |
(( i++ )) | |
done | |
fg+=([reset]=$(tput setaf 9)) | |
bg+=([reset]=$(tput setab 9)) | |
} | |
function init_parms | |
{ | |
_user=$(whoami) | |
_host=$(hostname -s) | |
_tty=$(tty | sed s@/dev/@@) | |
_rprompt= | |
_lpos= | |
_rpos= | |
_cont_prompt= | |
case $(id -u) in | |
0) _prompt=\#;; | |
*) _prompt=\$;; | |
esac | |
_prompt=$(tput md)${_prompt}$(tput me) | |
# Use alternative characters to draw lines if supported or degrade | |
# to normal characters if not. | |
alt_on=$(tput as) | |
alt_off=$(tput ae) | |
_hbar=${altchar[q]:--} | |
_vbar=${altchar[x]:-\|} | |
_ulcorner=${altchar[l]:--} | |
_llcorner=${altchar[m]:--} | |
_urcorner=${altchar[k]:--} | |
_lrcorner=${altchar[j]:--} | |
_lbracket=${altchar[u]:-\[} | |
_rbracket=${altchar[t]:-\]} | |
integer colormax=$(tput colors) | |
if (( ${colormax:-0} >= 8 )); then | |
load_colors | |
case $(id -u) in | |
0) | |
_bgcolor=${bg[red]} | |
_fgcolor=${fg[white]} | |
;; | |
*) | |
_bgcolor=${bg[white]} | |
_fgcolor=${fg[black]} | |
;; | |
esac | |
fi | |
# Enable alternate char set. | |
tput enacs | |
} | |
# Like pwd but display the $HOME directory as ~ | |
function _pwd | |
{ | |
typeset dir="${PWD:-$(pwd -L)}" | |
dir="${dir#$HOME/}" | |
case $dir in | |
"$HOME") | |
dir=\~ ;; | |
/*) | |
;; | |
*) | |
dir=\~/$dir ;; | |
esac | |
print $dir | |
} | |
#### Two lines prompt. | |
# This function is executed before PS1 is referenced. It sets _rpos to | |
# the position of the right prompt and _lpos to the position after the | |
# left prompt. See discipline function in the man page of ksh93. | |
function PS1.get | |
{ | |
typeset rc=$? # save the return value of the last command | |
typeset dir="$(_pwd)" padline | |
typeset uprompt="--[${_user}@${_host}:${_tty}]--(${dir})--" | |
typeset rprompt="-(${_rstatue})--" lprompt="--(${_lstatue}|$)- " | |
integer termwidth=$(tput co) | |
integer offset=$(( ${#uprompt} - ${termwidth} )) | |
integer i | |
# Truncate the current directory if too long and define a line | |
# padding such that the upper prompt occupy the terminal width. | |
if (( $offset > 0 )) ; then | |
dir="...${dir:$(( $offset + 3 ))}" | |
padline="" | |
else | |
offset=$(( - $offset )) | |
padline=${alt_on} | |
for (( i=0; i<$offset; i++ )); do | |
padline=${padline}${_hbar} | |
done | |
padline=${padline}${alt_off} | |
fi | |
_rpos=$(( $termwidth - ${#rprompt} )) | |
_lpos=${#lprompt} | |
_cont_prompt= | |
# Upper prompt. | |
.sh.value="\ | |
${alt_on}${_ulcorner}${_hbar}${_lbracket}${alt_off}\ | |
${_bgcolor}${_fgcolor}\ | |
${_user}@${_host}:${_tty}\ | |
${fg[reset]}${bg[reset]}\ | |
${alt_on}${_rbracket}${alt_off}\ | |
${padline}\ | |
${alt_on}${_hbar}${_hbar}${alt_off}\ | |
$(tput md)(${dir})$(tput me)\ | |
${alt_on}${_hbar}${_urcorner}${alt_off}" | |
# If the terminal doesn't ignore a newline after the last column | |
# and has automatic margin (e.g. cons25), a newline or carriage | |
# return if written will be on the next line. So don't add a | |
# newline and for good mesure, move the cursor to the left before | |
# writing cr at the end of a line. | |
if ! tput am || tput xn; then | |
.sh.value=${.sh.value}$'\n' | |
fi | |
# Lower prompt using carriage return to display the right prompt. | |
.sh.value="${.sh.value}\ | |
$(tput RI $_rpos)\ | |
${_rprompt}\ | |
$(tput le)$(tput cr)\ | |
${alt_on}${_llcorner}${_hbar}${alt_off}\ | |
(${_lstatue}${alt_on}${_vbar}${alt_off}${_prompt})\ | |
${alt_on}${_hbar}${alt_off} " | |
return $rc | |
} | |
# Statue in the left prompt | |
function _lstatue.get | |
{ | |
.sh.value=$(date +%H:%M:%S) | |
} | |
export GIT_PS1_SHOWDIRTYSTATE=yes | |
export GIT_PS1_SHOWUNTRACKEDFILES=yes | |
# Statue in the right prompt | |
function _rstatue.get | |
{ | |
# Use the current branch in a git repository or the current date. | |
typeset b=$(__git_ps1 git:) | |
.sh.value=${b:-$(date "+%a, %d %b")} | |
} | |
# Right prompt. | |
function _rprompt.get | |
{ | |
.sh.value="\ | |
${alt_on}${_hbar}${alt_off}\ | |
(${_rstatue})\ | |
${alt_on}${_hbar}${_lrcorner}${alt_off}" | |
} | |
# Continuation prompt | |
function PS2.get | |
{ | |
_cont_prompt=yes | |
.sh.value="${alt_on}${_hbar}${_hbar}${alt_off} " | |
} | |
# Deletion characters in emacs editing mode and from stty. | |
typeset -A _delchars=( | |
[$'\ch']=DEL | |
[$'\177']=BS | |
[$'\E\177']=KILL-REGION | |
[$'\cw']=BACKWARD-KILL-WORD | |
[$'\cu']=KILL-LINE | |
) | |
# Erase the right prompt if the text reaches it and redraw it if the | |
# text fits in the region between the left prompt and the right one. | |
function _rpdisplay | |
{ | |
integer width=$(( $_rpos - $_lpos - 1)) | |
integer pos=${#.sh.edtext} | |
typeset -S has_rprompt=yes | |
typeset ch=${.sh.edchar} | |
if [[ -z $has_rprompt ]]; then | |
if (( $pos < $width )) || | |
( (($pos == $width+1)) && [[ -n ${_delchars[$ch]} ]] ); then | |
tput sc; tput vi | |
tput cr; tput RI $_rpos | |
print -n -- "${_rprompt}" | |
tput rc; tput ve | |
has_rprompt=yes | |
fi | |
elif (( $pos >= $width )) && [[ -z ${_delchars[$ch]} ]]; then | |
tput ce | |
has_rprompt= | |
fi | |
} | |
# Set the line status to the command buffer and the window title | |
# to the command name. | |
function _setscreen | |
{ | |
typeset hs=${.sh.edtext/#*(\s)/} # delete leading blanks | |
typeset cmd=${hs/%@(\s)*} | |
typeset args=${hs/#+(\S)/} | |
typeset sudopts=AbEHhKkLlnPSVvg:p:U:u:C:c: | |
typeset -S lastcmd | |
if [[ -n $cmd ]]; then | |
cmd=${cmd##*/} | |
if [[ $cmd == sudo || $cmd == *=* ]]; then | |
# Find the real command name | |
set -- $args | |
{ | |
while getopts $sudopts c; do | |
; # skip options | |
done | |
} 2>/dev/null | |
shift $((OPTIND-1)) | |
if [[ -n $1 ]]; then | |
cmd=${1##*/} | |
fi | |
fi | |
# Ignore variable assignment | |
if [[ $cmd != *=* ]]; then | |
lastcmd=$cmd | |
fi | |
fi | |
print -nR $'\E_'${hs}$'\E\\' | |
print -nR $'\Ek'${lastcmd}$'\E\\' | |
} | |
# Assoctiate a key with an action. | |
typeset -A Keytable | |
function keybind # key [action] | |
{ | |
typeset key=$(print -f "%q" "$2") | |
case $# in | |
2) Keytable[$1]=' .sh.edchar=${.sh.edmode}'"$key" | |
;; | |
1) unset Keytable[$1] | |
;; | |
*) print -u2 "Usage: $0 key [action]" | |
return 2 # usage errors return 2 by default | |
;; | |
esac | |
} | |
function _keytrap | |
{ | |
eval "${Keytable[${.sh.edchar}]}" | |
# Execute only if we're not on a continuation prompt | |
if [[ -z $_cont_prompt ]]; then | |
[[ $TERM == screen && ${.sh.edchar} == $'\r' ]] && _setscreen | |
_rpdisplay | |
fi | |
} | |
trap _keytrap KEYBD | |
# Swap ^W and M-baskspace in emacs editing mode. | |
keybind $'\cw' $'\E\177' | |
keybind $'\E\177' $'\cw' | |
init_parms |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment