How do I add a keyboard shortcut to clear scrollback buffer in Windows Terminal?

Solution 1:

Well this turned into a rabbit-trail-and-a-half ;-) ...

I would have thought this would have been pretty straightforward with the sendInput action introduced in Windows Terminal 1.3, but I keep coming up short using that method. I don't claim to be any expert at keybindings or terminal escape sequences, but I'm trying to muddle through.

First, from man clear, the "clear scrollback" sequence is Esc[3J. This works in Windows Terminal via:

  • Powershell: Write-Output "`e[3J"
  • bash, zsh, or fish: printf '\033[3J' (or equivalent echo)

It, of course, needs to be coupled with the "clear entire screen" sequence (\033[2J) and the "cursor to home position" (\033[H) (obtained from this answer).

Put it together, and printf '\033[2J\033[3J\033[H' gets us the clear (without arguments) behavior.

So I would think, given the sendInput example in the Windows Terminal 1.3 release notes that we could send that escape code via:

{ "command": { "action": "sendInput", "input": "\u001B[3J" }, "keys": "ctrl+shift+l"}

in the "actions" section (formerly "keybindings"). The \u001b[A example (up arrow) works fine for me, but the "clear scrollback" results in an error bell in bash and printing [3J in fish. The same occurs for \u001B[2J for just trying to clear the screen as well. If someone can figure out where I'm going wrong on that, I'd love to know.

But ... we can rebind the keys in the shells. However, they probably won't won't be able to tell the difference between Ctrl+L and Ctrl+Shift+L for this reason. Except for the recent PSReadLine 2.0, which is case-sensitive on key-bindings.

So if you really want to use Ctrl+Shift+l in both PowerShell and Linux shells in WSL, you'll need to do it in two steps:

First, set up a Windows Terminal action to sendInput with an unused keycode:

"actions":
// formerly "keybindings"
    [
      ...
        { "command": { "action": "sendInput", "input": "\uAC12" }, "keys": "ctrl+shift+l"},
      ...
    ]
}

Honestly, I'm not sure what the best way of picking a keycode is. I just went with something from the Hangul character set (\uAC12), since I'm fairly sure I'm never going to run across that in real-life. Note that this comment recommends using the "private use" E000-EFFF range, but it seemed fairly populated on Windows Terminal, and I'd already settled on Hangul, so I've left the examples below using \uAC12.

So then we need to bind \uAC12 in each shell to send the right escape sequences:

  • Bash:

    First, get the key sequence to bind to with printf '\uAC12' | xxd, which results in 00000000: eab0 92.

    Then, using that output, encode the bind command as bind -x '"\xEA\xB0\x92":"printf \\033[2J\\033[3J\\033[H"' (xxd idea from a comment in this answer.)

  • Zsh: It looks to be a bit more involved:

    function clear-scrollback {
      clear && printf '\e[3J'
      zle && zle .reset-prompt && zle -R
    }
    zle -N clear-scrollback
    bindkey '\uAC12' clear-scrollback
    
    

    (with assist from this answer).

  • Fish: bind \uAC12 "printf '\033[2J\033[3J\033[H'; commandline -f repaint"

  • PowerShell: Set-PSReadLineKeyHandler "$([char]0xAC12)" -ScriptBlock { Write-Output "`e[2J`e[3J"; [Microsoft.PowerShell.PSConsoleReadLine]::ClearScreen() }. Assist on the [char] casting from this answer, and dang if it didn't take me a while to find an example of calling a PSReadline function in a ScriptBlock.

  • PowerShell Core: Set-PSReadLineKeyHandler "$([char]0xAC12)" -ScriptBlock { Write-Host "`e[2J`e[3J"; [Microsoft.PowerShell.PSConsoleReadLine]::ClearScreen() }. Not sure why PowerShell and PowerShell Core behave differently here.

Corrections or suggestions for improvement welcome.

Solution 2:

Edit your ~/.bashrc

alias cls='clear && echo -en "\e[3J"'

Now you can type cls to clear the screen and scrollback inside your bash WSL session.

Edit your Windows Terminal JSON file

"actions": 
[
    // Command to reset terminal and scrollback
    { 
        "command": 
        { 
            "action": "sendInput", "input": "cls\r" 
        }, 
        "keys": "ctrl+k"
    },
]

Now pressing CTRL+k will enter the CLS command for you. For PowerShell or a CMD prompt, the CLS command is already supported by default, so no extra config is necessary.

Solution 3:

Update 2021-10-20: This is now natively supported as of version 1.12 (in preview at time of writing).

See PR #10906 for full details.

This adds a new action, clearBuffer. It accepts 3 values for the clear type:

  • "clear": "screen": Clear the terminal viewport content. Leaves the scrollback untouched. Moves the cursor row to the top of the viewport (unmodified).

  • "clear": "scrollback": Clear the scrollback. Leaves the viewport untouched.

  • "clear": "all": (default) Clear the scrollback and the visible viewport. Moves the cursor row to the top of the viewport (unmodified).

  • "Clear Buffer" has also been added to defaults.json.

These actions can be invoked from the command palette or can be bound to keyboard shortcuts via the settings UI, and directly in settings.json as covered in the official documentation.

Binding a shortcut to the Clear buffer action

Clear buffer action in settings.json

Windows Terminal clearBuffer action example


For reference, here's a discussion on the difference between Cmd ⌘+K and Ctrl+L: What is the difference between Ctrl+L and Cmd+K for clearing the terminal screen?

Longer answer

According to Mike Griese (zadjii-msft on GitHub), an engineer working on Windows Terminal:

To clarify for future me - cmd+k is not something that's being handled by bash or the shell. This is the Terminal itself handling the keybinding, and clearing both the buffer and the scrollback.

You've described a user story that makes sense to me, so I'm gonna put this on the backlog.

Dustin Howett (DHowett-MSFT on GitHub) goes on to say:

[T]his issue in particular that's thornier than most. For compatibility with Windows console applications that do not expect a terminal to be connected, we need to maintain a text buffer for them to read. That's all. Because we don't have a way to clear that text buffer (from the terminal side), and we just haven't written one yet, it's only more complex than clearing the local screen. It's not a complexity class issue with all of Terminal.

Reference: https://github.com/microsoft/terminal/issues/1882