aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: b590d6132fa1d0ccdb7bfbea0c32d0cb4fb0ef96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
## 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 <alias>`, 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.