aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2024-04-10 14:16:20 -0700
committerKaz Kylheku <kaz@kylheku.com>2024-04-10 14:16:20 -0700
commit5977af54dc0806445445a8732905c8d7ba572e41 (patch)
tree2ff5b934ba98592e82fcb184576485417a94bfb8
parent285220820eb842b4dfe52c19852bf71fca517c74 (diff)
downloadcdlog-5977af54dc0806445445a8732905c8d7ba572e41.tar.gz
cdlog-5977af54dc0806445445a8732905c8d7ba572e41.tar.bz2
cdlog-5977af54dc0806445445a8732905c8d7ba572e41.zip
New: search feature.
* cdlog.sh (cdlog.at2index, cdlog.at2path): New functions. (cdlog.chdir, cdlog.rot, cdlog.mcd): Support searches as way of specifying the target path or entry. * README.md: Document searches.
-rw-r--r--README.md22
-rw-r--r--cdlog.sh114
2 files changed, 109 insertions, 27 deletions
diff --git a/README.md b/README.md
index d0b26b0..8af4d6c 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,28 @@ array. The `cdlog.chdir` function recognizes an alias only if
it is invoked as `cdlog.chdir -p <alias>`, which is the way
`cd` invokes it.
+## Searches
+
+Search are arguments which begin with `@`. The rest
+of such an argument argument is interpreted as a pattern which is applied
+against the history to find the most recent path containing a match.
+
+In commands which accept a numeric argument denoting a reference
+to the `cdlog` history by position, the `@` prefix may be omitted
+from the search pattern. For instance `cs foo` will
+swap the current directory with the most recent history entry
+whose path contains a match for `foo`, and `cs @foo` will do
+exactly the same thing.
+
+When a pattern can is used in situations in which a path
+or alias is expected, namely as an argument to `cd`, the `@`
+is not optional, because without it, the argument would be
+interpreted as a path or alias.
+
+To include a leading `@` as part of the search pattern, write `@@`:
+the first `@` is recognized as the prefix, and removed; the
+second `@` remains as part of the pattern.
+
## Persistence
Whenever the history changes, the current directory and the
diff --git a/cdlog.sh b/cdlog.sh
index e5a6aae..25118ff 100644
--- a/cdlog.sh
+++ b/cdlog.sh
@@ -152,6 +152,37 @@ cdlog.recover()
fi
}
+# Resolve @ search item to number
+cdlog.at2index()
+{
+ local i
+ local pat=${1#@}
+
+ for i in "${!cdlog_hist[@]}"; do
+ if [[ ${cdlog_hist[$i]} =~ $pat ]] ; then
+ echo $i
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Resolve @ search item to path
+cdlog.at2path()
+{
+ local i
+ local pat=${1#@}
+
+ for i in "${!cdlog_hist[@]}"; do
+ local path=${cdlog_hist[$i]}
+ if [[ $path =~ $pat ]] ; then
+ echo $path
+ return 0
+ fi
+ done
+ return 1
+}
+
# Change to directory: this is aliased to cd command.
cdlog.chdir()
{
@@ -162,6 +193,15 @@ cdlog.chdir()
if [ $# -eq 2 -a "$1" = -P ] ; then
case $2 in
+ ( @* )
+ if def=$(cdlog.at2path "$2"); then
+ set -- -P "$def"
+ print=y
+ else
+ printf "cdlog.chdir: no match for %s\n" "$2"
+ return 1
+ fi
+ ;;
( */* )
;;
( [1-9] )
@@ -218,6 +258,7 @@ cdlog.rot()
local cur=$PWD
local p=$cur
local n=$cur
+ local i
declare -n d=cdlog_hist
local first=y
@@ -225,22 +266,30 @@ cdlog.rot()
while [ $# -gt 0 ] ; do
n=$1; shift
- case $n in
- ( [1-9] )
- if [ $first ] ; then
- command cd "${d[$n]}" || return
- printf "%s\n" "$PWD"
- else
- d[$p]=${d[$n]}
- fi
- first=
- p=$n
- ;;
- ( * )
- printf "cdlog.rot: bad argument: %s\n" "$n"
- return 1
- ;;
- esac
+ while true; do
+ case $n in
+ ( [1-9] )
+ if [ $first ] ; then
+ command cd "${d[$n]}" || return
+ printf "%s\n" "$PWD"
+ else
+ d[$p]=${d[$n]}
+ fi
+ first=
+ p=$n
+ ;;
+ ( * )
+ if i=$(cdlog.at2index "$n"); then
+ n=$i
+ continue
+ else
+ printf "cdlog.rot: no match for %s\n" "$n"
+ return 1
+ fi
+ ;;
+ esac
+ break
+ done
done
d[$p]=$cur
@@ -324,18 +373,29 @@ cdlog.mcd()
printf "\e[A\e[K"
done
- case "$sel" in
- ( [1-9] )
- if [ $swap ] ; then
- cdlog.rot $sel
- else
- if cdlog.chdir -P "${d[$sel]}" ; then
- printf "%s\n" "$PWD"
+ while true; do
+ case "$sel" in
+ ( [1-9] )
+ if [ $swap ] ; then
+ cdlog.rot $sel
+ else
+ if cdlog.chdir -P "${d[$sel]}" ; then
+ printf "%s\n" "$PWD"
+ fi
fi
- fi
- res=$?
- ;;
- esac
+ res=$?
+ ;;
+ ( * )
+ if i=$(cdlog.at2index "$sel"); then
+ sel=$i
+ continue
+ else
+ printf "cdlog.mcd: no match for %s\n" "$sel"
+ return 1
+ fi
+ esac
+ break
+ done
return $res
}