diff --git a/doc/pages/changelog.asciidoc b/doc/pages/changelog.asciidoc index 9cbd18efd7..d5b85cd89f 100644 --- a/doc/pages/changelog.asciidoc +++ b/doc/pages/changelog.asciidoc @@ -5,6 +5,9 @@ released versions. == Development version +* `` and `` to expand line selections downwards and upwards, + respectively. + * History is now stored linearly instead of in a tree * `` and `` now undo selection history diff --git a/doc/pages/keys.asciidoc b/doc/pages/keys.asciidoc index eaadd17ff7..cca3092117 100644 --- a/doc/pages/keys.asciidoc +++ b/doc/pages/keys.asciidoc @@ -168,6 +168,14 @@ the Shift modifier and moving will extend each selection instead. trim selections to only contain full lines (not including last end-of-line) +*X*:: + expand selections to contain full lines (including end-of-lines) and extend + the selected block one line downwards + +**:: + expand selections to contain full lines (including end-of-lines) and extend + the selected block one line upwards + *%*, **:: select whole buffer diff --git a/src/main.cc b/src/main.cc index ac4a5625ac..bb7c720ca1 100644 --- a/src/main.cc +++ b/src/main.cc @@ -52,6 +52,8 @@ struct { "strings (as double quoted strings)\n" "» {+u}show-matching -previous{} switch\n" "» {+b}{} to cancel current operation\n" + "» {+b}{} and {+b}{} to expand line selections downwards and " + "upwards, respectively\n" }, { 20221031, "» {+b}{} does not end macro recording anymore, use {+b}Q{}\n" diff --git a/src/normal.cc b/src/normal.cc index 08ce028de5..b0fb635498 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -2344,6 +2344,9 @@ static constexpr HashMap { {'x'}, {"extend selections to whole lines", select} }, { {alt('x')}, {"crop selections to whole lines", select} }, + { {'X'}, {"extend selections to whole lines downwards", repeated>} }, + { {alt('X')}, {"extend selections to whole lines upwards", repeated>} }, + { {'m'}, {"select to matching character", select>} }, { {alt('m')}, {"backward select to matching character", select>} }, { {'M'}, {"extend to matching character", select>} }, diff --git a/src/selectors.cc b/src/selectors.cc index e3cba87d73..27b2db9705 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -861,6 +861,38 @@ trim_partial_lines(const Context& context, const Selection& selection) return Selection{anchor, {cursor, max_column}}; } +Optional +extend_lines_downwards(const Context& context, const Selection& selection) +{ + auto& buffer = context.buffer(); + BufferCoord anchor = selection.anchor(); + BufferCoord cursor = selection.cursor(); + BufferCoord& to_line_start = anchor <= cursor ? anchor : cursor; + BufferCoord& to_line_end = anchor <= cursor ? cursor : anchor; + + to_line_start.column = 0; + to_line_end.column = buffer[to_line_end.line].length()-1; + to_line_end.line = std::min(to_line_end.line + 1, buffer.line_count() - 1); + + return Selection{anchor, {cursor, max_column}}; +} + +Optional +extend_lines_upwards(const Context& context, const Selection& selection) +{ + auto& buffer = context.buffer(); + BufferCoord anchor = selection.anchor(); + BufferCoord cursor = selection.cursor(); + BufferCoord& to_line_start = anchor <= cursor ? anchor : cursor; + BufferCoord& to_line_end = anchor <= cursor ? cursor : anchor; + + to_line_start.column = 0; + to_line_start.line = std::max(to_line_start.line - 1, LineCount(0)); + to_line_end.column = buffer[to_line_end.line].length()-1; + + return Selection{anchor, {cursor, max_column}}; +} + static RegexExecFlags match_flags(const Buffer& buf, const BufferIterator& begin, const BufferIterator& end) { diff --git a/src/selectors.hh b/src/selectors.hh index 8d85a600a0..a3ca2f31c9 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -107,6 +107,12 @@ select_lines(const Context& context, const Selection& selection); Optional trim_partial_lines(const Context& context, const Selection& selection); +Optional +extend_lines_downwards(const Context& context, const Selection& selection); + +Optional +extend_lines_upwards(const Context& context, const Selection& selection); + enum class RegexMode; template