Daniel Cazzulino's Blog

Go Back to
kzu′s Latest post

PowerShell: vastly improved tab expansion/completion (or do you still miss VS intellisense?)

I’m an intellisense-addict. I hate doing work that my computer can do for me, and typing long namespace and class names certainly fits that category.

[If you know all about PowerShell and just want to try it really quick, go get the straight dope now ;) ]

Out of the box, PowerShell (PS) does fairly minimal tab completion: simple member expansion on variables, variable name expansion and parameter completion on commands. The tab expansion in PS is implemented in a script function named TabExpansion. Turns out that functions are exposed via a custom PS provider (like the file system provider, the registry provider, etc.), meaning you can “cd” into functions and do a dir|gci|get-childitem on it

PS C:\> Get-PSProvider

Name                 Capabilities----                 ------------Alias                ShouldProcessEnvironment          ShouldProcessFileSystem           Filter, ShouldProcessFunction             ShouldProcessRegistry             ShouldProcessVariable             ShouldProcessCertificate          ShouldProcess

PS C:\> cd Function:PS Function:\> gci

CommandType     Name-----------     ----Function        promptFunction        TabExpansionFunction        Clear-HostFunction        moreFunction        helpFunction        man...

Now, being exposed as items over a provider, means that you can also call cat|gc|get-content on it, and see the actual function implementation:

PS Function:\> gc TabExpansion

            # This is the default function to use for tab expansion. It handles simple            # member expansion on variables, variable name expansion and parameter completion            # on commands. It doesn't understand strings so strings containing ; | ( or { may            # cause expansion to fail.

            param($line, $lastWord)

            switch -regex ($lastWord)            {                # Handle property and method expansion...                 ...

You can also do gc function:tabexpantion, directly. That’s pretty amazing. Read more about it at the Windows PowerShell blog.

Being just a function, it can be overridden in your profile, so you can grab the default expansion implementation, and extend it in any way you want. I found a coupleversions of a pretty cool extended tab expansion that did almost what I wanted: full expansion on namespace, type name and members. Looks like the latest version is hosted in CodePlex. With that extended function added to my profile, I can do (first the line ending with the [TAB] keypress, next what’s completed by the tab expansion):

PS C:\> [S[TAB]PS C:\> [SystemPS C:\> [System.Ref[TAB]PS C:\> [System.ReflectionPS C:\> [System.Reflection.As[TAB]PS C:\> [System.Reflection.Assembly]PS C:\> [System.Reflection.Assembly]::LoadW[TAB]PS C:\> [System.Reflection.Assembly]::LoadWithPartialName(PS C:\> [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Build.Framework")

Bold is what I actually had to type. So I entered a 79 characters statement only typing 43 characters! And of those, 28 were the actual method parameter! So, if I don’t count the parameter, I typed 1/3 of what I would have had to before. Amazing boost in speed :) .

There were a couple annoyances with the implementation, though: System and Microsoft were hardcoded as the only top level namespaces recognized, and it didn’t refresh the cache when I loaded an assembly via Assembly.LoadX. Those were significant drawbacks that I set to fix for myself. In the course of fixing it, I ended up re-implementing the caching in a completely different way, that makes for a much faster in-memory cache building process, as well as an optimized storage. Now I can load an assembly on the prompt, and have immediate intellisense on the types from that assembly :)

Get the improved tab expansion from the PowerShell Wiki.