JanDeDobbeleer / oh-my-posh

The most customisable and low-latency cross platform/shell prompt renderer
https://ohmyposh.dev
MIT License
17.37k stars 2.39k forks source link

Long lines that wrap in terminal cause a background "highlight" on the next line #65

Closed tillig closed 4 years ago

tillig commented 4 years ago

Prerequisites

Description

If you have a prompt that ends up wrapping to the next line and then ending, the next line will have a background color that matches the background of the segment at the end of the previous line.

Put another way:

Line wrapping in the prompt

Environment

Steps to Reproduce

  1. Create a theme that has a really long line that will cause wrapping and has a background color.
  2. Run oh-my-posh with the theme and note the display of the second line.
Example theme JSON with a long line ```json { "blocks": [ { "alignment": "left", "segments": [ { "foreground": "#ff8080", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "always_enabled": false, "display_exit_code": true, "error_color": "#e91e63", "postfix": "]", "prefix": "[⌧ EXIT" }, "style": "powerline", "trailing_diamond": "", "type": "exit" }, { "background": "#ffe9aa", "foreground": "#100e23", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "root_icon": "☠" }, "style": "powerline", "trailing_diamond": "", "type": "root" }, { "background": "#000000", "foreground": "#ffffff", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "postfix": " ", "user_info_separator": "@" }, "style": "powerline", "trailing_diamond": "", "type": "session" }, { "background": "#0000c0", "foreground": "#ffffff", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "prefix": "  ", "style": "short" }, "style": "powerline", "trailing_diamond": "", "type": "path" }, { "background": "#00ffff", "foreground": "#000000", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "command": "o=$(dotnet --version 2>/dev/null); X=$?; if [ $X -eq 0 ]; then { echo $o; exit 0; }; elif [ $X -eq 145 ]; then { echo \"[unsupported global.json]\"; exit 0; }; else exit 1; fi", "prefix": "  ", "shell": "bash" }, "style": "powerline", "type": "command" }, { "background": "#ebcc34", "foreground": "#000000", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "text": "This is a really long line that should cause things to wrap and might not end nicely." }, "style": "powerline", "type": "text" }, { "background": "#00cc00", "foreground": "#000000", "powerline_symbol": "", "properties": { "bitbucket_icon": "", "branch_ahead_icon": "↑", "branch_behind_icon": "↓", "branch_icon": "", "branch_identical_icon": "≡", "cherry_pick_icon": " ", "commit_icon": " ", "display_stash_count": true, "display_upstream_icon": true, "git_icon": "", "github_icon": "", "gitlab_icon": "", "local_staged_icon": "", "local_working_icon": "", "merge_icon": " ", "rebase_icon": " ", "stash_count_icon": " ", "tag_icon": "笠 " }, "style": "powerline", "type": "git" } ], "type": "prompt", "vertical_offset": 0 } ], "console_title": false, "final_space": true } ```
JanDeDobbeleer commented 4 years ago

@tillig this only seems to happen once. When I set the this prompt the first time, it had the issue. However, every subsequent call (when set in the prompt) it did not occur again.

JanDeDobbeleer commented 4 years ago
afbeelding
tillig commented 4 years ago

Maybe there's a difference in how it works between when it's run interactively vs. setting the prompt in the background?

JanDeDobbeleer commented 4 years ago

Got it, when I print your prompt it also happens on mine.

afbeelding

EDIT: those colors are killing me :-)

JanDeDobbeleer commented 4 years ago

Fixed

afbeelding
tillig commented 4 years ago

It could be just me... but I'm still seeing this using 3.17.0. It happens with both a manual execution and as a prompt backing a PowerShell Core session.

Continued color block at end of screen

The first prompt is fine, but an ls -la makes the second prompt appear at the bottom of the screen and scroll. This is when I see the color.

I thought it might have to do with my right-aligned time segment or the newline in my theme, but removing them doesn't seem to matter.

Cursor at the end of the prompt but INSIDE the colored bar

Here's the theme I'm using if it helps:

