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'

# Builds the history list and shows it in Out-ConsoleGridView, inserting the
# chosen command at the prompt. Invoked by the PSReadLine key handlers.
function Show-PSTuiCommandHistory {
    [CmdletBinding()]
    param(
        # Show history from all PowerShell sessions (PSReadLine) instead of just this one.
        [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

    # Replace the current line with the selection (if any).
    [Microsoft.PowerShell.PSConsoleReadLine]::DeleteLine()
    if ($selection) {
        $command = $selection.CommandLine
        [Microsoft.PowerShell.PSConsoleReadLine]::Insert($command)
        if ($command.StartsWith($line)) {
            [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor)
        }
        else {
            [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($command.Length)
        }
    }
}

<#
.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-PSTuiCommandHistory }

    Set-PSReadLineKeyHandler -Chord $script:ShiftF7Chord `
        -BriefDescription 'PSTui: Command History (all sessions)' `
        -Description 'Show global command history in Out-ConsoleGridView (PSTui)' `
        -ScriptBlock { Show-PSTuiCommandHistory -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 Enable-PSTuiHistoryKeyHandler, Disable-PSTuiHistoryKeyHandler