Skip to content

Commit 920f44f

Browse files
committed
Fix options autocompletion showing for GitAliases.Extra shortcuts
1 parent a43c3a5 commit 920f44f

2 files changed

Lines changed: 130 additions & 9 deletions

File tree

modules/GitAliases.Extras/GitAliases.Extras.psm1

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,59 @@ function Convert-ToPowerShellBranchCompletionText {
7070
return $BranchName
7171
}
7272

73+
function Get-GitLongOptionCompletions {
74+
param(
75+
[Parameter(Mandatory = $true)]
76+
[string]$SubCommand,
77+
[Parameter(Mandatory = $true)]
78+
[string]$WordToComplete
79+
)
80+
81+
if (-not $WordToComplete.StartsWith('-')) {
82+
return @()
83+
}
84+
85+
try {
86+
$helpText = git $SubCommand -h 2>&1 | Out-String
87+
if (-not $helpText) { return @() }
88+
89+
$rawTokens = [regex]::Matches($helpText, '--[^\s,]+') |
90+
ForEach-Object { $_.Value } |
91+
Sort-Object -Unique
92+
93+
$expanded = foreach ($token in $rawTokens) {
94+
$clean = $token.Trim().TrimEnd(',', ';')
95+
$clean = $clean -replace '<.*$', ''
96+
97+
if ($clean -match '^--\[no-\](.+)$') {
98+
$suffix = $matches[1] -replace '\[.*$', ''
99+
if ($suffix) {
100+
"--$suffix"
101+
"--no-$suffix"
102+
}
103+
continue
104+
}
105+
106+
$clean = $clean -replace '\[.*$', ''
107+
if ($clean.StartsWith('--')) {
108+
$clean
109+
}
110+
}
111+
112+
$options = $expanded |
113+
Sort-Object -Unique |
114+
Where-Object { $_ -like "$WordToComplete*" }
115+
116+
if (-not $options) { return @() }
117+
118+
return $options | ForEach-Object {
119+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_)
120+
}
121+
} catch {
122+
return @()
123+
}
124+
}
125+
73126

