PowerLine.psm1
using namespace PoshCode using namespace System.Management.Automation using namespace System.Collections.Generic using namespace PoshCode.Pansies #Region '.\Classes\PowerLineTheme.ps1' 0 #using namespace PoshCode class PowerLineTheme { [TerminalBlock[]]$Prompt [BlockCaps]$DefaultCaps [string]$DefaultSeparator [scriptblock]$Title [bool]$SetCurrentDirectory [bool]$HideErrors [string]$RepeatPrompt [RgbColor[]]$PSReadLineErrorColor [string]$PSReadLineContinuationPrompt [string]$PSReadLineContinuationPromptColor [string[]]$PSReadLinePromptText [int]$DefaultAddIndex = -1 } Add-MetadataConverter @{ [PowerLineTheme] = { "PSObject @{ DefaultCaps = '$($_.DefaultCaps.Left)', '$($_.DefaultCaps.Right)' DefaultSeparator = '$($_.DefaultSeparator)' Prompt = @( $($_.Prompt.ToPsScript() -join "`n ") ) PSReadLineContinuationPrompt = '$($_.PSReadLineContinuationPrompt)' PSReadLineContinuationPromptColor = '$($_.PSReadLineContinuationPromptColor)' PSReadLineErrorColor = '$($_.PSReadLineErrorColor -join "','")' HideErrors = $(if ($_.HideErrors) { '$true' } else { '$false' }) RepeatPrompt = '$(if ($_.RepeatPrompt) { $_.RepeatPrompt } else { 'CachedPrompt' })' SetCurrentDirectory = $(if ($_.SetCurrentDirectory) { '$true' } else { '$false' })$( if (![string]::IsNullOrWhiteSpace($_.Title)) { "`n Title = ScriptBlock @'`n$($_.Title)`n'@" })$( if ($_.DefaultAddIndex -ge 0) { "`n DefaultAddIndex = $($_.DefaultAddIndex)" }) }" } } #EndRegion '.\Classes\PowerLineTheme.ps1' 39 #Region '.\Private\_init.ps1' 0 #!/usr/bin/env powershell #using namespace System.Management.Automation #using namespace System.Collections.Generic #using namespace PoshCode.Pansies [PoshCode.TerminalBlock]::DefaultCaps = "","$([char]0xE0B0)" # Ensure the global prompt variable exists and is typed the way we expect [System.Collections.Generic.List[PoshCode.TerminalBlock]]$Global:Prompt = [PoshCode.TerminalBlock[]]@( if (Test-Path Variable:Prompt) { $Prompt | ForEach-Object { [PoshCode.TerminalBlock]$_ } } ) #EndRegion '.\Private\_init.ps1' 14 #Region '.\Private\WriteExceptions.ps1' 0 function WriteExceptions { [CmdletBinding()] param( # A dictionary mapping script blocks to the exceptions which threw them [System.Collections.Specialized.OrderedDictionary]$ScriptExceptions ) $ErrorString = "" if ($PromptErrors.Count -gt 0) { $global:PromptErrors = [ordered]@{} + $ScriptExceptions Write-Warning "$($global:PromptErrors.Count) error(s) in prompt. Check `$PromptErrors for details. To ignore, Set-PowerLinePrompt -HideError" if ((Test-Path Variable:\PSStyle) -and $PSStyle.Formatting.Error) { foreach ($e in $ScriptExceptions.Values) { $ErrorString += $PSStyle.Formatting.Error + "$e" + $PSStyle.Reset + "`n" } } elseif (@($Host.PrivateData.PSTypeNames)[0] -eq "Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy") { foreach ($e in $ScriptExceptions.Values) { $ErrorString += [PoshCode.Pansies.Text]@{ ForegroundColor = $Host.PrivateData.ErrorForegroundColor BackgroundColor = $Host.PrivateData.ErrorBackgroundColor Object = $e } $ErrorString += "`n" } } else { foreach ($e in $ScriptExceptions) { $ErrorString += [PoshCode.Pansies.Text]@{ ForegroundColor = "Red" BackgroundColor = "Black" Object = $e } $ErrorString += "`n" } } } $ErrorString } #EndRegion '.\Private\WriteExceptions.ps1' 39 #Region '.\Public\Add-PowerLineBlock.ps1' 0 function Add-PowerLineBlock { <# .Synopsis Insert text or a ScriptBlock into the $Prompt .Description This function exists primarily to ensure that modules are able to modify the prompt easily without repeating themselves. .Example Add-PowerLineBlock { "`nI ♥ PS" } Adds the classic "I ♥ PS" to your prompt on a new line. We actually recommend having a simple line in pure 16-color mode on the last line of your prompt, to ensures that PSReadLine won't mess up your colors. PSReadline overwrites your prompt line when you type -- and it can only handle 16 color mode. .Example Add-PowerLineBlock { New-TerminalBlock { Show-Elapsed } -ForegroundColor White -BackgroundColor DarkBlue -ErrorBackground DarkRed -ElevatedForegroundColor Yellow } -Index -2 # This example uses Add-PowerLineBlock to insert a block into the prommpt _before_ the last block # It calls Show-Elapsed to show the duration of the last command as the text of the block # It uses New-TerminalBlock to control the color so that it's highlighted in red if there is an error, but otherwise in dark blue (or yellow if it's an elevated host). #> [CmdletBinding()] param( # The text, object, or scriptblock to show as output [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias("Text", "Content")] $InputObject, # The position to insert the InputObject at, by default, inserts in the same place as the last one [int]$Index = -1, # When set by a module, hooks the calling module to remove this block if the module is removed [Switch]$AutoRemove, # If set, adds the input to the prompt without checking if it's already there [Switch]$Force ) process { Write-Debug "Add-PowerLineBlock $InputObject" if(!$PSBoundParameters.ContainsKey("Index")) { $Index = $Script:PowerLineConfig.DefaultAddIndex++ } if ($InputObject -isnot [PoshCode.TerminalBlock]) { $InputObject = New-TerminalBlock $InputObject } # If force is true, it doesn't matter what Skip is. Otherwise, calculate Skip $Skip = $Force -or @($Global:Prompt).ForEach{ $_.Content.ToString().Trim() } -eq $InputObject.Content.ToString().Trim() if ($Force -or !$Skip) { if ($Index -eq -1 -or $Index -ge $Global:Prompt.Count) { Write-Verbose "Appending '$InputObject' to the end of the prompt" $Global:Prompt.Add($InputObject) $Index = $Global:Prompt.Count } elseif($Index -lt 0) { $Index = $Global:Prompt.Count - $Index Write-Verbose "Inserting '$InputObject' at $Index of the prompt" $Global:Prompt.Insert($Index, $InputObject) } else { Write-Verbose "Inserting '$InputObject' at $Index of the prompt" $Global:Prompt.Insert($Index, $InputObject) } $Script:PowerLineConfig.DefaultAddIndex = $Index + 1 } else { Write-Verbose "Prompt already contained the InputObject block" } if ($AutoRemove) { if (($CallStack = Get-PSCallStack).Count -ge 2) { if ($Module = $CallStack[1].InvocationInfo.MyCommand.Module) { $Module.OnRemove = { Remove-PowerLineBlock $InputObject }.GetNewClosure() } } } } } #EndRegion '.\Public\Add-PowerLineBlock.ps1' 76 #Region '.\Public\Export-PowerLinePrompt.ps1' 0 function Export-PowerLinePrompt { [CmdletBinding()] param() Get-PowerLineTheme | Export-Configuration -AsHashtable } #EndRegion '.\Public\Export-PowerLinePrompt.ps1' 8 #Region '.\Public\Get-PowerLineTheme.ps1' 0 function Get-PowerLineTheme { <# .SYNOPSIS Get the themeable PowerLine settings #> [CmdletBinding()] param() [PowerLineTheme]$Local:Configuration = $Script:PowerLineConfig # We use global:Prompt except when importing and exporting $Configuration.Prompt = [PoshCode.TerminalBlock[]]$global:Prompt if (Get-Command Get-PSReadLineOption) { $PSReadLineOptions = Get-PSReadLineOption # ContinuationPrompt can have colors in them $Configuration.PSReadLineContinuationPrompt = $PSReadLineOptions.ContinuationPrompt # If the ContinuationPrompt has color in it, this is irrelevant, but keep it anyway $Configuration.PSReadLineContinuationPromptColor = $PSReadLineOptions.ContinuationPromptColor } $Configuration } #EndRegion '.\Public\Get-PowerLineTheme.ps1' 24 #Region '.\Public\Remove-PowerLineBlock.ps1' 0 function Remove-PowerLineBlock { <# .Synopsis Remove text or a ScriptBlock from the $Prompt .Description This function exists primarily to ensure that modules are able to clean up the prompt easily when they're removed .Example Remove-PowerLineBlock -Index -1 Removes the last block from the prompt .Example Show-ElapsedTime | Add-PowerLineBlock Show-ElapsedTime | Remove-PowerLineBlock Adds and then removes the Show-ElapsedTime block from the prompt #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidDefaultValueForMandatoryParameter', "Index", Justification = 'This rule should ignore parameters that are only mandatory in some parameter sets')] [CmdletBinding(DefaultParameterSetName="ByObject")] param( # The text, object, or scriptblock to show as output [Parameter(Position=0, Mandatory, ValueFromPipeline, ParameterSetName = "ByObject")] [Alias("Text")] $InputObject, [Parameter(Mandatory, ParameterSetName = "ByIndex")] [int]$Index = -1 ) process { # We always remove by index so we can adjust the DefaultAddIndex if ($PSCmdlet.ParameterSetName -eq "ByObject") { if ($InputObject -is [PoshCode.TerminalBlock]) { $Index = @($Global:Prompt).IndexOf($InputObject) if ($Index -lt 0) { $InputObject = $InputObject.Content } } if ($Index -lt 0) { $Index = @($Global:Prompt).ForEach("Content").IndexOf($InputObject) } if ($Index -lt 0) { $InputString = $InputObject.ToString().Trim() $Index = @($Global:Prompt).ForEach{ $_.Content.ToString().Trim() }.IndexOf($InputString) if ($Index -ge 0) { Write-Warning "Removing `$Prompt[$Index] from the prompt with partial match." } } } elseif ($Index -lt 0) { # We are ADDING the negative number to subract. $Index = $Global:Prompt.Count + $Index } if ($Index -ge 0) { $null = $Global:Prompt.RemoveAt($Index) if ($Index -lt $Script:PowerLineConfig.DefaultAddIndex) { $Script:PowerLineConfig.DefaultAddIndex-- } } else { Write-Error "Could not find $InputObject to remove from the prompt." } } } #EndRegion '.\Public\Remove-PowerLineBlock.ps1' 66 #Region '.\Public\Set-PowerLinePrompt.ps1' 0 function Set-PowerLinePrompt { #.Synopsis # Set the default PowerLine prompt function which uses the $Prompt variable #.Description # Overwrites the current prompt function with one that uses the $Prompt variable # Note that this doesn't try to preserve any changes already made to the prompt by modules like ZLocation #.Example # Set-PowerLinePrompt -SetCurrentDirectory # # Sets the powerline prompt and activates and option supported by this prompt function to update the .Net environment with the current directory each time the prompt runs. #.Example # Set-PowerLinePrompt -SetCurrentDirectory -Title { # Show-Path -HomeString "~" -Depth 2 -GitDir # } -RestoreVirtualTerminal # # Turns on all the non-prompt features of PowerLine: # - Update the .net environment with the current directory each time the prompt runs # - Update the title with a short version of the path each time the prompt runs # - This legacy option calls a Windows api to enable VirtualTerminal processing on old versions of the Windows Console where this wasn't the default (if git is messing up your terminal, try this). #.Example # Set-PowerLinePrompt -PowerLineFont # # Sets the prompt using the default PowerLine characters. Note that you can still change the characters used to separate blocks in the PowerLine output after running this, by setting the Cap and Separator. #.Example # Set-PowerLinePrompt -NoBackground # # Sets the powerline prompt without the PowerLine effect. This disables background color on ALL current blocks, and switches the Cap and Separator to just a space. Remember that you can change the characters used to separate blocks in your prompt, by setting the Cap and Separator without affecting backgrounds. [Alias("Set-PowerLineTheme")] [CmdletBinding(DefaultParameterSetName = "Manual")] param( # One or more scriptblocks or TerminalBlocks you want to use as your new prompt [Parameter(Position = 0, ValueFromPipelineByPropertyName)] $Prompt, # Resets the prompt to use the default PowerLine characters as cap and separator [Parameter(ParameterSetName = "PowerLine", Mandatory)] [switch]$PowerLineFont, # PowerLine uses TerminalBlocks, and the DefaultCaps parameter sets [PoshCode.TerminalBlocks]::DefaultCaps # These are the cap character(s) that will be used (by default) on blocks # Pass two characters: the first for the left side, the second for the right side. [Parameter(ParameterSetName = "Manual", ValueFromPipelineByPropertyName)] [PoshCode.BlockCaps]$DefaultCaps, # PowerLine uses TerminalBlocks, and the DefaultSeparator parameter sets [PoshCode.TerminalBlocks]::DefaultSeparator # The separator character is used by some TerminalBlocks to separate multiple objects (like a path separator) [Parameter(ParameterSetName = "Manual", ValueFromPipelineByPropertyName)] [Alias("Separator")] [string]$DefaultSeparator, # Sets the powerline prompt without the PowerLine effect. # Disables background on ALL TerminalBlocks # Switches the Cap and Separator to just a space. [Parameter(ParameterSetName = "Reset", Mandatory)] [switch]$NoBackground, # If set, calls Export-PowerLinePrompt [Parameter()] [Switch]$Save, # A script which outputs a string used to update the Window Title each time the prompt is run [Parameter(ValueFromPipelineByPropertyName)] [scriptblock]$Title, # Keep the .Net Current Directory in sync with PowerShell's [Parameter(ValueFromPipelineByPropertyName)] [Alias("CurrentDirectory")] [switch]$SetCurrentDirectory, # Prevent errors in the prompt from being shown (like the normal PowerShell behavior) [Parameter(ValueFromPipelineByPropertyName)] [switch]$HideErrors, # How to render repeated prompts. A prompt is considered a repeat if it's run multiple times without a command, # such as when pressing enter repeatedly, or hitting Ctrl+C or Ctrl+L (any time the $MyInvcation.HistoryId does not change) # # By default, PowerLine uses "CachedPrompt" which repeats the whole prompt, but doesn't re-run the prompt blocks. # # You can choose to render only the last block, or the last line of the prompt, or to Recalculate the whole prompt. [Parameter(ValueFromPipelineByPropertyName)] [ValidateSet("LastBlock", "LastLine", "CachedPrompt", "Recalculate")] [string]$RepeatPrompt, # When there's a parse error, PSReadLine changes a part of the prompt based on it's PromptText configuration. # This setting causes PowerLine to update the PSReadLiine PromptText on each run. # # By default, if the last prompt block has a background color, it will be set to tomato red (otherwise, the foreground color) # If you pass just one color, that color will be used instead of tomato red. # If you pass a pair of colors, the first will be replaced with the second throughout the entire last line of the prompt # # To disable this feature, pass an empty array, and PowerLine will not change the PromptText [Parameter(ValueFromPipelineByPropertyName)] [RgbColor[]]$PSReadLineErrorColor, # When you type a command that requires a second line (like if you type | and hit enter) # This is the prompt text. Can be an empty string. Can be anything, really. [Parameter(ValueFromPipelineByPropertyName)] [AllowEmptyString()] [string]$PSReadLineContinuationPrompt, # Let's you set the fg/bg of the PSReadLine continuation prompt as escape sequences. # The easy way is to use PANSIES notation: "$fg:Red$Bg:White" [Parameter(ValueFromPipelineByPropertyName)] [AllowEmptyString()] [string]$PSReadLineContinuationPromptColor ) begin { if ($null -eq $script:OldPrompt) { $script:OldPrompt = $function:global:prompt $MyInvocation.MyCommand.Module.OnRemove = { $function:global:prompt = $script:OldPrompt } } # Switches have a (non-null) default value, so we need to set them in case they were not passed explicitly $Configuration = Import-Configuration -ErrorAction SilentlyContinue | Update-Object @{ HideErrors = $HideErrors SetCurrentDirectory = $SetCurrentDirectory } # Strip common parameters to avoid adding nonsense to the object foreach ($name in [System.Management.Automation.PSCmdlet]::CommonParameters + @("Save", "NoBackground", "PowerLineFont")) { $null = $PSBoundParameters.Remove($name) } } process { [PowerLineTheme]$Local:PowerLineConfig = $Configuration | Update-Object $PSBoundParameters # Set the default cap & separator before we cast prompt blocks if ($NoBackground) { $PowerLineConfig.DefaultCaps = [PoshCode.TerminalBlock]::DefaultCaps = "", " " $PowerLineConfig.DefaultSeparator = [PoshCode.TerminalBlock]::DefaultSeparator = "/" } # For backward compatibility: if ($PSBoundParameters.ContainsKey("PowerLineFont")) { if ($PowerLineFont) { # Make sure we're using the default PowerLine characters: [PoshCode.Pansies.Entities]::ExtendedCharacters['ColorSeparator'] = [char]0xe0b0 [PoshCode.Pansies.Entities]::ExtendedCharacters['ReverseColorSeparator'] = [char]0xe0b2 [PoshCode.Pansies.Entities]::ExtendedCharacters['Separator'] = [char]0xe0b1 [PoshCode.Pansies.Entities]::ExtendedCharacters['ReverseSeparator'] = [char]0xe0b3 [PoshCode.Pansies.Entities]::ExtendedCharacters['Branch'] = [char]0xE0A0 [PoshCode.Pansies.Entities]::ExtendedCharacters['Gear'] = [char]0x26EF # [PoshCode.Pansies.Entities]::EnableNerdFonts = $true } else { # Use characters that at least work in Consolas and Lucida Console [PoshCode.Pansies.Entities]::ExtendedCharacters['ColorSeparator'] = [char]0x258C [PoshCode.Pansies.Entities]::ExtendedCharacters['ReverseColorSeparator'] = [char]0x2590 [PoshCode.Pansies.Entities]::ExtendedCharacters['Separator'] = [char]0x25BA [PoshCode.Pansies.Entities]::ExtendedCharacters['ReverseSeparator'] = [char]0x25C4 [PoshCode.Pansies.Entities]::ExtendedCharacters['Branch'] = [char]0x00A7 [PoshCode.Pansies.Entities]::ExtendedCharacters['Gear'] = [char]0x263C } # Set the new Cap and Separator options too [PoshCode.TerminalBlock]::DefaultCaps = $PowerLineConfig.DefaultCaps = "", [PoshCode.Pansies.Entities]::ExtendedCharacters["ColorSeparator"] [PoshCode.TerminalBlock]::DefaultSeparator = $PowerLineConfig.Separator = [PoshCode.Pansies.Entities]::ExtendedCharacters["Separator"] } if ($PSBoundParameters.ContainsKey("DefaultCaps")) { [PoshCode.TerminalBlock]::DefaultCaps = $PowerLineConfig.DefaultCaps = $DefaultCaps [PoshCode.Pansies.Entities]::ExtendedCharacters["ColorSeparator"] = $DefaultCaps.Right [PoshCode.Pansies.Entities]::ExtendedCharacters["ReverseColorSeparator"] = $DefaultCaps.Left } elseif (!$PowerLineConfig.DefaultCaps) { # If there's nothing in the config, then default to Powerline style! [PoshCode.TerminalBlock]::DefaultCaps = $PowerLineConfig.DefaultCaps = "", [PoshCode.Pansies.Entities]::ExtendedCharacters["ColorSeparator"] } elseif ($PowerLineConfig.DefaultCaps) { [PoshCode.TerminalBlock]::DefaultCaps = $PowerLineConfig.DefaultCaps } if ($PSBoundParameters.ContainsKey("DefaultSeparator")) { [PoshCode.TerminalBlock]::DefaultSeparator = $PowerLineConfig.DefaultSeparator = $DefaultSeparator } elseif (!$PowerLineConfig.DefaultSeparator) { # If there's nothing in the config, then default to Powerline style! [PoshCode.TerminalBlock]::DefaultSeparator = $PowerLineConfig.DefaultSeparator = [PoshCode.Pansies.Entities]::ExtendedCharacters["DefaultSeparator"] } elseif ($PowerLineConfig.DefaultSeparator) { [PoshCode.TerminalBlock]::DefaultSeparator = $PowerLineConfig.DefaultSeparator } # These switches aren't stored in the config $null = $PSBoundParameters.Remove("Save") Write-Verbose "Setting global:Prompt" # We want to support modifying the global:prompt variable outside this function [PoshCode.TerminalBlock[]]$PowerLineConfig.Prompt = @( if ($PSBoundParameters.ContainsKey("Prompt")) { Write-Verbose "Setting global:Prompt from prompt parameter" $Local:Prompt # They didn't pass anything, and there's nothing set } elseif ($global:Prompt.Count -eq 0) { # If we found something in config if ($PowerLineConfig.Prompt.Count -gt 0) { Write-Verbose "Setting global:Prompt from powerline config" # If the config is already TerminalBlock, just use that: if ($PowerLineConfig.Prompt -as [PoshCode.TerminalBlock[]]) { $PowerLineConfig.Prompt } else { # Try to upgrade by casting through scriptblock [ScriptBlock[]]@($PowerLineConfig.Prompt) } } else { Write-Verbose "Setting global:Prompt from default prompt" # The default PowerLine Prompt Show-HistoryId -DefaultBackgroundColor DarkGray -ErrorBackgroundColor Red Show-Path -DefaultBackgroundColor White } } else { Write-Verbose "Setting global:Prompt from existing global:prompt" $global:Prompt } ) if ($NoBackground) { foreach($block in $PowerLineConfig.Prompt){ $block.BackgroundColor = $null } } [System.Collections.Generic.List[PoshCode.TerminalBlock]]$global:Prompt = $PowerLineConfig.Prompt if ($null -eq $PowerLineConfig.DefaultAddIndex) { $PowerLineConfig.DefaultAddIndex = -1 } $Script:PowerLineConfig = $PowerLineConfig if (Get-Module PSReadLine) { $Options = @{} if ($PowerLineConfig.PSReadLineContinuationPrompt) { $Options["ContinuationPrompt"] = $PowerLineConfig.PSReadLineContinuationPrompt } if ($PowerLineConfig.PSReadLineContinuationPromptColor) { $Options["Colors"] = @{ ContinuationPrompt = $PowerLineConfig.PSReadLineContinuationPromptColor } } if ($Options) { Write-Verbose "Updating PSReadLine prompt options: `n$($Options.PromptText -join "`n")`n`n$($Options["Colors"]["ContinuationPrompt"])$($Options["ContinuationPrompt"])" Set-PSReadLineOption @Options } } # Finally, update the prompt function $function:global:prompt = { Write-PowerlinePrompt } [PoshCode.Pansies.RgbColor]::ResetConsolePalette() # If they asked us to save, or if there's nothing saved yet if($Save -or ($PSBoundParameters.Count -and !(Test-Path (Join-Path (Get-StoragePath) Configuration.psd1)))) { Export-PowerLinePrompt } } } #EndRegion '.\Public\Set-PowerLinePrompt.ps1' 255 #Region '.\Public\Write-PowerlinePrompt.ps1' 0 function Write-PowerlinePrompt { [CmdletBinding()] [OutputType([string])] param() try { $PromptErrors = [ordered]@{} ### PowerLinePrompt Features: # Title if ($Script:PowerLineConfig.Title) { try { $Host.UI.RawUI.WindowTitle = [System.Management.Automation.LanguagePrimitives]::ConvertTo( (& $Script:PowerLineConfig.Title), [string] ) } catch { $PromptErrors.Add("0 {$($Script:PowerLineConfig.Title)}", $_) Write-Error "Failed to set Title from scriptblock { $($Script:PowerLineConfig.Title) }" } } # SetCurrentDirectory (for dotnet) if ($Script:PowerLineConfig.SetCurrentDirectory) { try { # Make sure Windows & .Net know where we are # They can only handle the FileSystem, and not in .Net Core [System.IO.Directory]::SetCurrentDirectory( (Get-Location -PSProvider FileSystem).ProviderPath ) } catch { $PromptErrors.Add("0 { SetCurrentDirectory }", $_) Write-Error "Failed to set CurrentDirectory to: (Get-Location -PSProvider FileSystem).ProviderPath" } } # RepeatPrompt (for speed) if ($MyInvocation.HistoryId -eq $Script:LastHistoryId) { if ($Script:PowerLineConfig.RepeatPrompt -eq "LastLine") { # Repeat only the last line $LastLine = 1 + $Prompt.FindLastIndex([Predicate[PoshCode.TerminalBlock]] { $args[0].Content -in "NewLine", "`n" }) $local:Prompt = $Prompt.GetRange($LastLine, $Prompt.Count - $LastLine) } elseif ($Script:PowerLineConfig.RepeatPrompt -eq "LastBlock") { # Repeat only the last block $local:Prompt = $Prompt.GetRange($Prompt.Count - 1, 1) } } $CacheKey = $Script:LastHistoryId = $MyInvocation.HistoryId if ($Script:PowerLineConfig.RepeatPrompt -eq "Recalculate") { $CacheKey = $null } ### Invoke the prompt blocks (before we start outputting anything), to find out whether they have content $PromptErrors = [ordered]@{} for ($b = 0; $b -lt $Prompt.Count; $b++) { try { # ignore the original output (we'll fetch it from the cache with ToString to handle colors) $null = $Prompt[$b].Invoke($CacheKey) if ($Prompt[$b].HadErrors) { foreach ($e in $Prompt[$b].Streams.Error) { $PromptErrors.Add("$b { $($Prompt[$b].Content) }", $e) } } } catch { $PromptErrors.Add("$b { $($Prompt[$b].Content) }", $_) } } [string]$PromptErrorString = if (-not $Script:PowerLineConfig.HideErrors) { WriteExceptions $PromptErrors } ### Output the prompt blocks, using the color of adjacent blocks for PowerLine's classic cap "overlap" $builder = [System.Text.StringBuilder]::new($PromptErrorString) # create the number of lines we need for output up front: $extraLineCount = $Prompt.Where{ $_.Content -eq "NewLine" }.Count $null = $builder.Append("`n" * $extraLineCount) $null = $builder.Append("$([char]27)M" * $extraLineCount) $rightAlign = $false # Add-Content -Value "BEFORE $($extraLineCount+1) line prompt: $EOL" -Path $HOME\PowerLine.log for ($b = 0; $b -lt $Prompt.Count; $b++) { $PreviousNeighbor = $NextNeighbor = $null $Block = $Prompt[$b] # Your previous neighbor is the previous non-empty block with the same alignment as you for ($p = $b - 1; $p -ge 0; $p--){ $Prev = $Prompt[$p] if ($Prev.Content -is [PoshCode.SpecialBlock]) { break; } elseif ($Prev.Cache) { $PreviousNeighbor = $Prev break; } } # Your next neighbor is the next non-empty block with the same alignment as you for ($n = $b + 1; $n -lt $Prompt.Count; $n++) { $Next = $Prompt[$n] if ($Next.Content -is [PoshCode.SpecialBlock]) { break; } elseif ($Next.Cache) { $NextNeighbor = $Next break; } } # Don't render spacers, if they don't have a real (non-space) neighbors on the "next" side if ($Block.Content -in "Spacer" -and (!$NextNeighbor.Cache -or $NextNeighbor.Content -eq "Spacer")) { continue } $null = $builder.Append($Block.ToString($PreviousNeighbor.BackgroundColor, $NextNeighbor.BackgroundColor, $CacheKey)) } if ($Colors = $PowerLineConfig.PSReadLineErrorColor) { $DefaultColor, $Replacement = if ($Colors.Count -eq 1) { $Prompt.BackgroundColor.Where({$_},"Last",1) $Colors[0] } else { $Colors[0] $Colors[-1] } if ($DefaultColor -and $Replacement) { $LastLine = $builder.ToString().Split("`n")[-1] Set-PSReadLineOption -PromptText @( $LastLine $LastLine -replace ([regex]::escape($DefaultColor.ToVt())), $Replacement.ToVt() -replace ([regex]::escape($DefaultColor.ToVt($true))), $Replacement.ToVt($true) ) } } # At the end, output everything that's left $builder.ToString() # Add-Content -Value "return prompt:`n$($Builder.ToString())" -Path $HOME\PowerLine.log if ($global:LASTEXITCODE) { Write-Warning "LASTEXITCODE set in PowerLinePrompt: $global:LASTEXITCODE" } } catch { Write-Warning "Exception in Write-PowerLinePrompt`n$_" "${PWD}>" } finally { # Put back LASTEXITCODE so you don't have to turn off your prompt when things go wrong $global:LASTEXITCODE = [PoshCode.TerminalBlock]::LastExitCode } } #EndRegion '.\Public\Write-PowerlinePrompt.ps1' 142 #Region '.\postfix.ps1' 0 if (Get-Module EzTheme -ErrorAction SilentlyContinue) { Get-ModuleTheme | Set-PowerLineTheme } else { Set-PowerLinePrompt } #EndRegion '.\postfix.ps1' 6 |