.. _intro_zsh_directory_stacks:

Directory Stacks
================

If you use csh, you may know about directory stacks. The :literal:`pushd` command puts the current directory on the stack, and changes to a new directory; the :literal:`popd` command pops a directory off the stack and changes to it.

.. code-block:: text
   :caption: pushd and the directory stack
   :name: directory_stacks_pushd_popd

   phoenix% cd 
   phoenix% PROMPT='Z %~> '
   Z ~> pushd /tmp
   /tmp ~
   Z /tmp> pushd /usr/etc
   /usr/etc /tmp ~
   Z /usr/etc> pushd /usr/bin
   /usr/bin /usr/etc /tmp ~
   Z /usr/bin> popd
   /usr/etc /tmp ~
   Z /usr/etc> popd
   /tmp ~
   Z /tmp> pushd /etc
   /etc /tmp ~
   Z /etc> popd 
   /tmp ~

:literal:`zsh`'s directory stack commands work similarly.  One difference is the way :literal:`pushd` is handled if no arguments are given.  As in csh, this exchanges the top two elements of the directory stack:

.. code-block:: text
   :caption: pushd swaps top two
   :name: directory_stacks_pushd_swap

   Z /tmp> dirs
   /tmp ~
   Z /tmp> pushd
   ~ /tmp

unless the stack only has one entry:

.. code-block:: text
   :caption: pushd with one entry
   :name: directory_stacks_pushd_one_entry

   Z ~> popd
   /tmp
   Z /tmp> dirs
   /tmp
   Z /tmp> pushd
   ~ /tmp
   Z ~>

.. _PUSHD_TO_HOME:

.. index:: single: PUSHD_TO_HOME

or unless the :literal:`PUSHD_TO_HOME` option is set:

.. code-block:: text
   :caption: PUSHD_TO_HOME option
   :name: directory_stacks_pushd_to_home

   Z ~> setopt pushdtohome
   Z ~> pushd
   ~ ~ /tmp

As an alternative to using directory stacks in this manner, we can get something like a :emphasis:`directory history` by setting a few more options and parameters:

.. code-block:: text
   :caption: Directory history with AUTOPUSHD
   :name: directory_stacks_autopushd

   ~> DIRSTACKSIZE=8
   ~> setopt autopushd pushdminus pushdsilent pushdtohome
   ~> alias dh='dirs -v'
   ~> cd /tmp
   /tmp> cd /usr
   /usr> cd bin
   /usr/bin> cd ../pub
   /usr/pub> dh
   0       /usr/pub
   1       /usr/bin
   2       /usr
   3       /tmp
   4       ~
   /usr/pub> cd -3
   /tmp> dh
   0       /tmp
   1       /usr/pub
   2       /usr/bin
   3       /usr
   4       ~
   /tmp> ls ~2/df
   /usr/bin/df
   /tmp> cd -4
   ~>

Note that :literal:`~2` expanded to the second directory in the history list, and that :literal:`cd -3` recalled the third directory in the list.

.. _AUTO_PUSHD:

.. index:: single: AUTO_PUSHD

.. _PUSHD_MINUS:

.. index:: single: PUSHD_MINUS

You may be wondering what all those options do. :literal:`AUTO_PUSHD` made :literal:`cd` act like :literal:`pushd`. (\ :literal:`alias cd=pushd` is not sufficient, for various reasons.) :literal:`PUSHD_MINUS` swapped the meaning of :literal:`cd +1` and :literal:`cd -1`; we want them to mean the opposite of what they mean in csh, because it makes more sense in this scheme, and it's easier to type:

.. code-block:: text
   :caption: PUSHD_MINUS with cd +n
   :name: directory_stacks_pushd_minus

   ~> dh
   0       ~
   1       /tmp
   2       /usr/pub
   3       /usr/bin
   4       /usr
   ~> unsetopt pushdminus
   ~> cd +1
   /tmp> dh
   0       /tmp
   1       ~
   2       /usr/pub
   3       /usr/bin
   4       /usr
   /tmp> cd +2
   /usr/pub>

.. _PUSHD_SILENT:

.. index:: single: PUSHD_SILENT

:literal:`PUSHD_SILENT` keeps the shell from printing the directory stack each time we do a :literal:`cd`, and :literal:`PUSHD_TO_HOME` we mentioned earlier:

.. code-block:: text
   :caption: PUSHD_SILENT hides stack
   :name: directory_stacks_pushd_silent

   /usr/pub> unsetopt pushdsilent
   /usr/pub> cd /etc
   /etc /usr/pub /tmp ~ /usr/bin /usr
   /etc> cd
   ~ /etc /usr/pub /tmp ~ /usr/bin /usr
   ~> unsetopt pushdtohome
   ~> cd
   /etc ~ /usr/pub /tmp ~ /usr/bin /usr
   /etc>

:literal:`DIRSTACKSIZE` keeps the directory stack from getting too large, much like :emphasis:`HISTSIZE`:

.. code-block:: text
   :caption: DIRSTACKSIZE limits stack
   :name: directory_stacks_dirstacksize

   /etc> setopt pushdsilent
   /etc> cd /
   /> cd /
   /> cd /
   /> cd /
   /> cd /
   /> cd /
   /> cd /
   /> cd /
   /> dh
   0       /
   1       /
   2       /
   3       /
   4       /
   5       /
   6       /
   7       /
