Skip to content

Commit

Permalink
Smart case sensitivity matching by default
Browse files Browse the repository at this point in the history
and add parameters to force case insensitive (`-i`) or case sensitive
(`-s`) matching.

Also rename `t` variable in main awk script to `now`, as used in the
`--add` awk script, use constant regular expression instead of string,
and add double quotes to shell script variables.

There are minor changes from smart-case to the original "prefer case
sensitive" implementation.

Considering these directories with their respective 'frecencies':

     3          /tmp/foo/bar
     5          /tmp/foo/Baz
     8          /tmp/Baz
     13         /tmp/bar
     21         /tmp

These would be the results of different queries with the two approaches,
considering a filesystem that allows directories with same names and
different cases:

| query | smart-case   | prefer case sensitive |
|-------|--------------|-----------------------|
| tm    | /tmp         | /tmp                  |
| Tm    | (nothing)    | /tmp                  |
| ba    | /tmp/bar     | /tmp/bar              |
| Ba    | /tmp/Baz     | /tmp/Baz              |
| fo ba | /tmp/foo/Baz | /tmp/foo/bar          |
| fo Ba | /tmp/foo/Baz | /tmp/foo/Baz          |

Fixes rupa#209
  • Loading branch information
ericbn committed Nov 20, 2017
1 parent a00e369 commit c6c4908
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 31 deletions.
9 changes: 7 additions & 2 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ NAME
z - jump around

SYNOPSIS
z [-chlrtx] [regex1 regex2 ... regexn]
z [-cehilrstx] [regex1 regex2 ... regexn]

AVAILABILITY
bash, zsh
Expand All @@ -16,7 +16,8 @@ DESCRIPTION

After a short learning phase, z will take you to the most 'frecent'
directory that matches ALL of the regexes given on the command line, in
order.
order. By default, smart case sensitivity is used, namely case insensi-
tive match when regexes are lower case, case sensitive match otherwise.

For example, z foo bar would match /foo/bar but not /bar/foo.

Expand All @@ -27,10 +28,14 @@ OPTIONS

-h show a brief help message

-i case insensitive match

-l list only

-r match by rank only

-s case sensitive match

-t match by recent access only

-x remove the current directory from the datafile
Expand Down
10 changes: 9 additions & 1 deletion z.1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ NAME
z \- jump around
.SH
SYNOPSIS
z [\-chlrtx] [regex1 regex2 ... regexn]
z [\-cehilrstx] [regex1 regex2 ... regexn]
.SH
AVAILABILITY
bash, zsh
Expand All @@ -14,6 +14,8 @@ Tracks your most used directories, based on 'frecency'.
.P
After a short learning phase, \fBz\fR will take you to the most 'frecent'
directory that matches ALL of the regexes given on the command line, in order.
By default, smart case sensitivity is used, namely case insensitive match when
regexes are lower case, case sensitive match otherwise.

For example, \fBz foo bar\fR would match \fB/foo/bar\fR but not \fB/bar/foo\fR.
.SH
Expand All @@ -28,12 +30,18 @@ echo the best match, don't cd
\fB\-h\fR
show a brief help message
.TP
\fB\-i\fR
case insensitive match
.TP
\fB\-l\fR
list only
.TP
\fB\-r\fR
match by rank only
.TP
\fB\-s\fR
case sensitive match
.TP
\fB\-t\fR
match by recent access only
.TP
Expand Down
57 changes: 29 additions & 28 deletions z.sh
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,20 @@ _z() {
else
# list/go
while [ "$1" ]; do case "$1" in
--) while [ "$1" ]; do shift; local fnd="$fnd${fnd:+ }$1";done;;
-*) local opt=${1:1}; while [ "$opt" ]; do case ${opt:0:1} in
--) while [ "$1" ]; do shift; local fnd="$fnd${fnd:+ }$1"; done;;
-*) local opt="${1:1}"; while [ "$opt" ]; do case "${opt:0:1}" in
c) local fnd="^$PWD $fnd";;
e) local echo=echo;;
h) echo "${_Z_CMD:-z} [-cehlrtx] args" >&2; return;;
h) echo "${_Z_CMD:-z} [-cehilrstx] [regex1 regex2 ... regexn]" >&2; return;;
i) local cas='i';;
l) local list=1;;
r) local typ="rank";;
t) local typ="recent";;
r) local typ='r';;
s) local cas='s';;
t) local typ='t';;
x) sed -i -e "\:^${PWD}|.*:d" "$datafile";;
esac; opt=${opt:1}; done;;
esac; opt="${opt:1}"; done;;
*) local fnd="$fnd${fnd:+ }$1";;
esac; local last=$1; [ "$#" -gt 0 ] && shift; done
esac; local last="$1"; [ "$#" -gt 0 ] && shift; done
[ "$fnd" -a "$fnd" != "^$PWD " ] || local list=1

# if we hit enter on a completion just go there
Expand All @@ -135,10 +137,10 @@ _z() {
[ -f "$datafile" ] || return

local cd
cd="$( < <( _z_dirs ) awk -v t="$(date +%s)" -v list="$list" -v typ="$typ" -v q="$fnd" -F"|" '
cd="$( < <( _z_dirs ) awk -v now="$(date +%s)" -v cas="$cas" -v list="$list" -v typ="$typ" -v q="$fnd" -F'|' '
function frecent(rank, time) {
# relate frequency and time
dx = t - time
dx = now - time
if( dx < 3600 ) return rank * 4
if( dx < 86400 ) return rank * 2
if( dx < 604800 ) return rank / 2
Expand Down Expand Up @@ -175,33 +177,32 @@ _z() {
return short
}
BEGIN {
gsub(" ", ".*", q)
hi_rank = ihi_rank = -9999999999
if( cas == "i" ) {
q = tolower(q)
imatch = 1
} else if( cas != "s" && q == tolower(q) ) imatch = 1
gsub(/ /, ".*", q)
hi_rank = -9999999999
}
{
if( typ == "rank" ) {
if( typ == "r" ) {
rank = $2
} else if( typ == "recent" ) {
rank = $3 - t
} else if( typ == "t" ) {
rank = $3 - now
} else rank = frecent($2, $3)
if( $1 ~ q ) {
if( imatch ) {
x = tolower($1)
} else x = $1
if( x ~ q ) {
matches[$1] = rank
} else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank
if( matches[$1] && matches[$1] > hi_rank ) {
best_match = $1
hi_rank = matches[$1]
} else if( imatches[$1] && imatches[$1] > ihi_rank ) {
ibest_match = $1
ihi_rank = imatches[$1]
if( rank > hi_rank ) {
best_match = $1
hi_rank = rank
}
}
}
END {
# prefer case sensitive
if( best_match ) {
output(matches, best_match, common(matches))
} else if( ibest_match ) {
output(imatches, ibest_match, common(imatches))
}
output(matches, best_match, common(matches))
}
')"

Expand Down

0 comments on commit c6c4908

Please sign in to comment.