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
510055a0
Commit
510055a0
authored
Nov 06, 2014
by
Robby Russell
Browse files
Merge pull request #3081 from pavoljuhas/master
update the scd plugin for smart change of directory.
parents
61184465
b6012bc2
Changes
2
Hide whitespace changes
Inline
Side-by-side
plugins/scd/README.md
View file @
510055a0
...
...
@@ -11,12 +11,9 @@ the index. A selection menu is displayed in case of several matches, with a
preference given to recently visited paths.
`scd`
can create permanent
directory aliases, which appear as named directories in zsh session.
## INSTALLATION
## INSTALLATION
NOTES
For oh-my-zsh, add
`scd`
to the
`plugins`
array in the ~/.zshrc file as in the
[
template file
](
../../templates/zshrc.zsh-template#L45
)
.
Besides 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
](
http://www.vim.org/
)
plugin and
[
IPython
](
http://ipython.org/
)
extension. For installation details, see
https://github.com/pavoljuhas/smart-change-directory.
...
...
@@ -34,7 +31,7 @@ scd [options] [pattern1 pattern2 ...]
add specified directories to the directory index.
</dd><dt>
--unindex
</dt><dd>
remove specified directories from the index.
</dd><dt>
remove
current or
specified directories from the index.
</dd><dt>
-r, --recursive
</dt><dd>
apply options
<em>
--add
</em>
or
<em>
--unindex
</em>
recursively.
</dd><dt>
...
...
@@ -47,6 +44,10 @@ scd [options] [pattern1 pattern2 ...]
remove ALIAS definition for the current or specified directory from
<em>
~/.scdalias.zsh
</em>
.
</dd><dt>
-A, --all
</dt><dd>
include all matching directories. Disregard matching by directory
alias and filtering of less likely paths.
</dd><dt>
--list
</dt><dd>
show matching directories and exit.
</dd><dt>
...
...
@@ -70,7 +71,7 @@ scd doc
scd a b c
# Change to a directory path that ends with "ts"
scd
"ts
(#e)
"
scd
"ts
$
"
# Show selection menu and ranking of 20 most likely directories
scd
-v
...
...
plugins/scd/scd
View file @
510055a0
...
...
@@ -11,20 +11,22 @@ fi
local
DOC
=
'scd -- smart change to a recently used directory
usage: scd [options] [pattern1 pattern2 ...]
Go to a directory path that contains all fixed string patterns. Prefer
recently visited directories a
nd directories with patterns in their tail
component.
Display a selection menu in case of multiple matches.
recent
or frequent
ly visited directories a
s found in the directory index.
Display a selection menu in case of multiple matches.
Options:
-a, --add add specified directories to the directory index
--unindex remove specified directories from the index
-r, --recursive apply options --add or --unindex recursively
-a, --add add specified directories to the directory index
.
--unindex remove
current or
specified directories from the index
.
-r, --recursive apply options --add or --unindex recursively
.
--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
directory from ~/.scdalias.zsh
--list show matching directories and exit
-v, --verbose display directory rank in the selection menu
-h, --help display this message and exit
directory from ~/.scdalias.zsh.
-A, --all include all matching directories. Disregard matching by
directory alias and filtering of less likely paths.
--list show matching directories and exit.
-v, --verbose display directory rank in the selection menu.
-h, --help display this message and exit.
'
local
SCD_HISTFILE
=
${
SCD_HISTFILE
:-${
HOME
}
/.scdhistory
}
...
...
@@ -35,9 +37,9 @@ local SCD_THRESHOLD=${SCD_THRESHOLD:-0.005}
local
SCD_SCRIPT
=
${
RUNNING_AS_COMMAND
:+
$SCD_SCRIPT
}
local
SCD_ALIAS
=
~/.scdalias.zsh
local
ICASE a d m p i
tdir
maxrank threshold
local
ICASE a d m p i maxrank threshold
local
opt_help opt_add opt_unindex opt_recursive opt_verbose
local
opt_alias opt_unalias opt_list
local
opt_alias opt_unalias
opt_all
opt_list
local
-A
drank dalias
local
dmatching
local
last_directory
...
...
@@ -56,7 +58,8 @@ zmodload -i zsh/zutil
zmodload
-i
zsh/datetime
zparseopts
-D
--
a
=
opt_add
-add
=
opt_add
-unindex
=
opt_unindex
\
r
=
opt_recursive
-recursive
=
opt_recursive
\
-alias
:
=
opt_alias
-unalias
=
opt_unalias
-list
=
opt_list
\
-alias
:
=
opt_alias
-unalias
=
opt_unalias
\
A
=
opt_all
-all
=
opt_all
-list
=
opt_list
\
v
=
opt_verbose
-verbose
=
opt_verbose
h
=
opt_help
-help
=
opt_help
\
||
$EXIT
$?
...
...
@@ -68,6 +71,11 @@ fi
# load directory aliases if they exist
[[
-r
$SCD_ALIAS
]]
&&
source
$SCD_ALIAS
# Private internal functions are prefixed with _scd_Y19oug_.
# Clean them up when the scd function returns.
setopt localtraps
trap
'unfunction -m "_scd_Y19oug_*"'
EXIT
# works faster than the (:a) modifier and is compatible with zsh 4.2.6
_scd_Y19oug_abspath
()
{
set
-A
$1
${
(ps
:
\0
:
)
"
$(
...
...
@@ -123,11 +131,52 @@ if [[ -n $opt_unalias ]]; then
$EXIT
$?
fi
# The "compress" function collapses repeated directories to
# one entry with a time stamp that gives equivalent-probability.
_scd_Y19oug_compress
()
{
awk
-v
epochseconds
=
$EPOCHSECONDS
-v
meanlife
=
$SCD_MEANLIFE
'
BEGIN { FS = "[:;]"; }
length($0) < 4096 && $2 > 0 {
tau = 1.0 * ($2 - epochseconds) / meanlife;
if (tau < -6.9078) tau = -6.9078;
prob = exp(tau);
sub(/^[^;]*;/, "");
if (NF) {
dlist[last[$0]] = "";
dlist[NR] = $0;
last[$0] = NR;
ptot[$0] += prob;
}
}
END {
for (i = 1; i <= NR; ++i) {
d = dlist[i];
if (d) {
ts = log(ptot[d]) * meanlife + epochseconds;
printf(": %.0f:0;%s\n", ts, d);
}
}
}
'
$*
}
# Rewrite directory index if it is at least 20% oversized
if
[[
-s
$SCD_HISTFILE
]]
&&
\
((
$(
wc
-l
<
$SCD_HISTFILE
)
>
1.2
*
$SCD_HISTSIZE
))
;
then
m
=(
${
(f)
"
$(
<
$SCD_HISTFILE
)
"
}
)
print
-lr
--
${
m
[-
$SCD_HISTSIZE
,-1]
}
>
|
${
SCD_HISTFILE
}
# compress repeated entries
m
=(
${
(f)
"
$(
_scd_Y19oug_compress
$SCD_HISTFILE
)
"
}
)
# purge non-existent directories
m
=(
${
(f)
"
$(
for
a
in
$m
;
do
if
[[
-d
${
a
#*;
}
]]
;
then
print
-r
--
$a
;
fi
done
)
"
}
)
# cut old entries if still oversized
if
[[
$#m
-gt
$SCD_HISTSIZE
]]
;
then
m
=(
${
m
[-
$SCD_HISTSIZE
,-1]
}
)
fi
print
-lr
--
$m
>
|
${
SCD_HISTFILE
}
fi
# Determine the last recorded directory
...
...
@@ -135,7 +184,6 @@ if [[ -s ${SCD_HISTFILE} ]]; then
last_directory
=
${
"
$(
tail
-1
${
SCD_HISTFILE
}
)
"
#*;
}
fi
# Internal functions are prefixed with "_scd_Y19oug_".
# The "record" function adds its arguments to the directory index.
_scd_Y19oug_record
()
{
while
[[
-n
$last_directory
&&
$1
==
$last_directory
]]
;
do
...
...
@@ -217,7 +265,7 @@ _scd_Y19oug_action() {
# set global arrays dmatching and drank
_scd_Y19oug_match
()
{
## single argument that is an existing directory or directory alias
if
[[
$#
==
1
]]
&&
\
if
[[
-z
$opt_all
&&
$#
==
1
]]
&&
\
[[
-d
${
d
::
=
$1
}
||
-d
${
d
::
=
${
nameddirs
[
$1
]
}}
]]
&&
[[
-x
$d
]]
;
then
_scd_Y19oug_abspath dmatching
$d
...
...
@@ -227,6 +275,8 @@ _scd_Y19oug_match() {
# ignore case unless there is an argument with an uppercase letter
[[
"
$*
"
==
*
[[
:upper:]]
*
]]
||
ICASE
=
'(#i)'
# support "$" as an anchor for the directory name ending
argv
=(
${
argv
/(#m)?[
$]
(#e)/
${
MATCH
[1]
}
(#e)
}
)
# calculate rank of all directories in the SCD_HISTFILE and keep it as drank
# include a dummy entry for splitting of an empty string is buggy
...
...
@@ -237,10 +287,10 @@ _scd_Y19oug_match() {
BEGIN { FS = "[:;]"; }
length($0) < 4096 && $2 > 0 {
tau = 1.0 * ($2 - epochseconds) / meanlife;
if (tau < -
4.61
) tau = -
4.61
;
pr
ec
= exp(tau);
if (tau < -
6.9078
) tau = -
6.9078
;
pr
ob
= exp(tau);
sub(/^[^;]*;/, "");
if (NF) ptot[$0] += pr
ec
;
if (NF) ptot[$0] += pr
ob
;
}
END { for (di in ptot) { print di; print ptot[di]; } }'
)
"
}
...
...
@@ -249,9 +299,12 @@ _scd_Y19oug_match() {
# filter drank to the entries that match all arguments
for
a
;
do
p
=
${
ICASE
}
"*
${
a
}
*"
p
=
${
ICASE
}
"*
(
${
a
}
)
*"
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
done
# require at least one argument matches the directory name
p
=
${
ICASE
}
"*(
${
(j
:|:
)argv
}
)[^/]#"
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
# build a list of matching directories reverse-sorted by their probabilities
dmatching
=(
${
(f)
"
$(
...
...
@@ -261,26 +314,6 @@ _scd_Y19oug_match() {
)
"
}
)
# if some directory paths match all patterns in order, discard all others
p
=
${
ICASE
}
"*
${
(j
:
*
:
)argv
}
*"
m
=(
${
(M)dmatching
:#
${
~p
}}
)
[[
-d
${
m
[1]
}
]]
&&
dmatching
=(
$m
)
# if some directory names match last pattern, discard all others
p
=
${
ICASE
}
"*
${
(j
:
*
:
)argv
}
[^/]#"
m
=(
${
(M)dmatching
:#
${
~p
}}
)
[[
-d
${
m
[1]
}
]]
&&
dmatching
=(
$m
)
# if some directory names match all patterns, discard all others
m
=(
$dmatching
)
for
a
;
do
p
=
${
ICASE
}
"*/[^/]#
${
a
}
[^/]#"
m
=(
${
(M)m
:#
${
~p
}}
)
done
[[
-d
${
m
[1]
}
]]
&&
dmatching
=(
$m
)
# if some directory names match all patterns in order, discard all others
p
=
${
ICASE
}
"/*
${
(j
:[^/]#:
)argv
}
[^/]#"
m
=(
${
(M)dmatching
:#
${
~p
}}
)
[[
-d
${
m
[1]
}
]]
&&
dmatching
=(
$m
)
# do not match $HOME or $PWD when run without arguments
if
[[
$#
==
0
]]
;
then
dmatching
=(
${
dmatching
:#
(
${
HOME
}
|
${
PWD
}
)
}
)
...
...
@@ -302,6 +335,9 @@ _scd_Y19oug_match() {
# discard all directories below the rank threshold
threshold
=
$((
maxrank
*
SCD_THRESHOLD
))
if
[[
-n
${
opt_all
}
]]
;
then
threshold
=
0
fi
dmatching
=(
${
^dmatching
}
(
Ne:
'(( ${drank[$REPLY]} >= threshold ))'
:
)
)
}
...
...
@@ -339,6 +375,7 @@ fi
## here we have multiple matches - display selection menu
a
=(
{
a-z
}
{
A-Z
}
)
a
=(
${
a
[1,
${#
dmatching
}
]
}
)
p
=(
)
for
i
in
{
1..
${#
dmatching
}
}
;
do
[[
-n
${
a
[i]
}
]]
||
break
...
...
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