Skip to content

Commit 12a9e70

Browse files
committed
Improved tab completion: New functions to add help hints to parameters (GitHintTabExpansion.ps1)
1 parent 5a87e8a commit 12a9e70

3 files changed

Lines changed: 200 additions & 0 deletions

File tree

src/GitHintTabExpansion.ps1

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
<#
2+
The following code is used to add hints to git tab completion
3+
It's called in GitTabExpansion.ps1 / Expand-GitCommand
4+
#>
5+
6+
# This caches the hints to reduce command executions
7+
$script:paramHints = @{}
8+
9+
<#
10+
.DESCRIPTION
11+
Returns a short help for the questioned git mode or $null if no help is available
12+
.PARAMETER Mode
13+
the mode for which the help is needed
14+
#>
15+
function Get-GITModeHint {
16+
param (
17+
[String] $Mode
18+
)
19+
20+
$Command="git"
21+
22+
# Ensure the "command key" is present
23+
if (-not $script:paramHints.containsKey($Command)) { $script:paramHints.add($Command, @{}) }
24+
# Populate the "mode branch" if empty
25+
if (-not $script:paramHints.$Command.containsKey("*")) {
26+
$helpStrings = Invoke-Utf8ConsoleCommand { & $Command --no-pager help -a 2>&1 }
27+
$modeTable = @{}
28+
foreach ($line in $helpStrings) {
29+
if ($line -match "\s{3,3}([^\s]*)\s+(.*)") {
30+
$modeTable.add($matches[1], $matches[2])
31+
}
32+
}
33+
$script:paramHints.$Command.add("*", $modeTable)
34+
}
35+
36+
# Create the results
37+
if ($script:paramHints.$Command."*".containsKey($Mode))
38+
{
39+
return @($Mode, $script:paramHints.$Command."*".$Mode)
40+
} else {
41+
return $null
42+
}
43+
}
44+
45+
<#
46+
.DESCRIPTION
47+
Returns a short help for the provided option or $null if no help is available
48+
.PARAMETER Mode
49+
The mode of git (e.g. commit)
50+
.PARAMETER Parameter
51+
The actual parameter, for which the help is needed
52+
#>
53+
function Get-GITParameterHint {
54+
param (
55+
[String] $Mode,
56+
[String] $Parameter
57+
)
58+
59+
$Command="git"
60+
61+
# Ensure the "command key" is present
62+
if (-not $script:paramHints.containsKey($Command)) { $script:paramHints.add($Command, @{}) }
63+
# Populate the "mode branch" if empty
64+
if (-not $script:paramHints.$Command.containsKey($Mode)) {
65+
$helpStrings = Invoke-Utf8ConsoleCommand { & $Command -C "$($env:temp)" --no-pager $Mode -h 2>&1 }
66+
$preProcessedStrings = @()
67+
# Preprocessing
68+
foreach ($line in $helpStrings)
69+
{
70+
switch -RegEx ($line) {
71+
"^\s{4,4}(-.*)$" {
72+
# this is a line defining a parameter
73+
$preProcessedStrings += "$($Matches[1])"
74+
}
75+
"^\s{25,25}(\s.*)$" {
76+
# this line belongs to the parameter description of the line before
77+
$preProcessedStrings[-1] = "$($preProcessedStrings[-1])$($Matches[1])"
78+
}
79+
}
80+
}
81+
$helpTable = [HashTable]::New(0, [StringComparer]::Ordinal)
82+
foreach ($line in $preProcessedStrings)
83+
{
84+
switch -RegEx ($line) {
85+
# -p, --param This is the parameter p
86+
"^(-.), --([^\s\[]+)\s+([^<]*)$" {
87+
$helpTable.add($matches[1], @(($matches[1] +" ("+ $matches[2] +")"), $matches[3]))
88+
$helpTable.add("--"+$matches[2], @(("--"+ $matches[2]), $matches[3]))
89+
break
90+
}
91+
# --param This is the parameter p
92+
"^--([^\s\[]+)\s+([^<]*)$" {
93+
$helpTable.add("--"+$matches[1], @(("--"+ $matches[1]), $matches[2]))
94+
break
95+
}
96+
# -p This is the parameter p
97+
"^(-[^-])\s+([^<]*)$" {
98+
$helpTable.add($matches[1], @($matches[1], $matches[2]))
99+
break
100+
}
101+
# -p, --param <file> This is the parameter p
102+
"^(-.), --([^\s\[]+)\s(<[^>]*>)\s+(.*)$" {
103+
$helpTable.add($matches[1], @(($matches[1] +" ("+ $matches[2] +")"), ($matches[3]+" | "+$matches[4])))
104+
$helpTable.add("--"+$matches[2], @(("--"+ $matches[2]), ($matches[3]+" | "+$matches[4])))
105+
break
106+
}
107+
# --param <file> This is the parameter p
108+
"^--([^\s\[]+)\s(<[^>]*>)\s+(.*)$" {
109+
$helpTable.add("--"+$matches[1], @(("--"+ $matches[1]), ($matches[2]+" | "+$matches[3])))
110+
break
111+
}
112+
# -p <file> This is the parameter p
113+
"^(-[^-])\s(<[^>]*>)\s+(.*)$" {
114+
$helpTable.add($matches[1], @($matches[1], ($matches[2]+" | "+$matches[3])))
115+
break
116+
}
117+
# -p, --param[=foo] This is the parameter p
118+
"^(-.), --([^\s\[]+)(\[[^\]]*\])\s+(.*)$" {
119+
$helpTable.add($matches[1], @(($matches[1] +" ("+ $matches[2] +")"), ($matches[3]+" | "+$matches[4])))
120+
$helpTable.add("--"+$matches[2], @(("--"+ $matches[2]), ($matches[3]+" | "+$matches[4])))
121+
break
122+
}
123+
# --param[=foo] This is the parameter p
124+
"^--([^\s\[]+)(\[[^\]]*\])\s+(.*)$" {
125+
$helpTable.add("--"+$matches[1], @(("--"+ $matches[1]), ($matches[2]+" | "+$matches[3])))
126+
break
127+
}
128+
# -p[=foo] This is the parameter p
129+
"^(-[^-])(\[[^\]]*\])\s+(.*)$" {
130+
$helpTable.add($matches[1], @($matches[1], ($matches[2]+" | "+$matches[3])))
131+
break
132+
}
133+
}
134+
}
135+
$script:paramHints.$Command.add($Mode, $helpTable)
136+
}
137+
138+
# Create the results
139+
if ($script:paramHints.$Command.$Mode.containsKey($Parameter))
140+
{
141+
return @(($script:paramHints.$Command.$Mode.$Parameter)[0], ($script:paramHints.$Command.$Mode.$Parameter)[1])
142+
} else {
143+
return $null
144+
}
145+
}
146+
147+
<#
148+
.DESCRIPTION
149+
The function takes the original command line and already defined possible completions; it will add the hints depending on the context
150+
.PARAMETER Command
151+
The originating command line
152+
.PARAMETER PossibleParams
153+
The possible parameters as a string array
154+
#>
155+
function Add-HintsToParams {
156+
param (
157+
[String] $Command,
158+
[String[]] $PossibleParams
159+
)
160+
161+
$cmdParts = $Command.split()
162+
163+
# We are only handling git at the moment
164+
if ($Command -notmatch "^$(Get-AliasPattern git) (.*)") { return $PossibleParams }
165+
166+
# Determing git mode, which is the first parameter without dashes, but not the last one, which is "" or an incomplete parameter
167+
$cmdMode = $null
168+
for ($i=1; $i -lt $cmdParts.length-1; $i++) {
169+
if (-not $cmdParts[$i].StartsWith("-")) {
170+
$cmdMode = $cmdParts[$i]
171+
break
172+
}
173+
}
174+
175+
$newTabCompletions = @()
176+
if ($cmdMode) {
177+
# we're searching a parameter for mode $cmdMode
178+
foreach ($p in $PossibleParams) {
179+
$desc = Get-GITParameterHint -Mode $cmdMode -Parameter $p
180+
if ($desc) {
181+
$newTabCompletions += [System.Management.Automation.CompletionResult]::new($p, $desc[0], 'ParameterValue', $desc[1])
182+
} else {
183+
$newTabCompletions += $p
184+
}
185+
}
186+
} else {
187+
# at the moment, we have no command mode in the command line and are looking for a mode
188+
foreach ($m in $PossibleParams) {
189+
$desc = Get-GITModeHint -Mode $m
190+
if ($desc) {
191+
$newTabCompletions += [System.Management.Automation.CompletionResult]::new($m, $desc[0], 'ParameterValue', $desc[1])
192+
} else {
193+
$newTabCompletions += $m
194+
}
195+
}
196+
}
197+
return $newTabCompletions
198+
}

src/GitTabExpansion.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ function script:expandParamValues($cmd, $param, $filter) {
302302

303303
function Expand-GitCommand($Command) {
304304
$res = Invoke-Utf8ConsoleCommand { GitTabExpansionInternal $Command $Global:GitStatus }
305+
$res = Add-HintsToParams -Command $Command -PossibleParams $res
305306
$res
306307
}
307308

src/posh-git.psm1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ if (Test-Path Env:\POSHGIT_ENABLE_STRICTMODE) {
1515
. $PSScriptRoot\GitUtils.ps1
1616
. $PSScriptRoot\GitPrompt.ps1
1717
. $PSScriptRoot\GitParamTabExpansion.ps1
18+
. $PSScriptRoot\GitHintTabExpansion.ps1
1819
. $PSScriptRoot\GitTabExpansion.ps1
1920
. $PSScriptRoot\TortoiseGit.ps1
2021

0 commit comments

Comments
 (0)