Skip to content

Navigation Menu

Sign in
Appearance settings
Sign up
Appearance settings

Track OSC 133 Prompts and Clear on Resize - #8961

#8961
Draft
nixpulvis wants to merge 1 commit into
alacritty:masteralacritty/alacritty:masterfrom
nixpulvis:terminal-reflownixpulvis/alacritty:terminal-reflowCopy head branch name to clipboard
Draft

Track OSC 133 Prompts and Clear on Resize#8961
nixpulvis wants to merge 1 commit into
alacritty:masteralacritty/alacritty:masterfrom
nixpulvis:terminal-reflownixpulvis/alacritty:terminal-reflowCopy head branch name to clipboard

Conversation

@nixpulvis

@nixpulvis nixpulvis commented May 29, 2026

Copy link
Copy Markdown
Contributor

Wire OSC 133 ;A and ;C through to Term. ;A records the prompt's cursor position as an active mark, ;C clears it. Before resizing the grid, erase from the active mark to the end of the viewport and damage the affected lines. This is not active in the alt-grid.

Why

In shells like Fish, we can now enable fish_handle_reflow and avoid this:
Screenshot 2026-05-29 at 6 54 52 PM
Fish disabled reflow for alacritty, which causes right prompts to wrap incorrectly on resize.

Details

Shells (notably fish) draw right-prompts with absolute cursor positioning, producing a sparse line of [left prompt][gap][right prompt]. shrink_columns reflows that detached tail onto a stray continuation row on horizontal shrink. The grid has no structural way to distinguish that gap from typed interior whitespace (shrink_reflow_empty_cell_inside_line deliberately reflows the latter), so any pure-grid fix would change that contract.

Erasing the grid after a OSC 133 mark instead and letting the shell repaint sidesteps the ambiguity and follows from what kitty (screen.c's prevent_current_prompt_from_rewrapping plus its blank-and-repaint on resize) and ghostty (Terminal.resize checking cursor.semantic_content != .output) already do to some degree. I looked a bit at various implementations of this and there are major differences across the board, but clearing after the prompt and relying on shells to redrawn on SIGWINCH is a theme. Some terminals wrap the shell to help facilitate the OSC 133 integration, which I don't think is a good idea for Alacritty.

This approach says, if you emit OSC 133, you agree to redraw your prompt completely. Simple as that.

Technically, kitty's approach of using the OSC 133 regions to save the prompt and reflow around it without clearing it in a visible draw frame avoids some flickering, but I'm personally not bothered by the flicker whie redrawing, and it's a lot more complexity to do things that way. The goal here is just to allow the end state to be consistent after a resize.

Shell Cooperation

Fish sets fish_handle_reflow=0 when $TERM matches alacritty*, predating this work. It can be overridden with set --global fish_handle_reflow 1 until fish drops the alacritty exclusion upstream. With fish_handle_reflow 1 on SIGWINCH the prompt will be redrawn completely and now correctly.

Users of bash or zsh don't get OSC 133 built in, but can be enabled by writing the escape sequence themselves.

It should be noted that bash only redraws the last line, so users who implement OSC 133 for themselves in bash and have multi-line prompts, will see their top line of the prompt cleared on resize, but not redrawn. I believe this is a valid tradeoff though, since most bash users are A) unlikely to be implementing OSC 133 I'd imagine, and B) also unlikely to be using multi-line prompts. I don't believe there's any other way for bash to show a regression.

Depends on alacritty/vte#152 for the new Handler methods. If/when that's released, this PR can be updated to use the released version, however the best way to do that is.

Wire up OSC 133 ;A and ;C through to Term. ;A records the prompt's
cursor position as an active mark; ;C clears it. Before resizing the
grid, erase from the active mark to the end of the viewport and damage
the affected lines.

Shells (e.g. fish) draw right-prompts with absolute cursor positioning,
producing a sparse line of [left prompt][gap][right prompt].
shrink_columns reflows that detached tail onto a stray continuation row
on horizontal shrink. The grid has no structural way to distinguish that
gap from typed interior whitespace (see the
shrink_reflow_empty_cell_inside_line test which deliberately reflows the
latter), so any pure-grid fix would change that contract. Erasing the
OSC 133 marked region instead and letting the shell repaint sidesteps
the ambiguity and matches what kitty and ghostty already do. Fish, for
example has a fish_handle_reflow variable to control this behavior.

;B and ;D are wired as default no-ops; Alacritty doesn't need them
for resize. Existing shrink_columns reflow behavior is unchanged for
content without an active prompt mark.
@chrisduerr

