Sunday, July 03, 2011

Powershell Tabexpansion

There must be a better way to do this, but one of the funny things I do is setup variables in Powershell for paths that I frequently navigate to. So my profile.ps1 file has lines like this:
$GLOBAL:g1 = "C:\whatever\some\path"
$GLOBAL:l1 = "C:\whatever\some\other\path"
, and I issue a lot of commands like cd $g1
ls $l1
cp $l1/bla $g1
... that kind of thing.

One thing that drives me crazy is that I often want to do something with a sub-directory or file under a path referenced by one of my jump variables, but Powershell tabexpansion won't expand the variable for me ... until now! I finally decided to look into how to customize Powershell's tab expansion, and sure enough there's a TabExpansion function that I can override. This bLog post has the details.
Anyway, I defined my own TabExpansion function in profile.ps1 with a patch that just adds one line to the default function. The default has this regex-switch case that expands variable names:

            foreach ($_v in Get-ChildItem ($_varName + '*') | sort Name)
            { 
                $_nameFound = $_v.name
                $(if ($_nameFound.IndexOfAny($_varsRequiringQuotes) -eq -1) {'{0}{1}{2}'}
                else {'{0}{{{1}{2}}}'}) -f $_prefix, $_provider, $_nameFound
            }
, and my patch just adds a line to the end of the loop that also returns the value of the expanded variable:
            foreach ($_v in Get-ChildItem ($_varName + '*') | sort Name)
            { 
                $_nameFound = $_v.name
                $(if ($_nameFound.IndexOfAny($_varsRequiringQuotes) -eq -1) {'{0}{1}{2}'}
                else {'{0}{{{1}{2}}}'}) -f $_prefix, $_provider, $_nameFound
                $_v.value
            }
Now when I enter 'ls $g', then for each tab Powershell scrolls through a series of possible expansions: $g1, value of $g1, $gr, value of $gr, then back to $g1. If I want to list some sub-directory of $g1, then when the value of $g1 shows up, I just enter a '/' and start tabbing again to find the sub-directory. Hopefully that makes sense. Let me know if there's a better approach!

No comments: