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

  1. 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 <dir>

change to <dir> (somewhere) under Project root dir (glob).

dr t <dir>

change to <dir> (somewhere) under current dir (glob).

dr e <dir>

change to <dir> (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 <file>

store bookmarks to <file>.

dr b l <file>

load bookmarks from <file>.

dr b d <num>

delete bookmark with <num>.

dr b <num>

change dir to bookmark <num>.

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 <num>

change dir to history <num>.

Scratch Pad commands:

dr s .

store current dir to Default Scratch Pad.

dr s . <reg>

store current dir to <reg> in Scratch Pad.

dr s <dir>

store <dir> to Default Scratch Pad.

dr s <d> <r>

store <dir> to <reg> in Scratch Pad.

dr s

change dir to Default Scratch Pad.

dr s <reg>

change dir to <reg> from Scratch Pad.

dr s =

display Scratch Pad content.

dr s !

reset (clear) Scratch Pad.

Lookup commands:

dr l

list all lookup <key>/<v> pairs.

dr !

remove all keys.

dr ! <key>

remove <key>.

dr l <key>

lookup value for <key>.

dr l <key> <v>

store value <v> for <key>.

Misc commands:

dr p

jump to peer dir, i.e. the peer of current (from options).

dr c <cmd>

issue RPC command to server (reset etc., see below).

dr f

list favorites dirs (from options).

dr f <dir>

change dir to favorite <dir>.

dr d m <dir>

make directory.

dr d r <dir>

remove directory.

dr i

show command info.

dr <dir>

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

<regexp>,<str> 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.