Private/GlobalStore.ps1
using module ./_EntryRegistry.psm1 class GlobalStore { $entries = [System.Collections.Generic.List[PowerShellRun.SelectorEntry]]::new() $defaultSelectorOption = [PowerShellRun.SelectorOption]::new() $psRunSelectorOption = [PowerShellRun.SelectorOption]::new() $registryClassNames = @( 'FunctionRegistry' 'FileSystemRegistry' 'WinGetRegistry' 'ApplicationRegistry' ) $registries = [System.Collections.Generic.List[EntryRegistry]]::new() $parentSelectorRestoreRequest = $false $originalPSConsoleHostReadLine = $null $isReadLineReplaced = $false $invokePsRunRequest = $false $invokePsRunRequestQuery = '' $psReadLineChord = $null $firstActionKey = [PowerShellRun.KeyCombination]::new([PowerShellRun.KeyModifier]::None, [PowerShellRun.Key]::None) $secondActionKey = [PowerShellRun.KeyCombination]::new([PowerShellRun.KeyModifier]::None, [PowerShellRun.Key]::None) $thirdActionKey = [PowerShellRun.KeyCombination]::new([PowerShellRun.KeyModifier]::None, [PowerShellRun.Key]::None) $copyActionKey = [PowerShellRun.KeyCombination]::new([PowerShellRun.KeyModifier]::None, [PowerShellRun.Key]::None) [void] Initialize() { $this.InitializeActionKeys() foreach ($className in $this.registryClassNames) { $registry = New-Object $className $this.registries.Add($registry) } } [void] Terminate() { # Wait for async entry initializations $this.UpdateEntries() $this.RemovePSReadLineKeyHandler() $this.RestorePSConsoleHostReadLine() } [void] InitializeActionKeys() { $_firstActionKey = [PowerShellRun.KeyCombination]::new('Enter') if ($script:isMacOs) { $_secondActionKey = [PowerShellRun.KeyCombination]::new('Alt+Enter') $_thirdActionKey = [PowerShellRun.KeyCombination]::new('Alt+J') $_copyActionKey = [PowerShellRun.KeyCombination]::new('Ctrl+C') } else { $_secondActionKey = [PowerShellRun.KeyCombination]::new('Shift+Enter') $_thirdActionKey = [PowerShellRun.KeyCombination]::new('Ctrl+Enter') $_copyActionKey = [PowerShellRun.KeyCombination]::new('Ctrl+C') } $this.SetActionKeys($_firstActionKey, $_secondActionKey, $_thirdActionKey, $_copyActionKey) } [void] SetActionKeys($firstActionKey, $secondActionKey, $thirdActionKey, $copyActionKey) { # Change the values instead of references so that entries that are already created can see the keys. $this.firstActionKey.Modifier = $firstActionKey.Modifier $this.firstActionKey.Key = $firstActionKey.Key $this.secondActionKey.Modifier = $secondActionKey.Modifier $this.secondActionKey.Key = $secondActionKey.Key $this.thirdActionKey.Modifier = $thirdActionKey.Modifier $this.thirdActionKey.Key = $thirdActionKey.Key $this.copyActionKey.Modifier = $copyActionKey.Modifier $this.copyActionKey.Key = $copyActionKey.Key } [void] SetDefaultSelectorOption([PowerShellRun.SelectorOption]$option) { $this.defaultSelectorOption = $option.DeepClone() $this.psRunSelectorOption = $option.DeepClone() $psRunKeyBinding = $this.psRunSelectorOption.KeyBinding $psRunKeyBinding.DefaultActionKeys[0].KeyCombination = $this.firstActionKey $psRunKeyBinding.DefaultActionKeys[0].Description = 'Quit' } [EntryRegistry] GetRegistry($typeName) { foreach ($registry in $this.registries) { if ($registry.GetType().Name -eq $typeName) { return $registry } } return $null } [void] EnableEntries([String[]]$entryCategories) { foreach ($registry in $this.registries) { $registry.EnableEntries($entryCategories) } } [void] UpdateEntries() { $updated = $false foreach ($registry in $this.registries) { $updated = $registry.UpdateEntries() -or $updated } if ($updated) { $this.entries.Clear() foreach ($registry in $this.registries) { if ($_entries = $registry.GetEntries()) { $this.entries.AddRange($_entries) } } } } [void] RequestParentSelectorRestore() { $this.parentSelectorRestoreRequest = $true } [void] ClearParentSelectorRestoreRequest() { $this.parentSelectorRestoreRequest = $false } [bool] IsParentSelectorRestoreRequested() { return $this.parentSelectorRestoreRequest } [void] ReplacePSConsoleHostReadLine() { if ($this.isReadLineReplaced) { return } $this.isReadLineReplaced = $true $this.originalPSConsoleHostReadLine = $function:global:PSConsoleHostReadLine $function:global:PSConsoleHostReadLine = { $script:globalStore.InvokePSConsoleHostReadLine() } } [void] RestorePSConsoleHostReadLine() { if (-not $this.isReadLineReplaced) { return } $function:global:PSConsoleHostReadLine = $this.originalPSConsoleHostReadLine $this.isReadLineReplaced = $false } [Object] InvokePSConsoleHostReadLine() { $command = $this.originalPSConsoleHostReadLine.Invoke() if ($this.invokePsRunRequest) { $this.invokePsRunRequest = $false if ($this.invokePsRunRequestQuery) { return ('Invoke-PSRun -InitialQuery "{0}"' -f $this.invokePsRunRequestQuery) } else { return 'Invoke-PSRun' } } else { return $command } } [void] RequestInvokePsRun($query) { $this.invokePsRunRequest = $true $this.invokePsRunRequestQuery = $query } [void] SetPSReadLineKeyHandler($chord) { $this.RemovePSReadLineKeyHandler() $this.psReadLineChord = $chord Set-PSReadLineKeyHandler -Chord $chord -ScriptBlock { $line = $null $cursor = $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) $script:globalStore.RequestInvokePsRun($line) [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() } } [void] RemovePSReadLineKeyHandler() { if ($this.psReadLineChord) { Remove-PSReadLineKeyHandler -Chord $this.psReadLineChord $this.psReadLineChord = $null } } # Class methods cannot pass through the output of invoked command line apps in realtime so we use ScriptBlock. $invokeFile = { param($path) $command = Get-Command $path -ErrorAction SilentlyContinue if ($command -and ($command.CommandType -eq 'Application')) { # do not open new window when this is a command line app. & $path } elseif ($path.Contains('shell:', 'OrdinalIgnoreCase')) { # On Windows, Invoke-Item cannot open special folders. Start-Process $path } else { # .ps1 files or .app files on macOS come here. Invoke-Item $path } } } |