Skip to content

Instantly share code, notes, and snippets.

@powercode
Last active April 10, 2017 20:15
Show Gist options
  • Save powercode/318b7f844d81815551227f62aa41042a to your computer and use it in GitHub Desktop.
Save powercode/318b7f844d81815551227f62aa41042a to your computer and use it in GitHub Desktop.
Generation of ArgumentCompleter for ripgrep
. C:\Users\Staffan\Documents\WindowsPowerShell\JoinItem.ps1
class OptionHelp {
[string] $Short
[string] $Long
[string] $Arg
[string] $Help
}
function Get-RGOption {
[CmdletBinding()]
param()
switch -regex ((D:\repos\ripgrep\target\release\rg.exe --help)) {
'^\s{4}(?<short>-\w), (?<long>--\S+)(?:\s(?<arg>\<\w+\>))?' {
$o = [OptionHelp] @{
Short = $matches.short
Long = $matches.Long
Arg = $matches.Arg
}
[string[]] $help = @()
while ($switch.MoveNext()) {
if ([string]::IsNullOrWhiteSpace($switch.Current)) {
break
}
$Help += $switch.Current.Trim()
}
$o.Help = $help -join [Environment]::NewLine
$o
}
'^\s{8}(?<long>--\S+)(?:\s(?<arg>\<\w+\>))?' {
$o = [OptionHelp] @{
Long = $matches.Long
Arg = $matches.Arg
}
[string[]] $help = @()
while ($switch.MoveNext()) {
if ([string]::IsNullOrWhiteSpace($switch.Current)) {
break
}
$help += $switch.Current.Trim()
}
$o.Help = $help -join [Environment]::NewLine
$o
}
}
}
function New-RGCompleter {
$opt = Get-RGOption
$adds = $opt.foreach{
$short = $_.Short
$long = $_.Long
$help = $_.Help.Replace("'", "''")
if ($help.Contains("`n")) {
$help = @"
@`"
$help
`"@
"@
}
else {
$help = "'$help'"
}
if ($short) {
$list = ($short + ' ' + $_.Arg).TrimEnd()
@"
`t`tif ([RGCompleter]::ShouldAdd("$short", `$wordToComplete, `$prevOpts, `$multiOpts)) {
`t`t`t`$result.Add([CompletionResult]::new("$short", "$list", [CompletionResultType]::ParameterName, $help))
`t`t}
`t
"@
}
else {
$list = ($long + ' ' + $_.Arg).TrimEnd()
@"
`t`tif ([RGCompleter]::ShouldAdd("$long", `$wordToComplete, `$prevOpts, `$multiOpts)) {
`t`t`t`$result.Add([CompletionResult]::new("$long", "$list", [CompletionResultType]::ParameterName, $help))
`t`t}
"@
}
}
$hasArgs = $opt.Where{$_.Arg}.Foreach{if ($_.short) {$_.short}; $_.long} | Join-Item -Quote
$multi = $opt.Where{$_.Help -match 'multiple'}.Foreach{if ($_.short) {$_.short}; $_.long} | Join-Item -Quote
$ofs = [Environment]::NewLine
@"
using namespace System.Collections.Generic
using namespace System.Management.Automation
class RGCompleter {
static [bool] ShouldAdd([string] `$completionText, [string] `$wordToComplete, [string[]] `$previousCommand, [string[]] `$multiOpt) {
if (`$completionText.StartsWith(`$wordToComplete, [StringComparison]::OrdinalIgnoreCase)){
if (`$completionText -in `$previousCommand -and `$completionText -notin `$multiOpt) {
return `$false
}
return `$true
}
return `$false
}
static [string[]] GetPreviousOptions([Language.CommandAst] `$ast, [int] `$cursorColumn) {
if (`$ast.CommandElements.Count -eq 1) {
return [string[]]::new(0)
}
return `$ast.CommandElements.Foreach{`$_.Extent.Text}
}
static [List[CompletionResult]] CompleteArgument([string] `$command, [string] `$previousCommand, [string]`$wordToComplete) {
`$result = [List[CompletionResult]]::new(10)
switch -regex -CaseSensitive (`$previousCommand){
'-(A|B|C)' {
(1..10).Where{"`$_".StartsWith(`$wordToComplete)}.Foreach{
`$result.Add([CompletionResult]::new(`$_,`$_, [CompletionResultType]::ParameterValue, `$_))
}
}
'--color(?!s)' {
('never','auto','always','ansi').Where{"`$_".StartsWith(`$wordToComplete)}.Foreach{
`$result.Add([CompletionResult]::new(`$_,`$_, [CompletionResultType]::ParameterValue, `$_))
}
}
'--colors' {
`$type = 'path','line','match'
`$attrib = 'fg','bg','style','none'
`$style ='nobold','bold','nointense','intense'
`$color = 'red','blue','green','cyan','magenta','yellow','white','black'
`$t,`$a,`$v = `$wordToComplete.Trim().Split(':')
`$completions = `$type.Foreach{
`$t=`$_
"`${t}:none"
('fg','bg').Foreach{`$a = `$_; `$color.Foreach{"`${t}:`${a}:`$_"}}
`$style.Foreach{"`${t}:style:`$_"}
}.Where{
`$_.StartsWith(`$wordToComplete, [Stringcomparison]::OrdinalIgnoreCase)
}.Foreach{`$result.Add([CompletionResult]::new(`$_, `$_, [CompletionResultType]::ParameterValue, `$_))}
}
'-(T|t)' {
(& `$command --type-list).Foreach{
`$c, `$t = `$_.Split(":",2)
if (`$c.StartsWith(`$wordToComplete, [StringComparison]::OrdinalIgnoreCase)) {
`$r = [CompletionResult]::new(`$c,`$c, [CompletionResultType]::ParameterValue, `$t)
`$result.Add(`$r)
}
}
}
}
return `$result;
}
static [List[CompletionResult]] CompleteInput([string] `$wordToComplete, [Language.CommandAst] `$ast, [int] `$cursorColumn){
`$hasArgOpts = $hasArgs
`$multiOpts = $multi
`$prevOpts = [RGCompleter]::GetPreviousOptions(`$ast, `$cursorColumn)
`$command = `$ast.CommandElements[0].Extent.Text
if (`$prevOpts.Length -gt 1 -and `$wordToComplete) {
`$previous = `$prevOpts[-2]
}
else {
`$previous = `$prevOpts[-1]
}
if (`$previous -in `$hasArgOpts) {
return [RGCompleter]::CompleteArgument(`$command, `$previous, `$wordToComplete)
}
`$result = [List[CompletionResult]]::new(60)
$adds
return `$result
}
}
Register-ArgumentCompleter -native -CommandName 'rg.exe' -scriptblock {
param([string] `$wordToComplete, [Language.CommandAst] `$ast, [int] `$cursorPosition)
return [RGCompleter]::CompleteInput(`$wordToComplete, `$ast, `$cursorPosition)
}
function Test-Completion{
param([string] `$cmd,
[string] `$wordToComplete,
[int]`$cursorColumn
)
if (`$cursorColumn -eq 0){
`$cursorColumn = `$cmd.Length
}
`$tokens = `$null
`$errors =`$null
`$ast = [Language.Parser]::ParseInput(`$cmd, [ref]`$tokens, [ref]`$errors)
`$commandAst = `$ast.EndBlock.Statements.PipelineElements[0]
[RGCompleter]::CompleteInput(`$wordToComplete, `$commandAst, `$cursorColumn)
}
"@
}
New-RGCompleter | Set-Content C:\Users\Staffan\Documents\WindowsPowerShell\rgcompleter.ps1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment