mirror of
https://github.com/nushell/nushell.git
synced 2025-05-10 09:52:58 +00:00
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
78 lines
2.0 KiB
Rust
78 lines
2.0 KiB
Rust
use crossterm::{
|
|
cursor::MoveTo,
|
|
terminal::{Clear as ClearCommand, ClearType},
|
|
QueueableCommand,
|
|
};
|
|
use nu_engine::command_prelude::*;
|
|
|
|
use std::io::Write;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Clear;
|
|
|
|
impl Command for Clear {
|
|
fn name(&self) -> &str {
|
|
"clear"
|
|
}
|
|
|
|
fn description(&self) -> &str {
|
|
"Clear the terminal."
|
|
}
|
|
|
|
fn extra_description(&self) -> &str {
|
|
"By default clears the current screen and the off-screen scrollback buffer."
|
|
}
|
|
|
|
fn signature(&self) -> Signature {
|
|
Signature::build("clear")
|
|
.category(Category::Platform)
|
|
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
|
.switch(
|
|
"keep-scrollback",
|
|
"Do not clear the scrollback history",
|
|
Some('k'),
|
|
)
|
|
}
|
|
|
|
fn run(
|
|
&self,
|
|
engine_state: &EngineState,
|
|
stack: &mut Stack,
|
|
call: &Call,
|
|
_input: PipelineData,
|
|
) -> Result<PipelineData, ShellError> {
|
|
match call.has_flag(engine_state, stack, "keep-scrollback")? {
|
|
true => {
|
|
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()?;
|
|
}
|
|
};
|
|
|
|
Ok(PipelineData::Empty)
|
|
}
|
|
|
|
fn examples(&self) -> Vec<Example> {
|
|
vec![
|
|
Example {
|
|
description: "Clear the terminal",
|
|
example: "clear",
|
|
result: None,
|
|
},
|
|
Example {
|
|
description: "Clear the terminal but not its scrollback history",
|
|
example: "clear --keep-scrollback",
|
|
result: None,
|
|
},
|
|
]
|
|
}
|
|
}
|