Added fish_sequence_key_delay_ms to set time to wait between sequence key presses (#7401) (#9926)

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

* fixed cargo fmt
This commit is contained in:
yanshay 2023-08-31 00:12:22 +03:00 committed by GitHub
parent b54faf9469
commit 01db48a712
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 12 deletions

View file

@ -61,6 +61,10 @@ static VAR_DISPATCH_TABLE: once_cell::sync::Lazy<VarDispatchTable> =
table.add_anon(L!("fish_term256"), handle_fish_term_change);
table.add_anon(L!("fish_term24bit"), handle_fish_term_change);
table.add_anon(L!("fish_escape_delay_ms"), update_wait_on_escape_ms);
table.add_anon(
L!("fish_sequence_key_delay_ms"),
update_wait_on_sequence_key_ms,
);
table.add_anon(L!("fish_emoji_width"), guess_emoji_width);
table.add_anon(L!("fish_ambiguous_width"), handle_change_ambiguous_width);
table.add_anon(L!("LINES"), handle_term_size_change);
@ -105,6 +109,11 @@ fn update_wait_on_escape_ms(vars: &EnvStack) {
let var = crate::env::environment::env_var_to_ffi(fish_escape_delay_ms);
crate::ffi::update_wait_on_escape_ms_ffi(var);
}
fn update_wait_on_sequence_key_ms(vars: &EnvStack) {
let fish_sequence_key_delay_ms = vars.get_unless_empty(L!("fish_sequence_key_delay_ms"));
let var = crate::env::environment::env_var_to_ffi(fish_sequence_key_delay_ms);
crate::ffi::update_wait_on_sequence_key_ms_ffi(var);
}
impl VarDispatchTable {
/// Add a callback for the variable `name`. We must not already be observing this variable.
@ -366,6 +375,7 @@ fn run_inits(vars: &EnvStack) {
init_curses(vars);
guess_emoji_width(vars);
update_wait_on_escape_ms(vars);
update_wait_on_sequence_key_ms(vars);
handle_read_limit_change(vars);
handle_fish_use_posix_spawn_change(vars);
handle_fish_trace(vars);

View file

@ -147,6 +147,7 @@ include_cpp! {
generate!("complete_invalidate_path")
generate!("complete_add_wrapper")
generate!("update_wait_on_escape_ms_ffi")
generate!("update_wait_on_sequence_key_ms_ffi")
generate!("autoload_t")
generate!("make_autoload_ffi")
generate!("perform_autoload_ffi")

View file

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

View file

@ -468,19 +468,24 @@ class event_queue_peeker_t {
/// 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.
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");
// See if we had a timeout already.
if (timed && had_timeout_) {
if (escaped && had_timeout_) {
return false;
}
// Grab a new event if we have exhausted what we have already peeked.
// Use either readch or readch_timed, per our param.
if (idx_ == peeked_.size()) {
char_event_t newevt{L'\0'};
if (!timed) {
newevt = event_queue_.readch();
} else if (auto mevt = event_queue_.readch_timed()) {
if (!escaped) {
if (auto mevt = event_queue_.readch_timed_sequence_key()) {
newevt = mevt.acquire();
} else {
had_timeout_ = true;
return false;
}
} else if (auto mevt = event_queue_.readch_timed_esc()) {
newevt = mevt.acquire();
} else {
had_timeout_ = true;
@ -545,7 +550,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
// user input intermixed with pseudo input generated by the tty emulator.
// 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;
}
@ -596,8 +601,8 @@ static bool try_peek_sequence(event_queue_peeker_t *peeker, const wcstring &str)
for (wchar_t c : str) {
// 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.
bool timed = prev == L'\x1B';
if (!peeker->next_is_char(c, timed)) {
bool escaped = prev == L'\x1B';
if (!peeker->next_is_char(c, escaped)) {
return false;
}
prev = c;

View file

@ -35,6 +35,9 @@
#define WAIT_ON_ESCAPE_DEFAULT 30
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) {}
/// Internal function used by readch to read one byte.
@ -157,6 +160,44 @@ void update_wait_on_escape_ms_ffi(std::unique_ptr<env_var_t> fish_escape_delay_m
}
}
// 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_unless_empty(L"fish_sequence_key_delay_ms");
if (!sequence_key_time_ms) {
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);
}
}
void update_wait_on_sequence_key_ms_ffi(std::unique_ptr<env_var_t> fish_sequence_key_delay_ms) {
if (!fish_sequence_key_delay_ms) {
wait_on_sequence_key_ms = WAIT_ON_SEQUENCE_KEY_INFINITE;
return;
}
long tmp = fish_wcstol(fish_sequence_key_delay_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",
fish_sequence_key_delay_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() {
if (queue_.empty()) {
return none();
@ -235,7 +276,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()) {
return evt;
}
@ -248,7 +300,7 @@ maybe_t<char_event_t> input_event_queue_t::readch_timed() {
// pselect expects timeouts in nanoseconds.
const uint64_t nsec_per_msec = 1000 * 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;
timeout.tv_sec = (wait_nsec) / nsec_per_sec;
timeout.tv_nsec = (wait_nsec) % nsec_per_sec;

View file

@ -189,6 +189,9 @@ class environment_t;
void update_wait_on_escape_ms(const environment_t &vars);
void update_wait_on_escape_ms_ffi(std::unique_ptr<env_var_t> fish_escape_delay_ms);
void update_wait_on_sequence_key_ms(const environment_t &vars);
void update_wait_on_sequence_key_ms_ffi(std::unique_ptr<env_var_t> fish_sequence_key_delay_ms);
/// 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.
class input_event_queue_t {
@ -204,7 +207,10 @@ class input_event_queue_t {
/// Like readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a
/// character to be available for reading.
/// \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
/// readch will return before actually reading from fd 0.