diff --git a/src/main.cc b/src/main.cc index 26694a43..20c64ad4 100644 --- a/src/main.cc +++ b/src/main.cc @@ -354,6 +354,8 @@ std::unordered_map> keymap { 'b', [](Window& window, int count) { do { window.select(false, select_to_previous_word); } while(--count > 0); } }, { 'B', [](Window& window, int count) { do { window.select(true, select_to_previous_word); } while(--count > 0); } }, { '.', [](Window& window, int count) { do { window.select(false, select_line); } while(--count > 0); } }, + { 'm', [](Window& window, int count) { window.select(false, select_matching); } }, + { 'M', [](Window& window, int count) { window.select(true, select_matching); } }, { '/', [](Window& window, int count) { do_search(window); } }, { 'u', [](Window& window, int count) { do { if (not window.undo()) { print_status("nothing left to undo"); break; } } while(--count > 0); } }, { 'U', [](Window& window, int count) { do { if (not window.redo()) { print_status("nothing left to redo"); break; } } while(--count > 0); } }, diff --git a/src/selectors.cc b/src/selectors.cc index ad65ea2a..8c04d545 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -1,8 +1,15 @@ #include "selectors.hh" +#include + namespace Kakoune { +static bool is_eol(char c) +{ + return c == '\n'; +} + static bool is_blank(char c) { return c == ' ' or c == '\t' or c == '\n'; @@ -75,4 +82,53 @@ Selection move_select(Window& window, const BufferIterator& cursor, const Window return Selection(cursor, window.iterator_at(new_pos)); } +Selection select_matching(const BufferIterator& cursor) +{ + std::vector matching_pairs = { '(', ')', '{', '}', '[', ']', '<', '>' }; + BufferIterator it = cursor; + std::vector::iterator match = matching_pairs.end(); + while (not is_eol(*it)) + { + match = std::find(matching_pairs.begin(), matching_pairs.end(), *it); + if (match != matching_pairs.end()) + break; + ++it; + } + if (match == matching_pairs.end()) + return Selection(cursor, cursor); + + BufferIterator begin = it; + + if (((match - matching_pairs.begin()) % 2) == 0) + { + int level = 0; + const char opening = *match; + const char closing = *(match+1); + while (not it.is_end()) + { + if (*it == opening) + ++level; + else if (*it == closing and --level == 0) + return Selection(begin, it+1); + + ++it; + } + } + else + { + int level = 0; + const char opening = *(match-1); + const char closing = *match; + while (not it.is_begin()) + { + if (*it == closing) + ++level; + else if (*it == opening and --level == 0) + return Selection(begin, it); + --it; + } + } + return Selection(cursor, cursor); +} + } diff --git a/src/selectors.hh b/src/selectors.hh index 0fe7fa17..d304227a 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -11,6 +11,7 @@ Selection select_to_next_word_end(const BufferIterator& cursor); Selection select_to_previous_word(const BufferIterator& cursor); Selection select_line(const BufferIterator& cursor); Selection move_select(Window& window, const BufferIterator& cursor, const WindowCoord& offset); +Selection select_matching(const BufferIterator& cursor); }