Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
oh-my-zsh
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
github
oh-my-zsh
Commits
510055a0
Commit
510055a0
authored
Nov 06, 2014
by
Robby Russell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3081 from pavoljuhas/master
update the scd plugin for smart change of directory.
parents
61184465
b6012bc2
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
86 additions
and
48 deletions
+86
-48
README.md
plugins/scd/README.md
+8
-7
scd
plugins/scd/scd
+78
-41
No files found.
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
...
@@ -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
preference given to recently visited paths.
`scd`
can create permanent
directory aliases, which appear as named directories in zsh session.
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
Besides oh-my-zsh,
`scd`
can be used with
*bash*
,
*dash*
or
*tcsh*
[
template file
](
../../templates/zshrc.zsh-template#L45
)
.
Besides zsh,
`scd`
can be used with
*bash*
,
*dash*
or
*tcsh*
shells and is also available as
[
Vim
](
http://www.vim.org/
)
plugin and
shells and is also available as
[
Vim
](
http://www.vim.org/
)
plugin and
[
IPython
](
http://ipython.org/
)
extension. For installation details, see
[
IPython
](
http://ipython.org/
)
extension. For installation details, see
https://github.com/pavoljuhas/smart-change-directory.
https://github.com/pavoljuhas/smart-change-directory.
...
@@ -34,7 +31,7 @@ scd [options] [pattern1 pattern2 ...]
...
@@ -34,7 +31,7 @@ scd [options] [pattern1 pattern2 ...]
add specified directories to the directory index.
</dd><dt>
add specified directories to the directory index.
</dd><dt>
--unindex
</dt><dd>
--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>
-r, --recursive
</dt><dd>
apply options
<em>
--add
</em>
or
<em>
--unindex
</em>
recursively.
</dd><dt>
apply options
<em>
--add
</em>
or
<em>
--unindex
</em>
recursively.
</dd><dt>
...
@@ -47,6 +44,10 @@ scd [options] [pattern1 pattern2 ...]
...
@@ -47,6 +44,10 @@ scd [options] [pattern1 pattern2 ...]
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>
.
</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>
--list
</dt><dd>
show matching directories and exit.
</dd><dt>
show matching directories and exit.
</dd><dt>
...
@@ -70,7 +71,7 @@ scd doc
...
@@ -70,7 +71,7 @@ scd doc
scd a b c
scd a b c
# Change to a directory path that ends with "ts"
# Change to a directory path that ends with "ts"
scd
"ts
(#e)
"
scd
"ts
$
"
# Show selection menu and ranking of 20 most likely directories
# Show selection menu and ranking of 20 most likely directories
scd
-v
scd
-v
...
...
plugins/scd/scd
View file @
510055a0
...
@@ -11,20 +11,22 @@ fi
...
@@ -11,20 +11,22 @@ 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 contains all fixed string patterns. Prefer
recent
ly visited directories and directories with patterns in their tail
recent
or frequently visited directories as found in the directory index.
component.
Display a selection menu in case of multiple matches.
Display a selection menu in case of multiple matches.
Options:
Options:
-a, --add add specified directories to the directory index
-a, --add add specified directories to the directory index
.
--unindex remove
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.
--list show matching directories and exit
-A, --all include all matching directories. Disregard matching by
-v, --verbose display directory rank in the selection menu
directory alias and filtering of less likely paths.
-h, --help display this message and exit
--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
}
local
SCD_HISTFILE
=
${
SCD_HISTFILE
:-${
HOME
}
/.scdhistory
}
...
@@ -35,9 +37,9 @@ local SCD_THRESHOLD=${SCD_THRESHOLD:-0.005}
...
@@ -35,9 +37,9 @@ 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
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_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
-A
drank dalias
local
dmatching
local
dmatching
local
last_directory
local
last_directory
...
@@ -56,7 +58,8 @@ zmodload -i zsh/zutil
...
@@ -56,7 +58,8 @@ zmodload -i zsh/zutil
zmodload
-i
zsh/datetime
zmodload
-i
zsh/datetime
zparseopts
-D
--
a
=
opt_add
-add
=
opt_add
-unindex
=
opt_unindex
\
zparseopts
-D
--
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
-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
\
v
=
opt_verbose
-verbose
=
opt_verbose
h
=
opt_help
-help
=
opt_help
\
||
$EXIT
$?
||
$EXIT
$?
...
@@ -68,6 +71,11 @@ fi
...
@@ -68,6 +71,11 @@ 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
# 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
# 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
:
)
"
$(
...
@@ -123,11 +131,52 @@ if [[ -n $opt_unalias ]]; then
...
@@ -123,11 +131,52 @@ if [[ -n $opt_unalias ]]; then
$EXIT
$?
$EXIT
$?
fi
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
# Rewrite directory index if it is at least 20% oversized
if
[[
-s
$SCD_HISTFILE
]]
&&
\
if
[[
-s
$SCD_HISTFILE
]]
&&
\
((
$(
wc
-l
<
$SCD_HISTFILE
)
>
1.2
*
$SCD_HISTSIZE
))
;
then
((
$(
wc
-l
<
$SCD_HISTFILE
)
>
1.2
*
$SCD_HISTSIZE
))
;
then
m
=(
${
(f)
"
$(
<
$SCD_HISTFILE
)
"
}
)
# compress repeated entries
print
-lr
--
${
m
[-
$SCD_HISTSIZE
,-1]
}
>
|
${
SCD_HISTFILE
}
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
fi
# Determine the last recorded directory
# Determine the last recorded directory
...
@@ -135,7 +184,6 @@ if [[ -s ${SCD_HISTFILE} ]]; then
...
@@ -135,7 +184,6 @@ if [[ -s ${SCD_HISTFILE} ]]; then
last_directory
=
${
"
$(
tail
-1
${
SCD_HISTFILE
})
"
#*;
}
last_directory
=
${
"
$(
tail
-1
${
SCD_HISTFILE
})
"
#*;
}
fi
fi
# Internal functions are prefixed with "_scd_Y19oug_".
# The "record" function adds its arguments to the directory index.
# The "record" function adds its arguments to the directory index.
_scd_Y19oug_record
()
{
_scd_Y19oug_record
()
{
while
[[
-n
$last_directory
&&
$1
==
$last_directory
]]
;
do
while
[[
-n
$last_directory
&&
$1
==
$last_directory
]]
;
do
...
@@ -217,7 +265,7 @@ _scd_Y19oug_action() {
...
@@ -217,7 +265,7 @@ _scd_Y19oug_action() {
# set global arrays dmatching and drank
# set 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
[[
$#
==
1
]]
&&
\
if
[[
-z
$opt_all
&&
$#
==
1
]]
&&
\
[[
-d
${
d
::
=
$1
}
||
-d
${
d
::
=
${
nameddirs
[
$1
]
}}
]]
&&
[[
-x
$d
]]
;
[[
-d
${
d
::
=
$1
}
||
-d
${
d
::
=
${
nameddirs
[
$1
]
}}
]]
&&
[[
-x
$d
]]
;
then
then
_scd_Y19oug_abspath dmatching
$d
_scd_Y19oug_abspath dmatching
$d
...
@@ -227,6 +275,8 @@ _scd_Y19oug_match() {
...
@@ -227,6 +275,8 @@ _scd_Y19oug_match() {
# ignore case unless there is an argument with an uppercase letter
# ignore case unless there is an argument with an uppercase letter
[[
"
$*
"
==
*
[[
:upper:]]
*
]]
||
ICASE
=
'(#i)'
[[
"
$*
"
==
*
[[
: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
# 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
# include a dummy entry for splitting of an empty string is buggy
...
@@ -237,10 +287,10 @@ _scd_Y19oug_match() {
...
@@ -237,10 +287,10 @@ _scd_Y19oug_match() {
BEGIN { FS = "[:;]"; }
BEGIN { FS = "[:;]"; }
length($0) < 4096 && $2 > 0 {
length($0) < 4096 && $2 > 0 {
tau = 1.0 * ($2 - epochseconds) / meanlife;
tau = 1.0 * ($2 - epochseconds) / meanlife;
if (tau < -
4.61) tau = -4.61
;
if (tau < -
6.9078) tau = -6.9078
;
pr
ec
= exp(tau);
pr
ob
= exp(tau);
sub(/^[^;]*;/, "");
sub(/^[^;]*;/, "");
if (NF) ptot[$0] += pr
ec
;
if (NF) ptot[$0] += pr
ob
;
}
}
END { for (di in ptot) { print di; print ptot[di]; } }'
END { for (di in ptot) { print di; print ptot[di]; } }'
)
"
}
)
"
}
...
@@ -249,9 +299,12 @@ _scd_Y19oug_match() {
...
@@ -249,9 +299,12 @@ _scd_Y19oug_match() {
# 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
=
${
ICASE
}
"*
(
${
a
}
)
*"
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
drank
=(
${
(kv)drank[(I)
${
~p
}
]
}
)
done
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
# build a list of matching directories reverse-sorted by their probabilities
dmatching
=(
${
(f)
"
$(
dmatching
=(
${
(f)
"
$(
...
@@ -261,26 +314,6 @@ _scd_Y19oug_match() {
...
@@ -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
# do not match $HOME or $PWD when run without arguments
if
[[
$#
==
0
]]
;
then
if
[[
$#
==
0
]]
;
then
dmatching
=(
${
dmatching
:#
(
${
HOME
}
|
${
PWD
}
)
}
)
dmatching
=(
${
dmatching
:#
(
${
HOME
}
|
${
PWD
}
)
}
)
...
@@ -302,6 +335,9 @@ _scd_Y19oug_match() {
...
@@ -302,6 +335,9 @@ _scd_Y19oug_match() {
# discard all directories below the rank threshold
# discard all directories below the rank threshold
threshold
=
$((
maxrank
*
SCD_THRESHOLD
))
threshold
=
$((
maxrank
*
SCD_THRESHOLD
))
if
[[
-n
${
opt_all
}
]]
;
then
threshold
=
0
fi
dmatching
=(
${
^dmatching
}
(
Ne:
'(( ${drank[$REPLY]} >= threshold ))'
:
)
)
dmatching
=(
${
^dmatching
}
(
Ne:
'(( ${drank[$REPLY]} >= threshold ))'
:
)
)
}
}
...
@@ -339,6 +375,7 @@ fi
...
@@ -339,6 +375,7 @@ fi
## here we have multiple matches - display selection menu
## here we have multiple matches - display selection menu
a
=(
{
a-z
}
{
A-Z
}
)
a
=(
{
a-z
}
{
A-Z
}
)
a
=(
${
a
[1,
${#
dmatching
}
]
}
)
p
=(
)
p
=(
)
for
i
in
{
1..
${#
dmatching
}
}
;
do
for
i
in
{
1..
${#
dmatching
}
}
;
do
[[
-n
${
a
[i]
}
]]
||
break
[[
-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