Skip to content

Commit

Permalink
Improved tab completion: New functions to add help hints to parameter…
Browse files Browse the repository at this point in the history
…s (GitHintTabExpansion.ps1)
  • Loading branch information
dodmi committed Apr 9, 2021
1 parent 5a87e8a commit 12a9e70
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 0 deletions.
198 changes: 198 additions & 0 deletions src/GitHintTabExpansion.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<#
The following code is used to add hints to git tab completion
It's called in GitTabExpansion.ps1 / Expand-GitCommand
#>

# This caches the hints to reduce command executions
$script:paramHints = @{}

<#
.DESCRIPTION
Returns a short help for the questioned git mode or $null if no help is available
.PARAMETER Mode
the mode for which the help is needed
#>
function Get-GITModeHint {
param (
[String] $Mode
)

$Command="git"

# Ensure the "command key" is present
if (-not $script:paramHints.containsKey($Command)) { $script:paramHints.add($Command, @{}) }
# Populate the "mode branch" if empty
if (-not $script:paramHints.$Command.containsKey("*")) {
$helpStrings = Invoke-Utf8ConsoleCommand { & $Command --no-pager help -a 2>&1 }
$modeTable = @{}
foreach ($line in $helpStrings) {
if ($line -match "\s{3,3}([^\s]*)\s+(.*)") {
$modeTable.add($matches[1], $matches[2])
}
}
$script:paramHints.$Command.add("*", $modeTable)
}

# Create the results
if ($script:paramHints.$Command."*".containsKey($Mode))
{
return @($Mode, $script:paramHints.$Command."*".$Mode)
} else {
return $null
}
}

<#
.DESCRIPTION
Returns a short help for the provided option or $null if no help is available
.PARAMETER Mode
The mode of git (e.g. commit)
.PARAMETER Parameter
The actual parameter, for which the help is needed
#>
function Get-GITParameterHint {
param (
[String] $Mode,
[String] $Parameter
)

$Command="git"

# Ensure the "command key" is present
if (-not $script:paramHints.containsKey($Command)) { $script:paramHints.add($Command, @{}) }
# Populate the "mode branch" if empty
if (-not $script:paramHints.$Command.containsKey($Mode)) {
$helpStrings = Invoke-Utf8ConsoleCommand { & $Command -C "$($env:temp)" --no-pager $Mode -h 2>&1 }
$preProcessedStrings = @()
# Preprocessing
foreach ($line in $helpStrings)
{
switch -RegEx ($line) {
"^\s{4,4}(-.*)$" {
# this is a line defining a parameter
$preProcessedStrings += "$($Matches[1])"
}
"^\s{25,25}(\s.*)$" {
# this line belongs to the parameter description of the line before
$preProcessedStrings[-1] = "$($preProcessedStrings[-1])$($Matches[1])"
}
}
}
$helpTable = [HashTable]::New(0, [StringComparer]::Ordinal)
foreach ($line in $preProcessedStrings)
{
switch -RegEx ($line) {
# -p, --param This is the parameter p
"^(-.), --([^\s\[]+)\s+([^<]*)$" {
$helpTable.add($matches[1], @(($matches[1] +" ("+ $matches[2] +")"), $matches[3]))
$helpTable.add("--"+$matches[2], @(("--"+ $matches[2]), $matches[3]))
break
}
# --param This is the parameter p
"^--([^\s\[]+)\s+([^<]*)$" {
$helpTable.add("--"+$matches[1], @(("--"+ $matches[1]), $matches[2]))
break
}
# -p This is the parameter p
"^(-[^-])\s+([^<]*)$" {
$helpTable.add($matches[1], @($matches[1], $matches[2]))
break
}
# -p, --param <file> This is the parameter p
"^(-.), --([^\s\[]+)\s(<[^>]*>)\s+(.*)$" {
$helpTable.add($matches[1], @(($matches[1] +" ("+ $matches[2] +")"), ($matches[3]+" | "+$matches[4])))
$helpTable.add("--"+$matches[2], @(("--"+ $matches[2]), ($matches[3]+" | "+$matches[4])))
break
}
# --param <file> This is the parameter p
"^--([^\s\[]+)\s(<[^>]*>)\s+(.*)$" {
$helpTable.add("--"+$matches[1], @(("--"+ $matches[1]), ($matches[2]+" | "+$matches[3])))
break
}
# -p <file> This is the parameter p
"^(-[^-])\s(<[^>]*>)\s+(.*)$" {
$helpTable.add($matches[1], @($matches[1], ($matches[2]+" | "+$matches[3])))
break
}
# -p, --param[=foo] This is the parameter p
"^(-.), --([^\s\[]+)(\[[^\]]*\])\s+(.*)$" {
$helpTable.add($matches[1], @(($matches[1] +" ("+ $matches[2] +")"), ($matches[3]+" | "+$matches[4])))
$helpTable.add("--"+$matches[2], @(("--"+ $matches[2]), ($matches[3]+" | "+$matches[4])))
break
}
# --param[=foo] This is the parameter p
"^--([^\s\[]+)(\[[^\]]*\])\s+(.*)$" {
$helpTable.add("--"+$matches[1], @(("--"+ $matches[1]), ($matches[2]+" | "+$matches[3])))
break
}
# -p[=foo] This is the parameter p
"^(-[^-])(\[[^\]]*\])\s+(.*)$" {
$helpTable.add($matches[1], @($matches[1], ($matches[2]+" | "+$matches[3])))
break
}
}
}
$script:paramHints.$Command.add($Mode, $helpTable)
}

# Create the results
if ($script:paramHints.$Command.$Mode.containsKey($Parameter))
{
return @(($script:paramHints.$Command.$Mode.$Parameter)[0], ($script:paramHints.$Command.$Mode.$Parameter)[1])
} else {
return $null
}
}

