Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Oh My Zsh
Commits
8d08f163
Unverified
Commit
8d08f163
authored
Aug 27, 2020
by
Pavol Juhas
Committed by
GitHub
Aug 27, 2020
Browse files
scd: update to 1.4.0 (#9066)
parent
cfb86cd0
Changes
4
Show whitespace changes
Inline
Side-by-side
plugins/scd/README.md
View file @
8d08f163
...
@@ -14,8 +14,9 @@ directory aliases, which appear as named directories in zsh session.
...
@@ -14,8 +14,9 @@ directory aliases, which appear as named directories in zsh session.
## INSTALLATION NOTES
## INSTALLATION NOTES
Besides oh-my-zsh,
`scd`
can be used with
*bash*
,
*dash*
or
*tcsh*
Besides oh-my-zsh,
`scd`
can be used with
*bash*
,
*dash*
or
*tcsh*
shells and is also available as
[
Vim
](
https://www.vim.org/
)
plugin and
shells and is also available as Vim plugin
[
IPython
](
https://ipython.org/
)
extension. For installation details, see
[
scd.vim
](
https://github.com/pavoljuhas/scd.vim
)
and
[
IPython
](
https://ipython.org
)
extension. For installation details, see
https://github.com/pavoljuhas/smart-change-directory.
https://github.com/pavoljuhas/smart-change-directory.
## SYNOPSIS
## SYNOPSIS
...
@@ -24,11 +25,31 @@ https://github.com/pavoljuhas/smart-change-directory.
...
@@ -24,11 +25,31 @@ https://github.com/pavoljuhas/smart-change-directory.
scd
[
options]
[
pattern1 pattern2 ...]
scd
[
options]
[
pattern1 pattern2 ...]
```
```
## PATTERNS
Patterns may use all zsh
[
glob operators
](
http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Operators
)
available with
*extendedglob*
option. Specified patterns must match
the absolute path and at least one of them must match in the tail.
Several special patterns are also recognized as follows:
<dl><dt>
^PAT
</dt><dd>
PAT must match at the beginning of the path, for example, "^/home"
</dd><dt>
PAT$
</dt><dd>
require PAT to match the end of the path, "man$"
</dd><dt>
./
</dt><dd>
match only subdirectories of the current directory
</dd><dt>
:PAT
</dt><dd>
require PAT to match over the tail component, ":doc", ":re/doc"
</dd>
</dl>
## OPTIONS
## OPTIONS
<dl><dt>
<dl><dt>
-a, --add
</dt><dd>
-a, --add
</dt><dd>
add specified directories to the directory index.
</dd><dt>
add
current or
specified directories to the directory index.
</dd><dt>
--unindex
</dt><dd>
--unindex
</dt><dd>
remove current or specified directories from the index.
</dd><dt>
remove current or specified directories from the index.
</dd><dt>
...
@@ -42,11 +63,16 @@ scd [options] [pattern1 pattern2 ...]
...
@@ -42,11 +63,16 @@ scd [options] [pattern1 pattern2 ...]
--unalias
</dt><dd>
--unalias
</dt><dd>
remove ALIAS definition for the current or specified directory from
remove ALIAS definition for the current or specified directory from
<em>
~/.scdalias.zsh
</em>
.
</dd><dt>
<em>
~/.scdalias.zsh
</em>
. Use "OLD" to purge aliases to non-existent
directories.
</dd><dt>
-A, --all
</dt><dd>
-A, --all
</dt><dd>
include all matching directories. Disregard matching by directory
display all directories even those excluded by patterns in
alias and filtering of less likely paths.
</dd><dt>
<em>
~/.scdignore
</em>
. Disregard the unique matching for a
directory alias and filtering of less likely paths.
</dd><dt>
-p, --push
</dt><dd>
use "pushd" to change to the target directory.
</dd><dt>
--list
</dt><dd>
--list
</dt><dd>
show matching directories and exit.
</dd><dt>
show matching directories and exit.
</dd><dt>
...
@@ -58,6 +84,7 @@ scd [options] [pattern1 pattern2 ...]
...
@@ -58,6 +84,7 @@ scd [options] [pattern1 pattern2 ...]
display this options summary and exit.
</dd>
display this options summary and exit.
</dd>
</dl>
</dl>
## Examples
## Examples
```
sh
```
sh
...
@@ -83,17 +110,26 @@ scd --alias=xray
...
@@ -83,17 +110,26 @@ scd --alias=xray
scd xray
scd xray
```
```
# FILES
#
# FILES
<dl><dt>
<dl><dt>
~/.scdhistory
</dt><dd>
~/.scdhistory
</dt><dd>
time-stamped index of visited directories.
</dd><dt>
time-stamped index of visited directories.
</dd><dt>
~/.scdalias.zsh
</dt><dd>
~/.scdalias.zsh
</dt><dd>
scd-generated definitions of directory aliases.
</dd>
scd-generated definitions of directory aliases.
</dd><dt>
~/.scdignore
</dt><dd>
<a
href=
"http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Operators"
>
glob patterns
</a>
for paths to be ignored in the scd search, for example,
<code>
/mnt/backup/
*
</code>
. The patterns are specified one per line
and are matched assuming the
<em>
extendedglob
</em>
zsh option. Lines
starting with "#" are skipped as comments. The .scdignore patterns
are not applied in the
<em>
--all
</em>
mode.
</dd>
</dl>
</dl>
# ENVIRONMENT
## ENVIRONMENT
<dl><dt>
<dl><dt>
SCD_HISTFILE
</dt><dd>
SCD_HISTFILE
</dt><dd>
...
...
plugins/scd/_scd
0 → 100644
View file @
8d08f163
#compdef scd
#description smart change directory
local curcontext="$curcontext" state line expl ret=1
typeset -A opt_args
local -a indexopts myargs
indexopts=( --add -a --unindex )
myargs=(
# common options
"(--help -h)"{--help,-h}"[print help and exit]"
# options for manipulating directory index
- index
"(--recursive -r)"{--recursive,-r}"[use recursive --add or --unindex]"
"($indexopts)"{--add,-a}"[add specified directories to the index]"
"($indexopts)--unindex[remove specified directories from the index]"
"*:directory:{ (( ${words[(I)-a|--add|--unindex]} )) && _path_files -/ }"
# define new directory alias
- alias
"--alias=[create alias for this or given directory]:directory-alias:()"
'1:directory:{ (( words[(I)--alias*] )) && _path_files -/ }'
# remove definition of directory alias
- unalias
"--unalias[remove definition of directory alias]"
"*::directory alias:->scd-alias-target"
# act on the directory change
- scd
"(--all -A)"{--all,-A}"[include less likely and ignored paths]"
"--list[print matching directories and exit]"
"(--verbose -v)"{--verbose,-v}"[show directory ranking and full paths]"
"(--push -p)"{--push,-p}"[change directory with 'pushd']"
"1::directory alias:->scd-alias-target"
"*:patterns:()"
)
_arguments -S -C $myargs && ret=0
if [[ "$state" == scd-alias-target && -s ~/.scdalias.zsh ]]; then
local -a scdaliases
scdaliases=( )
eval "$(setopt extendedglob
phome="(#b)(#s)${HOME}(/*)#(#e)"
builtin hash -dr
source ~/.scdalias.zsh &&
for k v in ${(kv)nameddirs}; do
scdaliases+=( $k:${v/${~phome}/"~"${match[1]}} )
done
complete_unalias=${+opt_args[unalias---unalias]}
if (( complete_unalias && ! ${+nameddirs[OLD]} )); then
scdaliases+=( 'OLD:all aliases to non-existent paths' )
fi
typeset -p scdaliases )"
_describe -t scdaliases scdalias scdaliases
fi
plugins/scd/scd
100644 → 100755
View file @
8d08f163
#!/bin/zsh -f
#!/bin/zsh -f
emulate
-L
zsh
emulate
-L
zsh
local
RUNNING_AS_COMMAND
=
local
EXIT
=
return
local
EXIT
=
return
if
[[
$(
whence
-w
$0
)
==
*
:
' '
command
]]
;
then
if
[[
$(
whence
-w
$0
)
==
*
:
' '
command
]]
;
then
emulate
-R
zsh
RUNNING_AS_COMMAND
=
1
local
RUNNING_AS_COMMAND
=
1
EXIT
=
exit
EXIT
=
exit
fi
fi
local
DOC
=
'scd -- smart change to a recently used directory
local
DOC
=
'scd -- smart change to a recently used directory
usage: scd [options] [pattern1 pattern2 ...]
usage: scd [options] [pattern1 pattern2 ...]
Go to a directory path that
contains all fixed string
patterns. Prefer
Go to a directory path that
matches all
patterns. Prefer
recent or
recent or
frequently visited directories as found in the directory index.
frequently visited directories as found in the directory index.
Display a selection menu in case of multiple matches.
Display a selection menu in case of multiple matches.
Special patterns:
^PAT match at the path root, "^/home"
PAT$ match paths ending with PAT, "man$"
./ match paths under the current directory
:PAT require PAT to span the tail, ":doc", ":re/doc"
Options:
Options:
-a, --add add specified directories to the
directory
index.
-a, --add add
current or
specified directories to the index.
--unindex remove current or specified directories from the index.
--unindex remove current or specified directories from the index.
-r, --recursive apply options --add or --unindex recursively.
-r, --recursive apply options --add or --unindex recursively.
--alias=ALIAS create alias for the current or specified directory and
--alias=ALIAS create alias for the current or specified directory and
store it in ~/.scdalias.zsh.
store it in ~/.scdalias.zsh.
--unalias remove ALIAS definition for the current or specified
--unalias remove ALIAS definition for the current or specified
directory from ~/.scdalias.zsh.
directory from ~/.scdalias.zsh.
-A, --all include all matching directories. Disregard matching by
Use "OLD" to purge aliases to non-existent directories.
directory alias and filtering of less likely paths.
-A, --all display all directories even those excluded by patterns
in ~/.scdignore. Disregard unique match for a directory
alias and filtering of less likely paths.
-p, --push use "pushd" to change to the target directory.
--list show matching directories and exit.
--list show matching directories and exit.
-v, --verbose display directory rank in the selection menu.
-v, --verbose display directory rank in the selection menu.
-h, --help display this message and exit.
-h, --help display this message and exit.
...
@@ -36,18 +46,28 @@ local SCD_MEANLIFE=${SCD_MEANLIFE:-86400}
...
@@ -36,18 +46,28 @@ local SCD_MEANLIFE=${SCD_MEANLIFE:-86400}
local
SCD_THRESHOLD
=
${
SCD_THRESHOLD
:-
0
.005
}
local
SCD_THRESHOLD
=
${
SCD_THRESHOLD
:-
0
.005
}
local
SCD_SCRIPT
=
${
RUNNING_AS_COMMAND
:+
$SCD_SCRIPT
}
local
SCD_SCRIPT
=
${
RUNNING_AS_COMMAND
:+
$SCD_SCRIPT
}
local
SCD_ALIAS
=
~/.scdalias.zsh
local
SCD_ALIAS
=
~/.scdalias.zsh
local
SCD_IGNORE
=
~/.scdignore
local
ICASE a d m p i maxrank threshold
# Minimum logarithm of probability. Avoids out of range warning in exp().
local
-r
MINLOGPROB
=
-15
# When false, use case-insensitive globbing to fix PWD capitalization.
local
PWDCASECORRECT
=
true
if
[[
${
OSTYPE
}
==
darwin
*
]]
;
then
PWDCASECORRECT
=
false
fi
local
a d m p i maxrank threshold
local
opt_help opt_add opt_unindex opt_recursive opt_verbose
local
opt_help opt_add opt_unindex opt_recursive opt_verbose
local
opt_alias opt_unalias opt_all opt_list
local
opt_alias opt_unalias opt_all
opt_push
opt_list
local
-A
drank dalias
local
-A
drank dalias
scdignore
local
dmatching
local
dmatching
local
last_directory
local
last_directory
setopt
extendedhistory
extendedglob noautonamedirs brace_ccl
setopt extendedglob noautonamedirs brace_ccl
# If SCD_SCRIPT is defined make sure th
e
file exists and is empty.
# If SCD_SCRIPT is defined make sure th
at that
file exists and is empty.
# This removes any previous
old
commands.
# This removes any
old
previous commands
from the SCD_SCRIPT file
.
[[
-n
"
$SCD_SCRIPT
"
]]
&&
[[
-s
$SCD_SCRIPT
||
!
-f
$SCD_SCRIPT
]]
&&
(
[[
-n
"
$SCD_SCRIPT
"
]]
&&
[[
-s
$SCD_SCRIPT
||
!
-f
$SCD_SCRIPT
]]
&&
(
umask
077
umask
077
:
>
|
$SCD_SCRIPT
:
>
|
$SCD_SCRIPT
...
@@ -56,13 +76,17 @@ setopt extendedhistory extendedglob noautonamedirs brace_ccl
...
@@ -56,13 +76,17 @@ setopt extendedhistory extendedglob noautonamedirs brace_ccl
# process command line options
# process command line options
zmodload
-i
zsh/zutil
zmodload
-i
zsh/zutil
zmodload
-i
zsh/datetime
zmodload
-i
zsh/datetime
zparseopts
-D
--
a
=
opt_add
-add
=
opt_add
-unindex
=
opt_unindex
\
zmodload
-i
zsh/parameter
zparseopts
-D
-E
--
a
=
opt_add
-add
=
opt_add
-unindex
=
opt_unindex
\
r
=
opt_recursive
-recursive
=
opt_recursive
\
r
=
opt_recursive
-recursive
=
opt_recursive
\
-alias
:
=
opt_alias
-unalias
=
opt_unalias
\
-alias
:
=
opt_alias
-unalias
=
opt_unalias
\
A
=
opt_all
-all
=
opt_all
-list
=
opt_list
\
A
=
opt_all
-all
=
opt_all
p
=
opt_push
-push
=
opt_push
-list
=
opt_list
\
v
=
opt_verbose
-verbose
=
opt_verbose
h
=
opt_help
-help
=
opt_help
\
v
=
opt_verbose
-verbose
=
opt_verbose
h
=
opt_help
-help
=
opt_help
\
||
$EXIT
$?
||
$EXIT
$?
# remove the first instance of "--" from positional arguments
argv[
(
i
)
--
]=(
)
if
[[
-n
$opt_help
]]
;
then
if
[[
-n
$opt_help
]]
;
then
print
$DOC
print
$DOC
$EXIT
$EXIT
...
@@ -71,6 +95,22 @@ fi
...
@@ -71,6 +95,22 @@ fi
# load directory aliases if they exist
# load directory aliases if they exist
[[
-r
$SCD_ALIAS
]]
&&
source
$SCD_ALIAS
[[
-r
$SCD_ALIAS
]]
&&
source
$SCD_ALIAS
# load scd-ignore patterns if available
if
[[
-s
$SCD_IGNORE
]]
;
then
setopt noglob
<
$SCD_IGNORE
\
while
read
p
;
do
[[
$p
!=
[
\#
]
*
]]
||
continue
[[
-n
$p
]]
||
continue
# expand leading tilde if it has valid expansion
if
[[
$p
==
[
~]
*
]]
&&
(
:
${
~p
}
)
2>/dev/null
;
then
p
=
${
~p
}
fi
scdignore[
$p
]=
1
done
setopt glob
fi
# Private internal functions are prefixed with _scd_Y19oug_.
# Private internal functions are prefixed with _scd_Y19oug_.
# Clean them up when the scd function returns.
# Clean them up when the scd function returns.
setopt localtraps
setopt localtraps
...
@@ -79,9 +119,17 @@ trap 'unfunction -m "_scd_Y19oug_*"' EXIT
...
@@ -79,9 +119,17 @@ trap 'unfunction -m "_scd_Y19oug_*"' EXIT
# works faster than the (:a) modifier and is compatible with zsh 4.2.6
# works faster than the (:a) modifier and is compatible with zsh 4.2.6
_scd_Y19oug_abspath
()
{
_scd_Y19oug_abspath
()
{
set
-A
$1
${
(ps
:
\0
:
)
"
$(
set
-A
$1
${
(ps
:
\0
:
)
"
$(
unfunction
-m
"*"
;
shift
setopt pushdsilent
unfunction
-m
"*"
unalias
-m
"*"
unset
CDPATH
shift
for
d
;
do
for
d
;
do
cd
$d
&&
print
-Nr
--
$PWD
&&
cd
$OLDPWD
pushd
$d
||
continue
$PWDCASECORRECT
&&
print
-Nr
--
$PWD
||
print
-Nr
--
(
#i)$PWD
popd
2>/dev/null
done
done
)
"}
)
"}
}
}
...
@@ -106,47 +154,76 @@ if [[ -n $opt_alias ]]; then
...
@@ -106,47 +154,76 @@ if [[ -n $opt_alias ]]; then
$EXIT
$?
$EXIT
$?
fi
fi
# undefine directory alias
# undefine
one or more
directory alias
es
if [[ -n
$opt_unalias
]]; then
if [[ -n
$opt_unalias
]]; then
if
[[
-n
$1
&&
!
-d
$1
]]
;
then
local -U uu
print
-u2
"'
$1
' is not a directory."
local ec=0
$EXIT
1
uu=(
${
*
:-${
PWD
}}
)
if ((
${
uu
[(I)OLD]
}
&&
${
+nameddirs[OLD]
}
== 0 )); then
uu=(
${
uu
:#OLD
}
${
(ps
:
\0
:
)
"
$(
hash
-dr
if
[[
-r
$SCD_ALIAS
]]
;
then
source
$SCD_ALIAS
fi
fi
_scd_Y19oug_abspath a
${
1
:-
$PWD
}
for
a d
in
${
(kv)nameddirs
}
;
do
a
=
$(
print
-rD
${
a
}
)
[[
-d
$d
]]
||
print
-Nr
--
$a
if
[[
$a
!=
[
~][^/]##
]]
;
then
done
$EXIT
)
"
}
)
fi
fi
a
=
${
a
#[~]
}
m=( )
# unalias in the current shell, update alias file if successful
for p in
$uu
; do
if
unhash
-d
--
$a
2>/dev/null
&&
[[
-r
$SCD_ALIAS
]]
;
then
d=
$p
if [[
${
+nameddirs[
$d
]
}
== 0 && -d
$d
]]; then
_scd_Y19oug_abspath d
$d
fi
a=
${
(k)nameddirs[
$d
]
:-${
(k)nameddirs[(r)
$d
]
}}
if [[ -z
$a
]]; then
ec=1
print -u2 "
'$p'
is neither a directory
alias
nor an aliased path.
"
continue
fi
# unalias in the current shell and remember to update the alias file
if unhash -d --
$a
2>/dev/null; then
m+=(
$a
)
fi
done
if [[
$#m
!= 0 && -r
$SCD_ALIAS
]]; then
(
(
umask 077
umask 077
hash -dr
hash -dr
source
$SCD_ALIAS
source
$SCD_ALIAS
unhash
-d
--
$a
2>/dev/null
&&
for a in
$m
; do
unhash -d --
$a
2>/dev/null
done
hash -dL >|
$SCD_ALIAS
hash -dL >|
$SCD_ALIAS
)
)
|| ec=
$?
fi
fi
$EXIT
$
?
$EXIT
$
ec
fi
fi
# The "compress" function collapses repeated directories to
# The "
compress
" function collapses repeated directories
in
to
#
on
e entry with a time
stamp
that gives
equivalent
-
probability.
#
a singl
e entry with a time
-
stamp
yielding an
equivalent
probability.
_scd_Y19oug_compress() {
_scd_Y19oug_compress() {
awk
-v
epochseconds
=
$EPOCHSECONDS
-v
meanlife
=
$SCD_MEANLIFE
'
awk -v epochseconds=
$EPOCHSECONDS
\
BEGIN { FS = "[:;]"; }
-v meanlife=
$SCD_MEANLIFE
\
length($0) < 4096 && $2 > 0 {
-v minlogprob=
$MINLOGPROB
\
tau = 1.0 * ($2 - epochseconds) / meanlife;
'
if (tau < -6.9078) tau = -6.9078;
BEGIN {
prob = exp(tau);
FS = "
[
:
;
]
";
sub(/^[^;]*;/, "");
pmin = exp(minlogprob);
if (NF) {
dlist[last[$0]] = "";
dlist[NR] = $0;
last[$0] = NR;
ptot[$0] += prob;
}
}
/^: deleted:0;/ { next; }
length(
$0
) < 4096 &&
$2
> 1000 {
df =
$0
;
sub("
^[^
;
]
*
;
", "", df);
if (!df) next;
tau = 1.0 * (
$2
- epochseconds) / meanlife;
prob = (tau < minlogprob) ? pmin : exp(tau);
dlist[last[df]] = "";
dlist[NR] = df;
last[df] = NR;
ptot[df] += prob;
}
}
END {
END {
for (i = 1; i <= NR; ++i) {
for (i = 1; i <= NR; ++i) {
...
@@ -160,15 +237,23 @@ _scd_Y19oug_compress() {
...
@@ -160,15 +237,23 @@ _scd_Y19oug_compress() {
'
$*
'
$*
}
}
# Rewrite directory index if it is at least 20% oversized
# Rewrite directory index if it is at least 20% oversized.
if
[[
-s
$SCD_HISTFILE
]]
&&
\
local curhistsize
((
$(
wc
-l
<
$SCD_HISTFILE
)
>
1.2
*
$SCD_HISTSIZE
))
;
then
if [[ -z
$opt_unindex
&& -s
$SCD_HISTFILE
]] &&
\
# compress repeated entries
curhistsize=
$(
wc
-l
<
$SCD_HISTFILE
)
&&
\
((
$curhistsize
> 1.2 *
$SCD_HISTSIZE
)); then
# Compress repeated entries in a background process.
(
m=(
${
(f)
"
$(
_scd_Y19oug_compress
$SCD_HISTFILE
)
"
}
)
m=(
${
(f)
"
$(
_scd_Y19oug_compress
$SCD_HISTFILE
)
"
}
)
# purge non-existent directories
# purge non-existent
and ignored
directories
m=(
${
(f)
"
$(
m=(
${
(f)
"
$(
for
a
in
$m
;
do
for
a
in
$m
;
do
if
[[
-d
${
a
#*;
}
]]
;
then
print
-r
--
$a
;
fi
d
=
${
a
#*;
}
[[
-z
${
scdignore
[(k)
$d
]
}
]]
||
continue
[[
-d
$d
]]
||
continue
$PWDCASECORRECT
||
d
=(
(
#i)${d} )
t
=
${
a
%%;*
}
print
-r
--
"
${
t
}
;
${
d
}
"
done
done
)
"}
)
"}
)
)
...
@@ -176,7 +261,11 @@ if [[ -s $SCD_HISTFILE ]] && \
...
@@ -176,7 +261,11 @@ if [[ -s $SCD_HISTFILE ]] && \
if [[
$#m
-gt
$SCD_HISTSIZE
]]; then
if [[
$#m
-gt
$SCD_HISTSIZE
]]; then
m=(
${
m
[-
$SCD_HISTSIZE
,-1]
}
)
m=(
${
m
[-
$SCD_HISTSIZE
,-1]
}
)
fi
fi
# Checking existence of many directories could have taken a while.
# Append any index entries added in meantime.
m+=(
${
(f)
"
$(
sed
"1,
${
curhistsize
}
d"
$SCD_HISTFILE
)
"
}
)
print -lr --
$m
>|
${
SCD_HISTFILE
}
print -lr --
$m
>|
${
SCD_HISTFILE
}
) &|
fi
fi
# Determine the last recorded directory
# Determine the last recorded directory
...
@@ -197,13 +286,8 @@ _scd_Y19oug_record() {
...
@@ -197,13 +286,8 @@ _scd_Y19oug_record() {
}
}
if [[ -n
$opt_add
]]; then
if [[ -n
$opt_add
]]; then
for
d
;
do
m=(
${
^
${
argv
:-
$PWD
}}
(N-/) )
if
[[
!
-d
$d
]]
;
then
_scd_Y19oug_abspath m
${
m
}
print
-u2
"Directory '
$d
' does not exist."
$EXIT
2
fi
done
_scd_Y19oug_abspath m
${
*
:-
$PWD
}
_scd_Y19oug_record
$m
_scd_Y19oug_record
$m
if [[ -n
$opt_recursive
]]; then
if [[ -n
$opt_recursive
]]; then
for d in
$m
; do
for d in
$m
; do
...
@@ -220,6 +304,7 @@ if [[ -n $opt_unindex ]]; then
...
@@ -220,6 +304,7 @@ if [[ -n $opt_unindex ]]; then
if [[ ! -s
$SCD_HISTFILE
]]; then
if [[ ! -s
$SCD_HISTFILE
]]; then
$EXIT
$EXIT
fi
fi
argv=(
${
argv
:-
$PWD
}
)
# expand existing directories in the argument list
# expand existing directories in the argument list
for i in {1..
$#}
; do
for i in {1..
$#}
; do
if [[ -d
${
argv
[i]
}
]]; then
if [[ -d
${
argv
[i]
}
]]; then
...
@@ -227,24 +312,28 @@ if [[ -n $opt_unindex ]]; then
...
@@ -227,24 +312,28 @@ if [[ -n $opt_unindex ]]; then
argv[i]=
${
d
}
argv[i]=
${
d
}
fi
fi
done
done
# strip trailing slashes, but preserve the root path
argv=(
${
argv
/(#m)?\/##(#e)/
${
MATCH
[1]
}}
)
m="
$(
awk
-v
recursive
=
${
opt_recursive
}
'
m="
$(
awk
-v
recursive
=
${
opt_recursive
}
'
BEGIN {
BEGIN {
for (i = 2; i < ARGC; ++i) {
for (i = 2; i < ARGC; ++i) {
argset[ARGV[i]] = 1;
argset[ARGV[i]] = 1;
delete ARGV[i];
delete ARGV[i];
}
}
unindex_root = ("/" in argset);
}
}
1 {
1 {
d = $0; sub(/^[^;]*;/, "", d);
d = $0; sub(/^[^;]*;/, "", d);
if (d in argset) next;
if (d in argset) next;
}
}
recursive {
recursive {
if (unindex_root) exit;
for (a in argset) {
for (a in argset) {
if (substr(d, 1, length(a) + 1) == a"/") next;
if (substr(d, 1, length(a) + 1) == a"/") next;
}
}
}
}
{ print $0 }
{ print $0 }
'
$SCD_HISTFILE
$
{
*
:-
$PWD
}
)
"
||
$EXIT
$?
'
$SCD_HISTFILE
$
*
)
" ||
$EXIT
$?
: >|
${
SCD_HISTFILE
}
: >|
${
SCD_HISTFILE
}
[[
${#
m
}
== 0 ]] || print -r --
$m
>>
${
SCD_HISTFILE
}
[[
${#
m
}
== 0 ]] || print -r --
$m
>>
${
SCD_HISTFILE
}
$EXIT
$EXIT
...
@@ -252,67 +341,113 @@ fi
...
@@ -252,67 +341,113 @@ fi
# The "
action
" function is called when there is just one target directory.
# The "
action
" function is called when there is just one target directory.
_scd_Y19oug_action() {
_scd_Y19oug_action() {
cd
$1
||
return
$?
local cdcmd=cd
[[ -z
${
opt_push
}
]] || cdcmd=pushd
builtin
$cdcmd
$1
|| return
$?
if [[ -z
$SCD_SCRIPT
&& -n
$RUNNING_AS_COMMAND
]]; then
if [[ -z
$SCD_SCRIPT
&& -n
$RUNNING_AS_COMMAND
]]; then
print -u2 "
Warning: running as
command
with SCD_SCRIPT undefined.
"
print -u2 "
Warning: running as
command
with SCD_SCRIPT undefined.
"
fi
fi
if [[ -n
$SCD_SCRIPT
]]; then
if [[ -n
$SCD_SCRIPT
]]; then
print
-r
"cd
${
(q)1
}
"
>
|
$SCD_SCRIPT
local d=
$1
if [[
$OSTYPE
== cygwin &&
${
(L)SCD_SCRIPT
}
== *.bat ]]; then
d=
$(
cygpath
-aw
.
)
fi
print -r "
${
cdcmd
}
${
(qqq)d
}
" >|
$SCD_SCRIPT
fi
fi
}
}
#
Match and rank patterns to the index file
#
Select and order indexed directories by matching command-line patterns.
#
s
et global arrays dmatching and drank
#
S
et global arrays dmatching and drank
.
_scd_Y19oug_match() {
_scd_Y19oug_match() {
## single argument that is an existing directory or directory alias
## single argument that is an existing directory or directory alias
if [[ -z
$opt_all
&&
$#
== 1 ]] &&
\
if [[ -z
$opt_all
&&
$#
== 1 ]] &&
\
[[
-d
${
d
::
=
$
1
}
||
-d
${
d
::
=
${
nameddirs
[
$1
]
}
}
]]
&&
[[
-x
$d
]]
;
[[ -d
${
d
::
=
$
{
nameddirs
[
$1
]
}}
|| -d
${
d
::
=
$1
}
]] && [[ -x
$d
]];
then
then
_scd_Y19oug_abspath dmatching
$d
_scd_Y19oug_abspath dmatching
$d
drank[
${
dmatching
[1]
}
]=1
drank[
${
dmatching
[1]
}
]=1
return
return
fi
fi
# ignore case unless there is an argument with an uppercase letter
# quote brackets when PWD is /Volumes/[C]/
[[
"
$*
"
==
*
[[
:upper:]]
*
]]
||
ICASE
=
'(#i)'
local qpwd=
${
PWD
//(#m)[][]/\\
${
MATCH
}}
# support "$" as an anchor for the directory name ending
# support "
./
" as an alias for
$PWD
to match only subdirectories.
argv=(
${
argv
/(#s).\/(#e)/(#s)
${
qpwd
}
(|/*)(#e)
}
)
# support "
./pat
" as an alias for
$PWD
/pat.
argv=(
${
argv
/(#m)(#s).\/?*/(#s)
${
qpwd
}${
MATCH
#.
}}
)
# support "
^
" as an anchor for the root directory, e.g., "
^
$HOME
".
argv=(
${
argv
/(#m)(#s)\^?*/(#s)
${${
~MATCH[2,-1]
}}}
)
# support "$" as an anchor at the end of directory name.
argv=(
${
argv
/(#m)?[
$]
(#e)/
${
MATCH
[1]
}
(#e)
}
)
argv=(
${
argv
/(#m)?[
$]
(#e)/
${
MATCH
[1]
}
(#e)
}
)
# calculate rank of all directories in the SCD_HISTFILE and keep it as drank
# support prefix "
:
" to match over the tail component.
# include a dummy entry for splitting of an empty string is buggy
argv=(
${
argv
/(#m)(#s)
:?
*/
${
MATCH
[2,-1]
}
[^/]#(#e)
}
)
# calculate rank of all directories in SCD_HISTFILE and store it in drank.
# include a dummy entry to avoid issues with splitting an empty string.
[[ -s
$SCD_HISTFILE
]] && drank=(
${
(f)
"
$(
[[ -s
$SCD_HISTFILE
]] && drank=(
${
(f)
"
$(
print
-l
/dev/null
-10
print
-l
/dev/null
-10
<
$SCD_HISTFILE
\
<
$SCD_HISTFILE
\
awk
-v
epochseconds
=
$EPOCHSECONDS
-v
meanlife
=
$SCD_MEANLIFE
'
awk
-v
epochseconds
=
$EPOCHSECONDS
\
BEGIN { FS = "[:;]"; }
-v
meanlife
=
$SCD_MEANLIFE
\
-v
minlogprob
=
$MINLOGPROB
\
'
BEGIN {
FS = "[:;]";
pmin = exp(minlogprob);
}
/^: deleted:0;/ {
df = $0;
sub("^[^;]*;", "", df);
delete ptot[df];
next;
}
length($0) < 4096 && $2 > 0 {
length($0) < 4096 && $2 > 0 {
df = $0;
sub("^[^;]*;", "", df);
if (!df) next;
dp = df;
while (!(dp in ptot)) {
ptot[dp] = pmin;
sub("//*[^/]*$", "", dp);
if (!dp) break;
}
if ($2 <= 1000) next;
tau = 1.0 * ($2 - epochseconds) / meanlife;
tau = 1.0 * ($2 - epochseconds) / meanlife;
if (tau < -6.9078) tau = -6.9078;
prob = (tau < minlogprob) ? pmin : exp(tau);
prob = exp(tau);
ptot[df] += prob;
sub(/^[^;]*;/, "");
if (NF) ptot[$0] += prob;
}
}
END { for (di in ptot) { print di; print ptot[di]; } }'
END { for (di in ptot) { print di; print ptot[di]; } }
'
)
"
}
)
"
}
)
)
unset "
drank[/dev/null]
"
unset "
drank[/dev/null]
"
# filter drank to the entries that match all arguments
# filter drank to the entries that match all arguments
for a; do
for a; do
p
=
${
ICASE
}
"
*(
${
a
}
)*"
p=
"
(
#l)
*(${a})*"
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
done
done
# require at least one argument matches
the
directory name
# require
that
at least one argument matches
in
directory
tail
name
.
p
=
${
ICASE
}
"
*(
${
(j
:|:
)argv
}
)[^/]#"
p
=
"(#l)
*(
${
(j
:|:
)argv
}
)[^/]#"
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
# discard ignored directories
if
[[
-z
${
opt_all
}
]]
;
then
for
d
in
${
(k)drank
}
;
do
[[
-z
${
scdignore
[(k)
$d
]
}
]]
||
unset
"drank[
$d
]"
done
fi
# build a list of matching directories reverse-sorted by their probabilities
# build a list of matching directories reverse-sorted by their probabilities
dmatching
=(
${
(f)
"
$(
dmatching
=(
${
(f)
"
$(
for
d p
in
${
(kv)drank
}
;
do
builtin printf
"%s %s
\n
"
${
(Oakv)drank
}
|
print
-r
--
"
$p
$d
"
;
/usr/bin/sort
-grk1
)
"
}
done
|
sort
-grk1
|
cut
-d
' '
-f
2-
)
"
}
)
)
dmatching
=(
${
dmatching
#*[[
:blank:]]
}
)
# do not match $HOME or $PWD when run without arguments
# do not match $HOME or $PWD when run without arguments
if
[[
$#
==
0
]]
;
then
if
[[
$#
==
0
]]
;
then
...
@@ -320,12 +455,20 @@ _scd_Y19oug_match() {
...
@@ -320,12 +455,20 @@ _scd_Y19oug_match() {
fi
fi
# keep at most SCD_MENUSIZE of matching and valid directories
# keep at most SCD_MENUSIZE of matching and valid directories
# mark up any deleted entries in the index
local
-A
isdeleted
m
=(
)
m
=(
)
isdeleted
=(
)
for
d
in
$dmatching
;
do
for
d
in
$dmatching
;
do
[[
${#
m
}
==
$SCD_MENUSIZE
]]
&&
break
[[
${#
m
}
==
$SCD_MENUSIZE
]]
&&
break
[[
-d
$d
&&
-x
$d
]]
&&
m+
=
$d
((
${
+isdeleted[
$d
]
}
==
0
))
||
continue
[[
-d
$d
]]
||
{
isdeleted[
$d
]=
1
;
continue
}
[[
-x
$d
]]
&&
m+
=
$d
done
done
dmatching
=(
$m
)
dmatching
=(
$m
)
if
[[
-n
${
isdeleted
}
]]
;
then
print
-lr
--
": deleted:0;"
${
^
${
(k)isdeleted
}}
>>
$SCD_HISTFILE
fi
# find the maximum rank
# find the maximum rank
maxrank
=
0.0
maxrank
=
0.0
...
@@ -343,7 +486,7 @@ _scd_Y19oug_match() {
...
@@ -343,7 +486,7 @@ _scd_Y19oug_match() {
_scd_Y19oug_match
$*
_scd_Y19oug_match
$*
## process
whatever
directories
that remained
## process
matching
directories
.
if
[[
${#
dmatching
}
==
0
]]
;
then
if
[[
${#
dmatching
}
==
0
]]
;
then
print
-u2
"No matching directory."
print
-u2
"No matching directory."
$EXIT
1
$EXIT
1
...
@@ -367,13 +510,13 @@ if [[ -n $opt_list ]]; then
...
@@ -367,13 +510,13 @@ if [[ -n $opt_list ]]; then
$EXIT
$EXIT
fi
fi
##
process single
directory
match
##
handle a single matching
directory
here.
if
[[
${#
dmatching
}
==
1
]]
;
then
if
[[
${#
dmatching
}
==
1
]]
;
then
_scd_Y19oug_action
$dmatching
_scd_Y19oug_action
$dmatching
$EXIT
$?
$EXIT
$?
fi
fi
##
h
ere we have multiple matches
- display
selection menu
##
H
ere we have multiple matches
. Let's use the
selection menu
.
a
=(
{
a-z
}
{
A-Z
}
)
a
=(
{
a-z
}
{
A-Z
}
)
a
=(
${
a
[1,
${#
dmatching
}
]
}
)
a
=(
${
a
[1,
${#
dmatching
}
]
}
)
p
=(
)
p
=(
)
...
...
plugins/scd/scd.plugin.zsh
View file @
8d08f163
## The scd script should autoload as a shell function.
## The scd script should autoload as a shell function.
autoload scd
autoload
-Uz
scd
## If the scd function exists, define a change-directory-hook function
## If the scd function exists, define a change-directory-hook function
## to record visited directories in the scd index.
## to record visited directories in the scd index.
if
[[
${
+functions[scd]
}
==
1
]]
;
then
if
[[
${
+functions[scd]
}
==
1
]]
;
then
scd_
chpwd_
hook
()
{
scd
--add
$PWD
}
chpwd_
scd
()
{
scd
--add
$PWD
}
autoload add-zsh-hook
autoload
-Uz
add-zsh-hook
add-zsh-hook chpwd
scd_
chpwd_
hook
add-zsh-hook chpwd chpwd_
scd
fi
fi
## Allow scd usage with unquoted wildcard characters such as "*" or "?".
alias
scd
=
'noglob scd'
## Load the directory aliases created by scd if any.
## Load the directory aliases created by scd if any.
if
[[
-s
~/.scdalias.zsh
]]
;
then
source
~/.scdalias.zsh
;
fi
if
[[
-s
~/.scdalias.zsh
]]
;
then
source
~/.scdalias.zsh
fi
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment