diff --git a/doc/pages/keys.asciidoc b/doc/pages/keys.asciidoc index d4b4f04d..63e8b55f 100644 --- a/doc/pages/keys.asciidoc +++ b/doc/pages/keys.asciidoc @@ -139,6 +139,18 @@ the Shift modifier and moving will extend each selection instead. select to the next sequence enclosed by matching character, see the `matching_pairs` option in <> +*M*:: + extend the current selection to the next sequence enclosed by matching + character, see the `matching_pairs` option in <> + +**:: + select to the previous sequence enclosed by matching character, see the + `matching_pairs` option in <> + +**:: + extend the current selection to the previous sequence enclosed by matching + character, see the `matching_pairs` option in <> + *x*:: select line on which the end of each selection lies (or next line when end lies on an end-of-line) diff --git a/src/normal.cc b/src/normal.cc index d7d88ab0..7a1533ee 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -2215,8 +2215,10 @@ static const HashMap key { {alt('x')}, {"extend selections to whole lines", select} }, { {alt('X')}, {"crop selections to whole lines", select} }, - { {'m'}, {"select to matching character", select} }, - { {'M'}, {"extend to matching character", select} }, + { {'m'}, {"select to matching character", select>} }, + { {alt('m')}, {"backward select to matching character", select>} }, + { {'M'}, {"extend to matching character", select>} }, + { {alt('M')}, {"backward extend to matching character", select>} }, { {'/'}, {"select next given regex match", search} }, { {'?'}, {"extend with next given regex match", search} }, diff --git a/src/selectors.cc b/src/selectors.cc index a11a200d..cbbc3f03 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -220,6 +220,7 @@ select_to_first_non_blank(const Context& context, const Selection& selection) return {it.coord()}; } +template Optional select_matching(const Context& context, const Selection& selection) { @@ -227,13 +228,23 @@ select_matching(const Context& context, const Selection& selection) auto& matching_pairs = context.options()["matching_pairs"].get>(); Utf8Iterator it{buffer.iterator_at(selection.cursor()), buffer}; auto match = matching_pairs.end(); - while (it != buffer.end()) + + if (forward) while (it != buffer.end()) { match = find(matching_pairs, *it); if (match != matching_pairs.end()) break; ++it; } + else while (true) + { + match = find(matching_pairs, *it); + if (match != matching_pairs.end() + or it == buffer.begin()) + break; + --it; + } + if (match == matching_pairs.end()) return {}; @@ -271,6 +282,10 @@ select_matching(const Context& context, const Selection& selection) } return {}; } +template Optional +select_matching(const Context& context, const Selection& selection); +template Optional +select_matching(const Context& context, const Selection& selection); template Optional> diff --git a/src/selectors.hh b/src/selectors.hh index 00bc83dd..2e56c214 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -31,6 +31,7 @@ select_to_previous_word(const Context& context, const Selection& selection); Optional select_line(const Context& context, const Selection& selection); +template Optional select_matching(const Context& context, const Selection& selection);