From 70354f9f5e570fb0a2804b0ac9bffc982ede351d Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Thu, 16 Mar 2017 18:35:44 +0100 Subject: [PATCH] Add bind --list-modes option Fixes #3872. --- doc_src/bind.txt | 3 +++ .../functions/__fish_shared_key_bindings.fish | 10 +++----- src/builtin.cpp | 24 ++++++++++++++++++- tests/bind.expect | 16 +++++++++++++ tests/bind.expect.out | 2 ++ 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/doc_src/bind.txt b/doc_src/bind.txt index 7d452a511..9bf1c651d 100644 --- a/doc_src/bind.txt +++ b/doc_src/bind.txt @@ -7,6 +7,7 @@ bind [(-M | --mode) MODE] [(-m | --sets-mode) NEW_MODE] bind [(-M | --mode) MODE] [(-k | --key)] SEQUENCE bind (-K | --key-names) [(-a | --all)] bind (-f | --function-names) +bind (-L | --list-modes) bind (-e | --erase) [(-M | --mode) MODE] (-a | --all | [(-k | --key)] SEQUENCE [SEQUENCE...]) \endfish @@ -43,6 +44,8 @@ The following parameters are available: - `-f` or `--function-names` Display a list of available input functions +- `-L` or `--list-modes` Display a list of defined bind modes + - `-M MODE` or `--mode MODE` Specify a bind mode that the bind is used in. Defaults to "default" - `-m NEW_MODE` or `--sets-mode NEW_MODE` Change the current mode to `NEW_MODE` after this binding is executed diff --git a/share/functions/__fish_shared_key_bindings.fish b/share/functions/__fish_shared_key_bindings.fish index b4dcee6d7..012697c53 100644 --- a/share/functions/__fish_shared_key_bindings.fish +++ b/share/functions/__fish_shared_key_bindings.fish @@ -126,18 +126,14 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod # # See http://thejh.net/misc/website-terminal-copy-paste. The second case will not be caught in KDE konsole. # Bind the starting sequence in every bind mode, even user-defined ones. - # HACK: We introspect `bind` here to list all modes. - # Re-running `bind` multiple times per mode is still faster than trying to make the list unique, - # even without calling `sort -u` or `uniq`, for the vi-bindings. - # TODO: This can be solved better once #3872 is implemented. # We usually just pass the text through as-is to facilitate pasting code, # but when the current token contains an unbalanced single-quote (`'`), # we escape all single-quotes and backslashes, effectively turning the paste # into one literal token, to facilitate pasting non-code (e.g. markdown or git commitishes) - set -l allmodes default - set allmodes $allmodes (bind -a | string match -r -- '-M \w+' | string replace -- '-M ' '') - for mode in $allmodes + + # Exclude paste mode or there'll be an additional binding after switching between emacs and vi + for mode in (bind --list-modes | string match -v paste) bind -M $mode -m paste \e\[200~ '__fish_start_bracketed_paste' end # This sequence ends paste-mode and returns to the previous mode we have saved before. diff --git a/src/builtin.cpp b/src/builtin.cpp index 5ee57a475..76e64b5c6 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "builtin.h" @@ -445,6 +446,22 @@ static int builtin_bind_erase(wchar_t **seq, int all, const wchar_t *mode, int u return res; } +/// List all current bind modes. +static void builtin_bind_list_modes(io_streams_t &streams) { + const std::vector lst = input_mapping_get_names(); + // A set accomplishes two things for us here: + // - It removes duplicates (no twenty "default" entries). + // - It sorts it, which makes it nicer on the user. + std::set modes; + + for (const input_mapping_name_t &binding : lst) { + modes.insert(binding.mode); + } + for (const auto& mode : modes) { + streams.out.append_format(L"%ls\n", mode.c_str()); + } +} + /// The bind builtin, used for setting character sequences. static int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wgetopter_t w; @@ -467,12 +484,13 @@ static int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {L"key", no_argument, 0, 'k'}, {L"key-names", no_argument, 0, 'K'}, {L"mode", required_argument, 0, 'M'}, + {L"list-modes", no_argument, 0, 'L'}, {L"sets-mode", required_argument, 0, 'm'}, {0, 0, 0, 0}}; while (1) { int opt_index = 0; - int opt = w.wgetopt_long_only(argc, argv, L"aehkKfM:m:", long_options, &opt_index); + int opt = w.wgetopt_long_only(argc, argv, L"aehkKfM:Lm:", long_options, &opt_index); if (opt == -1) break; switch (opt) { @@ -516,6 +534,10 @@ static int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) sets_bind_mode = w.woptarg; break; } + case 'L': { + builtin_bind_list_modes(streams); + return STATUS_BUILTIN_OK; + } case '?': { builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]); return STATUS_BUILTIN_ERROR; diff --git a/tests/bind.expect b/tests/bind.expect index 3f0508ddb..260f206e6 100644 --- a/tests/bind.expect +++ b/tests/bind.expect @@ -41,6 +41,14 @@ expect_prompt -re {\r\nmno pqrt\r\n} { puts stderr "emacs transpose words fail, default timeout: long delay" } +# Now test that exactly the expected bind modes are defined +send "bind --list-modes\r" +expect_prompt -re {\r\ndefault\r\npaste} { + puts "emacs bind modes" +} unmatched { + puts stderr "Unexpected bind modes" +} + # Test vi key bindings. # This should leave vi mode in the insert state. send "set -g fish_key_bindings fish_vi_key_bindings\r" @@ -147,6 +155,14 @@ expect_prompt -re {\r\nTENT\r\n} { puts stderr "Couldn't find expected output 'TENT'" } +# Now test that exactly the expected bind modes are defined +send "bind --list-modes\r" +expect_prompt -re {\r\ndefault\r\ninsert\r\npaste\r\nreplace-one\r\nvisual\r\n} { + puts "vi bind modes" +} unmatched { + puts stderr "Unexpected vi bind modes" +} + # Switch back to regular (emacs mode) key bindings. send "set -g fish_key_bindings fish_default_key_bindings\r" expect_prompt diff --git a/tests/bind.expect.out b/tests/bind.expect.out index e04e9bd3a..d76b605fe 100644 --- a/tests/bind.expect.out +++ b/tests/bind.expect.out @@ -1,6 +1,7 @@ emacs transpose words, default timeout: no delay emacs transpose words, default timeout: short delay emacs transpose words, default timeout: long delay +emacs bind modes prime vi mode, default timeout vi-mode default timeout set correctly vi replace line, default timeout: long delay @@ -9,6 +10,7 @@ vi mode delete char, default timeout: long delay vi replace line, 100ms timeout: long delay vi replace line, 100ms timeout: short delay t-binding success +vi bind modes default-mode custom timeout set correctly emacs transpose words, 100ms timeout: no delay emacs transpose words, 100ms timeout: short delay