<#
.DESCRIPTION
The function takes the original command line and already defined possible completions; it will add the hints depending on the context
.PARAMETER Command
The originating command line
.PARAMETER PossibleParams
The possible parameters as a string array
#>
function Add-HintsToParams {
param (
[String] $Command,
[String[]] $PossibleParams
)

$cmdParts = $Command.split()

# We are only handling git at the moment
if ($Command -notmatch "^$(Get-AliasPattern git) (.*)") { return $PossibleParams }

# Determing git mode, which is the first parameter without dashes, but not the last one, which is "" or an incomplete parameter
$cmdMode = $null
for ($i=1; $i -lt $cmdParts.length-1; $i++) {
if (-not $cmdParts[$i].StartsWith("-")) {
$cmdMode = $cmdParts[$i]
break
}
}

$newTabCompletions = @()
if ($cmdMode) {
# we're searching a parameter for mode $cmdMode
foreach ($p in $PossibleParams) {
$desc = Get-GITParameterHint -Mode $cmdMode -Parameter $p
if ($desc) {
$newTabCompletions += [System.Management.Automation.CompletionResult]::new($p, $desc[0], 'ParameterValue', $desc[1])
} else {
$newTabCompletions += $p
}
}
} else {
# at the moment, we have no command mode in the command line and are looking for a mode
foreach ($m in $PossibleParams) {
$desc = Get-GITModeHint -Mode $m
if ($desc) {
$newTabCompletions += [System.Management.Automation.CompletionResult]::new($m, $desc[0], 'ParameterValue', $desc[1])
} else {
$newTabCompletions += $m
}
}
}
return $newTabCompletions
}
1 change: 1 addition & 0 deletions src/GitTabExpansion.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ function script:expandParamValues($cmd, $param, $filter) {

function Expand-GitCommand($Command) {
$res = Invoke-Utf8ConsoleCommand { GitTabExpansionInternal $Command $Global:GitStatus }
$res = Add-HintsToParams -Command $Command -PossibleParams $res
$res
}

Expand Down
1 change: 1 addition & 0 deletions src/posh-git.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ if (Test-Path Env:\POSHGIT_ENABLE_STRICTMODE) {
. $PSScriptRoot\GitUtils.ps1
. $PSScriptRoot\GitPrompt.ps1
. $PSScriptRoot\GitParamTabExpansion.ps1
. $PSScriptRoot\GitHintTabExpansion.ps1
. $PSScriptRoot\GitTabExpansion.ps1
. $PSScriptRoot\TortoiseGit.ps1

Expand Down

0 comments on commit 12a9e70

Please sign in to comment.