Copy link
Copy Markdown
Member

I assume when opening this PR you just deleted the PR template that asked about no LLM being involved in the creation of this PR? Or was that not prefilled as part of the PR template at all?

@chrisduerr chrisduerr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach says, if you emit OSC 133, you agree to redraw your prompt completely. Simple as that.

Says who? This is just winging it for the result, isn't it?

From what I can tell, the entirety of this PR seems to be based around introducing some new proprietary escape sequence for the sole purpose of avoiding artifacts when resizing the window, which notably is not even the intended purpose of that escape sequence? Am I understanding this right?

It should be noted that bash only redraws the last line, so users who implement OSC 133 for themselves in bash and have multi-line prompts, will see their top line of the prompt cleared on resize, but not redrawn. I believe this is a valid tradeoff though, since most bash users are A) unlikely to be implementing OSC 133 I'd imagine, and B) also unlikely to be using multi-line prompts. I don't believe there's any other way for bash to show a regression.

What? So bash, the most common shell of them all is broken and somehow that's fine? Why are bash users any less likely to use this than OSC 133? Just because it's broken on bash? If we break it on all shells, then we just don't have to implement it, right?

Also why was this not brought up in #5850 before implementation?

@nixpulvis

nixpulvis commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

I assume when opening this PR you just deleted the PR template that asked about no LLM being involved in the creation of this PR? Or was that not prefilled as part of the PR template at all?

Was almost certainly my fault when I copy and pasted the description from my editor, sorry about that. No LLM written code here.

What? So bash, the most common shell of them all is broken and somehow that's fine? Why are bash users any less likely to use this than OSC 133? Just because it's broken on bash? If we break it on all shells, then we just don't have to implement it, right?

I wouldn't say it's completely broken, it just breaks multiline prompts when resizing. That said, it's really because I didn't feel you would be open to the hoops other terminals jump through to support this. For example ghostty injects custom OSC 133 escapes with a custom parameter of last=true on bash to only clear the last row to avoid this. Kitty does something I actually like a bit, but is much more work to save the state of the prompt, then clear it, reflow, then restore it. That could be what we agree on, since it's a complete solution I believe, but more machinery than this.

Also why was this not brought up in #5850 before implementation?

I guess I wanted a PoC to actually make sure I could solve my issue, and that issue seems more focused on the general case of tracking prompts, commands, and outputs. This doesn't expose any of that to users in any way. The VTE patch would absolutely make that possible, and I'd be in favor of implementing an action like "jump to next/last command" etc. Sorry for kinda jumping into this, I was just feeling crafty recently.

@chrisduerr

Copy link
Copy Markdown
Member

I wouldn't say it's completely broken, it just breaks multiline prompts when resizing. That said, it's really because I didn't feel you would be open to the hoops other terminals jump through to support this. For example ghostty injects custom OSC 133 escapes with a custom parameter of last=true on bash to only clear the last row to avoid this. Kitty does something I actually like a bit, but is much more work to save the state of the prompt, then clear it, reflow, then restore it. That could be what we agree on, since it's a complete solution I believe, but more machinery than this.

If this escape is not suitable to solve the problem you're trying to solve and instead requires hacks anyway, then isn't this a pretty clear indicator that this escape is not useful? I have no interest in supporting an escape just because it allows implementing a weird hack to work around a perceived issue.

I guess I wanted a PoC to actually make sure I could solve my issue
Sorry for kinda jumping into this, I was just feeling crafty recently.

That's fair, though I'm really not a fan of this escape, which I assume you could have guessed. I don't like forcing a decision by opening up a PR, so while I know you've been annoyed by the underlying issue for a long time, I have no interest in rushing the implementation of a proprietary escape we'll never be able to remove again. As long as that's okay with you, I have no problem with just opening up a PR.

@chrisduerr

Copy link
Copy Markdown
Member

@perfbot It's been a while, but this might alter scroll region performance.

@nixpulvis

Copy link
Copy Markdown
Contributor Author

Yea, I was by no means trying to force or rush anything. If anything I knew this wasn't going to be merged as-is, so I wanted to spark the discussion with something a bit more meaningful, and at least for my own understanding of the issue.

I wouldn't say the escape isn't meaningful here, it gives us exactly the region where the prompt lives, which is core to what could be a complete solution which handles bash properly as well. The issue at the moment is the simple "clear the viewport after the prompt" assumes shells redraw the whole prompt, which is true for zsh and fish for example, but not bash.

