PSTui.History.psm1

#
# Copyright (c) Tig Kindel and tui-cs contributors.
# Licensed under the MIT license.
#
# Graphical command-history key handlers for PSTui, folded in from the
# standalone F7History module (https://github.com/tui-cs/F7History).
#
# F7 -> this session's command history
# Shift+F7 -> global history across all PowerShell sessions (PSReadLine)
#
# The typed prefix is used as the initial filter, and the selected command is
# inserted at the prompt. Enabled by default. To opt out:
# * set $env:PSTUI_DISABLE_HISTORY_KEYS to 1/true/yes, or
# * set $PSTuiDisableHistoryKeyHandler = $true *before* Import-Module PSTui, or
# * run Disable-PSTuiHistoryKeyHandler at any time.
#

$script:F7Chord      = 'F7'
$script:ShiftF7Chord = 'Shift+F7'

<#
.SYNOPSIS
    Shows PowerShell command history in Out-ConsoleGridView and inserts the
    selected command at the prompt.
.DESCRIPTION
    Backs the F7 / Shift+F7 key handlers, and can be called or bound to other
    keys directly. The current prompt text is used as the initial filter; the
    selected command is inserted at the prompt.

    This command is exported (rather than module-private) so the PSReadLine key
    handlers, which run in the global session state, can resolve it — see #15.
.PARAMETER Global
    Show history from all PowerShell sessions (PSReadLine) instead of only this one.
#>

function Show-PSTuiHistory {
    [CmdletBinding()]
    param(
        [switch] $Global
    )

    $line = $null
    $cursor = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)

    if ($Global) {
        $title = 'Command History (all PowerShell sessions)'
        $items = [Microsoft.PowerShell.PSConsoleReadLine]::GetHistoryItems()
        if (-not $items) { return }
        [array]::Reverse($items)
        $seen = @{}
        $history = foreach ($item in $items) {
            $cmd = $item.CommandLine
            if ($cmd -and -not $seen.ContainsKey($cmd)) {
                $seen[$cmd] = $true
                [PSCustomObject]@{ CommandLine = $cmd }
            }
        }
    }
    else {
        $title = 'Command History'
        $history = Get-History |
            Sort-Object -Descending -Property Id |
            Select-Object -ExpandProperty CommandLine -Unique |
            ForEach-Object { [PSCustomObject]@{ CommandLine = $_ } }
    }

    if (-not $history) { return }

    $selection = $history | Out-ConsoleGridView -OutputMode Single -Title $title -Filter $line

    # Re-anchor PSReadLine's prompt at the *current* cursor row before touching
    # the buffer. Under Terminal.Gui v2, Out-ConsoleGridView renders inline by
    # default, so the screen has scrolled and PSReadLine's saved prompt row
    # (_initialY) is now stale; a plain DeleteLine/Render would repaint the
    # prompt in the wrong place (the F7History bug fixed in tui-cs/F7History#25).
    # Passing CursorTop as the arg makes InvokePrompt re-anchor on this row.
    [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt($null, [Console]::CursorTop)

    # Replace the typed prefix (used above as the filter) with the selection.
    [Microsoft.PowerShell.PSConsoleReadLine]::DeleteLine()
    if ($selection) {
        [Microsoft.PowerShell.PSConsoleReadLine]::Insert($selection.CommandLine)
    }
}

<#
.SYNOPSIS
    Binds F7 / Shift+F7 to PSTui's graphical command history.
.DESCRIPTION
    F7 shows this session's history; Shift+F7 shows global PSReadLine history.
    Called automatically when PSTui is imported (unless opted out). Safe to call
    again to re-bind after Disable-PSTuiHistoryKeyHandler.
#>

function Enable-PSTuiHistoryKeyHandler {
    [CmdletBinding()]
    param()

    if (-not (Get-Command -Name Set-PSReadLineKeyHandler -ErrorAction SilentlyContinue)) {
        Write-Verbose 'PSReadLine is not available; PSTui history key handlers were not set.'
        return
    }

    Set-PSReadLineKeyHandler -Chord $script:F7Chord `
        -BriefDescription 'PSTui: Command History' `
        -Description "Show this session's command history in Out-ConsoleGridView (PSTui)" `
        -ScriptBlock { Show-PSTuiHistory }

    Set-PSReadLineKeyHandler -Chord $script:ShiftF7Chord `
        -BriefDescription 'PSTui: Command History (all sessions)' `
        -Description 'Show global command history in Out-ConsoleGridView (PSTui)' `
        -ScriptBlock { Show-PSTuiHistory -Global }
}

<#
.SYNOPSIS
    Removes PSTui's F7 / Shift+F7 command-history key bindings.
#>

function Disable-PSTuiHistoryKeyHandler {
    [CmdletBinding()]
    param()

    if (-not (Get-Command -Name Remove-PSReadLineKeyHandler -ErrorAction SilentlyContinue)) {
        return
    }

    foreach ($chord in $script:F7Chord, $script:ShiftF7Chord) {
        try { Remove-PSReadLineKeyHandler -Chord $chord -ErrorAction Stop } catch { }
    }
}

# --- Auto-enable on import, unless the user opted out ------------------------
$optOut = ($env:PSTUI_DISABLE_HISTORY_KEYS -and
           $env:PSTUI_DISABLE_HISTORY_KEYS -in @('1', 'true', 'yes', 'on')) -or
          ($global:PSTuiDisableHistoryKeyHandler -eq $true)

if (-not $optOut) {
    # Never let key-handler setup break module import (e.g. no console host in CI).
    try { Enable-PSTuiHistoryKeyHandler } catch {
        Write-Verbose "PSTui: could not set history key handlers: $($_.Exception.Message)"
    }
}

Export-ModuleMember -Function Show-PSTuiHistory, Enable-PSTuiHistoryKeyHandler, Disable-PSTuiHistoryKeyHandler