## What is this? `cdlog` is a small amount of GNU Bash code that provides a better interactive experience for directory changes than Bash's built-in directory stack mechanism (commands `pushd`, `popd` and `dirs`, plus `~-` expansion). ## How to use Install the file `cdlog.sh` somewhere, and source it from your `.bashrc` script. When `cdlog` is loaded, a number of commands become available: * `cd` is an alias which calls the function `cdlog.chdir`. Every time you change directory, it pushes the previous directory into a history log which is stored in the `cdlog_hist` array. The log maintains nine entries. The ninth entry is erased. The entries are copied into the variables `c1` through `c9`. The first four entries are also copied into the variables `x`, `y`, `z` and `w` for shorter access. If the argument of `cd` is a number from 1 to 9, it changes to the specified `cdlog` history element. * `cs` (cd swap) is an alias for a command which exchanges the current directory with a selected `cslog` entry selected by a numeric argument, which defaults to 1. The current directory overwrites that entry in the log, and then the shell changes to the directory which was previously in that entry. If `cs` is given two or more arguments, it rotates among those. The directory is changed to the `cdlog` item indicated by the first argument. That item is overwritten by the second item, the second by the third and so on. The last item receives the previously current directory. * `pd` (pop dir) is an alias for a command which changes to (by default) the most recent directory in the log, and removes that entry from the log. The second most recent directory becomes most recent and so on. If it is given an argument value in the range 1 to 9, it changes to the specified entry, and removes it, moving the others down to close the gap. Thus `pd 1` is equivalent to `pd`. `pd` takes a `-f` option which means "force". This is useful when it's not possible to change to the indicated directory, in which case `-f` causes it to be removed in spite of this. * `cdlog` function shows a listing of the four most recent entries in the log, or all nine if given the `-l` argument. The `cl` command is an alias for for `cdlog` with no arguments and `cll` for `cdlog -l`. * The `mcd` and `mcs` are menu-selection-based analogs of `cd` and `cs`. They print the contents of the history (first nine entries), and you can pick which directory to change to or swap with. The terminal cursor is then retraced back to the top of the menu, and the screen is erased from that point to the bottom. * The `cdr` command is used for switching to and managing previous sessions. Though the `r` stands for "recovery", it may actually be used at any time and may be usefully used multiple times. When `cdlog` starts, it initially allocates a new session. The `cdr` recovery command presents you with a numbered menu of previous sessions. Entering an empty input line exits the menu. You can recover to one of the sessions by entering its number. The menu accepts additional notations for useful actions. Use a `c` prefix on the numeric selection to clone the session into the current session. Deleting unwanted sessions is possible with a `d` prefix; the specified entry is deleted and you remain in the recovery menu. There is an `n` command which will make current again that new new session that `cdlog` had allocated on startup. That new session does not appear in the numbered list of recoverable sessions unless it has been already persisted by the execution of a directory-changing command. * The `cdalias` command is used for defining or listing "cd aliases"; see below. * The `cdunalias` command removes a cd alias. * The `c` command provides an API into `cdlog`'s name resolution. It takes one argument. If it successfully resolves the argument to a path, that path it is printed, and the termination status is successful. Otherwise nothing is printed and the termination status is failed. If the argument is a digit in the range 1 to 9, then it resolves to the specified element in the `cdlog` history, if it is nonblank. If the argument begins with `@`, then it resolves as a search; see Searches below. Otherwise, it is tried as a `cdlog` alias; see Aliases below. In addition, the `cdlog.sh` script sets the Bash `direxpand` option. With the `direxpand` option, Tab completion on a directory coming from a variable name will expand that variable into the command line. The directory changing commands do nothing if you attempt to change into the same directory you are already in. There is no effect on the history. ## Aliases `cdlog` provides its own "cd alias" feature. If the argument to `cd` contains no slashes, then it is used as a key to look up an alias, which replaces it. The replacement is not considered to be an alias even if it looks like one. Aliases are defined using the `cdalias` command. It takes two arguments. Implementation notes: aliases are stored in the `cdlog_alias` array. The `cdlog.chdir` function recognizes an alias only if it is invoked as `cdlog.chdir -p `, which is the way `cd` invokes it. If the replacement (second argument) of `cdalias` is a digit from 1 to 9, then it refers to that entry in the `cdlog`. The path at that index will be retrieved and used as the alias value. If the replacement begins with `@` then it is a search. If the search succeeds, then the result will be used as the alias value. When `cdalias` is invoked with no arguments, it lists all the currently defined aliases. When `cdalias` is invoked with one argument, and that argument names an alias, it lists that alias. Otherwise it fails with an error message. The deprecated `cdaliases` command also lists aliases; it will disappear in a future version of `cdlog`. ## Searches A search is an arguments which begins with `@`. The rest of the argument is interpreted as a pattern which is applied against the history to find the most recent matching path. 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. 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 contents of the history are written to the file `~/.cslog.N.dirs`, one path per line, where `N` is an internal session number. (This location for the session file is only a default; see the section Alternative Session Directory below which describes the `cdlog_sess_dir` variable.) When `cdlog` initializes, it allocates a session by finding a free value `N` in the range 1 to 10. If it cannot find one due to the session store being full, it erases the one with the oldest time stamp and chooses its index. When one or more persisted session are present, `cdlog`'s initialization mentions this, suggesting that the `cdr` command may be used to recover to one of the sessions. See also the Auto Recovery section below. ## LRU Mode When the configuration variable `cdlog_lru` is set to the value `y`, LRU mode is enabled in the `cdlog.chdir` function, affecting the `cd` and `mcd` commands. LRU mode modifies the history algorithm in the following way. If the directory change successfully takes place to a directory which already exists in the history, then the most recent (topmost) occurrence of that directory is removed from the history before the previous directory is pushed into the history. Thus, in effect, a rotation is taking place: the existing entry in the history becomes the current directory, and is removed; the entries above it shift down to take its place, and the previous current directory becomes the top of the history. LRU mode is disabled when the `cdlog_lru` variable is empty, which is its initial value. LRU mode keeps duplicate directories out of the history and while promoting recently used directories toward the top. ## Alternative Session Directory By default, `cdlog` keeps the session recovery files in your home directory. They have numbered names like `.cdlog.1.dirs`. The variable `cdlog_sess_dir` may be assigned a directory path to specify an alternative directory. This path should omit the trailing slash. If the variable is empty, it denotes the root directory. If the directory doesn't exist, `cdlog` will try to create it. The main use for this configuration is to support the situation when a home directory is shared among multiple host machines with different environments. You can interpolate the value of `$HOSTNAME` into `cdlog_sess_dir` to have sessions specific to a host. ## Auto Recovery When the `cdlog_autorecover` variable is set to `y`, `cdlog` will automatically recover the session without the need for using the `cdr` command. This only happens when these two conditions hold: 1. Bash is either a login shell, or the `SHLVL` variable is `1`. 2. There is only one saved session. This feature exists because it is extremely common to use `cdr` upon logging in and to choose the only available session, by selecting `1`. However, automatic recovery may navigate away from the home directory, which may surprise the user who has not logged into that host in a long time. Thus it is not default behavior. When `cdlog_autorecover` is empty, which is the initial value, the feature is disabled. ## Completion `cdlog` provides its own Tab completion for the `cd` command, overriding the built-in completion. It includes the cd aliases, while completing on directories, taking into account `CDPATH`. ## How is this better? * It's not hard-coded C code inside the shell; it consists of a small amount of code whose behavior that can be customized by the end-user. * Uses simple variables, which are better supported for completion and require fewer keystrokes. * The `dirs` command for accessing the directory stack in Bash is too clumsy and won't be discussed here any more. * Bash's shorthand notation for accessing the nth element, namely `~-n`, takes more keystrokes than `cdlog`'s aliases for the first four elements, `$x` through `$w`. * Bash's shorthand notation requires an explicit slash to be typed in order for completion to work. `~-n` followed by tab is not sufficient. You must type a slash and then Tab. Whereas completing on the variable `$x` just requires Tab. One tab will automatically add the slash and then additional tabs engage further completion. * Bash's `direxpand` option does not work for `~-n` notation. Completion works, but the notation remains unexpanded. * Bash's `~-n` notation does not expand inside double quotes, whereas variables do. * `cdlog` has intuitive, simpler commands. The actions of pushing entries into the log, and rotating among them aren't conflated into a single command. The rotating command `cs` is usefully different from `pushd [+/-]n`, taking only positive integer arguments with no sign, and rotating among specified places, rather than a contiguous block of top entries. * The persistence feature recovers the directories from a previous session. ## License This is under distributed under a modified two-clause BSD license. See the license block at the bottom of the `cdlog.sh` file.