源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

Powershell ISE的抽象语法树编程示例

  • 时间:2020-12-17 01:27 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:Powershell ISE的抽象语法树编程示例
有一个让我非常喜欢Windows PowerShell ISE的理由,就是它将它的基础脚本对象模型暴露给用户,这样就允许用户按照自己的方式和需要去自定义脚本体验。 自定义ISE的核心是$psISE对象。$psISE对象允许用户去控制ISE许多方面的功能。你可以从[url=https://technet.microsoft.com/en-us/library/dd819500.aspx]这里[/url]获取关于$psISE的分层对象模型的介绍,和与这些对象相关联的功能。 这篇文章会讨论你怎样利用PowerShell公开提供的解释器接口,来结合ISE对象模型魅力,去创建脚本分析和快速定位的工具。 想象一下,你不得不分析一个相对庞大的PowerShell脚本。那这个脚本可能是别人写的,也有可能是你自己几个月前写的,扔了好久了。PowerShell ISE已经做了件非常棒的工作了,它提供了脚本环境。你可以通过添加Add-On(附加工具)来扩充它的功能,让你的脚本体验更好,更高效。从PowerShell 3.0开始,脚本的抽象语法树(AST)就可以使用语法解释器接口非常方便的获取了。下面的脚本行会获取当前打开的ISE中的脚本的AST:
[u]复制代码[/u] 代码如下:
$AbstractSyntaxTree = [System.Management.Automation.Language.Parser]:: ParseInput($psISE.CurrentFile.Editor.Text, [ref]$null, [ref]$null)
接下来让我们查询脚本中所有的函数:
[u]复制代码[/u] 代码如下:
$functionsInFile = $AbstractSyntaxTree.FindAll({$args[0] -is  [System.Management.Automation.Language.FunctionDefinitionAst]}, $true)
撇开函数定位的定义,如果我们能回到光标之前出现的位置,那将太漂亮了。实现这个也非常简单。我们所要做的只是存储这些行号,然后按照反转顺序反转他们。(是否有人已经知道了,“堆栈”) 下面的脚本块展示了展示了Go-To Definition的实现。
[u]复制代码[/u] 代码如下:
#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 功能,如果当前Powershell会话中存在的话,以上脚本会显示选中文本的定义。(另外,上面的脚本只是一个简单的例子,假如你的“function”关键字和函数名出现在脚本的同一行。这在PowerShell中并不是必须的,所以如果你的脚本风格不同,你可能需要微调一下逻辑。) 接下来应当是在Add-on(附加工具)菜单上添加这些脚本,并把它作为选中脚本的一个命令。下面两行就可以做这件事。
[u]复制代码[/u] 代码如下:
$global:__ISEGoToAddOnsb1 = {& $global:__ISEGoToAddOnscriptBlockGoTo | Out-Null} $null=$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add( "Go do definition", $global:__ISEGoToAddOnsb1, "F12")
现在来看看我们怎样实现Go-Back 功能,使用我们定义的全局堆栈,几行代码即可:
[u]复制代码[/u] 代码如下:
$global:__ISEGoToAddOnscriptBlockGoBack =   {   try   {   #Pop the line and column numbers from the stack to do a reverse traversal   $global:__ISEGoToAddOncurrLine =   $global:__ISEGoToAddOnstackOfLine.Pop()   $global:__ISEGoToAddOncurrcol =   $global:__ISEGoToAddOnstackOfCol.Pop()   $psISE.CurrentFile.Editor.SetCaretPosition(   $global:__ISEGoToAddOncurrLine, $global:__ISEGoToAddOncurrcol)   $psISE.CurrentFile.Editor.SelectCaretLine();   }   catch [System.Exception]   {   }   }   $global:__ISEGoToAddOnsb2 = {& $global:__ISEGoToAddOnscriptBlockGoBack | Out-Null}   $null=$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Go Back",$global:__ISEGoToAddOnsb2, "Shift+F12")
就到这里了,只用了一些PowerShell代码就实现了Visual Studio中的Go-To Definition (转向定义)和Go-Back(返回)功能。 你还可以继续扩展这个脚本,让它包含这些任务:诸如显示脚本中所有函数,点击函数转到函数定义。作为大家进一步扩展功能的鼓励,我给你看下我的 ISE附加工具现在的样子。 [img]http://files.jb51.net/file_images/article/201503/201532590523141.png?20152259546[/img] 扩展PowerShell ISE 中的 “附加工具”菜单
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部