core/completion/win.ps1

Add-Member -InputObject $PSCompletions -MemberType ScriptMethod generate_completion {
    if ($PSCompletions.config.enable_menu_enhance -and $PSCompletions.config.enable_menu) {
        Add-Member -InputObject $PSCompletions -MemberType ScriptMethod handle_completion {
            Set-PSReadLineKeyHandler -Key $PSCompletions.config.trigger_key -ScriptBlock {
                $buffer = ''
                $cursorPosition = 0
                [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$buffer, [ref]$cursorPosition)
                if (!$cursorPosition) {
                    return
                }

                # 是否是按下空格键触发的补全
                $space_tab = if ($buffer[-1] -eq ' ') { 1 }else { 0 }
                # 使用正则表达式进行分割,将命令行中的每个参数分割出来,形成一个数组, 引号包裹的内容会被当作一个参数,且数组会包含 "--"
                $input_arr = @()
                $matches = [regex]::Matches($buffer, "(?:`"[^`"]*`"|'[^']*'|\S)+")
                foreach ($match in $matches) { $input_arr += $match.Value }

                # 触发补全的值,此值可能是别名或命令名
                $root = $alias = $input_arr[0]

                $PSCompletions.menu.by_TabExpansion2 = $false

                if ($PSCompletions.data.aliasMap[$alias] -ne $null -and $input_arr[-1] -notmatch '^(?:\.\.?|~)?(?:[/\\]).*') {
                    if ($buffer -eq $alias) { return }
                    # 原始的命令名,也是 completions 目录下的命令目录名
                    $PSCompletions.root_cmd = $root = $PSCompletions.data.aliasMap.$alias

                    $input_arr = if ($input_arr.Count -le 1) { , @() } else { $input_arr[1..($input_arr.Count - 1)] }

                    $filter_list = $PSCompletions.get_completion()
                    $result = $PSCompletions.menu.show_module_menu($filter_list)
                    if ($result -ne $null) {
                        if ($space_tab) {
                            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($result)
                        }
                        else {
                            $input_arr = if ($input_arr.Count -le 1) { , @() } else { $input_arr[0..($input_arr.Count - 2)] }
                            $result = if ($input_arr.Count -eq 0) { "$alias $result" }else { "$alias $($input_arr -join ' ') $result" }
                            [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $buffer.Length, $result)
                        }
                    }
                }
                else {
                    try {
                        $completion = TabExpansion2 $buffer $cursorPosition
                    }
                    catch {
                        return
                    }
                    if (!$completion.CompletionMatches) {
                        return
                    }

                    $filter_list = @()
                    foreach ($item in $completion.CompletionMatches) {
                        # XXX: 像 Get-*、Set-* 等内置命令的 ToolTip 会在每个示例的开头添加 4 个(空格或换行),末尾添加 2 个(空格或换行)
                        # 因此,其他命令的 tip 不能在开头添加 4 个(空格或换行),或者末尾添加 2 个(空格或换行)
                        # 这里通过 \s 去匹配空格或换行
                        $tip = @()
                        if ($item.ToolTip -match "^\s{4,}" -or $item.ToolTip -match ".*\s{2,}$") {
                            foreach ($i in $item.ToolTip -split "\s{4,}") {
                                $t = $i.Trim()
                                if ($t) {
                                    $tip += "$t`n`n"
                                }
                            }
                        }
                        else {
                            $tip += $item.ToolTip
                        }

                        $filter_list += @{
                            CompletionText = $item.CompletionText
                            ListItemText   = $item.ListItemText
                            ToolTip        = $tip
                        }
                    }

                    if ($PSCompletions.config.enable_completions_sort -eq 1 -and (Get-Command $alias -ErrorAction SilentlyContinue)) {
                        $path_order = "$($PSCompletions.path.order)/$root.json"
                        if ($PSCompletions.order."$($root)_job") {
                            if ($PSCompletions.order."$($root)_job".State -eq 'Completed') {
                                $PSCompletions.order.$root = Receive-Job $PSCompletions.order."$($root)_job"
                                Remove-Job $PSCompletions.order."$($root)_job"
                                $PSCompletions.order.Remove("$($root)_job")
                            }
                        }
                        else {
                            if (Test-Path $path_order) {
                                try {
                                    $PSCompletions.order.$root = $PSCompletions.ConvertFrom_JsonToHashtable($PSCompletions.get_raw_content($path_order))
                                }
                                catch {
                                    $PSCompletions.order.$root = $null
                                }
                            }
                            else {
                                $PSCompletions.order.$root = $null
                            }
                        }
                        $order = $PSCompletions.order.$root
                        if ($order) {
                            $PSCompletions._i = 0 # 这里使用 $PSCompletions._i 而非 $i 是因为在 Sort-Object 中,普通的 $i 无法累计
                            $filter_list = $filter_list | Sort-Object {
                                $PSCompletions._i --
                                # 不能使用 $order.($_.CompletionText),它可能获取到对象中的 OverloadDefinitions
                                $o = $order[$_.CompletionText]
                                if ($o) { $o }else { $PSCompletions._i }
                            } -Descending -CaseSensitive
                        }
                        $PSCompletions.order_job((Get-PSReadLineOption).HistorySavePath, $root, $path_order)
                    }

                    $PSCompletions.menu.by_TabExpansion2 = $true
                    $result = $PSCompletions.menu.show_module_menu($filter_list)
                    # apply the completion
                    if ($result -ne $null) {
                        [Microsoft.PowerShell.PSConsoleReadLine]::Replace($completion.ReplacementIndex, $completion.ReplacementLength, $result)
                    }
                }
            }
        }
    }
    else {
        Add-Member -InputObject $PSCompletions -MemberType ScriptMethod handle_completion {
            foreach ($_ in $PSCompletions.data.aliasMap.keys) {
                Register-ArgumentCompleter -CommandName $_ -ScriptBlock {
                    param($word_to_complete, $command_ast, $cursor_position)

                    $space_tab = if (!$word_to_complete.length) { 1 }else { 0 }

                    $input_arr = @()
                    $matches = [regex]::Matches($command_ast.CommandElements, "(?:`"[^`"]*`"|'[^']*'|\S)+")
                    foreach ($match in $matches) { $input_arr += $match.Value }

                    $alias = $input_arr[0]

                    $PSCompletions.root_cmd = $root = $PSCompletions.data.aliasMap.$alias

                    $input_arr = if ($input_arr.Count -le 1) { , @() } else { $input_arr[1..($input_arr.Count - 1)] }

                    $filter_list = $PSCompletions.get_completion()

                    $PSCompletions.menu.by_TabExpansion2 = $false

                    if ($PSCompletions.config.enable_menu -eq 1) {
                        $PSCompletions.menu.show_module_menu($filter_list)
                    }
                    else {
                        $PSCompletions.menu.show_powershell_menu($filter_list)
                    }
                }
            }
        }
    }
}