想象一下,你不得不分析一個相對龐大的PowerShell腳本。那這個腳本可能是別人寫的,也有可能是你自己幾個月前寫的,扔了好久了。PowerShell ISE已經(jīng)做了件非常棒的工作了,它提供了腳本環(huán)境。你可以通過添加Add-On(附加工具)來擴充它的功能,讓你的腳本體驗更好,更高效。從PowerShell 3.0開始,腳本的抽象語法樹(AST)就可以使用語法解釋器接口非常方便的獲取了。下面的腳本行會獲取當(dāng)前打開的ISE中的腳本的AST:
撇開函數(shù)定位的定義,如果我們能回到光標(biāo)之前出現(xiàn)的位置,那將太漂亮了。實現(xiàn)這個也非常簡單。我們所要做的只是存儲這些行號,然后按照反轉(zhuǎn)順序反轉(zhuǎn)他們。(是否有人已經(jīng)知道了,“堆棧”)
#Define some useful global variables
$global:__ISEGoToAddOncurrLine=1
$global:__ISEGoToAddOncurrcol=1
$global:__ISEGoToAddOnlineToGoTo=1
$global:__ISEGoToAddOncolToGoTo=1
#We need two stacks - one each for line and column
$global:__ISEGoToAddOnstackOfLine = New-Object System.Collections.Stack
$global:__ISEGoToAddOnstackOfCol = New-Object System.Collections.Stack
#This script block has the logic for the implementation of the Go-To definition functionality
$global:__ISEGoToAddOnscriptBlockGoTo =
{
$AbstractSyntaxTree =[System.Management.Automation.Language.Parser]::ParseInput($psISE.CurrentFile.Editor.Text,[ref]$null, [ref]$null)
$functionsInFile = $AbstractSyntaxTree.FindAll(
{$args[0] -is[System.Management.Automation.Language.FunctionDefinitionAst]}, $true)
#Get the text of the line where we have the cursor
$str = $psISE.CurrentFile.Editor.CaretLineText
#Store them on the stack for later use
$global:__ISEGoToAddOnstackOfLine.Push($psISE.CurrentFile.Editor.CaretLine)
$global:__ISEGoToAddOnstackOfCol.Push($psISE.CurrentFile.Editor.CaretColumn)
$global:__ISEGoToAddOncurrLine = $global:__ISEGoToAddOnstackOfLine.Peek()
$global:__ISEGoToAddOncurrcol = $global:__ISEGoToAddOnstackOfCol.Peek()
#Get the selected text so that it can be used for searching existing functions
$selectedFunction = $psISE.CurrentFile.Editor.SelectedText
#Ensure that the cursor is somewhere between the
word boundaries of the function
$functionsInFile | %{if(($str.Contains($_.name)) `
–and ($global:__ISEGoToAddOncurrcol -ge
$str.IndexOf($_.name)) `
-and ($global:__ISEGoToAddOncurrcol -le
($str.IndexOf($_.name)+$_.name.length))
)
{$selectedFunction = $_.name}
}
if($selectedFunction -ne "")
{
#See if the selected function exists in the current open file
$functionToGoTo = $functionsInFile | ?{$_.name -eq "$selectedFunction"}
$global:__ISEGoToAddOnlineToGoTo = $functionToGoTo.Extent.StartLineNumber
$global:__ISEGoToAddOncolToGoTo = $functionToGoTo.Extent.StartColumnNumber
}
if($functionToGoTo -eq $null)
{
try
{
$comm = Get-Command -Name "$selectedFunction" -ErrorAction SilentlyContinue
$comm.Definition | Out-GridView
}
catch [System.Exception]
{
}
}
else
{
#Select the function definition, assuming the function name immediately follows the keyword 'function'
try
{
$psise.CurrentFile.Editor.Select($global:__ISEGoToAddOnlineToGoTo,
($global:__ISEGoToAddOncolToGoTo+9),
$global:__ISEGoToAddOnlineToGoTo,
($global:__ISEGoToAddOncolToGoTo+8+$selectedFunction.length+1))
}
catch [System.Exception]
{
}
}
}
補充一下,Go-To Definition 功能,如果當(dāng)前Powershell會話中存在的話,以上腳本會顯示選中文本的定義。(另外,上面的腳本只是一個簡單的例子,假如你的“function”關(guān)鍵字和函數(shù)名出現(xiàn)在腳本的同一行。這在PowerShell中并不是必須的,所以如果你的腳本風(fēng)格不同,你可能需要微調(diào)一下邏輯。)
就到這里了,只用了一些PowerShell代碼就實現(xiàn)了Visual Studio中的Go-To Definition (轉(zhuǎn)向定義)和Go-Back(返回)功能。
你還可以繼續(xù)擴展這個腳本,讓它包含這些任務(wù):諸如顯示腳本中所有函數(shù),點擊函數(shù)轉(zhuǎn)到函數(shù)定義。作為大家進一步擴展功能的鼓勵,我給你看下我的 ISE附加工具現(xiàn)在的樣子。