::::::::: PowerShell :::::::::
Thursday, June 08, 2006
  Extending TabExpansion function Part 2
EDIT2*:Pastebin.com site's been down for a while so pasted the colorized source on the bottom...

EDIT*: Modified the source a bit but no functional changes made
Simply changed name of Script variables($_Method, $_ScopeNames) in "begin" blocks to $Script:Method and $Script:ScopeNames respectively according Mow's suggestion.
It can be found here

On completion of PowerShell Tab Completion Part 4, /\/\o\/\/ has suggested me that I should do multilevel scoped variable completion.

I had to cheat a bit by taking Mow's piece of code and turning it into a function for a reuse.
The source is on PowerShell.Pastebin.com.

In my version of TabCompletion, Mow's Multilevel variable completion functionality is in a function called "MultiLevelPropertyExpansion" in "begin" block.
Since list of functionalities are listed on PowerShell Tab Completion Part 4 already, I will just mention one tiny improvement.

In previous version, tab expansion occurred only on the first level
$global:Host.U[tab] -> $global:Host
$global:Host.UI.R[tab] -> $global:Host.UI

But now, multi-level expansion works, as well for scoped variables
$global:Host.u[tab] -> $global:Host.UI
$global:Host.UI.r[tab] -> $global:Host.UI.RawUI

$global:hos[tab].u[tab].r[tab].g[tab] -> $global:Host.UI.RawUI.get_BackgroundColor(


Uhm, "TabExpansion.ps1"
# TabExpansion.ps1
# Version 0.4
# Replacement of default TabExpansion function
# /\/\o\/\/ 2006

function TabExpansion {
# This is the default function that gets called for tab expansion.
# Edited by /\/\o\/\/ from the original to handle :
# - Cached tab completion on types (janel / mow).
# - Methods and properties of types
# - shows get_ methods
# - MultiLevel variable Tab Completion
# - Bracet Removal
# Edited by DBMwS: Added Progressbar and Scoped variable name expansion
# - MultiLevel variable Tab Completion for Scoped variables
# - Changed $_* variables to $Script:*

param($line, $lastWord)

begin {
$Script:Method = [Management.Automation.PSMemberTypes] `
'Method,CodeMethod,ScriptMethod,ParameterizedProperty'
$Script:ScopeNames = @("global", "local", "script", "private")

function MultiLevelPropertyExpansion {
param($parent, $child)

$private:explodedChild = $child.split('.')
$private:level = $explodedChild.Count
$private:value = $parent
if ($private:level -gt 1) {
$private:value += ".$($explodedChild[0..($level - 2)])"
}
$private:pattern = $private:explodedChild[($level -1)] + '*'

# /\/\o\/\/ removed : -and $n -notmatch '^[ge]et_'
# to get get_ methods on WMI and AD objects
$private:result = @()
$private:inputObject = '$' + $private:value
invoke-expression "Get-Member -InputObject $inputObject" |
Sort-Object name | where {$_.name -like $pattern } |
foreach {
$private:result += @{
MemberType = $_.MemberType;
Name = $_.Name;
Value = $private:value;
}
}

return $private:result
}

}

process {
switch -regex ($lastWord)
{
# Handle methods of Types (/\/\o\/\/).
# E.g.) [DateTime]::F[tab]
'(\[.*\])::(\w*)' {
invoke-expression "$($matches[1]) | gm -static" |
where { $n = $_.Name;
$n -like "$($matches[2])*" -and `
$n -notmatch '^([gs]et|op)_'} |
foreach {
if ($_.MemberType -band $Script:Method) {
"$($matches[1])::$($_.name)" + '('
} Else {
"$($matches[1])::$($_.name)"
}
}
break;
}


# Remove Brackets from typename (/\/\o\/\/)
'(\[.*\])=(\w*)' {
"$($matches[1].replace('[','').replace(']',''))"
break;
}


# Cache and Handle namespace and TypeNames (/\/\o\/\/) ..
'\[(.*)' {
$matched = $matches[1]
# only the first time Fill a DataTable with
# Typenames,namespaces and dotCount (level)
if (!($global:dtAssemblies)) {
$global:dtAssemblies = New-Object System.Data.Datatable
[void]($global:dtAssemblies.Columns.Add('name',[string]))
[void]($global:dtAssemblies.Columns.Add('DC',[int]))
[void]($global:dtAssemblies.Columns.Add('NS',[string]))
$assemblies = [appdomain]::CurrentDomain.GetAssemblies()
[void] ($assemblies | % {$i = 0} {
$i++;
[int]$assemblyProgress =
($i * 100) / $assemblies.Length
Write-Progress Caching "$assemblyProgress" `
-perc $assemblyProgress

$types = $_.GetTypes()
$types |
foreach {$j = 0} {
$j++;
if (($j % 500) -eq 0) {
[int]$typeProgress = ($j * 100) / $types.Length
Write-Progress "Adding types" "$typeProgress" `
-perc $typeProgress -id 1
}

$dc = $_.fullName.split(".").count - 1
$ns = $_.namespace
$global:dtAssemblies.rows.add("$_",$dc,$ns)
}
Write-Progress "Adding types" "100" -perc 100 -id 1
})
}

