summaryrefslogtreecommitdiff
path: root/Functions/Chpwd/cdr
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2010-07-09 14:47:48 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2010-07-09 14:47:48 +0000
commit5da6530d831ea8a00943b39359d535ea59996894 (patch)
tree2a4fcd827214fa4fd2a8d172341a07cb8b76cda0 /Functions/Chpwd/cdr
parent924f40b772d7c222ffe8db502fb88cc897fd9902 (diff)
downloadzsh-5da6530d831ea8a00943b39359d535ea59996894.tar.gz
zsh-5da6530d831ea8a00943b39359d535ea59996894.zip
28065 plus unposted zsh.mdd:
add cdr and related functions and docs
Diffstat (limited to 'Functions/Chpwd/cdr')
-rw-r--r--Functions/Chpwd/cdr311
1 files changed, 311 insertions, 0 deletions
diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr
new file mode 100644
index 000000000..551710499
--- /dev/null
+++ b/Functions/Chpwd/cdr
@@ -0,0 +1,311 @@
+# Description
+# ===========
+#
+# Change to a recently used directory recorded in a file so that the
+# recent file list persists across sessions.
+#
+# To use this system,
+#
+# autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
+# add-zsh-hook chpwd chpwd_recent_dirs
+#
+# (add-zsh-hook appeared in zsh version 4.3.4.) This ensures that all
+# directories you change to interactively are registered. The
+# chpwd_recent_dirs function does some guesswork to see if you are "really"
+# changing directory permanently, see below.
+#
+# The argument to cdr is a number corresponding to the Nth most recently
+# changed-to directory starting at 1 for the immediately preceeding
+# directory (the current directory is remembered but is not offered as a
+# destination). You can use directory arguments if you set the
+# recent-dirs-default style, see below; however, it should be noted
+# that if you do you gain nothing over using cd directly (the recent
+# directory list is updated in either case).
+#
+# If the argument is omitted, 1 is assumed.
+#
+# Completion is available if compinit has been run; menu selection is
+# recommended, using
+#
+# zstyle ':completion:*:*:cdr:*:*' menu selection
+#
+# and also the verbose style to ensure the directory is shown (this
+# is on by default).
+#
+# Options
+# =======
+#
+# "cdr -l" lists the numbers and the corresponding directories in
+# abbreviated form (i.e. with "~" substitution reapplied), one per line.
+# The directories here are not quoted (this would only be an issue if a
+# directory name contained a newline). This is used by the completion
+# system.
+#
+# "cdr -r" sets the parameter "reply" to the current set of directories.
+#
+# "cdr -e" allows you to edit the list of directories, one per line. The
+# list can be edited to any extent you like; no sanity checking is
+# performed. Completion is available. No quoting is necessary (except for
+# newlines, where I have in any case no sympathy); directories are in
+# unabbreviated from and contain an absolute path, i.e. they start with /
+# (and only /). Usually the first entry should be left as the current
+# directory.
+#
+# Details of directory handling
+# =============================
+#
+# Recent directories are saved to a file immediately and hence are
+# preserved across sessions. Note currently no file locking is applied:
+# the list is updated immediately on interactive commands and nowhere else
+# (unlike history), and it is assumed you are only going to change
+# directory in one window at once. This is not safe on shared accounts,
+# but in any case the system has limited utility when someone else is
+# changing to a different set of directories behind your back.
+#
+# To make this a little safer, only directory changes instituted from the
+# command line, either directly or indirectly through shell function calls
+# (but not through subshells, evals, traps, completion functions and the
+# like) are saved. This works best in versions of the shell from 4.3.11
+# which has facilities to check the evaluation context. Shell functions
+# should use cd -q or pushd -q to avoid side effects if the change to the
+# directory is to be invisible at the command line. See the function
+# chpwd_recent_dirs for more details.
+#
+# Styles
+# ======
+#
+# Various styles are available. The context for setting styles should be
+# ':chpwd:*' in case the meaning of the context is extended in future, for
+# example:
+#
+# zstyle ':chpwd:*' recent-dirs-max 0
+#
+# although the style name is specific enough that a context of '*' should
+# be fine in practice. The only exception is recent-dirs-insert, which is
+# used exclusively by the completion system and so has the usual completion
+# system context (':completion:*' if nothing more specific is needed,
+# though again '*' should be fine in practice).
+#
+# recent-dirs-default
+# If true, and the command is expecting a recent directory index, and
+# either there is more than one argument or the argument is not an
+# integer, then fall through to "cd". This allows the lazy to use only
+# one command for directory changing. Completion recognises this, too;
+# see recent-dirs-insert for how to control completion when this option
+# is in use.
+#
+# recent-dirs-file
+# The file where the list of directories is saved. The default
+# is ${ZDOTDIR:-$HOME}/.chpwd-recent-dirs, i.e. this is in your
+# home directory unless you have set ZDOTDIR to point somewhere else.
+# Directory names are saved in $'...' quoted form, so each line
+# in the file can be supplied directly to the shell as an argument.
+#
+# The value of this style may be an array. In this case, the first
+# file in the list will always be used for saving directories while any
+# other files are left untouched. When reading the recent directory
+# list, if there are fewer than the maximum number of entries in the
+# first file, the contents of later files in the array will be appended
+# with duplicates removed from the list shown. The contents of the two
+# files are not sorted together, i.e. all the entries in the first file
+# are shown first. The special value "+" can appear in the list to
+# indicate the default file should be read at that point. This allows
+# effects like the following:
+#
+# zstyle recent-dirs-file ':chpwd:*' ~/.chpwd-recent-dirs-${TTY##*/} +
+#
+# Recent directories are read from a file numbered according to
+# the terminal. If there are insufficient entries the list
+# is supplemented from the default file.
+#
+# recent-dirs-insert
+# Used by completion. If recent-dirs-default is true, then setting
+# this to true causes the actual directory, rather than its index, to
+# be inserted on the command line; this has the same effect as using
+# the corresponding index, but makes the history clearer and the line
+# easier to edit. With this setting, if part of an argument was
+# already typed, normal directory completion rather than recent
+# directory completion is done; this is because recent directory
+# completion is expected to be done by cycling through entries menu
+# fashion. However, if the value of the style is "always", then only
+# recent directories will be completed; in that case, use the cd
+# command when you want to complete other directories. If the value is
+# "fallback", recent directories will be tried first, then normal
+# directory completion is performed if recent directory completion
+# failed to find a match. Finally, if the value is "both" then both
+# sets of completions are presented; the usual tag mechanism can be
+# used to distinguish results, with recent directories tagged as
+# "recent-dirs". Note that the recent directories inserted are
+# abbreviated with directory names where appropriate.
+#
+# recent-dirs-max
+# The maximum number of directories to save to the file. If
+# this is zero or negative there is no maximum. The default is 20.
+# Note this includes the current directory, which isn't offered,
+# so the highest number of directories you will be offered
+# is one less than the maximum.
+#
+# recent-dirs-prune
+# This style is an array determining what directories should (or should
+# not) be added to the recent list. Elements of the array can include:
+# parent
+# Prune parents (more accurately, ancestors) from the recent list.
+# If present, changing directly down by any number of directories
+# causes the current directory to be overwritten. For example,
+# changing from ~pws to ~pws/some/other/dir causes ~pws not to be
+# left on the recent directory stack. This only applies to direct
+# changes to descendant diretories; earlier directories on the
+# list are not pruned. For example, changing from ~pws/yet/another
+# to ~pws/some/other/dir does not cause ~pws to be pruned.
+# pattern:<pattern>
+# Gives a zsh pattern for directories that should not be
+# added to the recent list (if not already there). This element
+# can be repeated to add different patterns. For example,
+# 'pattern:/tmp(|/*)' stops /tmp or its descendants from being
+# added. The EXTENDED_GLOB option is always turned on for
+# these patterns.
+#
+# recent-dirs-pushd
+# If set to true, cdr will use pushd instead of cd to change the
+# directory, so the directory is saved on the directory stack. As the
+# directory stack is completely separate from the list of files saved
+# by the mechanism used in this file there is no obvious reason to do
+# this.
+#
+# Use with dynamic directory naming
+# =================================
+#
+# It is possible to refer to recent directories using the dynamic directory
+# name syntax that appeared in zsh version 4.3.7. If you create and
+# autoload a function zsh_directory_name containing the following code,
+# ~[1] will refer to the most recent directory other than $PWD, and so on.
+# This also includes completion (version 4.3.11 is required for this to
+# work; previous versions needed the file _dynamic_directory_name to
+# be overloaded).
+#
+# if [[ $1 = n ]]; then
+# if [[ $2 = <-> ]]; then
+# # Recent directory
+# typeset -ga reply
+# autoload -Uz cdr
+# cdr -r
+# if [[ -n ${reply[$2]} ]]; then
+# reply=(${reply[$2]})
+# return 0
+# else
+# reply=()
+# return 1
+# fi
+# fi
+# elif [[ $1 = c ]]; then
+# if [[ $PREFIX = <-> || -z $PREFIX ]]; then
+# typeset -a keys values
+#
+# values=(${${(f)"$(cdr -l)"}/ ##/:})
+# keys=(${values%%:*})
+#
+# _describe -t dir-index 'recent directory index' \
+# values keys -V unsorted -S']'
+# return
+# fi
+# fi
+# return 1
+
+
+emulate -L zsh
+setopt extendedglob
+
+autoload -Uz chpwd_recent_filehandler chpwd_recent_add
+
+integer list set_reply i bad edit
+local opt dir
+local -aU dirs
+
+while getopts "elr" opt; do
+ case $opt in
+ (e)
+ edit=1
+ ;;
+
+ (l)
+ list=1
+ ;;
+
+ (r)
+ set_reply=1
+ ;;
+
+ (*)
+ return 1
+ ;;
+ esac
+done
+shift $(( OPTIND - 1 ))
+
+if (( set_reply )); then
+ typeset -ga reply
+else
+ local -a reply
+fi
+
+if (( list || set_reply || edit )); then
+ (( $# )) && bad=1
+else
+ if [[ $#1 -eq 0 ]]; then
+ 1=1
+ elif [[ $# -ne 1 || $1 != <-> ]]; then
+ if zstyle -t ':chpwd:' recent-dirs-default; then
+ cd "$@"
+ return
+ else
+ bad=1
+ fi
+ fi
+fi
+
+if (( bad )); then
+ print "Usage: $0 [-l | -r | <dir-num> ]
+Use $0 -l or completion to see possible directories."
+ return 1
+fi
+
+chpwd_recent_filehandler
+
+if [[ $PWD != $reply[1] ]]; then
+ # When we first start we don't have the current directory.
+ # Add it now for consistency.
+ chpwd_recent_add $PWD && chpwd_recent_filehandler $reply
+fi
+
+if (( edit )); then
+ local compcontext='directories:directory:_path_files -/'
+IFS='
+' vared reply || return 1
+chpwd_recent_filehandler $reply
+fi
+
+# Skip current directory if present (may have been pruned).
+[[ $reply[1] = $PWD ]] && reply=($reply[2,-1])
+
+if (( list )); then
+ dirs=($reply)
+ for (( i = 1; i <= ${#dirs}; i++ )); do
+ print -n ${(r.5.)i}
+ print -D ${dirs[i]}
+ done
+ return
+fi
+
+(( set_reply || edit )) && return
+
+if (( $1 > ${#reply} )); then
+ print "Not enough directories ($(( ${#dirs} - 1)) possibilities)" >&2
+ return 1
+fi
+dir=${reply[$1]}
+
+if zstyle -t ':chpwd:' recent-dirs-pushd; then
+ pushd -- $dir
+else
+ cd -- $dir
+fi