illig.json ```json { "blocks": [ { "alignment": "left", "segments": [ { "foreground": "#ff8080", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "always_enabled": false, "display_exit_code": true, "error_color": "#e91e63", "postfix": "]", "prefix": "[⌧ EXIT" }, "style": "powerline", "trailing_diamond": "", "type": "exit" }, { "background": "#ffe9aa", "foreground": "#100e23", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "root_icon": "☠" }, "style": "powerline", "trailing_diamond": "", "type": "root" }, { "background": "#000000", "foreground": "#ffffff", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "postfix": " ", "user_info_separator": "@" }, "style": "powerline", "trailing_diamond": "", "type": "session" }, { "background": "#0000c0", "foreground": "#ffffff", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "prefix": "  ", "style": "short" }, "style": "powerline", "trailing_diamond": "", "type": "path" }, { "background": "#00ffff", "foreground": "#000000", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "prefix": "  " }, "style": "powerline", "type": "dotnet" }, { "background": "#ebcc34", "foreground": "#000000", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "prefix": " ⎈ " }, "style": "powerline", "type": "kubectl" }, { "background": "#3493eb", "foreground": "#000000", "invert_powerline": false, "leading_diamond": "", "powerline_symbol": "", "properties": { "prefix": " ﴃ " }, "style": "powerline", "type": "az" }, { "background": "#00cc00", "foreground": "#000000", "powerline_symbol": "", "properties": { "bitbucket_icon": "", "branch_ahead_icon": "↑", "branch_behind_icon": "↓", "branch_icon": "", "branch_identical_icon": "≡", "cherry_pick_icon": " ", "commit_icon": " ", "display_stash_count": true, "display_upstream_icon": true, "git_icon": "", "github_icon": "", "gitlab_icon": "", "local_staged_icon": "", "local_working_icon": "", "merge_icon": " ", "rebase_icon": " ", "stash_count_icon": " ", "tag_icon": "笠 " }, "style": "powerline", "type": "git" } ], "type": "prompt", "vertical_offset": 0 }, { "alignment": "right", "segments": [ { "foreground": "#ffffff", "properties": { "postfix": "]", "prefix": "[", "time_format": "15:04" }, "style": "plain", "type": "time" } ], "type": "prompt", "vertical_offset": 0 }, { "type": "newline" }, { "alignment": "left", "segments": [ { "properties": { "postfix": ">" }, "style": "plain", "type": "shell" } ], "type": "prompt", "vertical_offset": 0 } ], "console_title": false, "final_space": true } ```
JanDeDobbeleer commented 4 years ago

That's super strange and really shouldn't happen as it literally makes no sense. There's no other shell where this seems to happen so PS needs to get its act together. I couldn't reproduce it anymore, but I'll try to play around with your config 👍🏻

nwykes commented 4 years ago

not sure if helpful, but another way to reproduce this is to add a newline block as the first block. prompt will display correctly until something like a dir is done, then I get the background issue on the main block. only happens in PowerShell. my zsh on Mac and linux don't exhibit this.

JanDeDobbeleer commented 4 years ago

@tillig the last release contains a change in how the newline is created, that might have a positive impact on this as well (didn't test it yet, looking forward to your experience).

tillig commented 4 years ago

Under 3.20.1 it's actually worse. Not only do I still get the bar, but I have a newline in my prompt and that gets ignored so the cursor ends up on the wrong line when the prompt is rendered. You can see three cases here:

Screen Shot 2020-10-20 at 6 53 21 AM
tillig commented 4 years ago

Unclear if it helps, but the only way I found to fix this in the original OMP was to actively write blank characters to clear the next line, then reset the rendering location to the beginning of the line to continue rendering.

Like an old typewriter where \r is actually separate from \n:

I mean, I get that's not how this version works, but maybe it will spark an idea or something.

JanDeDobbeleer commented 4 years ago

This still sounds a lot more like a bug on Powershell than anything we can consistently solve. First, I'll revert this one as it works on MacOS Powershell on my end, but not consistently everywhere else.

tillig commented 4 years ago

I found an issue that describes this somewhat, possibly connected? PowerShell/PowerShell#11267

JanDeDobbeleer commented 4 years ago

I think we'll need to keep a list of issues that are specific to Powershell. Currently there's two I observed:

tillig commented 4 years ago

Yeah, I mean, it sounds like it's definitely PowerShell and not the terminal. Perhaps just some docs to make it well known is good enough.

Meantime... I may end up switching back to original PowerShell OMP v2 since I'd figured out a solution to this stuff using the $host and manually clearing things on wrap. It's not the new fancy stuff, but it worked. 😢

fdncred commented 4 years ago

Piling on. I just noticed this in pwsh in vscode. Using 3.20.4. I only notice this when using vscode. Using Windows Terminal. Going to try work-around. image

JanDeDobbeleer commented 4 years ago

I have the impression everything is connected to the newline issue. So, there's no way to get consistent newline behavior that doesn't break the prompt without using \x1b[1000C in Powershell. To my understanding that's what's possibly causing this issue. Now, using the following in the prompt function does not work (at least on MacOS):

`n 
\n

Hacking the prompt function like this does work however:

[ScriptBlock]$Prompt = {
    $err = $? ? 0 : 1
    $prompts = (oh-my-posh -config $theme -error $err) -split "\n"
    Foreach ($prompt in $prompts) {
        Write-Host $prompt -NoNewline
        if ($prompt -ne $prompts[-1]) {
            Write-Host "`n" -NoNewline
        }
    }
    return " "
}

