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
Ohmyzsh
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
Hide 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
}}
)
fi
if ((
${
uu
[(I)OLD]
}
&&
${
+nameddirs[OLD]
}
== 0 )); then
_scd_Y19oug_abspath a
${
1
:-
$PWD
}
uu=(
${
uu
:#OLD
}
${
(ps
:
\0
:
)
"
$(
a
=
$(
print
-rD
${
a
}
)
hash
-dr
if
[[
$a
!=
[
~][^/]##
]]
;
then
if
[[
-r
$SCD_ALIAS
]]
;
then
$EXIT
source
$SCD_ALIAS
fi
for
a d
in
${
(kv)nameddirs
}
;
do
[[
-d
$d
]]
||
print
-Nr
--
$a
done
)
"
}
)
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
\
'
BEGIN {
FS = "
[
:
;
]
";
pmin = exp(minlogprob);
}
/^: deleted:0;/ { next; }
length(
$0
) < 4096 &&
$2
> 1000 {
df =
$0
;
sub("
^[^
;
]
*
;
", "", df);
if (!df) 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);
dlist[last[df]] = "";
sub(/^[^;]*;/, "");
dlist[NR] = df;
if (NF) {
last[df] = NR;
dlist[last[$0]] = "";
ptot[df] += prob;
dlist[NR] = $0;
last[$0] = NR;
ptot[$0] += prob;
}
}
}
END {
END {
for (i = 1; i <= NR; ++i) {
for (i = 1; i <= NR; ++i) {
...
@@ -157,26 +234,38 @@ _scd_Y19oug_compress() {
...
@@ -157,26 +234,38 @@ _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
)
&&
\
m
=(
${
(f)
"
$(
_scd_Y19oug_compress
$SCD_HISTFILE
)
"
}
)
((
$curhistsize
> 1.2 *
$SCD_HISTSIZE
)); then
# purge non-existent directories
# Compress repeated entries in a background process.
m
=(
${
(f)
"
$(
(
for
a
in
$m
;
do
m=(
${
(f)
"
$(
_scd_Y19oug_compress
$SCD_HISTFILE
)
"
}
)
if
[[
-d
${
a
#*;
}
]]
;
then
print
-r
--
$a
;
fi
# purge non-existent and ignored directories
done
m=(
${
(f)
"
$(
)
"
}
for
a
in
$m
;
do
)
d
=
${
a
#*;
}
# cut old entries if still oversized
[[
-z
${
scdignore
[(k)
$d
]
}
]]
||
continue
if
[[
$#m
-gt
$SCD_HISTSIZE
]]
;
then
[[
-d
$d
]]
||
continue
m
=(
${
m
[-
$SCD_HISTSIZE
,-1]
}
)
$PWDCASECORRECT
||
d
=(
(
#i)${d} )
fi
t
=
${
a
%%;*
}
print
-lr
--
$m
>
|
${
SCD_HISTFILE
}
print
-r
--
"
${
t
}
;
${
d
}
"
done
)
"}
)
# cut old entries if still oversized
if [[
$#m
-gt
$SCD_HISTSIZE
]]; then
m=(
${
m
[-
$SCD_HISTSIZE
,-1]
}
)
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
}
) &|
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