Send both 2J and 3J on clear (#14181)

Fixes #14176

# Description

Since the Linux `/usr/bin/clear` binary doesn't exhibit the issue in
#14176, I checked to see what ANSI escapes it is emitting:

```nu
nu -c '^clear; "111\n222\n333"' | less
# or
bash -c 'clear -x; echo -e "111\n222\n333"' | less
```

Both show the same thing:

```
ESC[HESC[2JESC[3J111
222
333
(END)
```

This is the equivalent of:

```nu
$"(ansi home)(ansi clear_entire_screen)(ansi clear_entire_screen_plus_buffer)111\n222\n333"
```

However, our internal `clear` is sending only the Home and 3J. While
this *should*, in theory, work, it's (a) clear that it doesn't, and (b)
`/usr/bin/clear` seemingly knows this and already has the solution (or
at least workaround). From looking at the `ncurses` source, it appears
it is getting this information from the terminal capabilities. That
said, support for `2J` and `3J` is fairly universal, and it's what we
send in `clear` and `clear --keep-scrollback` anyway, so there's no harm
AFAICT in sending both like `/usr/bin/clear` does.

Also tested and fixes the issue on Windows. Note that PowerShell
`Clear-Host` also did not have the issue.

Side-note: It's interesting that on Tmux, which doesn't support 2J and
3J, that `/usr/bin/clear` knows this and doesn't send those codes,
sending just an escape-[J instead. However, Nushell's `clear`, of
course, isn't checking terminal capabilities, and is continuing to send
the unsupported codes. Fortunately this doesn't appear to cause any
issues on Tmux.

# User-Facing Changes

None, AFAICT - Bugfix only.

# Tests + Formatting

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

N/A
This commit is contained in:
Douglas 2024-10-28 07:42:18 -04:00 committed by GitHub
parent 69d81cc065
commit eedf833b6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -41,14 +41,21 @@ impl Command for Clear {
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let clear_type: ClearType = match call.has_flag(engine_state, stack, "keep-scrollback")? { match call.has_flag(engine_state, stack, "keep-scrollback")? {
true => ClearType::All, true => {
_ => ClearType::Purge, std::io::stdout()
.queue(MoveTo(0, 0))?
.queue(ClearCommand(ClearType::All))?
.flush()?;
}
_ => {
std::io::stdout()
.queue(MoveTo(0, 0))?
.queue(ClearCommand(ClearType::All))?
.queue(ClearCommand(ClearType::Purge))?
.flush()?;
}
}; };
std::io::stdout()
.queue(ClearCommand(clear_type))?
.queue(MoveTo(0, 0))?
.flush()?;
Ok(PipelineData::Empty) Ok(PipelineData::Empty)
} }