My theory is that if I or someone else can crack the newline nut, this issue will also get resolved.

JanDeDobbeleer commented 4 years ago

I might have found something. Stay tuned.

JanDeDobbeleer commented 4 years ago

Looking forward to seeing the experience with 3.23.0

tillig commented 4 years ago

Using v3.23.1 and the prescribed PowerShell block in my profile...

[ScriptBlock]$Prompt = {
    $realLASTEXITCODE = $global:LASTEXITCODE
    if ($realLASTEXITCODE -isnot [int]) {
        $realLASTEXITCODE = 0
    }
    $startInfo = New-Object System.Diagnostics.ProcessStartInfo
    # I just downloaded it and ran it directly
    $startInfo.FileName = "/Users/tillig/Downloads/posh-darwin-amd64"
    # I think $config is a remnant from something else. There's no other
    # reference to it anywhere here.
    # $config = $global:PoshSettings.Theme
    $startInfo.Arguments = "-config /Users/tillig/dev/tillig/PowerShellProfile/themes/illig.json -pwd $PWD -error $realLASTEXITCODE"
    $startInfo.Environment["TERM"] = "xterm-256color"
    $startInfo.CreateNoWindow = $true
    $startInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8
    $startInfo.RedirectStandardOutput = $true
    $startInfo.UseShellExecute = $false
    if ($PWD.Provider.Name -eq "FileSystem") {
        $startInfo.WorkingDirectory = $PWD
    }
    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $startInfo
    $process.Start() | Out-Null
    $standardOut = $process.StandardOutput.ReadToEnd()
    $process.WaitForExit()
    $standardOut
    $global:LASTEXITCODE = $realLASTEXITCODE
    Remove-Variable realLASTEXITCODE -Confirm:$false
}
Set-Item -Path Function:prompt -Value $Prompt -Force

When I run it in iTerm2 on Mac I still see the issue when it scrolls past the end of the window.

Startup - so far so good...

New window, prompt working

...scrolling at the bottom, uh oh.

Scroll at the bottom still wraps
JanDeDobbeleer commented 4 years ago

Great. Just great. throws table

tillig commented 4 years ago

What if OMP was, itself, responsible for the line wrapping? Which is to say, perhaps a line length parameter could be provided such that if the line reached that length then OMP could reset the color; manually insert a newline; start the color again; and continue on. Default behavior without the line length parameter could be to do what it's doing now; for PowerShell it could be based on $host.UI.RawUI.BufferSize.Width.

JanDeDobbeleer commented 4 years ago

I already reset the colors so to be fair it's really a Powershell issue in my experience.

tillig commented 4 years ago

I'm not disagreeing that it's PowerShell, but the colors aren't getting reset on line wrap, are they? Maybe I missed that. From the linked issue, I gather it's like:

The idea was that if the lines don't wrap and instead

Then maybe it wouldn't be seen. But I understand, it's totally an artifact of the "get the previous line color and fill the next line" that PowerShell alone is doing.

JanDeDobbeleer commented 4 years ago

Let's try this for the sake of experience 😀

nwykes commented 4 years ago

I no longer have this issue with my newline as first block example.

JanDeDobbeleer commented 4 years ago

I think...I really think...I found a fix. And I can't understand why I didn't see this option before. I could consistently reproduce it and with this change it's gone.