# actual tab completion
$dots = $matches[1].split(".").count - 1
switch ($dots) {
0 {"[System","[Microsoft"}
Default {
$res = @()
$res += $global:dtAssemblies.select(
"ns like '$($matched)%' and dc = $($dots + 1)") |
Select-Object -Unique ns |
foreach {"[$($_.ns)"};
$res += $global:dtAssemblies.select(
"name like '$($matched)%' and dc = $dots") |
foreach {"[$($_.name)]"}
$res
}
}
break;
}


# Handle property and method expansion (MultiLevel added /\/\o\/\/)...
'\$(\w+)\.(.*)' {
# parent variable name e.g.) $host.ui.-> parent is "host"
$parent = $matches[1];
# child variable name e.g.) $host.ui.rawui-> child is "ui.rawui"
$child = $matches[2]

MultiLevelPropertyExpansion $parent $child |
foreach {
$output = "$" + $_["Value"] + '.' + $_["Name"]
if ($_["MemberType"] -band $Script:Method) { $output += "(" }
return $output
}

break;
}


# Handle expansions for both "Scope Variable Name"
# and "Type Variable Names" (DbmwS)
'(.*^\$)(\w+):(\w+)(\.(.*))*$' {
# "function", "variable", "alias", "env:", etc...
$type = $matches[2];
# E.g.) '$' + 'function'
$prefix = $matches[1] + $type;
# e.g. in '$function:C', $typeName will be 'C'
$typeName = $matches[3];
# e.g. in '$global:host.ui.rawui', child will be 'ui.rawui'
$child = $matches[5];

# Scope Variable Name Expansion for $global:, $private:, $script:, $local:
if ($Script:ScopeNames -contains $type) {
if ($child) {
# Handle *multi-level* property and method expansion
MultiLevelPropertyExpansion $typeName $child |
foreach {
$output = $prefix + ":" + $_["Value"] + '.' + $_["Name"]
# Append "(" for method
if ($_["MemberType"] -band $Script:Method) { $output += '('}
return $output
}
} else { # Expand scope variable name
foreach ($scopeVariable in
(Get-Variable "$($typeName)*" -Scope $type |
Sort-Object name)) {
$prefix + ":" + $scopeVariable.Name
}
}
} else {
# Type name expansion for $function:, $variable, $env:, etc
foreach ($t in
(Get-ChildItem ($type + ":" + $typeName + '*') |
Sort-Object name)) {
$prefix + ":" + $t.Name
}
}

break;
}


###
### Default functions below this line
###


# Handle property and method expansion...
'\$(\w+)\.(\w*)' {
$variableName = $matches[1]
$val = Get-Variable -value $variableName
$pat = $matches[2] + '*'
Get-Member -inputobject $val |
where { $n = $_.name; `
$n -like $pat -and $n -notmatch '^([gs]et|op)_' } |
foreach {
if ($_.MemberType -band $Script:Method) {
# Return a method...
'$' + $variableName + '.' + $_.name + '('
} else {
# Return a property...
'$' + $variableName + '.' + $_.name
}
}
break;
}


# Handle variable name expansion...
'(.*^\$)(\w+)$' {
$prefix = $matches[1]
$varName = $matches[2]
foreach ($v in Get-Childitem ('variable:' + $varName + '*')) {
$prefix + $v.name
}
break;
}


# Do completion on parameters (original) ...
'^-([\w0-9]*)' {
$pat = $matches[1] + '*'

# extract the command name from the string
# first split the string into statements and pipeline elements
# This doesnt handle strings however.
$cmdlet = [regex]::Split($line, '[|;]')[-1]

# Extract the trailing unclosed block
if ($cmdlet -match '\{([^\{\}]*)$') {
$cmdlet = $matches[1]
}

# Extract the longest unclosed parenthetical expression...
if ($cmdlet -match '\(([^()]*)$') {
$cmdlet = $matches[1]
}

# take the first space separated token of the remaining string
# as the command to look up. Trim any leading or trailing spaces
# so you dont get leading empty elements.
$cmdlet = $cmdlet.Trim().Split()[0]

# now get the info object for it...
$cmdlet = @(Get-Command -type 'cmdlet,alias' $cmdlet)[0]

# loop resolving aliases...
while ($cmdlet.CommandType -eq 'alias') {
$cmdlet = @(Get-Command -type 'cmdlet,alias' `
$cmdlet.Definition)[0]
}

# expand the parameter sets and emit the matching elements
foreach ($n in ($cmdlet.ParameterSets |
Select-Object -expand parameters)) {
$n = $n.name
if ($n -like $pat) { '-' + $n }
}
break;
}
} # EO switch
} # EO Process
}



Tags :
 
Comments: Post a Comment



<< Home
Let's get lazy with PowerShell!

Name:
Location: Flushing, NY, United States

Experimenting with a different format of blogs...

Links
ARCHIVES
10/01/2005 - 11/01/2005 / 11/01/2005 - 12/01/2005 / 12/01/2005 - 01/01/2006 / 01/01/2006 - 02/01/2006 / 02/01/2006 - 03/01/2006 / 03/01/2006 - 04/01/2006 / 04/01/2006 - 05/01/2006 / 05/01/2006 - 06/01/2006 / 06/01/2006 - 07/01/2006 / 07/01/2006 - 08/01/2006 / 08/01/2006 - 09/01/2006 / 10/01/2006 - 11/01/2006 / 11/01/2006 - 12/01/2006 /


Powered by Blogger