Skip to content

Commit

Permalink
Improve shorten_path script
Browse files Browse the repository at this point in the history
  • Loading branch information
blueyed committed May 22, 2015
1 parent e52f109 commit e9cc134
Showing 1 changed file with 63 additions and 35 deletions.
98 changes: 63 additions & 35 deletions usr/bin/shorten_path
@@ -1,46 +1,74 @@
#!/bin/sh
#!/usr/bin/zsh -f
#
# Shorten path according to hashed dir list ('hash -d' in Zsh)
# It also replaces $HOME with ~.
# Shorten path according to hashed dir list ('hash -d' in Zsh),
# maintained in ~/.dotfiles/oh-my-zsh/lib/hash_dirs.
# This also replaces $HOME with ~.
#
# This is used from vimrc.

# TODO: relative to current dir?! currently done by Vim
# Plain sh would be ~4x faster on startup, but with cat/sed etc similar slow/fast,
# and needs a cache file.
#!/bin/sh

# Self-tests: run with '--test'. {{{
tests() {
hash -d df=~/.dotfiles

set -x -e
cd ~
[[ $(shorten_path .dotfiles/vimrc) == '~df/vimrc' ]]

cd .dotfiles
[[ $(shorten_path ~/.dotfiles/vimrc) == 'vimrc' ]]
[[ $(shorten_path vimrc) == 'vimrc' ]]
[[ $(shorten_path ../.dotfiles/vimrc) == 'vimrc' ]]

[[ $(shorten_path ~/.dotfiles/foo/bar) == 'foo/bar' ]]
[[ $(shorten_path foo/bar) == 'foo/bar' ]]
[[ $(shorten_path ../.dotfiles/foo/bar) == 'foo/bar' ]]

# With "base" dir.
cd ~
[[ $(shorten_path .dotfiles/vimrc $PWD) == '~df/vimrc' ]]
[[ $(shorten_path vimrc .dotfiles) == 'vimrc' ]]
[[ $(shorten_path ~/.dotfiles/vimrc /) == '~df/vimrc' ]]

cd .dotfiles
[[ $(shorten_path ../.vimrc) == '../.vimrc' ]]
[[ $(shorten_path ../non-existent) == '../non-existent' ]]

set +x
time ( for i in {1..200}; do shorten_path foo; done )
}
if [ x$1 = 'x--test' ]; then
tests
return
fi
# }}}

if [ -z "$1" ]; then
echo "Argument (path) required." >&2
exit 1
fi

path="$1"
if [ -n "$2" ]; then
cd "$2"
fi

hash_file=$HOME/.cache/hashd
source ~/.dotfiles/oh-my-zsh/lib/hash_dirs.zsh
test -f ~/.dotfiles/oh-my-zsh/lib/hash_dirs.local.zsh && source ~/.dotfiles/oh-my-zsh/lib/hash_dirs.local.zsh

# Regenerate hash cache file, if zshrc/zshrc.local (which contains hash
# commands) is newer.
# if ! [ -f $hash_file ] || [ $(( $(date +%s) - $(stat -c %Y $hash_file) )) -gt 86400 ]; then
if ! [ -f $hash_file ] || [ ~/.zshrc -nt $hash_file ] || [ ~/.zshrc.local -nt $hash_file ]; then
# Generate list, sorted by length (so ~omz gets shortened instead of ~df/oh-my-zsh).
# zsh -i -c 'hash -d' | awk '{print length, $0;}' | sort -nr | cut -d\ -f2- > $hash_file
# dir=${path:h:a}

# Use a temporary file to only get the output from "hash -d".
(cd /tmp \
&& t=$(mktemp) \
&& zsh -i -c "hash -d > $t" 2>/dev/null \
&& awk '{print length, $0;}' $t | sort -nr | cut -d\ -f2- > $hash_file)
abs_path=${path:a}
# Keep relative dirs, which are not going back to below base/$PWD.
if [[ $path = ../* ]] && [[ $abs_path != $PWD/* ]]; then
printf $path
return
fi

set -f # Disable path globbing, in case there's '*' in the cache file.
IFS='
'
for line in $(cat $hash_file); do
var=${line%%=*}
val=${line#*=}
# Skip any unexpected lines.
[ "$var" != "$line" ] && [ "$val" != "" ] || continue

# TODO: match only at beginning?!
# echo "$var => $val"
new=${path#$val}
if [ "$new" != "$path" ]; then
new="~$var$new"
echo -n $new
exit
fi
done
echo -n $path | sed "s:^$HOME:~:"
pwd_short=${(D)PWD}/
path_short=${(D)abs_path}
printf ${path_short#$pwd_short}
exit

0 comments on commit e9cc134

Please sign in to comment.