From 46fef8167bfcf9719a639611d305677425005488 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Wed, 14 Sep 2016 23:30:53 -0500 Subject: [PATCH 1/4] Use ANSI color codes if SupportsVirtualTerminal --- GitPrompt.ps1 | 47 ++++++++++++++++++++++++++++----------------- Utils.ps1 | 47 +++++++++++++++++++++++++++++++++++++++++++++ profile.example.ps1 | 4 ++-- 3 files changed, 78 insertions(+), 20 deletions(-) diff --git a/GitPrompt.ps1 b/GitPrompt.ps1 index a8ddfd24f..4056c4578 100644 --- a/GitPrompt.ps1 +++ b/GitPrompt.ps1 @@ -106,11 +106,18 @@ if (Get-Module NuGet) { } function Write-Prompt($Object, $ForegroundColor, $BackgroundColor = -1) { + if ($Host.UI.SupportsVirtualTerminal) { + $e = [char]27 + "[" + $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor + $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor + return "${f}${b}${Object}${e}0m" + } if ($BackgroundColor -lt 0) { Write-Host $Object -NoNewLine -ForegroundColor $ForegroundColor } else { Write-Host $Object -NoNewLine -ForegroundColor $ForegroundColor -BackgroundColor $BackgroundColor } + return "" } function Format-BranchName($branchName){ @@ -126,8 +133,9 @@ function Format-BranchName($branchName){ function Write-GitStatus($status) { $s = $global:GitPromptSettings + $p = '' if ($status -and $s) { - Write-Prompt $s.BeforeText -BackgroundColor $s.BeforeBackgroundColor -ForegroundColor $s.BeforeForegroundColor + $p += Write-Prompt $s.BeforeText -BackgroundColor $s.BeforeBackgroundColor -ForegroundColor $s.BeforeForegroundColor $branchStatusSymbol = $null $branchStatusBackgroundColor = $s.BranchBackgroundColor @@ -160,47 +168,47 @@ function Write-GitStatus($status) { $branchStatusSymbol = "?" } - Write-Prompt (Format-BranchName($status.Branch)) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor + $p += Write-Prompt (Format-BranchName($status.Branch)) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor if ($branchStatusSymbol) { - Write-Prompt (" {0}" -f $branchStatusSymbol) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor + $p += Write-Prompt (" {0}" -f $branchStatusSymbol) -BackgroundColor $branchStatusBackgroundColor -ForegroundColor $branchStatusForegroundColor } if($s.EnableFileStatus -and $status.HasIndex) { - Write-Prompt $s.BeforeIndexText -BackgroundColor $s.BeforeIndexBackgroundColor -ForegroundColor $s.BeforeIndexForegroundColor + $p += Write-Prompt $s.BeforeIndexText -BackgroundColor $s.BeforeIndexBackgroundColor -ForegroundColor $s.BeforeIndexForegroundColor if($s.ShowStatusWhenZero -or $status.Index.Added) { - Write-Prompt (" $($s.FileAddedText)$($status.Index.Added.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor + $p += Write-Prompt (" $($s.FileAddedText)$($status.Index.Added.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor } if($s.ShowStatusWhenZero -or $status.Index.Modified) { - Write-Prompt (" $($s.FileModifiedText)$($status.Index.Modified.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor + $p += Write-Prompt (" $($s.FileModifiedText)$($status.Index.Modified.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor } if($s.ShowStatusWhenZero -or $status.Index.Deleted) { - Write-Prompt (" $($s.FileRemovedText)$($status.Index.Deleted.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor + $p += Write-Prompt (" $($s.FileRemovedText)$($status.Index.Deleted.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor } if ($status.Index.Unmerged) { - Write-Prompt (" $($s.FileConflictedText)$($status.Index.Unmerged.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor + $p += Write-Prompt (" $($s.FileConflictedText)$($status.Index.Unmerged.Count)") -BackgroundColor $s.IndexBackgroundColor -ForegroundColor $s.IndexForegroundColor } if($status.HasWorking) { - Write-Prompt $s.DelimText -BackgroundColor $s.DelimBackgroundColor -ForegroundColor $s.DelimForegroundColor + $p += Write-Prompt $s.DelimText -BackgroundColor $s.DelimBackgroundColor -ForegroundColor $s.DelimForegroundColor } } if($s.EnableFileStatus -and $status.HasWorking) { if($s.ShowStatusWhenZero -or $status.Working.Added) { - Write-Prompt (" $($s.FileAddedText)$($status.Working.Added.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor + $p += Write-Prompt (" $($s.FileAddedText)$($status.Working.Added.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor } if($s.ShowStatusWhenZero -or $status.Working.Modified) { - Write-Prompt (" $($s.FileModifiedText)$($status.Working.Modified.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor + $p += Write-Prompt (" $($s.FileModifiedText)$($status.Working.Modified.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor } if($s.ShowStatusWhenZero -or $status.Working.Deleted) { - Write-Prompt (" $($s.FileRemovedText)$($status.Working.Deleted.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor + $p += Write-Prompt (" $($s.FileRemovedText)$($status.Working.Deleted.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor } if ($status.Working.Unmerged) { - Write-Prompt (" $($s.FileConflictedText)$($status.Working.Unmerged.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor + $p += Write-Prompt (" $($s.FileConflictedText)$($status.Working.Unmerged.Count)") -BackgroundColor $s.WorkingBackgroundColor -ForegroundColor $s.WorkingForegroundColor } } @@ -222,16 +230,16 @@ function Write-GitStatus($status) { } if ($localStatusSymbol) { - Write-Prompt (" {0}" -f $localStatusSymbol) -BackgroundColor $localStatusBackgroundColor -ForegroundColor $localStatusForegroundColor + $p += Write-Prompt (" {0}" -f $localStatusSymbol) -BackgroundColor $localStatusBackgroundColor -ForegroundColor $localStatusForegroundColor } if ($s.EnableStashStatus -and ($status.StashCount -gt 0)) { - Write-Prompt $s.BeforeStashText -BackgroundColor $s.BeforeStashBackgroundColor -ForegroundColor $s.BeforeStashForegroundColor - Write-Prompt $status.StashCount -BackgroundColor $s.StashBackgroundColor -ForegroundColor $s.StashForegroundColor - Write-Prompt $s.AfterStashText -BackgroundColor $s.AfterStashBackgroundColor -ForegroundColor $s.AfterStashForegroundColor + $p += Write-Prompt $s.BeforeStashText -BackgroundColor $s.BeforeStashBackgroundColor -ForegroundColor $s.BeforeStashForegroundColor + $p += Write-Prompt $status.StashCount -BackgroundColor $s.StashBackgroundColor -ForegroundColor $s.StashForegroundColor + $p += Write-Prompt $s.AfterStashText -BackgroundColor $s.AfterStashBackgroundColor -ForegroundColor $s.AfterStashForegroundColor } - Write-Prompt $s.AfterText -BackgroundColor $s.AfterBackgroundColor -ForegroundColor $s.AfterForegroundColor + $p += Write-Prompt $s.AfterText -BackgroundColor $s.AfterBackgroundColor -ForegroundColor $s.AfterForegroundColor if ($WindowTitleSupported -and $s.EnableWindowTitle) { if( -not $Global:PreviousWindowTitle ) { @@ -241,8 +249,11 @@ function Write-GitStatus($status) { $prefix = if ($s.EnableWindowTitle -is [string]) { $s.EnableWindowTitle } else { '' } $Host.UI.RawUI.WindowTitle = "$script:adminHeader$prefix$repoName [$($status.Branch)]" } + + return $p } elseif ( $Global:PreviousWindowTitle ) { $Host.UI.RawUI.WindowTitle = $Global:PreviousWindowTitle + return "" } } diff --git a/Utils.ps1 b/Utils.ps1 index b1aceb549..a4f720a31 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -31,6 +31,53 @@ function Get-LocalOrParentPath($path) { return $null } +# Color codes from https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx +function Get-ForegroundVirtualTerminalSequence($Color) { + $e = [char]27 + "[" + switch ($Color) { + ([ConsoleColor]::Black) { "${e}30m" } + ([ConsoleColor]::DarkRed) { "${e}31m" } + ([ConsoleColor]::DarkGreen) { "${e}32m" } + ([ConsoleColor]::DarkYellow) { "${e}33m" } + ([ConsoleColor]::DarkBlue) { "${e}34m" } + ([ConsoleColor]::DarkMagenta) { "${e}35m" } + ([ConsoleColor]::DarkCyan) { "${e}36m" } + ([ConsoleColor]::Gray) { "${e}37m" } + ([ConsoleColor]::DarkGray) { "${e}90m" } + ([ConsoleColor]::Red) { "${e}91m" } + ([ConsoleColor]::Green) { "${e}92m" } + ([ConsoleColor]::Yellow) { "${e}93m" } + ([ConsoleColor]::Blue) { "${e}94m" } + ([ConsoleColor]::Magenta) { "${e}95m" } + ([ConsoleColor]::Cyan) { "${e}96m" } + ([ConsoleColor]::White) { "${e}97m" } + default { "${e}39m" } + } +} + +function Get-BackgroundVirtualTerminalSequence($Color) { + $e = [char]27 + "[" + switch ($Color) { + ([ConsoleColor]::Black) { "${e}40m" } + ([ConsoleColor]::DarkRed) { "${e}41m" } + ([ConsoleColor]::DarkGreen) { "${e}42m" } + ([ConsoleColor]::DarkYellow) { "${e}43m" } + ([ConsoleColor]::DarkBlue) { "${e}44m" } + ([ConsoleColor]::DarkMagenta) { "${e}45m" } + ([ConsoleColor]::DarkCyan) { "${e}46m" } + ([ConsoleColor]::Gray) { "${e}47m" } + ([ConsoleColor]::DarkGray) { "${e}100m" } + ([ConsoleColor]::Red) { "${e}101m" } + ([ConsoleColor]::Green) { "${e}102m" } + ([ConsoleColor]::Yellow) { "${e}103m" } + ([ConsoleColor]::Blue) { "${e}104m" } + ([ConsoleColor]::Magenta) { "${e}105m" } + ([ConsoleColor]::Cyan) { "${e}106m" } + ([ConsoleColor]::White) { "${e}107m" } + default { "${e}49m" } + } +} + function dbg ($Message, [Diagnostics.Stopwatch]$Stopwatch) { if($Stopwatch) { Write-Verbose ('{0:00000}:{1}' -f $Stopwatch.ElapsedMilliseconds,$Message) -Verbose # -ForegroundColor Yellow diff --git a/profile.example.ps1 b/profile.example.ps1 index 84b17c2ab..38fa40602 100644 --- a/profile.example.ps1 +++ b/profile.example.ps1 @@ -14,10 +14,10 @@ function global:prompt { Write-Host($pwd.ProviderPath) -nonewline - Write-VcsStatus + $p = Write-VcsStatus $global:LASTEXITCODE = $realLASTEXITCODE - return "> " + return $p + "> " } Pop-Location From f87a410f7b8e26c10f137e5acd0ab787b33a358f Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Mon, 19 Sep 2016 14:26:51 -0500 Subject: [PATCH 2/4] Optimize ANSI escape lookup --- Utils.ps1 | 70 ++++++++++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/Utils.ps1 b/Utils.ps1 index a4f720a31..1242dd869 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -32,50 +32,40 @@ function Get-LocalOrParentPath($path) { } # Color codes from https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx -function Get-ForegroundVirtualTerminalSequence($Color) { - $e = [char]27 + "[" - switch ($Color) { - ([ConsoleColor]::Black) { "${e}30m" } - ([ConsoleColor]::DarkRed) { "${e}31m" } - ([ConsoleColor]::DarkGreen) { "${e}32m" } - ([ConsoleColor]::DarkYellow) { "${e}33m" } - ([ConsoleColor]::DarkBlue) { "${e}34m" } - ([ConsoleColor]::DarkMagenta) { "${e}35m" } - ([ConsoleColor]::DarkCyan) { "${e}36m" } - ([ConsoleColor]::Gray) { "${e}37m" } - ([ConsoleColor]::DarkGray) { "${e}90m" } - ([ConsoleColor]::Red) { "${e}91m" } - ([ConsoleColor]::Green) { "${e}92m" } - ([ConsoleColor]::Yellow) { "${e}93m" } - ([ConsoleColor]::Blue) { "${e}94m" } - ([ConsoleColor]::Magenta) { "${e}95m" } - ([ConsoleColor]::Cyan) { "${e}96m" } - ([ConsoleColor]::White) { "${e}97m" } - default { "${e}39m" } +$ConsoleColorToAnsi = @( + 30 # Black + 34 # DarkBlue + 32 # DarkGreen + 36 # DarkCyan + 31 # DarkRed + 35 # DarkMagenta + 33 # DarkYellow + 37 # Gray + 90 # DarkGray + 94 # Blue + 92 # Green + 96 # Cyan + 91 # Red + 95 # Magenta + 93 # Yellow + 97 # White +) +$AnsiDefaultColor = 39 +$AnsiEscape = [char]27 + "[" + +function Get-VirtualTerminalSequence ([ConsoleColor]$color, [int]$offset = 0) { + if (($color -lt 0) -or ($color -gt 15)) { + return "${AnsiEscape}$($AnsiDefaultColor + $offset)m" } + return "${AnsiEscape}$($ConsoleColorToAnsi[$color] + $offset)m" +} + +function Get-ForegroundVirtualTerminalSequence($Color) { + return Get-VirtualTerminalSequence $Color } function Get-BackgroundVirtualTerminalSequence($Color) { - $e = [char]27 + "[" - switch ($Color) { - ([ConsoleColor]::Black) { "${e}40m" } - ([ConsoleColor]::DarkRed) { "${e}41m" } - ([ConsoleColor]::DarkGreen) { "${e}42m" } - ([ConsoleColor]::DarkYellow) { "${e}43m" } - ([ConsoleColor]::DarkBlue) { "${e}44m" } - ([ConsoleColor]::DarkMagenta) { "${e}45m" } - ([ConsoleColor]::DarkCyan) { "${e}46m" } - ([ConsoleColor]::Gray) { "${e}47m" } - ([ConsoleColor]::DarkGray) { "${e}100m" } - ([ConsoleColor]::Red) { "${e}101m" } - ([ConsoleColor]::Green) { "${e}102m" } - ([ConsoleColor]::Yellow) { "${e}103m" } - ([ConsoleColor]::Blue) { "${e}104m" } - ([ConsoleColor]::Magenta) { "${e}105m" } - ([ConsoleColor]::Cyan) { "${e}106m" } - ([ConsoleColor]::White) { "${e}107m" } - default { "${e}49m" } - } + return Get-VirtualTerminalSequence $Color 10 } function dbg ($Message, [Diagnostics.Stopwatch]$Stopwatch) { From ad3d071fdabe89c6a60ee833a5bab4400d8db472 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Mon, 19 Sep 2016 15:10:17 -0500 Subject: [PATCH 3/4] Reset console mode on Write-VcsStatus Hat tip to @lzybkr --- ConsoleMode.ps1 | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ GitPrompt.ps1 | 5 +- posh-git.psm1 | 1 + 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 ConsoleMode.ps1 diff --git a/ConsoleMode.ps1 b/ConsoleMode.ps1 new file mode 100644 index 000000000..3147cb25b --- /dev/null +++ b/ConsoleMode.ps1 @@ -0,0 +1,121 @@ +# Hack! https://gist.github.com/lzybkr/f2059cb2ee8d0c13c65ab933b75e998c + +Add-Type @" +using System; +using System.Runtime.InteropServices; + +public class NativeConsoleMethods +{ + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr GetStdHandle(int handleId); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool GetConsoleMode(IntPtr hConsoleOutput, out uint dwMode); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool SetConsoleMode(IntPtr hConsoleOutput, uint dwMode); + + public static uint GetConsoleMode(bool input = false) + { + var handle = GetStdHandle(input ? -10 : -11); + uint mode; + if (GetConsoleMode(handle, out mode)) + { + return mode; + } + return 0xffffffff; + } + + public static uint SetConsoleMode(bool input, uint mode) + { + var handle = GetStdHandle(input ? -10 : -11); + if (SetConsoleMode(handle, mode)) + { + return GetConsoleMode(input); + } + return 0xffffffff; + } +} +"@ + +[Flags()] +enum ConsoleModeInputFlags +{ + ENABLE_PROCESSED_INPUT = 0x0001 + ENABLE_LINE_INPUT = 0x0002 + ENABLE_ECHO_INPUT = 0x0004 + ENABLE_WINDOW_INPUT = 0x0008 + ENABLE_MOUSE_INPUT = 0x0010 + ENABLE_INSERT_MODE = 0x0020 + ENABLE_QUICK_EDIT_MODE = 0x0040 + ENABLE_EXTENDED_FLAGS = 0x0080 + ENABLE_AUTO_POSITION = 0x0100 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0200 +} + +[Flags()] +enum ConsoleModeOutputFlags +{ + ENABLE_PROCESSED_OUTPUT = 0x0001 + ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 +} + +function Get-ConsoleMode +{ + [CmdletBinding()] + param( + [switch] + $StandardInput + ) + + $mode = [NativeConsoleMethods]::GetConsoleMode($StandardInput) + if ($StandardInput) + { + [ConsoleModeInputFlags]$mode + } + else + { + [ConsoleModeOutputFlags]$mode + } +} + +function Set-ConsoleMode +{ + param( + [Parameter(ParameterSetName = "ANSI")] + [switch] + $ANSI, + + [Parameter(ParameterSetName = "Mode")] + [uint32] + $Mode, + + [switch] + $StandardInput + ) + + if ($ANSI) + { + $outputMode = [NativeConsoleMethods]::GetConsoleMode($false) + $null = [NativeConsoleMethods]::SetConsoleMode($false, $outputMode -bor [ConsoleModeOutputFlags]::ENABLE_VIRTUAL_TERMINAL_PROCESSING) + + if ($StandardInput) + { + $inputMode = [NativeConsoleMethods]::GetConsoleMode($true) + $null = [NativeConsoleMethods]::SetConsoleMode($true, $inputMode -bor [ConsoleModeInputFlags]::ENABLE_VIRTUAL_TERMINAL_PROCESSING) + } + } + else + { + [NativeConsoleMethods]::SetConsoleMode($StandardInput, $Mode) + } +} + +function Reset-Colors +{ + $mode = [NativeConsoleMethods]::GetConsoleMode() + Set-ConsoleMode -ANSI + "$([char]0x1b)[0m" + [NativeConsoleMethods]::SetConsoleMode($false, $mode) +} diff --git a/GitPrompt.ps1 b/GitPrompt.ps1 index 4056c4578..8757d1e2b 100644 --- a/GitPrompt.ps1 +++ b/GitPrompt.ps1 @@ -273,7 +273,10 @@ if ($Host.UI.RawUI.BackgroundColor -eq [ConsoleColor]::DarkMagenta) { $s.WorkingForegroundColor = $s.WorkingForegroundBrightColor } -function Global:Write-VcsStatus { $Global:VcsPromptStatuses | foreach { & $_ } } +function Global:Write-VcsStatus { + Set-ConsoleMode -ANSI + $Global:VcsPromptStatuses | foreach { & $_ } +} # Add scriptblock that will execute for Write-VcsStatus $PoshGitVcsPrompt = { diff --git a/posh-git.psm1 b/posh-git.psm1 index 96efea065..d1442cc85 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -14,6 +14,7 @@ if ($psv.Major -lt 3 -and !$NoVersionWarn) { Push-Location $psScriptRoot .\CheckVersion.ps1 > $null +. .\ConsoleMode.ps1 . .\Utils.ps1 . .\GitUtils.ps1 . .\GitPrompt.ps1 From 52712732bf0760d99250a5560a1cf29f4a5192bb Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Wed, 21 Sep 2016 16:32:08 -0500 Subject: [PATCH 4/4] Add $GitPromptSettings.AnsiConsole - Enabled if $Host.UI.SupportsVirtualTerminal - Enabled if %ConEmuANSI% is 'ON' - Can be manually set in $PROFILE for other ANSI-capable consoles --- GitPrompt.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GitPrompt.ps1 b/GitPrompt.ps1 index 8757d1e2b..87f081eda 100644 --- a/GitPrompt.ps1 +++ b/GitPrompt.ps1 @@ -89,6 +89,8 @@ $global:GitPromptSettings = New-Object PSObject -Property @{ EnableWindowTitle = 'posh~git ~ ' + AnsiConsole = $Host.UI.SupportsVirtualTerminal -or ($Env:ConEmuANSI -eq "ON") + Debug = $false BranchNameLimit = 0 @@ -106,7 +108,7 @@ if (Get-Module NuGet) { } function Write-Prompt($Object, $ForegroundColor, $BackgroundColor = -1) { - if ($Host.UI.SupportsVirtualTerminal) { + if ($GitPromptSettings.AnsiConsole) { $e = [char]27 + "[" $f = Get-ForegroundVirtualTerminalSequence $ForegroundColor $b = Get-BackgroundVirtualTerminalSequence $BackgroundColor