added support for fish_sequence_key_delay_ms to set how long to wait between sequence key presses

This commit is contained in:
yanshay 2023-07-29 19:23:07 +03:00 committed by Fabian Boehm
parent 724b44907e
commit 8a8c7abb0f
5 changed files with 56 additions and 12 deletions

View file

@ -317,6 +317,7 @@ static std::unique_ptr<const var_dispatch_table_t> create_dispatch_table() {
var_dispatch_table->add(L"fish_term256", handle_fish_term_change); var_dispatch_table->add(L"fish_term256", handle_fish_term_change);
var_dispatch_table->add(L"fish_term24bit", handle_fish_term_change); var_dispatch_table->add(L"fish_term24bit", handle_fish_term_change);
var_dispatch_table->add(L"fish_escape_delay_ms", update_wait_on_escape_ms); var_dispatch_table->add(L"fish_escape_delay_ms", update_wait_on_escape_ms);
var_dispatch_table->add(L"fish_sequence_key_delay_ms", update_wait_on_sequence_key_ms);
var_dispatch_table->add(L"fish_emoji_width", guess_emoji_width); var_dispatch_table->add(L"fish_emoji_width", guess_emoji_width);
var_dispatch_table->add(L"fish_ambiguous_width", handle_change_ambiguous_width); var_dispatch_table->add(L"fish_ambiguous_width", handle_change_ambiguous_width);
var_dispatch_table->add(L"LINES", handle_term_size_change); var_dispatch_table->add(L"LINES", handle_term_size_change);

View file

@ -237,7 +237,7 @@ static void process_input(bool continuous_mode, bool verbose) {
if (reader_test_and_clear_interrupted()) { if (reader_test_and_clear_interrupted()) {
evt = char_event_t{shell_modes.c_cc[VINTR]}; evt = char_event_t{shell_modes.c_cc[VINTR]};
} else { } else {
evt = queue.readch_timed(); evt = queue.readch_timed_esc();
} }
if (!evt || !evt->is_char()) { if (!evt || !evt->is_char()) {
output_bind_command(bind_chars); output_bind_command(bind_chars);

View file

@ -465,19 +465,24 @@ class event_queue_peeker_t {
/// Check if the next event is the given character. This advances the index on success only. /// Check if the next event is the given character. This advances the index on success only.
/// If \p timed is set, then return false if this (or any other) character had a timeout. /// If \p timed is set, then return false if this (or any other) character had a timeout.
bool next_is_char(wchar_t c, bool timed = false) { bool next_is_char(wchar_t c, bool escaped = false) {
assert(idx_ <= peeked_.size() && "Index must not be larger than dequeued event count"); assert(idx_ <= peeked_.size() && "Index must not be larger than dequeued event count");
// See if we had a timeout already. // See if we had a timeout already.
if (timed && had_timeout_) { if (escaped && had_timeout_) {
return false; return false;
} }
// Grab a new event if we have exhausted what we have already peeked. // Grab a new event if we have exhausted what we have already peeked.
// Use either readch or readch_timed, per our param. // Use either readch or readch_timed, per our param.
if (idx_ == peeked_.size()) { if (idx_ == peeked_.size()) {
char_event_t newevt{L'\0'}; char_event_t newevt{L'\0'};
if (!timed) { if (!escaped) {
newevt = event_queue_.readch(); if (auto mevt = event_queue_.readch_timed_sequence_key()) {
} else if (auto mevt = event_queue_.readch_timed()) { newevt = mevt.acquire();
} else {
had_timeout_ = true;
return false;
}
} else if (auto mevt = event_queue_.readch_timed_esc()) {
newevt = mevt.acquire(); newevt = mevt.acquire();
} else { } else {
had_timeout_ = true; had_timeout_ = true;
@ -542,7 +547,7 @@ static bool have_mouse_tracking_csi(event_queue_peeker_t *peeker) {
// Maximum length of any CSI is NPAR (which is nominally 16), although this does not account for // Maximum length of any CSI is NPAR (which is nominally 16), although this does not account for
// user input intermixed with pseudo input generated by the tty emulator. // user input intermixed with pseudo input generated by the tty emulator.
// Check for the CSI first. // Check for the CSI first.
if (!peeker->next_is_char(L'\x1b') || !peeker->next_is_char(L'[', true /* timed */)) { if (!peeker->next_is_char(L'\x1b') || !peeker->next_is_char(L'[', true /* escaped */)) {
return false; return false;
} }
@ -593,8 +598,8 @@ static bool try_peek_sequence(event_queue_peeker_t *peeker, const wcstring &str)
for (wchar_t c : str) { for (wchar_t c : str) {
// If we just read an escape, we need to add a timeout for the next char, // If we just read an escape, we need to add a timeout for the next char,
// to distinguish between the actual escape key and an "alt"-modifier. // to distinguish between the actual escape key and an "alt"-modifier.
bool timed = prev == L'\x1B'; bool escaped = prev == L'\x1B';
if (!peeker->next_is_char(c, timed)) { if (!peeker->next_is_char(c, escaped)) {
return false; return false;
} }
prev = c; prev = c;

View file

@ -34,6 +34,9 @@
#define WAIT_ON_ESCAPE_DEFAULT 30 #define WAIT_ON_ESCAPE_DEFAULT 30
static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT; static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
#define WAIT_ON_SEQUENCE_KEY_INFINITE (-1)
static int wait_on_sequence_key_ms = WAIT_ON_SEQUENCE_KEY_INFINITE;
input_event_queue_t::input_event_queue_t(int in) : in_(in) {} input_event_queue_t::input_event_queue_t(int in) : in_(in) {}
/// Internal function used by readch to read one byte. /// Internal function used by readch to read one byte.
@ -138,6 +141,26 @@ void update_wait_on_escape_ms(const environment_t& vars) {
} }
} }
// Update the wait_on_sequence_key_ms value in response to the fish_sequence_key_delay_ms user variable being
// set.
void update_wait_on_sequence_key_ms(const environment_t& vars) {
auto sequence_key_time_ms = vars.get(L"fish_sequence_key_delay_ms");
if (sequence_key_time_ms.missing_or_empty()) {
wait_on_sequence_key_ms = WAIT_ON_SEQUENCE_KEY_INFINITE;
return;
}
long tmp = fish_wcstol(sequence_key_time_ms->as_string().c_str());
if (errno || tmp < 10 || tmp >= 5000) {
std::fwprintf(stderr,
L"ignoring fish_sequence_key_delay_ms: value '%ls' "
L"is not an integer or is < 10 or >= 5000 ms\n",
sequence_key_time_ms->as_string().c_str());
} else {
wait_on_sequence_key_ms = static_cast<int>(tmp);
}
}
maybe_t<char_event_t> input_event_queue_t::try_pop() { maybe_t<char_event_t> input_event_queue_t::try_pop() {
if (queue_.empty()) { if (queue_.empty()) {
return none(); return none();
@ -216,7 +239,18 @@ char_event_t input_event_queue_t::readch() {
} }
} }
maybe_t<char_event_t> input_event_queue_t::readch_timed() { maybe_t<char_event_t> input_event_queue_t::readch_timed_esc() {
return readch_timed(wait_on_escape_ms);
}
maybe_t<char_event_t> input_event_queue_t::readch_timed_sequence_key() {
if (wait_on_sequence_key_ms == WAIT_ON_SEQUENCE_KEY_INFINITE) {
return readch();
}
return readch_timed(wait_on_sequence_key_ms);
}
maybe_t<char_event_t> input_event_queue_t::readch_timed(const int wait_time_ms) {
if (auto evt = try_pop()) { if (auto evt = try_pop()) {
return evt; return evt;
} }
@ -229,7 +263,7 @@ maybe_t<char_event_t> input_event_queue_t::readch_timed() {
// pselect expects timeouts in nanoseconds. // pselect expects timeouts in nanoseconds.
const uint64_t nsec_per_msec = 1000 * 1000; const uint64_t nsec_per_msec = 1000 * 1000;
const uint64_t nsec_per_sec = nsec_per_msec * 1000; const uint64_t nsec_per_sec = nsec_per_msec * 1000;
const uint64_t wait_nsec = wait_on_escape_ms * nsec_per_msec; const uint64_t wait_nsec = wait_time_ms * nsec_per_msec;
struct timespec timeout; struct timespec timeout;
timeout.tv_sec = (wait_nsec) / nsec_per_sec; timeout.tv_sec = (wait_nsec) / nsec_per_sec;
timeout.tv_nsec = (wait_nsec) % nsec_per_sec; timeout.tv_nsec = (wait_nsec) % nsec_per_sec;

View file

@ -188,6 +188,7 @@ class char_event_t {
/// Adjust the escape timeout. /// Adjust the escape timeout.
class environment_t; class environment_t;
void update_wait_on_escape_ms(const environment_t &vars); void update_wait_on_escape_ms(const environment_t &vars);
void update_wait_on_sequence_key_ms(const environment_t& vars);
/// A class which knows how to produce a stream of input events. /// A class which knows how to produce a stream of input events.
/// This is a base class; you may subclass it for its override points. /// This is a base class; you may subclass it for its override points.
@ -204,7 +205,10 @@ class input_event_queue_t {
/// Like readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a /// Like readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a
/// character to be available for reading. /// character to be available for reading.
/// \return none on timeout, the event on success. /// \return none on timeout, the event on success.
maybe_t<char_event_t> readch_timed(); maybe_t<char_event_t> readch_timed(const int wait_time_ms);
maybe_t<char_event_t> readch_timed_esc();
maybe_t<char_event_t> readch_timed_sequence_key();
/// Enqueue a character or a readline function to the queue of unread characters that /// Enqueue a character or a readline function to the queue of unread characters that
/// readch will return before actually reading from fd 0. /// readch will return before actually reading from fd 0.