diff --git a/doc_src/cmds/abbr.rst b/doc_src/cmds/abbr.rst index ba5a6293b..00a13e672 100644 --- a/doc_src/cmds/abbr.rst +++ b/doc_src/cmds/abbr.rst @@ -9,7 +9,7 @@ Synopsis .. synopsis:: abbr --add NAME [--position command | anywhere] [--regex PATTERN] - [--set-cursor SENTINEL] + [--set-cursor[=MARKER]] [-f | --function] EXPANSION abbr --erase NAME ... abbr --rename OLD_WORD NEW_WORD @@ -38,7 +38,7 @@ Abbreviations may be added to :ref:`config.fish `. Abbreviations .. synopsis:: abbr [-a | --add] NAME [--position command | anywhere] [--regex PATTERN] - [--set-cursor SENTINEL] + [--set-cursor[=MARKER]] [-f | --function] EXPANSION ``abbr --add`` creates a new abbreviation. With no other options, the string **NAME** is replaced by **EXPANSION**. @@ -47,7 +47,7 @@ With **--position command**, the abbreviation will only expand when it is positi With **--regex**, the abbreviation matches using the regular expression given by **PATTERN**, instead of the literal **NAME**. The pattern is interpreted using PCRE2 syntax and must match the entire token. If multiple abbreviations match the same token, the last abbreviation added is used. -With **--set-cursor**, the cursor is moved to the first occurrence of **SENTINEL** in the expansion. That **SENTINEL** value is erased. +With **--set-cursor=MARKER**, the cursor is moved to the first occurrence of **MARKER** in the expansion. The **MARKER** value is erased. The **MARKER** may be omitted (i.e. simply ``--set-cursor``), in which case it defaults to ``%``. With **-f** or **--function**, **EXPANSION** is treated as the name of a fish function instead of a literal replacement. When the abbreviation matches, the function will be called with the matching token as an argument. If the function's exit status is 0 (success), the token will be replaced by the function's output; otherwise the token will be left unchanged. @@ -69,7 +69,7 @@ Add a new abbreviation where ``-C`` will be replaced with ``--color``. The ``--` :: - abbr -a L --position anywhere --set-cursor ! "! | less" + abbr -a L --position anywhere --set-cursor "% | less" Add a new abbreviation where ``L`` will be replaced with ``| less``, placing the cursor before the pipe. diff --git a/src/abbrs.cpp b/src/abbrs.cpp index 4199e4bb3..a7b31c323 100644 --- a/src/abbrs.cpp +++ b/src/abbrs.cpp @@ -41,7 +41,7 @@ abbrs_replacer_list_t abbrs_set_t::match(const wcstring &token, abbrs_position_t const abbreviation_t &abbr = *it; if (abbr.matches(token, position)) { result.push_back(abbrs_replacer_t{abbr.replacement, abbr.replacement_is_function, - abbr.set_cursor_indicator}); + abbr.set_cursor_marker}); } } return result; @@ -123,10 +123,10 @@ abbrs_replacement_t abbrs_replacement_t::from(source_range_t range, wcstring tex abbrs_replacement_t result{}; result.range = range; result.text = std::move(text); - if (replacer.set_cursor_indicator.has_value()) { - size_t pos = result.text.find(*replacer.set_cursor_indicator); + if (replacer.set_cursor_marker.has_value()) { + size_t pos = result.text.find(*replacer.set_cursor_marker); if (pos != wcstring::npos) { - result.text.erase(pos, replacer.set_cursor_indicator->size()); + result.text.erase(pos, replacer.set_cursor_marker->size()); result.cursor = pos + range.start; } } diff --git a/src/abbrs.h b/src/abbrs.h index 4d4012f4b..f257eb511 100644 --- a/src/abbrs.h +++ b/src/abbrs.h @@ -43,7 +43,7 @@ struct abbreviation_t { abbrs_position_t position{abbrs_position_t::command}; /// If set, then move the cursor to the first instance of this string in the expansion. - maybe_t set_cursor_indicator{}; + maybe_t set_cursor_marker{}; /// Mark if we came from a universal variable. bool from_universal{}; @@ -76,7 +76,7 @@ struct abbrs_replacer_t { bool is_function; /// If set, the cursor should be moved to the first instance of this string in the expansion. - maybe_t set_cursor_indicator; + maybe_t set_cursor_marker; }; using abbrs_replacer_list_t = std::vector; diff --git a/src/builtins/abbr.cpp b/src/builtins/abbr.cpp index 649b8709a..f28bdcbdf 100644 --- a/src/builtins/abbr.cpp +++ b/src/builtins/abbr.cpp @@ -41,7 +41,7 @@ struct abbr_options_t { bool function{}; maybe_t regex_pattern; maybe_t position{}; - maybe_t set_cursor_indicator{}; + maybe_t set_cursor_marker{}; wcstring_list_t args; @@ -78,11 +78,11 @@ struct abbr_options_t { streams.err.append_format(_(L"%ls: --function option requires --add\n"), CMD); return false; } - if (!add && set_cursor_indicator.has_value()) { + if (!add && set_cursor_marker.has_value()) { streams.err.append_format(_(L"%ls: --set-cursor option requires --add\n"), CMD); return false; } - if (set_cursor_indicator.has_value() && set_cursor_indicator->empty()) { + if (set_cursor_marker.has_value() && set_cursor_marker->empty()) { streams.err.append_format(_(L"%ls: --set-cursor argument cannot be empty\n"), CMD); return false; } @@ -107,9 +107,8 @@ static int abbr_show(const abbr_options_t &, io_streams_t &streams) { comps.push_back(L"--regex"); comps.push_back(escape_string(abbr.key)); } - if (abbr.set_cursor_indicator.has_value()) { - comps.push_back(L"--set-cursor"); - comps.push_back(escape_string(*abbr.set_cursor_indicator)); + if (abbr.set_cursor_marker.has_value()) { + comps.push_back(L"--set-cursor=" + escape_string(*abbr.set_cursor_marker)); } if (abbr.replacement_is_function) { comps.push_back(L"--function"); @@ -249,7 +248,7 @@ static int abbr_add(const abbr_options_t &opts, io_streams_t &streams) { abbreviation_t abbr{std::move(name), std::move(key), std::move(replacement), position}; abbr.regex = std::move(regex); abbr.replacement_is_function = opts.function; - abbr.set_cursor_indicator = opts.set_cursor_indicator; + abbr.set_cursor_marker = opts.set_cursor_marker; abbrs_get_set()->add(std::move(abbr)); return STATUS_CMD_OK; } @@ -278,26 +277,27 @@ maybe_t builtin_abbr(parser_t &parser, io_streams_t &streams, const wchar_t const wchar_t *cmd = argv[0]; abbr_options_t opts; // Note 1 is returned by wgetopt to indicate a non-option argument. - enum { NON_OPTION_ARGUMENT = 1, REGEX_SHORT }; + enum { NON_OPTION_ARGUMENT = 1, REGEX_SHORT, SET_CURSOR_SHORT }; // Note the leading '-' causes wgetopter to return arguments in order, instead of permuting // them. We need this behavior for compatibility with pre-builtin abbreviations where options // could be given literally, for example `abbr e emacs -nw`. static const wchar_t *const short_options = L"-afrseqgUh"; - static const struct woption long_options[] = {{L"add", no_argument, 'a'}, - {L"position", required_argument, 'p'}, - {L"regex", required_argument, REGEX_SHORT}, - {L"set-cursor", required_argument, 'C'}, - {L"function", no_argument, 'f'}, - {L"rename", no_argument, 'r'}, - {L"erase", no_argument, 'e'}, - {L"query", no_argument, 'q'}, - {L"show", no_argument, 's'}, - {L"list", no_argument, 'l'}, - {L"global", no_argument, 'g'}, - {L"universal", no_argument, 'U'}, - {L"help", no_argument, 'h'}, - {}}; + static const struct woption long_options[] = { + {L"add", no_argument, 'a'}, + {L"position", required_argument, 'p'}, + {L"regex", required_argument, REGEX_SHORT}, + {L"set-cursor", optional_argument, SET_CURSOR_SHORT}, + {L"function", no_argument, 'f'}, + {L"rename", no_argument, 'r'}, + {L"erase", no_argument, 'e'}, + {L"query", no_argument, 'q'}, + {L"show", no_argument, 's'}, + {L"list", no_argument, 'l'}, + {L"global", no_argument, 'g'}, + {L"universal", no_argument, 'U'}, + {L"help", no_argument, 'h'}, + {}}; int argc = builtin_count_args(argv); int opt; @@ -346,13 +346,14 @@ maybe_t builtin_abbr(parser_t &parser, io_streams_t &streams, const wchar_t opts.regex_pattern = w.woptarg; break; } - case 'C': { - if (opts.set_cursor_indicator.has_value()) { + case SET_CURSOR_SHORT: { + if (opts.set_cursor_marker.has_value()) { streams.err.append_format( _(L"%ls: Cannot specify multiple set-cursor options\n"), CMD); return STATUS_INVALID_ARGS; } - opts.set_cursor_indicator = w.woptarg; + // The default set-cursor indicator is '%'. + opts.set_cursor_marker = w.woptarg ? w.woptarg : L"%"; break; } case 'f': diff --git a/tests/pexpects/abbrs.py b/tests/pexpects/abbrs.py index 370c1cd4d..a9f900712 100644 --- a/tests/pexpects/abbrs.py +++ b/tests/pexpects/abbrs.py @@ -143,7 +143,14 @@ expect_prompt(r"6 : @abc@ ") # Test cursor positioning. sendline(r"""abbr --erase (abbr --list) """) expect_prompt() -sendline(r"""abbr LLL --position anywhere --set-cursor !HERE! '!HERE! | less'""") +sendline(r"""abbr LLL --position anywhere --set-cursor 'abc%ghi'""") +expect_prompt() +send(r"""echo LLL def?""") +expect_str(r"") + +sendline(r"""abbr --erase (abbr --list) """) +expect_prompt() +sendline(r"""abbr LLL --position anywhere --set-cursor=!HERE! '!HERE! | less'""") expect_prompt() send(r"""echo LLL derp?""") -expect_str(r"echo derp | less ") +expect_str(r"")