MSH: Decent CD Function

Here’s the CD function I’m currently using.  I think this function helps illustrate the programming capabilities of MSH.  BTW, if you want to use this CD function, drop it into your profile.msh file.

$global:__cd_backstack > $null
$global:__cd_forestack > $null
$global:__profileLoadCount += 1
if ($global:__profileLoadCount -eq 1) {
    $global:__cd_windowTitle = $host.ui.rawui.WindowTitle
}
remove-item alias:cd -ea silentlycontinue

function cd {
    # If more than one arg then error
    if ($args.Length -gt 1) {
        write-error "Takes only one argument."
        return
    }

    # If not already created, initialize ArrayLists to track directories
    if ($global:__cd_backstack -eq $null) {
        $global:__cd_backstack = new-object "System.Collections.ArrayList"
        $global:__cd_forestack = new-object "System.Collections.ArrayList"
    }
   
    $curPath = $(get-location)

    # Dump the directory stack
    if ($args.Length -eq 0) {
        # Command to dump the back & fore stacks
        ""
        "     # Directory Stack:"
        "   — —————-"
        if ($global:__cd_backstack.Count -ge 0) {
            for ($i = 0; $i -lt $global:__cd_backstack.Count; $i++) {
                "   {0,3} {1}" -f $i, $global:__cd_backstack[$i]
            }
        }

        write-host ("-> {0,3} {1}" -f $i++, $curPath)

        if ($global:__cd_forestack.Count -ge 0) {
            $ndx = $i
            for ($i = 0; $i -lt $global:__cd_forestack.Count; $i++) {
                "   {0,3} {1}" -f ($ndx+$i), $global:__cd_forestack[$i]
            }
        }
        ""
        return
    }

    $path = $args[0]   
    # Expand ..[.]+ out to ..\..[\..]+
    if ($path -like "*…*") {
        $regex = new-object System.Text.RegularExpressions.regex("\.\.\.")
        while ($regex.ismatch($path)) {
            $path = $regex.Replace($path, "..\..")
        }
    }

    # Handle the rest of the commands plus the path arg
    if ($path -eq "-?") {
        ""
        "Usage: cd path | command"
        "Commands:"
        "    <no arg> : Display the directory stack"
        "    ~        : Change directory to your `$Home directory"
        "    –        : Change directory to the previous directory in the stack"
        "    +        : Change directory to the next directory in the stack"
        "    -number  : Change directory to the specified directory in the stack"
        "    ..[.]*   : Change directory to a parent directory of the current directory"
        "    -?       : Display this usage information"
        ""
    }
    elseif ($path -eq "-") {
        if ($global:__cd_backstack.Count -eq 0) {
            write-host "`nThe backward stack is empty.`n"
        }
        else {       
            $lastNdx = $global:__cd_backstack.Count – 1
            $prevPath = $global:__cd_backstack[$lastNdx]
            set-location $prevPath
            [void]$global:__cd_forestack.Insert(0, $curPath)
            $global:__cd_backstack.RemoveAt($lastNdx)
        }
    }
    elseif ($path -eq "+") {
        if ($global:__cd_forestack.Count -eq 0) {
            write-host "`nThe foreward stack is empty.`n"
        }
        else {
            $nextPath = $global:__cd_forestack[0]
            set-location $nextPath   
            [void]$global:__cd_backstack.Add($curPath)
            $global:__cd_forestack.RemoveAt(0)
        }
    }
    elseif ($args[0] -like "-[0-9]*")
    {
        [int]$num = $args[0].replace("-","")
        $backstackSize = $global:__cd_backstack.Count
        $forestackSize = $global:__cd_forestack.Count
        if ($num -eq $backstackSize) {
            write-host "`nDude, you’re already there!`n"
        }
        elseif ($num -lt $backstackSize) {
            $selectedPath = $global:__cd_backstack[$num]
            set-location $selectedPath
            [void]$global:__cd_forestack.Insert(0, $curPath)
            $global:__cd_backstack.RemoveAt($num)
           
            [int]$ndx = $num
            [int]$count = $global:__cd_backstack.Count – $ndx
            if ($count -gt 0) {
                $itemsToMove = $global:__cd_backstack.GetRange($ndx, $count)
                $global:__cd_forestack.InsertRange(0, $itemsToMove)
                $global:__cd_backstack.RemoveRange($ndx, $count)
            }
        }
        elseif ($num -gt $backstackSize -and $num -lt ($backstackSize + 1 + $forestackSize)) {
            [int]$ndx = $num – ($backstackSize + 1)
            $selectedPath = $global:__cd_forestack[$ndx]
            set-location $selectedPath
            [void]$global:__cd_backstack.Add($curPath)
            $global:__cd_forestack.RemoveAt($ndx)
           
            [int]$count = $ndx
            if ($count -gt 0) {
                $itemsToMove = $global:__cd_forestack.GetRange(0, $count)
                $global:__cd_backstack.InsertRange(($global:__cd_backstack.Count), $itemsToMove)
                $global:__cd_forestack.RemoveRange(0, $count)
            }
        }
        else {
            write-host "`n$num is out of range.`n"
        }
    }
    else
    {
        set-location $path -ea:stop
        $global:__cd_forestack.Clear();
        [void]$global:__cd_backstack.Add($curPath)
    }
    $host.ui.rawui.windowTitle = $global:__cd_windowTitle + " – " + $(get-location)
}

Advertisements
This entry was posted in Monad. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s