74127
# --- Custom Git Command Functions ---
75128
function UpMerge {
@@ -353,12 +406,21 @@ function Register-GitAliasCompletion {
353406
if ($gitCursorPosition -lt 0) { $gitCursorPosition = 0 }
354407
if ($gitCursorPosition -gt $gitLine.Length) { $gitCursorPosition = $gitLine.Length }
355408

356-
# Use posh-git's official completion function
357-
if (Get-Command GitTabExpansion -ErrorAction SilentlyContinue) {
358-
try {
359-
$results = GitTabExpansion $gitLine $gitCursorPosition
409+
# Delegate to native completion for `git <subcommand> ...`.
410+
# This preserves completion for long options (e.g. --track, --detach)
411+
# and other git-specific argument completion behavior.
412+
try {
413+
$nativeCompletion = [System.Management.Automation.CommandCompletion]::CompleteInput(
414+
$gitLine,
415+
$gitCursorPosition,
416+
$null
417+
)
418+
if ($null -ne $nativeCompletion -and
419+
$null -ne $nativeCompletion.CompletionMatches -and
420+
$nativeCompletion.CompletionMatches.Count -gt 0) {
421+
$delegateMatches = @($nativeCompletion.CompletionMatches)
360422
if ($subCommand -in @('checkout', 'switch', 'merge', 'rebase', 'branch', 'reset', 'revert')) {
361-
return $results | ForEach-Object {
423+
$delegateMatches = @($nativeCompletion.CompletionMatches | ForEach-Object {
362424
if ($null -eq $_) { return }
363425
$completionText = $_.CompletionText
364426
if ($completionText -is [string] -and $completionText.StartsWith('#')) {
@@ -372,16 +434,40 @@ function Register-GitAliasCompletion {
372434
}
373435

374436
return $_
437+
})
438+
}
439+
440+
if ($wordToComplete -like '-*') {
441+
$optionCompletions = Get-GitLongOptionCompletions -SubCommand $subCommand -WordToComplete $wordToComplete
442+
if ($optionCompletions -and $optionCompletions.Count -gt 0) {
443+
$combined = @()
444+
$seen = @{}
445+
foreach ($item in @($delegateMatches + $optionCompletions)) {
446+
if ($null -eq $item) { continue }
447+
$key = $item.CompletionText
448+
if (-not $seen.ContainsKey($key)) {
449+
$combined += $item
450+
$seen[$key] = $true
451+
}
452+
}
453+
454+
return $combined
375455
}
376456
}
377457

378-
return $results
379-
} catch {
380-
Write-Warning "posh-git's GitTabExpansion failed for alias '$commandName'."
458+
return $delegateMatches
381459
}
460+
} catch {
461+
Write-Warning "Native completion delegation failed for alias '$commandName'."
462+
}
463+
464+
# Long option fallback when native completion isn't available.
465+
$optionCompletions = Get-GitLongOptionCompletions -SubCommand $subCommand -WordToComplete $wordToComplete
466+
if ($optionCompletions -and $optionCompletions.Count -gt 0) {
467+
return $optionCompletions
382468
}
383469

384-
# Fallback if posh-git isn't loaded or its function fails
470+
# Final fallback when delegated completion is unavailable
385471
if ($subCommand -in @('checkout', 'switch', 'merge', 'rebase', 'branch', 'reset', 'revert')) {
386472
try {
387473
$branches = git branch -a --format='%(refname:short)' |

tests/GitAliases.Extras.Tests.ps1

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
$ErrorActionPreference = 'Stop'
22
Set-StrictMode -Version Latest
3+
$script:HasGcoAlias = [bool](Get-Command gco -ErrorAction SilentlyContinue)
34

45
BeforeAll {
56
function Script:Invoke-GitCommand {
@@ -69,7 +70,13 @@ BeforeAll {
6970
[string]$script:RepoRoot = Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..') |
7071
Select-Object -ExpandProperty Path -First 1
7172
$script:ModuleManifest = Join-Path $script:RepoRoot 'modules\GitAliases.Extras\GitAliases.Extras.psd1'
73+
74+
if (Get-Module -ListAvailable -Name git-aliases) {
75+
Import-Module git-aliases -DisableNameChecking -ErrorAction SilentlyContinue
76+
}
77+
7278
Import-Module $script:ModuleManifest -Force
79+
$script:HasGcoAlias = [bool](Get-Command gco -ErrorAction SilentlyContinue)
7380
}
7481

7582
AfterAll {
@@ -189,6 +196,34 @@ Describe 'gfp integration' {
189196
}
190197

191198
Describe 'gsw integration' {
199+
It 'completes long options for gsw alias' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) {
200+
Push-Location $script:RepoRoot
201+
try {
202+
$line = 'gsw --'
203+
$result = TabExpansion2 -inputScript $line -cursorColumn $line.Length
204+
} finally {
205+
Pop-Location
206+
}
207+
208+
$result.CompletionMatches.Count | Should -BeGreaterThan 0
209+
$completionTexts = @($result.CompletionMatches | Select-Object -ExpandProperty CompletionText)
210+
$completionTexts | Should -Contain '--track'
211+
}
212+
213+
It 'completes long options for gco alias from git-aliases module' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue) -or -not $script:HasGcoAlias) {
214+
Push-Location $script:RepoRoot
215+
try {
216+
$line = 'gco --'
217+
$result = TabExpansion2 -inputScript $line -cursorColumn $line.Length
218+
} finally {
219+
Pop-Location
220+
}
221+
222+
$result.CompletionMatches.Count | Should -BeGreaterThan 0
223+
$completionTexts = @($result.CompletionMatches | Select-Object -ExpandProperty CompletionText)
224+
$completionTexts | Should -Contain '--detach'
225+
}
226+
192227
It 'returns PowerShell-safe completion text for branches starting with # when escaped prefix is used' -Skip:(-not (Get-Command git -ErrorAction SilentlyContinue)) {
193228
$tempRoot = Join-Path ([IO.Path]::GetTempPath()) ("gsw-complete-" + [guid]::NewGuid().Guid)
194229
$repoPath = Join-Path $tempRoot 'repo'

0 commit comments

Comments
 (0)