1# Shrink directory paths, e.g. /home/me/foo/bar/quux -> ~/f/b/quux.
2#
3# For a fish-style working directory in your command prompt, add the following
4# to your theme or zshrc:
5#
6#   setopt prompt_subst
7#   PS1='%n@%m $(shrink_path -f)>'
8#
9# The following options are available:
10#
11#   -f, --fish       fish simulation, equivalent to -l -s -t.
12#   -g, --glob       Add asterisk to allow globbing of shrunk path (equivalent to -e "*")
13#   -l, --last       Print the last directory's full name.
14#   -s, --short      Truncate directory names to the number of characters given by -#. Without
15#                    -s, names are truncated without making them ambiguous.
16#   -t, --tilde      Substitute ~ for the home directory.
17#   -T, --nameddirs  Substitute named directories as well.
18#   -#               Truncate each directly to at least this many characters inclusive of the
19#                    ellipsis character(s) (defaulting to 1).
20#   -e SYMBOL        Postfix symbol(s) to indicate that a directory name had been truncated.
21#   -q, --quote      Quote special characters in the shrunk path
22#
23# The long options can also be set via zstyle, like
24#   zstyle :prompt:shrink_path fish yes
25#
26# Note: Directory names containing two or more consecutive spaces are not yet
27# supported.
28#
29# Keywords: prompt directory truncate shrink collapse fish
30#
31# Copyright (C) 2008 by Daniel Friesel <derf@xxxxxxxxxxxxxxxxxx>
32# License: WTFPL <http://www.wtfpl.net>
33#
34# Ref: https://www.zsh.org/mla/workers/2009/msg00415.html
35#      https://www.zsh.org/mla/workers/2009/msg00419.html
36
37shrink_path () {
38        setopt localoptions
39        setopt rc_quotes null_glob
40
41        typeset -i lastfull=0
42        typeset -i short=0
43        typeset -i tilde=0
44        typeset -i named=0
45        typeset -i length=1
46        typeset ellipsis=""
47        typeset -i quote=0
48        typeset -i expand=0
49
50        if zstyle -t ':prompt:shrink_path' fish; then
51                lastfull=1
52                short=1
53                tilde=1
54        fi
55        if zstyle -t ':prompt:shrink_path' nameddirs; then
56                tilde=1
57                named=1
58        fi
59        zstyle -t ':prompt:shrink_path' last && lastfull=1
60        zstyle -t ':prompt:shrink_path' short && short=1
61        zstyle -t ':prompt:shrink_path' tilde && tilde=1
62        zstyle -t ':prompt:shrink_path' glob && ellipsis='*'
63        zstyle -t ':prompt:shrink_path' quote && quote=1
64        zstyle -t ':prompt:shrink_path' expand && expand=1
65
66        while [[ $1 == -* ]]; do
67                case $1 in
68                        --)
69                                shift
70                                break
71                        ;;
72                        -f|--fish)
73                                lastfull=1
74                                short=1
75                                tilde=1
76                        ;;
77                        -h|--help)
78                                print 'Usage: shrink_path [-f -l -s -t] [directory]'
79                                print ' -f, --fish      fish-simulation, like -l -s -t'
80                                print ' -g, --glob      Add asterisk to allow globbing of shrunk path (equivalent to -e "*")'
81                                print ' -l, --last      Print the last directory''s full name'
82                                print ' -s, --short     Truncate directory names to the number of characters given by -#. Without'
83                                print '                 -s, names are truncated without making them ambiguous.'
84                                print ' -t, --tilde     Substitute ~ for the home directory'
85                                print ' -T, --nameddirs Substitute named directories as well'
86                                print ' -#              Truncate each directly to at least this many characters inclusive of the'
87                                print '                 ellipsis character(s) (defaulting to 1).'
88                                print ' -e SYMBOL       Postfix symbol(s) to indicate that a directory name had been truncated.'
89                                print ' -q, --quote     Quote special characters in the shrunk path'
90                                print ' -x, --expand    Print the full path. This takes precedence over the other options'
91                                print ''
92                                print 'The long options can also be set via zstyle, like'
93                                print '  zstyle :prompt:shrink_path fish yes'
94                                return 0
95                        ;;
96                        -l|--last) lastfull=1 ;;
97                        -s|--short) short=1 ;;
98                        -t|--tilde) tilde=1 ;;
99                        -T|--nameddirs)
100                                tilde=1
101                                named=1
102                        ;;
103                        -[0-9]|-[0-9][0-9])
104                                length=${1/-/}
105                        ;;
106                        -e)
107                                shift
108                                ellipsis="$1"
109                        ;;
110                        -g|--glob)
111                                ellipsis='*'
112                        ;;
113                        -q|--quote)
114                                quote=1
115                        ;;
116                        -x|--expand)
117                                expand=1
118                        ;;
119                esac
120                shift
121        done
122
123        typeset -i elllen=${#ellipsis}
124        typeset -a tree expn
125        typeset result part dir=${1-$PWD}
126        typeset -i i
127
128        [[ -d $dir ]] || return 0
129
130        if (( expand )) {
131                echo "$dir"
132                return 0
133        }
134
135        if (( named )) {
136                for part in ${(k)nameddirs}; {
137                        [[ $dir == ${nameddirs[$part]}(/*|) ]] && dir=${dir/#${nameddirs[$part]}/\~$part}
138                }
139        }
140        (( tilde )) && dir=${dir/#$HOME/\~}
141        tree=(${(s:/:)dir})
142        (
143                if [[ $tree[1] == \~* ]] {
144                        cd -q ${~tree[1]}
145                        result=$tree[1]
146                        shift tree
147                } else {
148                        cd -q /
149                }
150                for dir in $tree; {
151                        if (( lastfull && $#tree == 1 )) {
152                                result+="/$tree"
153                                break
154                        }
155                        expn=(a b)
156                        part=''
157                        i=0
158                        until [[ $i -gt 99 || ( $i -ge $((length - ellen)) || $dir == $part ) && ( (( ${#expn} == 1 )) || $dir = $expn ) ]]; do
159                                (( i++ ))
160                                part+=$dir[$i]
161                                expn=($(echo ${part}*(-/)))
162                                (( short )) && [[ $i -ge $((length - ellen)) ]] && break
163                        done
164
165                        typeset -i dif=$(( ${#dir} - ${#part} - ellen ))
166                        if [[ $dif -gt 0 ]]
167                        then
168                            (( quote )) && part=${(q)part}
169                            part+="$ellipsis"
170                        else
171                            part="$dir"
172                            (( quote )) && part=${(q)part}
173                        fi
174                        result+="/$part"
175                        cd -q $dir
176                        shift tree
177                }
178                echo ${result:-/}
179        )
180}
181
182## vim:ft=zsh
183