Fix the Buffer::end() madness
Until now, buffer had multiple recognized end coordinates, either { line_count, 0 } or { line_count - 1, line[line_count - 1].length }. Now the only correct end coord is { line_count, 0 }, removing the need for various special cases.
This commit is contained in:
parent
b4647a16dd
commit
63a791d651
|
@ -88,7 +88,7 @@ Buffer::Buffer(String name, Flags flags, StringView data,
|
||||||
#endif
|
#endif
|
||||||
static_cast<BufferLines&>(m_lines) = std::move(parsed_lines.lines);
|
static_cast<BufferLines&>(m_lines) = std::move(parsed_lines.lines);
|
||||||
|
|
||||||
m_changes.push_back({ Change::Insert, true, {0,0}, line_count() });
|
m_changes.push_back({ Change::Insert, {0,0}, line_count() });
|
||||||
|
|
||||||
apply_options(options(), parsed_lines);
|
apply_options(options(), parsed_lines);
|
||||||
|
|
||||||
|
@ -241,11 +241,11 @@ void Buffer::reload(StringView data, timespec fs_timestamp)
|
||||||
|
|
||||||
if (not record_undo)
|
if (not record_undo)
|
||||||
{
|
{
|
||||||
m_changes.push_back({ Change::Erase, true, {0,0}, line_count() });
|
m_changes.push_back({ Change::Erase, {0,0}, line_count() });
|
||||||
|
|
||||||
static_cast<BufferLines&>(m_lines) = std::move(parsed_lines.lines);
|
static_cast<BufferLines&>(m_lines) = std::move(parsed_lines.lines);
|
||||||
|
|
||||||
m_changes.push_back({ Change::Insert, true, {0,0}, line_count() });
|
m_changes.push_back({ Change::Insert, {0,0}, line_count() });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -268,7 +268,7 @@ void Buffer::reload(StringView data, timespec fs_timestamp)
|
||||||
Modification::Insert, cur_line + line,
|
Modification::Insert, cur_line + line,
|
||||||
parsed_lines.lines[(int)(d.posB + line)]);
|
parsed_lines.lines[(int)(d.posB + line)]);
|
||||||
|
|
||||||
m_changes.push_back({ Change::Insert, it == m_lines.end(), cur_line, cur_line + d.len });
|
m_changes.push_back({ Change::Insert, cur_line, cur_line + d.len });
|
||||||
m_lines.insert(it, &parsed_lines.lines[d.posB], &parsed_lines.lines[d.posB + d.len]);
|
m_lines.insert(it, &parsed_lines.lines[d.posB], &parsed_lines.lines[d.posB + d.len]);
|
||||||
it = m_lines.begin() + (int)(cur_line + d.len);
|
it = m_lines.begin() + (int)(cur_line + d.len);
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ void Buffer::reload(StringView data, timespec fs_timestamp)
|
||||||
m_lines.get_storage(cur_line + line));
|
m_lines.get_storage(cur_line + line));
|
||||||
|
|
||||||
it = m_lines.erase(it, it + d.len);
|
it = m_lines.erase(it, it + d.len);
|
||||||
m_changes.push_back({ Change::Erase, it == m_lines.end(), cur_line, cur_line + d.len });
|
m_changes.push_back({ Change::Erase, cur_line, cur_line + d.len });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,8 +453,6 @@ BufferCoord Buffer::do_insert(BufferCoord pos, StringView content)
|
||||||
|
|
||||||
const bool at_end = is_end(pos);
|
const bool at_end = is_end(pos);
|
||||||
const bool append_lines = at_end and (m_lines.empty() or byte_at(back_coord()) == '\n');
|
const bool append_lines = at_end and (m_lines.empty() or byte_at(back_coord()) == '\n');
|
||||||
if (at_end)
|
|
||||||
pos = append_lines ? line_count() : end_coord();
|
|
||||||
|
|
||||||
const StringView prefix = append_lines ?
|
const StringView prefix = append_lines ?
|
||||||
StringView{} : m_lines[pos.line].substr(0, pos.column);
|
StringView{} : m_lines[pos.line].substr(0, pos.column);
|
||||||
|
@ -490,7 +488,7 @@ BufferCoord Buffer::do_insert(BufferCoord pos, StringView content)
|
||||||
const auto end = at_end ? line_count()
|
const auto end = at_end ? line_count()
|
||||||
: BufferCoord{ last_line, m_lines[last_line].length() - suffix.length() };
|
: BufferCoord{ last_line, m_lines[last_line].length() - suffix.length() };
|
||||||
|
|
||||||
m_changes.push_back({ Change::Insert, at_end, pos, end });
|
m_changes.push_back({ Change::Insert, pos, end });
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,7 +500,7 @@ BufferCoord Buffer::do_erase(BufferCoord begin, BufferCoord end)
|
||||||
kak_assert(is_valid(begin));
|
kak_assert(is_valid(begin));
|
||||||
kak_assert(is_valid(end));
|
kak_assert(is_valid(end));
|
||||||
StringView prefix = m_lines[begin.line].substr(0, begin.column);
|
StringView prefix = m_lines[begin.line].substr(0, begin.column);
|
||||||
StringView suffix = m_lines[end.line].substr(end.column);
|
StringView suffix = end.line == line_count() ? StringView{} : m_lines[end.line].substr(end.column);
|
||||||
|
|
||||||
BufferCoord next;
|
BufferCoord next;
|
||||||
if (not prefix.empty() or not suffix.empty())
|
if (not prefix.empty() or not suffix.empty())
|
||||||
|
@ -514,11 +512,11 @@ BufferCoord Buffer::do_erase(BufferCoord begin, BufferCoord end)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line + 1);
|
m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line);
|
||||||
next = is_end(begin) ? end_coord() : BufferCoord{begin.line, 0};
|
next = begin.line;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_changes.push_back({ Change::Erase, is_end(begin), begin, end });
|
m_changes.push_back({ Change::Erase, begin, end });
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,24 +582,11 @@ BufferCoord Buffer::erase(BufferCoord begin, BufferCoord end)
|
||||||
|
|
||||||
BufferCoord Buffer::replace(BufferCoord begin, BufferCoord end, StringView content)
|
BufferCoord Buffer::replace(BufferCoord begin, BufferCoord end, StringView content)
|
||||||
{
|
{
|
||||||
if (not (m_flags & Flags::NoUndo))
|
if (is_end(end) and not content.empty() and content.back() == '\n')
|
||||||
m_current_undo_group.emplace_back(Modification::Erase, begin,
|
content = content.substr(0, content.length() - 1);
|
||||||
intern(string(begin, end)));
|
|
||||||
auto pos = do_erase(begin, end);
|
|
||||||
|
|
||||||
StringDataPtr real_content;
|
auto pos = erase(begin, end);
|
||||||
if (is_end(pos) and content.back() != '\n')
|
return insert(pos, content);
|
||||||
real_content = intern(content + "\n");
|
|
||||||
else
|
|
||||||
real_content = intern(content);
|
|
||||||
|
|
||||||
bool last_char_is_eol = not (m_lines.empty() or
|
|
||||||
m_lines.back().empty() or
|
|
||||||
m_lines.back().back() != '\n');
|
|
||||||
auto coord = is_end(pos) and last_char_is_eol ? line_count() : pos;
|
|
||||||
if (not (m_flags & Flags::NoUndo))
|
|
||||||
m_current_undo_group.emplace_back(Modification::Insert, coord, real_content);
|
|
||||||
return do_insert(pos, real_content->strview());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::is_modified() const
|
bool Buffer::is_modified() const
|
||||||
|
@ -662,8 +647,6 @@ BufferCoord Buffer::char_next(BufferCoord coord) const
|
||||||
coord.column = 0;
|
coord.column = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (coord.line == m_lines.size() - 1)
|
|
||||||
coord.column = m_lines.back().length();
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++coord.line;
|
++coord.line;
|
||||||
|
@ -675,9 +658,7 @@ BufferCoord Buffer::char_next(BufferCoord coord) const
|
||||||
BufferCoord Buffer::char_prev(BufferCoord coord) const
|
BufferCoord Buffer::char_prev(BufferCoord coord) const
|
||||||
{
|
{
|
||||||
kak_assert(is_valid(coord));
|
kak_assert(is_valid(coord));
|
||||||
if (is_end(coord))
|
if (coord.column == 0)
|
||||||
return {(int)m_lines.size()-1, m_lines.back().length() - 1};
|
|
||||||
else if (coord.column == 0)
|
|
||||||
{
|
{
|
||||||
if (coord.line > 0)
|
if (coord.line > 0)
|
||||||
coord.column = m_lines[--coord.line].length() - 1;
|
coord.column = m_lines[--coord.line].length() - 1;
|
||||||
|
|
|
@ -89,9 +89,9 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SafePtr<const Buffer> m_buffer;
|
SafePtr<const Buffer> m_buffer;
|
||||||
StringView m_line;
|
|
||||||
BufferCoord m_coord;
|
BufferCoord m_coord;
|
||||||
LineCount m_last_line;
|
LineCount m_line_count;
|
||||||
|
StringView m_line;
|
||||||
};
|
};
|
||||||
|
|
||||||
using BufferLines = Vector<StringDataPtr, MemoryDomain::BufferContent>;
|
using BufferLines = Vector<StringDataPtr, MemoryDomain::BufferContent>;
|
||||||
|
@ -205,7 +205,6 @@ public:
|
||||||
{
|
{
|
||||||
enum Type : char { Insert, Erase };
|
enum Type : char { Insert, Erase };
|
||||||
Type type;
|
Type type;
|
||||||
bool at_end;
|
|
||||||
BufferCoord begin;
|
BufferCoord begin;
|
||||||
BufferCoord end;
|
BufferCoord end;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,8 +17,6 @@ inline BufferCoord Buffer::next(BufferCoord coord) const
|
||||||
{
|
{
|
||||||
if (coord.column < m_lines[coord.line].length() - 1)
|
if (coord.column < m_lines[coord.line].length() - 1)
|
||||||
++coord.column;
|
++coord.column;
|
||||||
else if (coord.line == m_lines.size() - 1)
|
|
||||||
coord.column = m_lines.back().length();
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++coord.line;
|
++coord.line;
|
||||||
|
@ -59,7 +57,6 @@ inline bool Buffer::is_valid(BufferCoord c) const
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (c.line < line_count() and c.column < m_lines[c.line].length()) or
|
return (c.line < line_count() and c.column < m_lines[c.line].length()) or
|
||||||
(c.line == line_count() - 1 and c.column == m_lines.back().length()) or
|
|
||||||
(c.line == line_count() and c.column == 0);
|
(c.line == line_count() and c.column == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,14 +107,13 @@ inline BufferCoord Buffer::back_coord() const
|
||||||
|
|
||||||
inline BufferCoord Buffer::end_coord() const
|
inline BufferCoord Buffer::end_coord() const
|
||||||
{
|
{
|
||||||
return m_lines.empty() ?
|
return line_count();
|
||||||
BufferCoord{0,0} : BufferCoord{ line_count() - 1, m_lines.back().length() };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BufferIterator::BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept
|
inline BufferIterator::BufferIterator(const Buffer& buffer, BufferCoord coord) noexcept
|
||||||
: m_buffer(&buffer), m_coord(coord),
|
: m_buffer{&buffer}, m_coord{coord},
|
||||||
m_line((*m_buffer)[coord.line]),
|
m_line_count{buffer.line_count()},
|
||||||
m_last_line(buffer.line_count()-1) {}
|
m_line{coord.line < buffer.line_count() ? (*m_buffer)[coord.line] : StringView{}} {}
|
||||||
|
|
||||||
inline bool BufferIterator::operator==(const BufferIterator& iterator) const noexcept
|
inline bool BufferIterator::operator==(const BufferIterator& iterator) const noexcept
|
||||||
{
|
{
|
||||||
|
@ -197,9 +193,10 @@ inline BufferIterator& BufferIterator::operator-=(ByteCount size)
|
||||||
|
|
||||||
inline BufferIterator& BufferIterator::operator++()
|
inline BufferIterator& BufferIterator::operator++()
|
||||||
{
|
{
|
||||||
if (++m_coord.column == m_line.length() and m_coord.line != m_last_line)
|
if (++m_coord.column == m_line.length())
|
||||||
{
|
{
|
||||||
m_line = (*m_buffer)[++m_coord.line];
|
m_line = (++m_coord.line < m_line_count) ?
|
||||||
|
(*m_buffer)[m_coord.line] : StringView{};
|
||||||
m_coord.column = 0;
|
m_coord.column = 0;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -207,7 +204,7 @@ inline BufferIterator& BufferIterator::operator++()
|
||||||
|
|
||||||
inline BufferIterator& BufferIterator::operator--()
|
inline BufferIterator& BufferIterator::operator--()
|
||||||
{
|
{
|
||||||
if (m_coord.column == 0 and m_coord.line > 0)
|
if (m_coord.column == 0)
|
||||||
{
|
{
|
||||||
m_line = (*m_buffer)[--m_coord.line];
|
m_line = (*m_buffer)[--m_coord.line];
|
||||||
m_coord.column = m_line.length() - 1;
|
m_coord.column = m_line.length() - 1;
|
||||||
|
|
|
@ -10,22 +10,11 @@ static LineModification make_line_modif(const Buffer::Change& change)
|
||||||
{
|
{
|
||||||
LineCount num_added = 0, num_removed = 0;
|
LineCount num_added = 0, num_removed = 0;
|
||||||
if (change.type == Buffer::Change::Insert)
|
if (change.type == Buffer::Change::Insert)
|
||||||
{
|
|
||||||
num_added = change.end.line - change.begin.line;
|
num_added = change.end.line - change.begin.line;
|
||||||
// inserted a new line at buffer end but end coord is on same line
|
|
||||||
if (change.at_end and change.end.column != 0)
|
|
||||||
++num_added;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
num_removed = change.end.line - change.begin.line;
|
num_removed = change.end.line - change.begin.line;
|
||||||
// removed last line, but end coord is on same line
|
|
||||||
if (change.at_end and change.end.column != 0)
|
|
||||||
++num_removed;
|
|
||||||
}
|
|
||||||
// modified a line
|
// modified a line
|
||||||
if (not change.at_end and
|
if ((change.begin.column != 0 or change.end.column != 0))
|
||||||
(change.begin.column != 0 or change.end.column != 0))
|
|
||||||
{
|
{
|
||||||
++num_removed;
|
++num_removed;
|
||||||
++num_added;
|
++num_added;
|
||||||
|
@ -116,7 +105,7 @@ UnitTest test_line_modifications{[]()
|
||||||
{
|
{
|
||||||
Buffer buffer("test", Buffer::Flags::None, "line 1\nline 2\n");
|
Buffer buffer("test", Buffer::Flags::None, "line 1\nline 2\n");
|
||||||
auto ts = buffer.timestamp();
|
auto ts = buffer.timestamp();
|
||||||
buffer.insert({1, 7}, "line 3");
|
buffer.insert({2, 0}, "line 3");
|
||||||
|
|
||||||
auto modifs = compute_line_modifications(buffer, ts);
|
auto modifs = compute_line_modifications(buffer, ts);
|
||||||
kak_assert(modifs.size() == 1 and modifs[0] == LineModification{ 2, 2, 0, 1 });
|
kak_assert(modifs.size() == 1 and modifs[0] == LineModification{ 2, 2, 0, 1 });
|
||||||
|
|
|
@ -448,17 +448,15 @@ void SelectionList::erase()
|
||||||
kak_assert(m_buffer->is_valid(sel.cursor()));
|
kak_assert(m_buffer->is_valid(sel.cursor()));
|
||||||
|
|
||||||
auto pos = Kakoune::erase(*m_buffer, sel);
|
auto pos = Kakoune::erase(*m_buffer, sel);
|
||||||
sel.anchor() = sel.cursor() = m_buffer->clamp(pos);
|
sel.anchor() = sel.cursor() = pos;
|
||||||
changes_tracker.update(*m_buffer, m_timestamp);
|
changes_tracker.update(*m_buffer, m_timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferCoord back_coord = m_buffer->back_coord();
|
BufferCoord back_coord = m_buffer->back_coord();
|
||||||
for (auto& sel : m_selections)
|
for (auto& sel : m_selections)
|
||||||
{
|
{
|
||||||
if (sel.anchor() > back_coord)
|
auto pos = m_buffer->clamp(sel.cursor());
|
||||||
sel.anchor() = back_coord;
|
sel.anchor() = sel.cursor() = std::min(pos, back_coord);
|
||||||
if (sel.cursor() > back_coord)
|
|
||||||
sel.cursor() = back_coord;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buffer->check_invariant();
|
m_buffer->check_invariant();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user