Add a clear-screen bind function to clear the screen (#10044)

This can be bound like `bind \cl clear-screen`, and is, by default

In contrast to the current way it doesn't need the external `clear`
command that was always awkward.

Also it will clear the screen and first draw the old prompt to remove
flicker.
Then it will immediately trigger a repaint, so the prompt will be overwritten.
This commit is contained in:
Fabian Boehm 2023-10-08 11:41:30 +02:00 committed by GitHub
parent f7e7396c69
commit c4ca1a68d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 36 additions and 3 deletions

View File

@ -142,6 +142,9 @@ The following special input functions are available:
``capitalize-word``
make the current word begin with a capital letter
``clear-screen``
clears the screen and redraws the prompt. if the terminal doesn't support clearing the screen it is the same as ``repaint``.
``complete``
guess the remainder of the current token

View File

@ -87,9 +87,7 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
bind --preset $argv \el __fish_list_current_token
bind --preset $argv \eo __fish_preview_current_file
bind --preset $argv \ew __fish_whatis_current_token
# ncurses > 6.0 sends a "delete scrollback" sequence along with clear.
# This string replace removes it.
bind --preset $argv \cl 'echo -n (clear | string replace \e\[3J ""); commandline -f repaint'
bind --preset $argv \cl clear-screen
bind --preset $argv \cc cancel-commandline
bind --preset $argv \cu backward-kill-line
bind --preset $argv \cw backward-kill-path-component

View File

@ -107,6 +107,7 @@ static constexpr const input_function_metadata_t input_function_metadata[] = {
{L"cancel", readline_cmd_t::cancel},
{L"cancel-commandline", readline_cmd_t::cancel_commandline},
{L"capitalize-word", readline_cmd_t::capitalize_word},
{L"clear-screen", readline_cmd_t::clear_screen_and_repaint},
{L"complete", readline_cmd_t::complete},
{L"complete-and-search", readline_cmd_t::complete_and_search},
{L"delete-char", readline_cmd_t::delete_char},

View File

@ -92,6 +92,8 @@ enum class readline_cmd_t {
end_undo_group,
repeat_jump,
disable_mouse_tracking,
// ncurses uses the obvious name
clear_screen_and_repaint,
// NOTE: This one has to be last.
reverse_repeat_jump
};

View File

@ -4341,6 +4341,27 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
outp.writestr(L"\x1B[?1000l");
break;
}
case rl::clear_screen_and_repaint: {
parser().libdata().is_repaint = true;
auto clear = screen_clear();
if (!clear.empty()) {
// Clear the screen if we can.
// This is subtle: We first clear, draw the old prompt,
// and *then* reexecute the prompt and overdraw it.
// This removes the flicker,
// while keeping the prompt up-to-date.
outputter_t &outp = stdoutput();
outp.writestr(clear.c_str());
screen.reset_line(true /* redraw prompt */);
this->layout_and_repaint(L"readline");
}
exec_prompt();
screen.reset_line(true /* redraw prompt */);
this->layout_and_repaint(L"readline");
force_exec_prompt_and_repaint = false;
parser().libdata().is_repaint = false;
break;
}
// Some commands should have been handled internally by inputter_t::readch().
case rl::self_insert:
case rl::self_insert_notfirst:

View File

@ -266,6 +266,13 @@ maybe_t<size_t> escape_code_length(const wchar_t *code) {
return found ? maybe_t<size_t>{esc_seq_len} : none();
}
wcstring screen_clear() {
if (clear_screen) {
return str2wcstring(clear_screen);
}
return wcstring{};
}
long escape_code_length_ffi(const wchar_t *code) {
auto found = escape_code_length(code);
return found.has_value() ? (long)*found : -1;

View File

@ -335,5 +335,6 @@ maybe_t<size_t> escape_code_length(const wchar_t *code);
// Always return a value, by moving checking of sequence start to the caller.
long escape_code_length_ffi(const wchar_t *code);
wcstring screen_clear();
void screen_set_midnight_commander_hack();
#endif