#!/usr/bin/env python

"""This module defines the "%scd" magic command in an IPython session.
The %scd or smart-cd command can find and change to any directory,
without having to know its exact path.  In addition, this module updates
the %cd, %popd, %pushd magic commands so that they record the visited
directory in the scd index file.

The scd executable script must be in the system PATH or the
ipy_scd.scd_executable  must be set to its full path.

To define the %scd magic for every IPython session, add this module
to the c.TerminalIPythonApp.extensions list in the
IPYTHON/profile_default/ipython_config.py file.
"""

import IPython

# Require IPython version 0.13 or later --------------------------------------

ipyversion = []
for w in IPython.__version__.split('.'):
    if not w.isdigit():  break
    ipyversion.append(int(w))

assert ipyversion >= [0, 13], "ipy_scd requires IPython 0.13 or later."

# We have a recent IPython here ----------------------------------------------

import os
import subprocess

from IPython.core.magic import Magics, magics_class, line_magic


class _cdcommands:
    """Namespace class for saving original cd-related commands."""
    cd = None
    pushd = None
    popd = None
    pass


def whereisexecutable(program):
    '''Return a list of files in the system PATH executable by the user.

    program  -- command name that is looked for in the PATH

    Return a list of absolute paths to the program.  When program
    contains any path components, just check if that file is executable.
    '''
    isexecutable = lambda f: os.access(f, os.X_OK) and os.path.isfile(f)
    ppath, pname = os.path.split(program)
    rv = []
    if ppath:
        rv += [program]
    else:
        rv += [os.path.join(d, program)
                for d in os.environ['PATH'].split(os.pathsep)]
    rv = [os.path.abspath(f) for f in rv if isexecutable(f)]
    return rv


# full path to the scd_executable or an empty string when not found
scd_executable = (whereisexecutable('scd') + [''])[0]


@magics_class
class SCDMagics(Magics):

    @line_magic
    def scd(self, arg):