aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Kurtis Rader <krader@skepticism.us>2016-01-14 21:46:53 -0800
committerGravatar Kurtis Rader <krader@skepticism.us>2016-01-17 17:45:30 -0800
commit4b9fece9f48615f2e8068054c60763e844415a7c (patch)
tree794abe80d918138297592c13054c75a4dcb4db20
parent6969cfab3dc20de9f757b94b8832b504ed1fdd40 (diff)
allow configuring the escape delay timeout
Introduce a "fish_escape_delay_ms" variable to allow the user to configure the delay used when seeing a bare escape before assuming no other characters will be received that might match a bound character sequence. This is primarily useful for vi mode so that a bare escape character (i.e., keystroke) can switch to vi "insert" to "normal" mode in a timely fashion.
-rw-r--r--src/env.cpp6
-rw-r--r--src/input_common.cpp59
-rw-r--r--src/input_common.h3
-rw-r--r--tests/bind.expect121
-rw-r--r--tests/bind.expect.out12
5 files changed, 146 insertions, 55 deletions
diff --git a/src/env.cpp b/src/env.cpp
index 3d7023db..527ed253 100644
--- a/src/env.cpp
+++ b/src/env.cpp
@@ -303,7 +303,7 @@ static void handle_locale()
}
-/** React to modifying hte given variable */
+/** React to modifying the given variable */
static void react_to_variable_change(const wcstring &key)
{
if (var_is_locale(key))
@@ -319,6 +319,10 @@ static void react_to_variable_change(const wcstring &key)
{
reader_react_to_color_change();
}
+ else if (key == L"fish_escape_delay_ms")
+ {
+ update_wait_on_escape_ms();
+ }
}
/**
diff --git a/src/input_common.cpp b/src/input_common.cpp
index cda4ca11..291a37a7 100644
--- a/src/input_common.cpp
+++ b/src/input_common.cpp
@@ -33,9 +33,11 @@ Implementation file for the low level input library
reading after \\x1b is read before assuming that escape key was
pressed, and not an escape sequence.
- This is the value used by the readline library.
+ This is the value used by the readline library. It can be overridden by
+ setting the fish_escape_delay_ms variable.
*/
-#define WAIT_ON_ESCAPE 500
+#define WAIT_ON_ESCAPE_DEFAULT 500
+static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
/** Characters that have been read and returned by the sequence matching code */
static std::deque<wint_t> lookahead_list;
@@ -79,6 +81,7 @@ static int (*interrupt_handler)();
void input_common_init(int (*ih)())
{
interrupt_handler = ih;
+ update_wait_on_escape_ms();
}
void input_common_destroy()
@@ -214,36 +217,48 @@ static wint_t readb()
return arr[0];
}
+// Update the wait_on_escape_ms value in response to the fish_escape_delay_ms
+// user variable being set.
+void update_wait_on_escape_ms()
+{
+ env_var_t escape_time_ms = env_get_string(L"fish_escape_delay_ms");
+ if (escape_time_ms.missing_or_empty())
+ {
+ wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
+ return;
+ }
+
+ wchar_t *endptr;
+ long tmp = wcstol(escape_time_ms.c_str(), &endptr, 10);
+
+ if (*endptr != '\0' || tmp < 10 || tmp >= 5000)
+ {
+ fwprintf(stderr, L"ignoring fish_escape_delay_ms: value '%ls' "
+ "is not an integer or is < 10 or >= 5000 ms\n",
+ escape_time_ms.c_str());
+ }
+ else
+ {
+ wait_on_escape_ms = (int)tmp;
+ }
+}
+
+
wchar_t input_common_readch(int timed)
{
if (! has_lookahead())
{
if (timed)
{
- int count;
fd_set fds;
- struct timeval tm=
- {
- 0,
- 1000 * WAIT_ON_ESCAPE
- }
- ;
-
FD_ZERO(&fds);
FD_SET(0, &fds);
- count = select(1, &fds, 0, 0, &tm);
-
- switch (count)
+ struct timeval tm = {wait_on_escape_ms / 1000,
+ 1000 * (wait_on_escape_ms % 1000)};
+ int count = select(1, &fds, 0, 0, &tm);
+ if (count <= 0)
{
- case 0:
- return WEOF;
-
- case -1:
- return WEOF;
- break;
- default:
- break;
-
+ return WEOF;
}
}
diff --git a/src/input_common.h b/src/input_common.h
index 5ec34b39..72ccc073 100644
--- a/src/input_common.h
+++ b/src/input_common.h
@@ -35,6 +35,9 @@ void input_common_init(int (*ih)());
*/
void input_common_destroy();
+// Adjust the escape timeout.
+void update_wait_on_escape_ms();
+
/**
Function used by input_readch to read bytes from stdin until enough
bytes have been read to convert them to a wchar_t. Conversion is
diff --git a/tests/bind.expect b/tests/bind.expect
index 6c80b8f1..9bde0689 100644
--- a/tests/bind.expect
+++ b/tests/bind.expect
@@ -2,59 +2,124 @@
spawn $fish
expect_prompt
-# Test switching key bindings to vi mode.
-# This should leave the mode in the appropriate state (i.e., insert mode).
+# Test switching key bindings to vi mode. This should leave the mode in the
+# appropriate state (i.e., insert mode). These initial tests assume the
+# default escape timeout of 500ms is in effect.
send "set -g fish_key_bindings fish_vi_key_bindings\r"
expect_prompt
-send -h "echo fail\033"
+send "echo fail: default escape timeout"
+send "\033"
# Delay needed to allow fish to transition to vi "normal" mode.
sleep 0.510
-send -h "ddiecho success\r"
-expect_prompt -re {\r\nsuccess\r\n} {
- puts "vi replace line success"
+send "ddi"
+send "echo success: default escape timeout\r"
+expect_prompt -re {\r\nsuccess: default escape timeout\r\n} {
+ puts "vi replace line: default escape timeout"
} -nounmatched -re {\r\nfail} {
- puts stderr "vi replace line fail"
+ puts stderr "vi replace line fail: default escape timeout"
} unmatched {
- puts stderr "Couldn't find expected output 'success'"
+ puts stderr "couldn't find expected output: replace line, default escape timeout"
}
# Verify that a human can transpose words using \et (which is an emacs default
# binding but should be valid while in vi insert mode).
-send "echo abc def\033"
-# Fish should still be in vi "insert" mode after this delay.
+send "echo abc def"
+send "\033"
+# Fish should still be in vi insert mode after this delay to simulate a slow
+# typist.
sleep 0.400
send "t\r"
expect_prompt -re {\r\ndef abc\r\n} {
- puts "vi transpose words success"
+ puts "vi transpose words: default escape timeout"
} unmatched {
- puts stderr "vi transpose words fail"
+ puts stderr "vi transpose words fail: default escape timeout"
}
# Test replacing a single character.
-send -h "echo TEXT\033"
+send "echo TEXT"
+send "\033"
# Delay needed to allow fish to transition to vi "normal" mode.
sleep 0.510
-send -h "hhrAi\r"
+send "hhrAi\r"
expect_prompt -re {\r\nTAXT\r\n} {
- puts "vi mode replace success"
+ puts "vi mode replace: default escape timeout"
} -nounmatched -re {\r\nfail} {
- puts stderr "vi mode replace fail"
+ puts stderr "vi mode replace fail: default escape timeout"
} unmatched {
- puts stderr "Couldn't find expected output 'TAXT'"
+ puts stderr "couldn't find expected output 'TAXT': default escape timeout"
+}
+
+# Verify that changing the escape timeout has an effect. The vi key bindings
+# should still be in effect.
+send "set -g fish_escape_delay_ms 100\r"
+expect_prompt
+send "echo fail: shortened escape timeout"
+send "\033"
+sleep 0.110
+send "ddi"
+send "echo success: shortened escape timeout\r"
+expect_prompt -re {\r\nsuccess: shortened escape timeout\r\n} {
+ puts "vi replace line: shortened escape timeout"
+} -nounmatched -re {\r\nfail} {
+ puts stderr "vi replace line fail: shortened escape timeout"
+} unmatched {
+ puts stderr "couldn't find expected output: replace_line, shortened escape timeout"
+}
+
+# Verify that we don't switch to vi normal mode if we don't wait long enough
+# after sending escape. The vi key bindings should still be in effect.
+send "echo fail: no normal mode"
+send "\033"
+sleep 0.050
+send "ddi"
+send "inserted\r"
+expect_prompt -re {\r\nfail: no normal modediinserted\r\n} {
+ puts "vi normal mode: shortened escape timeout"
+} -nounmatched -re {\r\nfail} {
+ puts stderr "vi normal mode fail: shortened escape timeout"
+} unmatched {
+ puts stderr "couldn't find expected output: no normal mode"
}
# Switch back to regular (emacs mode) key bindings.
-send -h "set -g fish_key_bindings fish_default_key_bindings\r"
+send "set -g fish_key_bindings fish_default_key_bindings\r"
+expect_prompt
+
+# Verify the emacs transpose word (\et) behavior using various delays,
+# including none, after the escape character.
+
+# Start by testing with no delay. This should transpose the words.
+send "echo abc def"
+send "\033t\r"
+expect_prompt -re {\r\ndef abc\r\n} {
+ puts "emacs transpose words: no escape delay"
+} unmatched {
+ puts stderr "emacs transpose words fail: no escape delay"
+}
+
+# Now test with a delay > 0 and < the escape timeout. This should transpose
+# the words.
+send "set -g fish_escape_delay_ms 100\r"
expect_prompt
-send "echo success\r"
-expect_prompt -re {\r\nsuccess\r\n} {
- puts "emacs success"
-} unmatched {
- puts stderr "Couldn't find expected output 'success'"
-} timeout {
- set msg ""
- append msg "Timeout after setting fish_key_bindings to fish_default_key_bindings\n" \
- "\$fish_bind_mode is most likely still set to 'insert'"
- abort $msg
+send "echo ghi jkl"
+send "\033"
+sleep 0.050
+send "t\r"
+expect_prompt -re {\r\njkl ghi\r\n} {
+ puts "emacs transpose words: short escape delay"
+} unmatched {
+ puts stderr "emacs transpose words fail: short escape delay"
+}
+
+# Now test with a delay > the escape timeout. The transposition should not
+# occur and the "t" should become part of the text that is echoed.
+send "echo mno pqr"
+send "\033"
+sleep 0.110
+send "t\r"
+expect_prompt -re {\r\nmno pqrt\r\n} {
+ puts "emacs transpose words: long escape delay"
+} unmatched {
+ puts stderr "emacs transpose words fail: long escape delay"
}
diff --git a/tests/bind.expect.out b/tests/bind.expect.out
index f82eec23..f4682d2c 100644
--- a/tests/bind.expect.out
+++ b/tests/bind.expect.out
@@ -1,4 +1,8 @@
-vi replace line success
-vi transpose words success
-vi mode replace success
-emacs success
+vi replace line: default escape timeout
+vi transpose words: default escape timeout
+vi mode replace: default escape timeout
+vi replace line: shortened escape timeout
+vi normal mode: shortened escape timeout
+emacs transpose words: no escape delay
+emacs transpose words: short escape delay
+emacs transpose words: long escape delay