Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write-VcsStatus behaving differently #612

Closed
codedog opened this issue Aug 28, 2018 · 7 comments
Closed

Write-VcsStatus behaving differently #612

codedog opened this issue Aug 28, 2018 · 7 comments

Comments

@codedog
Copy link

codedog commented Aug 28, 2018

  • posh-git version/path: 1.0.0.0 beta2x C:\source\posh-git\src
  • PowerShell version: 5.1.17134.228
  • git version 2.18.0.windows.1
  • OS: Microsoft Windows NT 10.0.17134.0

Issue Description

I have a custom multi-lines prompt that used to work with v0.6.1.20160330 of posh-git. The git status stays on the first line. The second line contains just the right angle bracket. Now I have installed it on a new machine, and git status is appearing in the second line.

Here's the content of my profile script:

if(!(Test-Path function:\TabExpansion)) { New-Item function:\Global:TabExpansion -value '' | Out-Null }

function Test-Administrator {
    $user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

function prompt {
    $realLASTEXITCODE = $LASTEXITCODE

    Write-Host

    if (Test-Administrator) {  # Use different username if elevated
        Write-Host "^" -NoNewline -ForegroundColor White
    }

    Write-Host "$ENV:USERNAME@" -NoNewline -ForegroundColor DarkYellow
    Write-Host "$ENV:COMPUTERNAME" -NoNewline -ForegroundColor Magenta

    if ($s -ne $null) {  # color for PSSessions
        Write-Host " (`$s: " -NoNewline -ForegroundColor DarkGray
        Write-Host "$($s.Name)" -NoNewline -ForegroundColor Yellow
        Write-Host ") " -NoNewline -ForegroundColor DarkGray
    }

    Write-Host ":" -NoNewline -ForegroundColor DarkGray
    Write-Host $($(Get-Location) -replace ($env:USERPROFILE).Replace('\','\\'), "~") -NoNewline -ForegroundColor Blue
    Write-Host ":" -NoNewline -ForegroundColor DarkGray
    Write-Host (Get-Date -Format "d-MMM HH:mm:ss") -NoNewline -ForegroundColor DarkMagenta
    Write-Host ":" -NoNewline -ForegroundColor DarkGray

    $global:LASTEXITCODE = $realLASTEXITCODE

    Write-VcsStatus

    Write-Host ""

    return "> "
}

function which($command) {
  get-command $command | Format-Table Path
}

Set-Alias which gcm

Import-Module 'C:\source\posh-git\src\posh-git.psd1'

I have somewhat limited understanding of Powershell and can't remember how I cobbled up that prompt. What I was trying to achieve there is an updated timestamp in the prompt every time a command is executed.

Any ideas why Write-VcsStatus now inserts a newline before it?

@rkeithhill
Copy link
Collaborator

rkeithhill commented Aug 29, 2018

A lot has changed WRT to the way the Git status is written in order to support ANSI capable hosts. I have a way to fix you prompt function above but I think you'd be better off just using the new customization support in v1. Put this settings right after you import posh-git:

$GitPromptSettings.DefaultPromptPrefix.Text = "$(if (Test-Administrator) {'^'})${env:USERNAME}@${env:COMPUTERNAME} "
$GitPromptSettings.DefaultPromptPrefix.ForegroundColor = [System.ConsoleColor]::DarkYellow
$GitPromptSettings.PathStatusSeparator.Text = " $(Get-Date -Format "d-MMM HH:mm:ss") "
$GitPromptSettings.PathStatusSeparator.ForegroundColor = [System.ConsoleColor]::DarkMagenta

$GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true
$GitPromptSettings.DefaultPromptPath.ForegroundColor = [System.ConsoleColor]::Blue

@rkeithhill
Copy link
Collaborator

rkeithhill commented Aug 29, 2018

If you want to use your old prompt function, change it to this:

function prompt {
    $realLASTEXITCODE = $LASTEXITCODE

    Write-Host

    if (Test-Administrator) {  # Use different username if elevated
        Write-Host "^" -NoNewline -ForegroundColor White
    }

    Write-Host "$ENV:USERNAME@" -NoNewline -ForegroundColor DarkYellow
    Write-Host "$ENV:COMPUTERNAME" -NoNewline -ForegroundColor Magenta

    if ($s -ne $null) {  # color for PSSessions
        Write-Host " (`$s: " -NoNewline -ForegroundColor DarkGray
        Write-Host "$($s.Name)" -NoNewline -ForegroundColor Yellow
        Write-Host ") " -NoNewline -ForegroundColor DarkGray
    }

    Write-Host ":" -NoNewline -ForegroundColor DarkGray
    Write-Host $($(Get-Location) -replace ($env:USERPROFILE).Replace('\','\\'), "~") -NoNewline -ForegroundColor Blue
    Write-Host ":" -NoNewline -ForegroundColor DarkGray
    Write-Host (Get-Date -Format "d-MMM HH:mm:ss") -NoNewline -ForegroundColor DarkMagenta
    Write-Host ":" -NoNewline -ForegroundColor DarkGray

    $global:LASTEXITCODE = $realLASTEXITCODE

    "$(Write-VcsStatus)> "
}

Essentially the Write-VcsStatus returns a string in v1.x when ANSI mode is enabled ($GitPromptSettings.AnsiConsole is $true). That contains the string to display. This string has VT char sequences in it to color the text. However when your prompt function emits two strings e.g.:

    Write-VcsStatus # output string here

    Write-Host ""

    return "> " # output string here

That object array outuput is not accepted by PowerShell. You can see this by executing:

PS> Get-Member -InputObject (prompt)

   TypeName: System.Object[]

So outputting just "$(Write-VcsStatus)> " results in the prompt function output being a single string.

@rkeithhill
Copy link
Collaborator

rkeithhill commented Aug 29, 2018

In the process of coming up with a $GitPromptSettings customization to get you your exact prompt (sans the PSSession bit - couldn't tell exactly where $s was coming from), I found a few bugs in v1 that I'd like to fix. The following won't work right now but it should after I get a few changes merged in. After those changes are merged, the following will work:

$GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true
$GitPromptSettings.DefaultPromptPath.Text = $null
$GitPromptSettings.DefaultPromptPrefix.CustomAnsi =
    "`n`$(Get-PromptConnectionInfo -Format '[{1}@{0}]: ')" +
    "`$(if (global:Test-Administrator) {`"$([char]27)[37m^`"})" +
    "$([char]27)[33m`${env:USERNAME}@$([char]27)[95m`${env:COMPUTERNAME}$([char]27)[90m:" +
    "$([char]27)[94m`$(Get-PromptPath)$([char]27)[90m:" +
    "$([char]27)[35m`$(Get-Date -Format `"d-MMM HH:mm:ss`")$([char]27)[90m:"  

This will give a prompt like this:

image

BTW if you ran only on PS Core, you could use the esc char e support to simplify the one setting:

# ONLY WORKS IN POWERSHELL CORE AFTER FIXES MERGED
$GitPromptSettings.DefaultPromptPrefix.CustomAnsi =
    "`n`$(Get-PromptConnectionInfo -Format '[{1}@{0}]: ')" +
    "`$(if (global:Test-Administrator) {`"`e[37m^`"})" +
    "`e[33m`${env:USERNAME}@`e[95m`${env:COMPUTERNAME}`e[90m:" +
    "`e[94m`$(Get-PromptPath)`e[90m:" +
    "`e[35m`$(Get-Date -Format `"d-MMM HH:mm:ss`")`e[90m:" 

@codedog
Copy link
Author

codedog commented Aug 30, 2018

Thank you for all that. I ended up modifying my prompt function as you suggested, adding a newline character in the final output to be $(Write-VcsStatus) and >. Now it works just like before! I used this method because I would like this prompt even if I didn't have posh-git installed. I can just remove the call to Write-VcsStatus in that case.

@dahlbyk dahlbyk closed this as completed Aug 31, 2018
@rkeithhill
Copy link
Collaborator

@dahlbyk I think this actually reveals a subtle bug that could trip up folks moving from v0.x to v1 and are running in a host without VT support. This is somewhat of a corner case scenario given the v1 requires PS v5. But if someone has v5 installed on Win7, they could hit it. The issue is this. In v0.x, Write-VcsStatus returned nothing. It simply wrote to the host. So this part of the OP's prompt worked fine because it output a single string > :

    Write-VcsStatus
    Write-Host ""
    return "> "

However, in v1 when AnsiConsole is $false and we use Write-Host, we still output a single, empty string from Write-VcsStatus. That changes the function above to output [object[]] now with an empty string in ndx 0 and > at ndx 1. That breaks PowerShell's prompt handling. It gets confused by the prompt function outputting something other than a single string.

In order to fix this, we'd have to modify Write-GitStatus and Write-VcsStatus to not output anything - not even an empty string - when AnsiConsole is $false. Is it worth it?

@dahlbyk
Copy link
Owner

dahlbyk commented Sep 4, 2018

In order to fix this, we'd have to modify Write-GitStatus and Write-VcsStatus to not output anything - not even an empty string - when AnsiConsole is $false. Is it worth it?

This seems like it should be simple to fix, isn't it?

@rkeithhill
Copy link
Collaborator

I think so. I'll submit a PR so we can see what the changes look like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants