terminal icon indicating copy to clipboard operation
terminal copied to clipboard

Clear buffer: option to clear up to the current cursor line

Open elibarzilay opened this issue 7 months ago • 4 comments

Description of the new feature

This is a followup to #18732, which is locked. The request there is to have an option to preserve the current line in clearBuffer.

I don't have VS installed, so I can't play with the code, but I think that adding something like the below case to ControlCore::ClearBuffer should be very close to implementing this.

[It will fail in case of editing multi-line inputs, but as I described in the other issue, this is still hugely useful as a default over the current always-remove-everything option. The one thing that bothers me more about this is that it uses the beginning of the current physical line rather than the logical line. If there's a way to get that information, it would be much better.]

Proposed technical implementation details

Disclaimer: mostly made-up code based on what I see in the file. Also assumes that there's a .x and .y fields, and that they're 0-based.

        case ClearBufferType::AllToCursor:
            const til::point pos = _terminal->GetTextBuffer().GetCursor().GetPosition();
            if (til.y == 0)
            {
                // cursor at the top of the screen: just remove the scrollback
                command = L"\x1b[3J";
            }
            else
            {
                // otherwise: clear scrallback, move to top at the same column, delete rows up to cursor position
                command = fmt::format(FMT_COMPILE(L"\x1b[3J\x1b[H\x1b[{}M\x1b[1;{}H"), pos.y, pos.x + 1);
            }
            break;

For reference, a bash version of this:

clearToCursor() {
  # read cursor position
  IFS='[;' read -s -d R -p $'\e[6n' -r -u 0 _ ROW COL
  if [[ $ROW -eq 1 ]]; then
    # on top row => just clear the scrollback
    printf '\e[3J'
  else
    # clear scrollback, goto top, delete ROW-1 lines
    printf '\e[3J\e[H\e[%dM\e[1;%dH' $((ROW-1)) $COL
  fi
}

elibarzilay avatar May 05 '25 12:05 elibarzilay

Two more bits of relevant information:

  • Now that #18885 is merged, this could use the same logic to make it even better and preserve the last logical line rather than the physical one. (But I added a comment there that might be considered WRT a logical line that is partially visible.)

  • By complete chance, I was using CMD today, and tried clearing the buffer. The result is strange in a way that looks like things are complicated: it works as expected when nothing is type (ie, after an enter) -- but if I start typing stuff, then clear the buffer, then type more, the editing continues from the same place. Looks like once typing starts, whatever is CMD's idea of a line-editor does not get reset. I also tried powershell, and it's the same as CMD, except that even after an enter it behaves in the same broken way. Screen-recording follows:

https://github.com/user-attachments/assets/392fb0b8-967a-47b0-b64c-dcacd5ae5bf9

Sidenote: I only mention this for completeness, since whatever was the original issue that triggered the new behavior might have been related to how things work in CMD/PS, which I almost never use (and therefore how it's broken now is not something that I care much about :).

elibarzilay avatar May 10 '25 01:05 elibarzilay

I was able to kind of install VS in a VM, not really in a productive way (since each recompilation took around 30m), but I did manage to verify that the following code seem to work:

            {
                const auto lock = _terminal->LockForWriting();
                const til::point pos = _terminal->GetCursorPosition();
                int ofs = ScrollOffset();
                if (pos.y - ofs == 0)
                {
                    // cursor is already at the top of the screen: just remove the scrollback
                    command = L"\x1b[3J";
                }
                else
                {
                    command = fmt::format(L"\x1b[3J\x1b[H\x1b[{}M\x1b[1;{}H", pos.y - ofs, pos.x + 1);
                }
            }

It's not ideal in releasing the lock just to re-grab it later when sending the string, but it does seem to do the trick.

Re my last comment, it would be nice to have that working too (clearing up to the beginning of the current logical line), but given the 30m recompilation cycle I gave up. For reference, there is a control sequence for scrolling up, eg: \x1b[2T to scroll two rows up.

elibarzilay avatar May 12 '25 07:05 elibarzilay

Your suggested fix doesn't take into account that the buffers between ConPTY and Windows Terminal should stay mostly synchronized. ClearBuffer clears the buffer fully which has useful properties. This puts the cursor at position 0,0. Since your approach only clears the Windows Terminal side, the cursors aren't synchronized anymore.

This is the entire crux why this behavior can't be changed trivially. Edit: While on a walk I think I had an idea how to fix this "simply" and somewhat elegantly. Edit 2: Doesn't work. Fuck it. Shitty solution it is.

lhecker avatar May 27 '25 13:05 lhecker

  1. My suggestion uses only control sequences -- are they not implemented properly somehow?

  2. See the second part in my earlier comment: it is currently already broken in CMD/PS, which makes me think that the answer to the above is "yes".

  3. Regardless, it seems to me like a good direction to implement a control-sequence-only solution independently of fixing whatever's broken. More so given that it's broken in CMD/PS anyway.

elibarzilay avatar May 27 '25 15:05 elibarzilay