JanDeDobbeleer commented 4 years ago

@tillig when you have time can you double check on your end?

tillig commented 4 years ago

Oh, yeah, sorry, I didn't get a notification that anything had changed. I'll try it today.

tillig commented 4 years ago

Using 3.23.7, MacOS, iTerm2, PowerShell Core 7.0.3... No luck. At least, not when just running it from a command prompt. It's somewhat involved to switch my PS profile back and forth between OMP2 and OMP3 so in this case I just commented out the OMP2 from my profile and ran OMP3 directly. I'm not sure it would make a difference.

Screen Shot 2020-10-30 at 7 09 43 AM
tillig commented 4 years ago

I'm not great with ANSI codes, but the thing that clears to EOL... can that be given a particular color? What if I could provide it with my shell background color so even if PowerShell is getting the background color of the next line from the color ending the previous line (which I gather is the issue) it could be overridden by just saying, "No, the color to clear with is 'black' so do that, please."

JanDeDobbeleer commented 4 years ago

It clears the line meaning it actually removes all colors (and text). I could reproduce it consistently just like your screenshot, but with that fix it didn't happen anymore. That being said, I also changed the invocation so it could as well be the combination of both is needed for this. The only fix, which is a hack, would be to write the colors and restore the cursor but that just ridiculous. I would really check it when set in the prompt as I know there's a clear difference in how it behaves.

tillig commented 4 years ago

Sure, it'll take a bit to swap over but I'll give it a go and get back here. Might not be today.

JanDeDobbeleer commented 4 years ago

I've got time, I was trying to break it again but don't seem to be able to.

JanDeDobbeleer commented 4 years ago

@tillig found it. I can reproduce your issue, I see what I have to do.

JanDeDobbeleer commented 4 years ago

@tillig v3.23.8 contains a fix that solves it for me, I tried to recreate your prompt which got me the same issue. As I only cleared the line AFTER writing the prompt, it didn't work for multiline prompts when scrolling and only for the last line (that was my test intially). Now it clears the line after every write, which, at least on my machine, results in what I expect in terms of rendering.

tillig commented 4 years ago

🎉 🎉 🎉

SUCCESS! I can now run it and also no longer see the background color issue even when it scrolls. EXCELLENT WORK!

tillig commented 4 years ago

Of course, PowerShell Gallery is down now so I can't upgrade my modules. But I'll get there. 😄

JanDeDobbeleer commented 4 years ago

I can't even push modules 😭🤣

JanDeDobbeleer commented 4 years ago

@tillig published. If everything checks out can you close the issue?

tillig commented 4 years ago

Yup yup. It'll be Monday before I get back here but I'm on it.

tillig commented 4 years ago

Verified- this totally works! I have oh-my-posh module v3.26.2 installed and running now without the issue. Thanks!

tillig commented 1 year ago

@JanDeDobbeleer This seems to have been regressed in a recent release, likely as part of #3464 / #3471. Things were fine as of 14.2.1 and regressed at 14.2.2.

JanDeDobbeleer commented 1 year ago

@tillig yes, and this is a bug in PowerShell imho. We end the coloring correctly, it shouldn't do this. I put in a ton of work to get this right, and we can't end a prompt with those escape sequences, because that has other really annoying side effects.

tillig commented 1 year ago

I get it, it just wasn't expected or noted in the release or anything. I guess this can serve as the note that this is expected behavior.

tillig commented 1 year ago

Possibly related:

JanDeDobbeleer commented 1 year ago

@tillig I'll try to reproduce this on other shells. If it doesn't happen there we surely have a PowerShell bug. I could optionally ONLY do it for PowerShell, but that should be removed at one point in time.

JanDeDobbeleer commented 1 year ago

I know that this brings an issue back from the dead, but this hack can't stay in anymore as it breaks rprompt now. Let the PowerShell team fix their own bugs.

tillig commented 1 year ago

I get it, but the irony is not lost on me that the name of this thing is oh-my-posh - "posh" like "powershell" - and the hack to make it work in PowerShell is what's going away. 😆

JanDeDobbeleer commented 1 year ago

@tillig well, we cannot be held responsible to keep fixing their bugs. Keeping this hack in place creates another bug, namely chopping off the last character on the line. So it's not acceptable anymore.