NOUSERMACRO(xd)

includefile(../../release.yo)

htmlbodyopt(text)(#27408B)
htmlbodyopt(bgcolor)(#FFFAF0)
whenhtml(mailto(Frank B. Brokken: f.b.brokken@rug.nl))

DEFINEMACRO(lsoption)(3)(\
    bf(--ARG1)=tt(ARG3) (bf(-ARG2))\
)
DEFINEMACRO(laoption)(2)(\
    bf(--ARG1)=tt(ARG2)\
)
DEFINEMACRO(loption)(1)(\
    bf(--ARG1)\
)
DEFINEMACRO(soption)(1)(\
    bf(-ARG1)\
)


DELETEMACRO(tt)
DEFINEMACRO(tt)(1)(em(ARG1))

COMMENT( man-request, section, date, distribution file, general name)
manpage(xd)(1)(_CurYrs_)(xd._CurVers_)
        (xd - fast directory changes)

COMMENT( man-request, larger title )
manpagename(xd)(eXtra fast Directory changer)

COMMENT( all other: add after () )
manpagesynopsis()
       bf(xd) [OPTIONS] tt(arguments)

manpagedescription()

    The program bf(xd) is used to perform e+bf(X)tra fast bf(D)irectory
changes. Usually to change a directory the user is required to enter a command
like, e.g., tt(cd /usr/local/bin), possibly using shell completion. Often this
is a tedious task: shell completion shows all entries, including files, when
we're only interested in directories and the full specification of our
intented directory may eventually require many keyboard actions.

    tt(Xd) was designed a long time ago (in the early 90s) to reduce the
effort of changing directories. Often we're well aware to which directory we
want to change, and it's easy to provide the initial directory characters of
that directory. E.g., if the intent is to tt(cd) to tt(/usr/local/bin),
it's easy to specify the letters tt(ulb).

    tt(Xd) capitalizes on this capability. By providing the initial directory
characters of directories tt(xd) determines the expansion(s) allowing you to
do fast directory changes. So, after entering the command tt(xd ulb) 
tt(xd) may directly perform the change-directory to tt(/usr/local/bin).

    Often, however, multiple alternatives can match the specified series of
characters. E.g., when entering tt(xd ulb) tt(xd) may find several
alternatives, like
        verb(
 1: /usr/lib/base-config
 2: /usr/lib/bonobo
 3: /usr/lib/bonobo-activation
 4: /usr/local/bin
        )
    If these are the alternatives, then this is exactly what tt(xd) shows
you. Then, by simply pressing the tt(4) key (em(no) tt(Enter) key required)
tt(xd) performs the required tt(/usr/local/bin) (see also the section
bf(DIRECT KEY ENTRY)).


    tt(Xd's) behavior can be fine-tuned in various ways:
    itemization(
    it() by default (as specified by the configuration file, see below) tt(xd)
looks for expansions starting at the user's home directory or at the system's
root directory;

    it() initial character bf(/): if the first character of the command is
tt(/) then all expansions are performed from the system's root
directory. E.g., tt(xd /t) produces tt(/tmp) but not tt(/home/user/tmp);

    it() initial character bf(.): if the first character of the command is
tt(.) then by default all expansions are performed from the user's home
directory. E.g., tt(xd .t) results in tt(/home/user/tmp) but not in
tt(/tmp). The home directory recognition character can be altered using the
tt(--homedir-char) option, see below (section bf(OPTIONS)). When merely
specifying tt(xd .) then tt(xd) changes the current directory to the user's
home directory.

    it() initial character bf(0): If the first character of the command is
tt(0), then all expansions start at the current working directory. When merely
specifying tt(xd 0) then tt(xd) returns leaving  the current directory
unchanged. When additional characters are appended to 0 then this command
operates like the following, starting from the current working directory;

    it() initial character bf(1..9): If the first character of the command is
a digit between tt(1) and tt(9) then all expansions start at that parent
directory level of the current working directory (up to the system's root
directory). E.g., if the current working directory is tt(/usr/share/doc) then
tt(xd 2lb) will offer the alternative tt(/usr/local/bin): two steps up, then
look for directories starting with tt(l) and therein directories starting with
tt(b). When merely specifying one of these characters tt(xd) changes the
current directory to the indicated parent, up to the root-directory (e.g.,
specifying tt(xd 5) at tt(/usr/bin) changes the current directory to the
root-directory)

    it() separators (space, and the forward slash (`tt(/)')): sometimes it is
clear that there are many alternatives and the intention is to reduce that
number. By using separators subsequently nested directories must start with
the characters between the separators. E.g., tt(xd u l bi) doesn't produce
the alternative tt(/usr/lib/base-config) anymore, since tt(base-config) does
not start with tt(bi). In this case only tt(/usr/local/bin) is produced. When
used as initial character in a pattern the forward slash always indicates the
root-directory;
    COMMENT(
   Separators may be mixed (tt(xd u/l bi) is identical to tt(xd u l
    bi)). Since the tt(/) can also be used as a root-directory specification,
    a conflict is implied by a command like tt(xd /u l bi). This conflict is
    solved by given the initial character a higher precedence than the
    separator. Using the underscore (_) separator in this case is another way
    to solve the conflict (which in practice hardly ever occurs).
    END)

    it() search patterns may contain dots (like tt(.s)). In such cases the dot
represents hidden directories. However, tt(xd) usually also finds patterns
containing tt(/./), as the current directory matches the dot. Such patterns
are considered spurious and are not reported.
    )

    If there's only one solution, tt(Xd) prepares for a direct directory
change to the solution's directory.

If there are multiple solutions, then by default lists of at most 62
alternatives (10 for the numbers 0..9, 26 for the letters a..z and 26 for the
letters A..Z) are written to the standard error stream from which the user may
select an alternative by simply pressing the key associated with the selection
of choice. If no selection is requested any other key may be pressed (e.g.,
the space bar or the tt(Enter) key). If there is no solutioon tt(xd) writes
the text tt(No Solutions) to the standard error stream.

    When tt(xd) is given at least one argument, all its output is sent to the
standard error stream, except for the selected directory name which should
become the next working directory. 

    tt(Xd) may insert the tt(cd) command directly into the command shell from
where tt(xd) was called. See also section bf(SHELL SCRIPTS)). In this mode of
operation tt(xd) returns a single dot if no selection is made, preventing an
unintended change of directory.

    If no selection is made or if the selection process is aborted a single
dot is written to the standard output stream. Usually tt(xd) will be called by
a shell alias, providing the tt(cd) command with tt(xd)'s output (see below at
the bf(SHELL SCRIPTS) section) executing tt(cd `xd $*`). The default dot
produced by tt(xd) prevents an unintended change of directory.

    When tt(xd) is merely given an initial directory specification, like a
single dot (tt(.)) or digit (a digit in the set tt([0..9])) then tt(xd)
returns the implied path. Specifying a parent before the root-directory (E.g.,
entering `tt(xd 5)' when the current working directory is `tt(/tmp)') results
in writing the root directory (`tt(/)') to the standard output stream.

    If tt(xd) is called without arguments its em(usage) information is
written to the standard error stream.

    tt(Xd) may be further configured using options and a configuration file,
discussed in the bf(OPTIONS) and bf(CONFIGURATION FILE) sections below.

manpagesection(DIRECT KEY ENTRY)

To pass the directory change command to the shell's input buffer bf(xd) calls
the function bf(ioctl)(2). That function is still available, although it's
also considered a somewhat deprecated function. But even though it's
available, by default it may not work. The program bf(sysctl)(8) shows the
values of system variables, among which tt(dev.tty.legacy_tiocsti):
        verb(
    sysctl -a | grep tiocsti
    dev.tty.legacy_tiocsti = 0
        )
    If, at your computer, tt(sysctl) shows tt(dev.tty.legacy_tiocsti = 0) then
define a file tt(/etc/sysctl.d/tiocsti.conf) containing the line
        verb(
    dev.tty.legacy_tiocsti=1
        )
Then, after rebooting tt(ioctl) will work as described in its man-page.

Alternatively, a shell script or alias can be defined to pass the command to
your shell. E.g., when using the tt(tcsh) shell program the following alias
can be defined:
        verb(
    alias xd 'cd `\xd --no-input \!*`' ) Or, when using tt(bash), define a
function tt(xd) calling, e.g., tt(/usr/bin/xd):
        verb(
    xd()
    {
        cd `/usr/bin/xd --no-input "$*"`
    }
)

manpagesection(GENERALIZED DIRECTORY SEARCH)

    tt(Xd) also supports generalized directory search commands (GDS). When GDS
is requested separators are no longer required, and tt(xd) finds all possible
alternatives resulting from all possible sequential combinations of the
initial search command. GDS is activated either by specifying the tt(-g)
option or by entering tt(generalized-search) in tt(xd)'s configuration
file. Alternatively, when the latter is specified then the tt(--traditional)
command line option suppresses GDS.

    When using GDS each initial substring of the command to tt(xd) is
considered as the initial characters of a directory. E.g., if the command
tt(xd tmps) is entered using GDS then directories matching the following
search patterns will be found;
    itemization(
    it() tt(/t*/m*/p*/s*/)
    it() tt(/t*/m*/ps*/)
    it() tt(/t*/mp*/s*/)
    it() tt(/t*/mps*/)
    it() tt(/tm*/p*/s*/)
    it() tt(/tm*/ps*/)
    it() tt(/tmp*/s*/)
    it() tt(/tmps*/)
    )
    With the traditional processing mode only the first one of these
alternative patterns is considered.

    Multiple command line arguments, the slash, and the underscore can still
be used with GDS. In this case they force a directory change using the
considered patterns. E.g., with the command tt(xd tm/ps) the following
patterns will be considered:
    itemization(
    it() tt(/t*/m*/p*/s*/)
    it() tt(/t*/m*/ps*/)
    it() tt(/tm*/p*/s*/)
    it() tt(/tm*/ps*/)
    )
    In this set all of the previous patterns showing the tt(...mp...)
combination were dropped, as a directory change is forced between the tt(m)
and tt(p) characters.

manpagesection(RETURN VALUES)

    tt(Xd) may return the following values to its caller, allowing scripts
calling tt(xd) to make decisions that depend on the actually performed action
by tt(xd):
    itemization(
    it() 0 is returned if tt(xd) issued a tt(cd) command;
    it() 1 is returned if tt(xd) received a non-space character, not selecting
        a directory to change to. When the tt(input) option has been specified
        this character is inserted into the command shell's input buffer;
    it() 2 is returned if tt(xd) received a space (or Enter) character,
        indicating that tt(xd) should perform no further action;
    it() 3 is returned if no directory was found matching the argument passed
        to tt(xd);
    it() 4 is returned if the tt(--help) or tt(--version) option was
        specified (see their descriptions in the tt(OPTIONS) section);
    it() 5 is returned if an error was encountered (e.g., when a non-existing
        configuration file is specified).
    )

manpageoptions()

    If available, single letter options are listed between parentheses
following their associated long-option variants. Single letter options require
arguments if their associated long options require arguments as well.

Most options can also be specified in tt(xd's) configuration file, in which
case the long option variants must be used, omitting the initial two dashes
(see the section tt(CONFIGURATION FILE) below for specific details about the
configuration file. 

By default the options can also be specified in the configuration
file. If an option cannot be specifiied in the configuration file it is
explicitly stated at its description. 

Options that are specified as command-line options take priority over options
specified in the configuration file.

    itemization(
    it() loption(add-root) tt(condition)nl()
            If the search starts at the user's home directory an additional
search starting at the system's root directory may be performed as well,
depending on the value specified for the tt(add-root) option. Conditions are
    quote(
        itemization(
        it() tt(never) (no additional search is performed),
        it() tt(if-empty) (an additional search is performed if the initial
            search did not yield any directory),
        it() tt(always) (an additional search is always performed);
        )
    )
    it() loption(all) soption(a)nl()
        If the configuration file (see below) contains tt(ignore) directives
then those directives are ignored when computing the alternatives from which
the user may select a directory to change to;

    it() lsoption(block-size)(b)(nr)nl()
       The possible directories matching tt(xd's) argument are listed in
        blocks of tt(<nr>) elements. the possible directories matching
        tt(xd's) argument are listed in blocks of tt(<nr>) elements. The
        built-in minimum block size is 5. If there are fewer alternatives then
        this built-in minimum then the actually available alternatives are
        displayed;

       When alternatives are split up in blocks, a tt(+) is displayed after
        listing the first block, a tt(-) is displayed after listing the last
        block, and tt(-+) is displayed after listing the intermediate
        blocks. In these cases, pressing - redisplays the previous block,
        pressing + displays the next block;

       Although these block-end prompts only show - and +, the characters ,
        and < (usually combined in one key) can be used instead of -, while
        . and > (also usually combined in one key) can be used instead of +.

    it() lsoption(config-file)(c)(filename)nl()
       The name of an tt(xd) configuration file. By default tt(xd) looks for
        the file tt(.xdrc) in the user's home directory. The existence of the
        default file is optional.

        This option cannot be specified in the configuration file;

    it() loption(directories) tt(inclusion)nl()
       Directories may be also be reached via symbolic links. The (default)
        inclusion type tt(all) adds these symbolic links to the list of
        alternatives. The inclusion type tt(unique) prevents symbolic links
        from being added to the list of alternatives;

    it() loption(generalized-search) soption(g)nl()
       When specified tt(xd) uses GDS unless the directive tt(traditional) is
        specified in the configuration file;

    it() loption(help) (soption(h))nl()
       Basic usage information is written to the standard error stream,
        whereafter tt(xd) terminates.

       This option cannot be specified in the configuration file;

    it() loption(homedir-char) tt(ch)nl()
       By default an initial dot character (`tt(.)') initiates a search from
        the user's home directory. There is a slight disadvantage to using the
        dot, as it is also be the initial character of `hidden'
        directories. Assuming that you have a directory tt(~/.ssh) then the
        command to xd to that directory would be tt(xd ..s), the first dot
        being the home directory indicator, after which tt(.s) is used to find
        tt(.ssh). The option tt(--homedir-char) can be used to specify another
        character. Homedir characters cannot be digits or a slash (`tt(/)') as
        these are used to specify, respectively, parent directories and the
        computer's root directory. Characters like ``tt(, @ % ^)'' or maybe
        `tt(H)' (assuming that it doesn't interfere with an existing directory
        beginning with tt(H)) could be used as homedir-characters, other than
        the default dot character.

       Caveat: command shells by default interpret characters like ``tt(~ $ \
        ' " ` < > |)'' etc., which therefore should probably not be specified
        as home directory specifiers;

    it() loption(history) tt([filename])nl()
       A history of previously made choices is kept in the file
        tt(filename). If tt(--history) is specified, but the filename is left
        empty the history file tt($HOME/.xd.his) is used. This file should
        only be modified by tt(xd) itself. If you can't resist editing it then
        use the following example showing the format of the lines in the
        history file.
       verb(
    1292596154 1 /home/frank/svn/xd/
        )
       The first field is the time (in seconds since the epoch) the entry was
        written, the second field is the number of times the entry has been
        selected and the third field is the associated path.

       The following tt(history-...) options are only interpreted if the
        tt(history) option is also specified.

    it() loption(history-lifetime) tt(spec)nl()
       The lifetime of the entries in the history file. The specification
        consists of a number followed by tt(D, W, M) or tt(Y), representing,
        resp. days, weeks, months, or years. A month is considered a period of
        30 days, a year a period of 365 days. If the specification is omitted
        a lifetime of tt(1M) (one month) is used. Entries older than
        tt(history-lifetime) are disregarded as history-items and are removed
        from the history file;

    it() loption(history-maxsize) tt(nr)nl()
       The maximum number of entries the history file may contain. By default
        there is no limit. When tt(history-maxsize) is specified and more than
        the maximum number of history items are found in the history file then
        the tt(nr) most popular choices are kept. Usually the cut-off point
        will be somewhere within a popularity category. In that case the most
        recently selected alternatives within that category are kept;

    it() loption(history-position) tt([top|bottom])nl()
       Previously found alternatives are displayed either at the top of the
        list or at the bottom of the list. If this option is omitted then the
        elements in the history are intermixed with new alternatives. The next
        option tt(history-separate) is only used when this option is also
        specified. By merely specifying tt(history-position) the history items
        are shown at the top of the list;

    it() loption(history-separate)nl()
       When specified a blank line is written between the items in the
        history and new alternatives (not previously selected). This option is
        only interpreted when the previous option is also specified;

    it() loption(icase) soption(i)nl() 
       Specify this option to use case-insensitive pattern matching. E.g.,
        specifying tt(xd /ub) returns the directory tt(/usr/bin), but not a
        directory like tt(/UnSpecified/Books), which is returned by tt(xd
        /UB). However, tt(xd -i /ub) (using any letter casing for the
        specification) returns both directories. The option tt(icase) could of
        course be specified in the configuration file, which which case
        case-insensitive matching is used by default. In the latter case
        specifying tt(-i) as a command line option reverts the matching
        procedure to case-sensitive directory matching. In general, when an
        even number of em(icase) specifications is provided tt(xd) uses
        case-sensitive directory matching, while an odd number of em(icase)
        specifications results in case-insensitive directory matching;

    it() bf(ignore) tt(path) nl()
       This option cannot be specified as command-line option. Instead, the
        configuration file may contain multiple tt(ignore) directives which
        are (different from the way other directives are handled) all
        interpreted. Each tt(ignore) directive is followed by a path
        specification as shown in a list of alternatives produced by tt(xd) or
        an initial substring of such a path terminating in a tt(*)
        character. When tt(xd) encounters a path matching any of the
        tt(ignore) directives (interpreting the final tt(*) as `any further
        directory name' specification) it will not display that path in its
        list of alternatives.

        This directive is overruled by the tt(---all) command line option;

    it() loption(input)nl()
       tt(Xd) itself issues the tt(cd) command for the selected directory to
        the shell, and enters other (non alternative-selecting characters)
        into the shell's input. 

       By specifying this option (or by entering tt(input) in the
        configuration file) an extra shell alias or script is not
        necessary. In this tt(input) mode tt(xd) directly inserts the
        requested tt(cd) command into the shell's input buffer. This mode has
        an additional feature: if a key is pressed that is not assiciated with
        a possible directory then the current directory is kept, and the
        character corresponding to the pressed key is entered into the shell's
        input buffer. E.g., if tt(xd ulb) shows a list of five alternatives,
        but the tt(L) key is pressed then tt(xd) ends and the shell's input
        buffer shows tt(l). Merely pressing tt(s) + Enter will then show the
        current directory content. To merely end tt(xd) in this mode the space
        bar or Enter key can be pressed;

        To merely end tt(xd) press the Enter key or space-bar;

    it() loption(no-input)nl()
       The tt(no-input) option can only be specified as a command-line option
        and suppresses the tt(input) option. The tt(no-input) option has no
        effect if the tt(input) option is not specified.

        By suppressing the tt(input) mode tt(xd) writes the name of the
        directory to change to to its standard output stream. This allows
        shell functions to process the directory returned by tt(xd). An
        example of its use is the function tt(pxd) (tt(pushd) using tt(xd))
        shown in section tt(SHELL SCRIPTS);

    it() loption(start-at) tt(origin)nl()
       Defines the default start location of directory searches. Origin
        tt(home) (the default) results in all default searches to start at the
        user's home directory. Origin tt(root) results in searches to begin at
        the disk's root (tt(/)) directory;

    it() loption(traditional)nl()
       tt(Xd) does not use GDS but uses its traditional mode. It overrules a
        tt(generalized-search) directive specified in the configuration file
        as well as the tt(-g) option;

    it() loption(verbose) (soption(V))nl()
       More extensive information about the actions taken by the tt(xd)
        program is written to the standard error stream.

       This option cannot be specified in the configuration file;

    it() loption(version) (soption(v))nl()
           tt(Xd)'s version number is written to the standard error stream
        whereafter tt(xd) terminates.

       This option cannot be specified in the configuration file.
    )

manpagesection(CONFGURATION FILE)

The default configuration file is tt(.xdrc) in the user's home directory. It
may be overruled by the program's tt(--config-file) command-line option.

Empty lines are ignored. Information at and beyond tt(#)-characters is
interpreted as comment and is also ignored.

Directives in tt(xd) configuration files follow the pattern
    verb(
    directive value
    )
    (for some directives there is no tt(value) term).

A line may at most contain one directive, but white space (including comment
at the end of the line) is OK. The same directive may be specified multiple
times, in which case the em(last) directive will be used (except for the
em(ignore) directive, which are all interpreted). All directives are
interpreted em(case sensitively) unless option tt(icase) is specified.
Non-empty lines not beginning with a recognized directive are silently
ignored.

manpagesection(SHELL SCRIPTS)

    Assuming tt(xd) is installed in tt(/usr/bin) scripts can be defined around
tt(xd) for various shell programs. This allows the shell to change directories
under control of tt(xd).

    itemization(
    it() Example 1.

       To use tt(xd) in combination with the tt(pushd) shell command tt(xd)
        itself should not perform directory changes. In such cases the
        tt(no-input) option should be specified in the shell function
        combining tt(pushd) and tt(xd).

       To use tt(xd) with the bf(bash)(1)-shell, the following function
        can be used (which could be added to, e.g., tt(.bash_login)):
       verb(
  pxd()                   # function to do `pushd` using `xd`
  {
      pushd "`/usr/bin/xd --no-input $*`"
  }
        )
       To use tt(xd) with the bf(tcsh)(1)-shell, the following alias
        can be defined in, e.g., the tt(~/.alias) file:
       verb(
  alias  pxd  'pushd `\xd --no-input \!*`'
        )

    it() Example 2.

       If the tt(input) option is specified (as command-line or configuration
        file option) then this example can be ignored.

       To use tt(xd) with the bf(bash)(1)-shell, the following function
        can be used (which could be added to, e.g., tt(.bash_login)):
       verb(
  xd()                    # function to do `cd` using `xd`
  {
      cd "`/usr/bin/xd $*`"
  }
        )
       To use tt(xd) with the bf(tcsh)(1)-shell, the following alias
        can be defined in, e.g., the tt(~/.alias) file:
       verb(
  alias  xd  'cd `\xd \!*`'
        ) 
       Having defined the tt(xd) alias or script tt(xd ...) commands results
        in the automatic (or optional) change of the current working directory
    )

    If your system uses blanks in directory names, the above tcsh-alias cannot
be used as the blanks are interpreted as argument-separaters. In that case the
following alias can be defined as the tt(xd) alias:
        verb(
  alias  xd  'setenv XD "`\xd \!*`";cd "$XD"'
        )


manpagesection(EXAMPLES)

    verb(
    xd ulb      - all directories starting subsequently,
                  with u, l and b origin is default, or
                  specified in .xdrc as  home or root

    xd 0t       - all directories starting with t below the cwd

    xd 2t       - all directories starting at the `grandparent'
                  (2 steps up) of the cwd

    xd --start-at root t
                - all directories at the root starting with t

    xd ..       - all directories starting with a dot in the cwd

    xd .        - the user's home directory

    xd 0        - the current working directory

    xd 1        - the current directory's parent directory
    )
    Assuming the following directories exist:
    verb(
  /usr/lib/bonobo
  /usr/lib/bonobo-activation
  /usr/local/bin
    )
    then the following two tt(ignore) specifications in tt(xd)'s configuration
file will result in ignoring the tt(bonobo) directory alternatives:

    First specification:
    verb(
  ignore /usr/lib/bonobo
  ignore /usr/lib/bonobo-activation
    )
    Second specification:
    verb(
  ignore /usr/lib/bonobo*
    )

manpagefiles()
    itemization(
    it() bf($HOME/.xdrc): Default location of the configuration file
    it() tt(https://fbb-git.gitlab.io/xd/): Home directory
    )

manpagesection(SEE ALSO)
    bf(bash)(1), bf(ioctl)(2), bf(sysctl)(8), bf(tcsh)(1)

manpagebugs()

    None reported

manpagesection(ABOUT xd)

    The program tt(xd) was initially (before 1994) written for the MS-DOS
platform. In 1994 it was redesigned to work under Unix (Linux, AIX) and it was
converted to bf(C++). The original bf(C++) code is still available from tag
tt(start) (tt(https://gitlab.com/fbb-git/xd/tags), find the tt(start) tag and
download) and is funny to look at as it is a remarkable illustration of
bf(C++) code written by bf(C) programmers who had just learned about
bf(C++). Versions tt(2.x) were used until 2008, and in late August 2008 I
rewrote tt(xd) completely, reflecting my then views about bf(C++), eventually
resulting in versions tt(3.x.y) and beyond. The tt(3.x.y) and later versions
extensively use the facilities offered by the bf(bobcat)(7) library.

manpagesection(ACKNOWLEDGEMENTS)

    GDS was added to tt(xd) following a suggestion by Bram Neijt (bram at
neijt dot nl).

manpageauthor()

Frank B. Brokken (f.b.brokken@rug.nl).