@chrisduerr

Copy link
Copy Markdown
Member

I wouldn't say the escape isn't meaningful here, it gives us exactly the region where the prompt lives, which is core to what could be a complete solution which handles bash properly as well. The issue at the moment is the simple "clear the viewport after the prompt" assumes shells redraw the whole prompt, which is true for zsh and fish for example, but not bash.

Shells that know Alacritty is resizing them can already work around this issue by taking this into account anyway though, right? Like even without any support from Alacritty.

*cell = bg.into();
}
if mark.line.0 + 1 < screen_lines {
self.grid.reset_region((mark.line + 1)..);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to ask if it made sense to create a function for resetting a region from row,col to row,col like this need or if this is fine as is.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably fine, we do the exact same thing for ansi::ClearMode::Below:

                if (cursor.line.0 as usize) < screen_lines - 1 {
                    self.grid.reset_region((cursor.line + 1)..);
                }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(though to be fair, this means there's at least 2 places where this is needed, so it could also be taken as an argument for introducing a new function)

@perfbot

perfbot commented May 30, 2026

Copy link
Copy Markdown

results

@chrisduerr

Copy link
Copy Markdown
Member

Hard to tell from just a single run, but that does look like a performance regression in region scrolling.

@chrisduerr

Copy link
Copy Markdown
Member

@perfbot Let's give it another shot with latest arch and rust.

@perfbot

perfbot commented May 30, 2026

Copy link
Copy Markdown

results

@chrisduerr

Copy link
Copy Markdown
Member

Now I wish I had run it twice before updating.

@nixpulvis
nixpulvis marked this pull request as draft May 30, 2026 13:59
@nixpulvis nixpulvis changed the title Track OSC 133 Prompts and Clear them on Resize Track OSC 133 Prompts and Clear on Resize May 30, 2026
@nixpulvis

Copy link
Copy Markdown
Contributor Author

Remind me, where are the SHAs coming from for these benches? Also what are the version numbers?

@chrisduerr

Copy link
Copy Markdown
Member

Remind me, where are the SHAs coming from for these benches? Also what are the version numbers?

SHAs are master (purple) and PR (green). By version I'd assume you mean the 1.96.0, which is the Rust version used.

@chrisduerr

Copy link
Copy Markdown
Member

My draft PR which prompted this (pun intended) was actually to support fish_handle_reflow: #8961, but A) I'm not happy with the prompt marking on the Term and B) it doesn't track the complete set of OSC 133 markers.

I'm thinking a better design would be to store the markers in a Cell with Flags and CellExtra. We seem to have exactly one bit left in Flags so it should fit without extending it, though there's a real question there of what to do when we want another new flag down the road. Saving this bit could be useful... So I'm open to suggestions here. CellExtra would store the OSC 133 marker kind.

If anyone has a thought on a better way to do this, I'm all ears. This avoids having to manually reflow marker points on resize and scroll though, which will be much more important when we start tracking not just the current prompt like my draft PR does, but every marker.

We should keep conversations about this specific implementation in this patch. I'm definitely not putting this into flags, it should go into CellExtra.

@nixpulvis

nixpulvis commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

Yea, good call about the Flags, seems like CellExtra is used more widely than I had originally thought and I was prematurely optimizing.

I'm looking into where we actually need to use this extra information now so it's not dropped on reflows and maybe other places.

@nixpulvis

Copy link
Copy Markdown
Contributor Author

OK, I've been playing around and this is quickly ballooning into a larger changeset than I anticipated. Some of it is expected tracking through linewraps and widechar edge cases... but then there's some things I'm still trying to understand about how Fish or other OSC 133 providers send these codes. One issue is that if we store the markers on the cells directly, then when those cells are cleared so are the marks. At first I thought this was desired, but one case specifically is making me rethink this. When the command_finished(exit_code) fires it will generally be at the same cell as the next prompt_start, that works if we allow each cell to hold multiple marks in some way (I'm testing with bitflags right now), but then fish will redraw this line, and we lose the command finished with the exit code.

I think I'll try to read over how other terminals implement this now. I know ghostty does some extra stuff to support right prompts with an additional argument to the prompt_start escape... I'm not sure if this is even documented anywhere. They refer to it as "semantic prompts" and some shells like nushell support it.

I'd love some basic support for this, so I'm not really advocating for going above and beyond the initial set of OSC 133 features. I'm not even 100% sure why the additional arguments are needed for the prompt escape. I would think just sending prompt start after command start would say the same thing... but I could be missing something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.