= Diru
- Introduction
- Quick start guide
- Getting started
- Client commands
- Configuration
- Practical usage
= Introduction
Diru is a Change Directory (cd) utility for augmenting Unix Shell
functionality. Diru makes it easy and efficient to jump around in
Project's directories. Diru uses client/server architecture, which
enables sharing of directory info and state between terminal sessions.
Each Server serves one Project. Project is a tree of related
directories where user wants to jump around and which has a logical
root. There can be multiple Servers, if user needs to access multiple
Projects concurrently.
Client queries directory info from Server and directory change is
pushed to Shell in order to change the current directory within the
Shell. Diru is not able to change the Shell directory by itself. User
must define a Shell function which can actually modify the state of
the Shell.
Diru features:
-
Support for multiple concurrent Projects.
-
User and Project specific options (configuration).
-
Jump to Project root.
-
Find and jump to dir under Project root (glob and regex search).
-
Find and jump to dir under current dir (glob search).
-
Fast directory search since Server maintains a memory image of
directories.
-
Configurable favorite directories, for persistent favorites.
-
Bookmark saving and referencing, for current favorites.
-
Directory change history and history referencing.
-
Scratch Pad (with named regs) for directory copy/paste.
-
Peer directory jumping, i.e. peer of current (regexp match).
-
Key/value store (Lookup) for general purpose information exchange
between terminals.
-
Online help.
= Quick start guide
This section defines a minimal number of steps for using Diru. The
description applies to a single server setup.
== Step 1
Define function (Bourne Shell) for using Diru Client:
dr()
{
ret=`diru -p 41115 -c $*`
if test $? -eq 0; then
cd $ret
fi
}
== Step 2
Setup project configuration:
shell> cd my_project
shell> diru -t > .diru.json
== Step 3
Start Diru Hub and default Diru Server for "my_project":
shell> diru --start
== Step 4
Use Client to store current directory to Scratch Pad:
shell> dr s .
Use Client as usual.
== Step 5
Kill all Servers and the Hub:
shell> diru --hkill
The Client was ready to use, but ".diru.json" included the default
template, which should be customized with project related
values. Modify the configuration before starting Hub and Server again.
= Getting started
The first thing to do is to start Diru Hub. Hub is a server process
that enables the Project specific Servers to be started. Hub will give
each new Server an unique port to operate with, starting from Hub Port
plus one.
Start Hub to port 42323:
shell> diru --hub --hport 42323
Start Server for a Project:
shell> cd <project_root_dir>
shell> diru --hport 42323 -s
Server will be listening to port "42324" (HubPort + 1). Following
Servers will get "42325", "42326" etc. Server displays the Port at
startup.
Server is a thread in Hub process. Servers can be started and killed
at will. Complete list of running Servers can be seen with:
shell> diru --hport 42323 -l
Servers are identified per user. This facilitates team use of shared
Hub.
When Server starts, it will detect the Project root. It can be a file
or defined as environment variable. Environment variable DIRU_ROOT has
higher precedence than a file based root. If ".diru_root_dir" file or
a ".diru.json" (or ".diru.yml") file is found from current dir or some
dir above, the dir containing either of the files will become the
Project root. If no files are found and DIRU_ROOT environment variable
is not used, an error is issued.
Client communicates with the Server in order to get and save directory
info. As mentioned above, Diru is more or less useless unless user has
defined a Shell function to realize the directory changes.
Here is an example of such function for Bourne Shell based shells:
dr()
{
ret=`diru -p 42324 -c $*`
if test $? -eq 0; then
cd $ret
fi
}
Diru Client command is defined as "dr" now. Option "-p" defines that
port "42324" is used to identify the Server and option "-c" defines
that we want to issue directory "change" commands. In practice only
part of the commands will change directory, since some commands are
only for queries. Directory is (and should be) changed if Diru returns
0. Otherwise Diru is performing a non-cd command, and Shell should
just ignore the current Diru execution.
If you want to see all Diru options, perform:
shell> diru -h
To jump to Project root, we do:
shell> dr r
If we want to jump to a subdir called "dir_0_0" (under root), we do:
shell> dr r dir_0_0
Note that "dir_0_0" does not have to be directly under Project root,
the directory is searched from the complete tree of directories under
Project root using glob (fnmatch) matching.
Now that we have changed directory for a couple of times, we can look
at the directory change history:
shell> dr h
We can reference the history by listed numbers. In order to jump back
to previous dir, we do:
shell> dr h 0
Bookmarks have the same type of number based referencing.
User can create a command sequence by separating commands with ","
character. For example if you want to reference Scratch Pad and then
jump to Peer, you can do:
shell> dr s , p
= Client commands
Client commands either change the current directory or query directory
info from Server.
Search commands:
dr r:: change to Project root dir.
dr r
:: change to (somewhere) under Project root dir
(glob).
dr t
:: change to (somewhere) under current dir (glob).
dr e
:: change to (somewhere) under Project root dir
(regexp).
Search can match multiple directories. First match is used and the
rest (Left-overs) are displayed to the user. Left-overs are also
stored, and they can be referenced and used in order of appearance
with simply issuing "dr" again.
Search pattern can be constructed from multiple pieces.
shell> dr r dir 1_0_1
The pieces are joined with '' for glob (fnmatch) based searches and
with '.' for regexp based searches. Glob based searches are
additionally pre-fixed with '' and post-fixed with ''. Glob does not
automatically match to the middle of the string, however regexp does.
Bookmark commands:
dr b:: display bookmarks.
dr b .:: add current dir to bookmarks.
dr b !:: reset (clear) bookmarks.
dr b s :: store bookmarks to .
dr b l :: load bookmarks from .
dr b d :: delete bookmark with .
dr b :: change dir to bookmark .
History commands:
dr h:: display history.
dr h .:: add current dir to history.
dr h !:: reset (clear) history.
dr h ,:: reference latest history item.
dr h :: change dir to history .
Scratch Pad commands:
dr s .:: store current dir to Default Scratch Pad.
dr s . :: store current dir to in Scratch Pad.
dr s
:: store to Default Scratch Pad.
dr s :: store to in Scratch Pad.
dr s:: change dir to Default Scratch Pad.
dr s :: change dir to from Scratch Pad.
dr s =:: display Scratch Pad content.
dr s !:: reset (clear) Scratch Pad.
Lookup commands:
dr l:: list all lookup / pairs.
dr !:: remove all keys.
dr ! :: remove .
dr l :: lookup value for .
dr l :: store value for .
Misc commands:
dr p:: jump to peer dir, i.e. the peer of current (from options).
dr c :: issue RPC command to server (reset etc., see below).
dr f:: list favorites dirs (from options).
dr f
:: change dir to favorite .
dr d m :: make directory.
dr d r :: remove directory.
dr i:: show command info.
dr :: change to given dir (must be under current).
dr:: change to next "Left-over" directory.
RPC (Remote Procedure Call) commands:
reset:: Reset Server state, i.e. History, Bookmarks, Left-overs.
abook:: Add current dir to Bookmarks.
lbook:: List Bookmarks.
rbook:: Reset Bookmarks.
doc:: Show command documentation.
dsync:: Synchronize Project dir content data with Server cache.
sync:: Synchronize Options File content to Server.
lregs:: List Scratch Pad registers.
= Configuration
Diru uses several environment variables, which are optional, and
provides thereby backup values for non-specified command line info.
DIRU_HUB_PORT:: Hub Port, or 41114 if not defined.
DIRU_PORT:: Server Port, or "~/.diru.prt" (Port File) if not
defined. See below for details.
DIRU_OPTS:: Options file, or "~/.diru.json" if not defined.
DIRU_ROOT:: Project root, which is used if ".diru_root_dir" and
".diru.json" are missing.
If Hub is started without "--hport" option, Diru checks if
DIRU_HUB_PORT is defined. If not, port 41114 is used.
If Client is used without "-p" option, Diru checks if DIRU_PORT is
defined. If not, Port File, i.e. "~/.diru.prt", is used. Client does
not work if no port info is given.
If Server is started in a directory where (or above) a file called
".diru_root_dir" is found, then Project root is the directory
containing ".diru_root_dir". If ".diru_root_dir" is not found, but
".diru.json" is found, then Project root is the directory
containing ".diru.json", and Options for Project are taken from
that file. Last resort for defining Project root, is DIRU_ROOT
definition.
If ".diru_root_dir" or DIRU_ROOT is used to define Project root, then
DIRU_OPTS is used to define Options File. However, if not defined,
then "~/.diru.json" is used for options.
The "json" format is searched before "yml" format, and hence "json" is
selected if both exist.
An example Options file can be displayed with:
shell> diru -t
Available options in Options File:
sync:: Options File and Project directory hierarchy refresh period
in seconds (for Server).
dsync:: Project directory hierarchy refresh period. This overrides
"sync" for Project updates (only). If value is 0, then no
updates are done after initial update when Server starts. User
might want to use 0, if the directory hierarchy is big and/or
does not change (often).
hist:: number of entries in history (max).
favs:: tagged favorite dirs.
peers:: , pairs for peer matching (String#sub method).
= Practical usage tips
After Hub has been started, user can start Server for each
Project. Each Server runs on its own Port, and user can either define
a Shell function for each Server with specific name, or define
environment variable (DIRU_PORT) and change it according to
Project. Depending on the usage pattern, user might as well want to
use the Port File.
Each Project could benefit from specific Options File, and hence user
can mark the Project Root with ".diru.json" (or ".diru.yml") and
specify the Project setup there. Default is to define the Project Root
with a ".diru.json" file.
Server caches all Project directory entries from disk to memory. This
means that Client can quickly jump to any directory, even deep in the
hierarchy. The target dir should be fairly accurately identified,
otherwise the search results in too many Left-overs, which is
impractical. Server updates the cache either periodically or only at
start-up. User might prefer no automatic update, if the hierarchy is
very large and extra load on disk is to be avoided. Cache update can
be performed, anyhow, at will with an RPC call, "dsync".
If user is working with a programming project, it is fairly common to
have separate sub-directories for source code and build targets. Let's
assume user starts with editing source code and has a terminal for
accessing files. When program is ready for running, user opens a new
terminal for handling the compile-run-debug iterations.
User can copy current source terminal directory to Scratch Pad. Then
in the new terminal, user can refer to Scratch Pad and change to same
directory as in source terminal. Finally user can change to a Peer of
current dir, i.e. where program running and debugging takes place.
If programming project is big enough, there might be several sub-dirs
where source files reside. User might setup favorites to Options File,
in order to easily reference the popular source code directories. For
less permanent favorites, user can use Bookmarks.
Options File can be edited while Server is running. Server reads the
Options File every 5 seconds (configurable with "sync") and refreshes
its internal state. Server also updates its internal cache of Project
directory content at each refresh cycle (by default). If "dsync"
Option is specified, it defines the "dsync" rate specifically.
The "dr" Shell function is in practice compulsory. In addition to "dr"
function, it is convenient to have a "dri" function. "dri" is meant
for interactive queries only, and obviously can have any name the user
wants.
dri() { diru -p 42324 -c $* 2>&1 }
This function returns Diru stderr responses as stdout and hence it is
easy to pipe this to other Shell commands.