Fast $PROFILE startup
Full sample of a minimal solution
This breaks with VS Code shell integration. To disable it, set “terminal.integrated.shellIntegration.enabled” to “false” in your settings.
| $Deferred = { | |
| . "/home/freddie/.local/share/chezmoi/PSHelpers/Console.ps1" | |
| . "/home/freddie/.local/share/chezmoi/PSHelpers/git_helpers.ps1" | |
| # ...other slow code... | |
| } | |
| # https://seeminglyscience.github.io/powershell/2017/09/30/invocation-operators-states-and-scopes | |
| $GlobalState = [psmoduleinfo]::new($false) | |
| $GlobalState.SessionState = $ExecutionContext.SessionState | |
| # to run our code asynchronously | |
| $Runspace = [runspacefactory]::CreateRunspace($Host) | |
| $Powershell = [powershell]::Create($Runspace) | |
| $Runspace.Open() | |
| $Runspace.SessionStateProxy.PSVariable.Set('GlobalState', $GlobalState) | |
| # ArgumentCompleters are set on the ExecutionContext, not the SessionState | |
| # Note that $ExecutionContext is not an ExecutionContext, it's an EngineIntrinsics 😡 | |
| $Private = [Reflection.BindingFlags]'Instance, NonPublic' | |
| $ContextField = [Management.Automation.EngineIntrinsics].GetField('_context', $Private) | |
| $Context = $ContextField.GetValue($ExecutionContext) | |
| # Get the ArgumentCompleters. If null, initialise them. | |
| $ContextCACProperty = $Context.GetType().GetProperty('CustomArgumentCompleters', $Private) | |
| $ContextNACProperty = $Context.GetType().GetProperty('NativeArgumentCompleters', $Private) | |
| $CAC = $ContextCACProperty.GetValue($Context) | |
| $NAC = $ContextNACProperty.GetValue($Context) | |
| if ($null -eq $CAC) | |
| { | |
| $CAC = [Collections.Generic.Dictionary[string, scriptblock]]::new() | |
| $ContextCACProperty.SetValue($Context, $CAC) | |
| } | |
| if ($null -eq $NAC) | |
| { | |
| $NAC = [Collections.Generic.Dictionary[string, scriptblock]]::new() | |
| $ContextNACProperty.SetValue($Context, $NAC) | |
| } | |
| # Get the AutomationEngine and ExecutionContext of the runspace | |
| $RSEngineField = $Runspace.GetType().GetField('_engine', $Private) | |
| $RSEngine = $RSEngineField.GetValue($Runspace) | |
| $EngineContextField = $RSEngine.GetType().GetFields($Private) | Where-Object {$_.FieldType.Name -eq 'ExecutionContext'} | |
| $RSContext = $EngineContextField.GetValue($RSEngine) | |
| # Set the runspace to use the global ArgumentCompleters | |
| $ContextCACProperty.SetValue($RSContext, $CAC) | |
| $ContextNACProperty.SetValue($RSContext, $NAC) | |
| $Wrapper = { | |
| # Without a sleep, you get issues: | |
| # - occasional crashes | |
| # - prompt not rendered | |
| # - no highlighting | |
| # Assumption: this is related to PSReadLine. | |
| # 20ms seems to be enough on my machine, but let's be generous - this is non-blocking | |
| Start-Sleep -Milliseconds 200 | |
| . $GlobalState {. $Deferred; Remove-Variable Deferred} | |
| } | |
| $null = $Powershell.AddScript($Wrapper.ToString()).BeginInvoke() |
Fast $PROFILE startup
Full sample of a minimal solution
This breaks with VS Code shell integration. To disable it, set “terminal.integrated.shellIntegration.enabled” to “false” in your settings.