Change + command not to duplicate identical selections more than once

The current exponential behaviour does not seem that useful, it seems
more predictible that pressing `+` twice would end up with 3 copies
of the original selections instead of 4.

Fixes #4533
This commit is contained in:
Maxime Coste 2023-08-13 03:33:32 +10:00
parent 0a06d9acbd
commit 6942a4c0c9
7 changed files with 40 additions and 18 deletions

View File

@ -3,6 +3,11 @@
This changelog contains major and/or breaking changes to Kakoune between This changelog contains major and/or breaking changes to Kakoune between
released versions. released versions.
== Development version
* `+` only duplicates identical selections a single time to avoid surprising
and slow exponential growth in the number of selections.
== Kakoune 2023.08.08 == Kakoune 2023.08.08
* Fix compilation errors on FreeBSD and MacOS using clang * Fix compilation errors on FreeBSD and MacOS using clang

View File

@ -45,6 +45,9 @@ struct {
unsigned int version; unsigned int version;
StringView notes; StringView notes;
} constexpr version_notes[] = { { } constexpr version_notes[] = { {
0,
"» {+b}+{} only duplicates identical selections a single time\n"
}, {
20230805, 20230805,
"» Fix FreeBSD/MacOS clang compilation\n" "» Fix FreeBSD/MacOS clang compilation\n"
}, { }, {

View File

@ -2191,9 +2191,17 @@ void duplicate_selections(Context& context, NormalParams params)
SelectionList& sels = context.selections(); SelectionList& sels = context.selections();
Vector<Selection> new_sels; Vector<Selection> new_sels;
const int count = params.count ? params.count : 2; const int count = params.count ? params.count : 2;
BasicSelection last{BufferCoord{-1,-1}};
size_t index = 0;
size_t main_index = 0;
for (const auto& sel : sels) for (const auto& sel : sels)
new_sels.insert(new_sels.end(), count, sel); {
context.selections().set(std::move(new_sels), sels.main_index() * count); new_sels.insert(new_sels.end(), sel != last ? count : 1, sel);
last = sel;
if (index++ == sels.main_index())
main_index = new_sels.size() - 1;
}
context.selections().set(std::move(new_sels), main_index);
} }
void force_redraw(Context& context, NormalParams) void force_redraw(Context& context, NormalParams)

View File

@ -13,17 +13,14 @@ using CaptureList = Vector<String, MemoryDomain::Selections>;
constexpr ColumnCount max_column{std::numeric_limits<int>::max()}; constexpr ColumnCount max_column{std::numeric_limits<int>::max()};
constexpr ColumnCount max_non_eol_column{max_column-1}; constexpr ColumnCount max_non_eol_column{max_column-1};
// A selection is a Selection, associated with a CaptureList struct BasicSelection
struct Selection
{ {
static constexpr MemoryDomain Domain = MemoryDomain::Selections; static constexpr MemoryDomain Domain = MemoryDomain::Selections;
Selection() = default; BasicSelection() = default;
Selection(BufferCoord pos) : Selection(pos,pos) {} BasicSelection(BufferCoord pos) : BasicSelection(pos,pos) {}
Selection(BufferCoord anchor, BufferCoordAndTarget cursor, BasicSelection(BufferCoord anchor, BufferCoordAndTarget cursor)
CaptureList captures = {}) : m_anchor{anchor}, m_cursor{cursor} {}
: m_anchor{anchor}, m_cursor{cursor},
m_captures(std::move(captures)) {}
BufferCoord& anchor() { return m_anchor; } BufferCoord& anchor() { return m_anchor; }
BufferCoordAndTarget& cursor() { return m_cursor; } BufferCoordAndTarget& cursor() { return m_cursor; }
@ -39,13 +36,7 @@ struct Selection
void set(BufferCoord coord) { set(coord, coord); } void set(BufferCoord coord) { set(coord, coord); }
CaptureList& captures() { return m_captures; } friend bool operator==(const BasicSelection&, const BasicSelection&) = default;
const CaptureList& captures() const { return m_captures; }
bool operator== (const Selection& other) const
{
return m_anchor == other.m_anchor and m_cursor == other.m_cursor;
}
// When selections are single char, we want the anchor to be considered min, and cursor max // When selections are single char, we want the anchor to be considered min, and cursor max
const BufferCoord& min() const { return m_anchor <= m_cursor ? m_anchor : m_cursor; } const BufferCoord& min() const { return m_anchor <= m_cursor ? m_anchor : m_cursor; }
@ -57,11 +48,23 @@ struct Selection
private: private:
BufferCoord m_anchor; BufferCoord m_anchor;
BufferCoordAndTarget m_cursor; BufferCoordAndTarget m_cursor;
};
;
struct Selection : BasicSelection
{
Selection() = default;
Selection(BufferCoord pos) : BasicSelection(pos,pos) {}
Selection(BufferCoord anchor, BufferCoordAndTarget cursor, CaptureList captures = {})
: BasicSelection{anchor, cursor}, m_captures(std::move(captures)) {}
CaptureList& captures() { return m_captures; }
const CaptureList& captures() const { return m_captures; }
private:
CaptureList m_captures; CaptureList m_captures;
}; };
inline bool overlaps(const Selection& lhs, const Selection& rhs) inline bool overlaps(const BasicSelection& lhs, const BasicSelection& rhs)
{ {
return lhs.min() <= rhs.min() ? lhs.max() >= rhs.min() return lhs.min() <= rhs.min() ? lhs.max() >= rhs.min()
: lhs.min() <= rhs.max(); : lhs.min() <= rhs.max();

View File

@ -0,0 +1 @@
++ao<esc>

View File

@ -0,0 +1 @@
%(f) %(b) %(t)

View File

@ -0,0 +1 @@
fooo booo tooo