Remove use of 'offset' in buffer iterators, lines are just String
No need to maintain line offsets anymore.
This commit is contained in:
parent
95200d1de1
commit
b6b646e9a2
|
@ -30,13 +30,11 @@ Buffer::Buffer(String name, Flags flags, std::vector<String> lines,
|
||||||
if (lines.empty())
|
if (lines.empty())
|
||||||
lines.emplace_back("\n");
|
lines.emplace_back("\n");
|
||||||
|
|
||||||
ByteCount pos = 0;
|
|
||||||
m_lines.reserve(lines.size());
|
m_lines.reserve(lines.size());
|
||||||
for (auto& line : lines)
|
for (auto& line : lines)
|
||||||
{
|
{
|
||||||
kak_assert(not line.empty() and line.back() == '\n');
|
kak_assert(not line.empty() and line.back() == '\n');
|
||||||
m_lines.emplace_back(Line{ pos, std::move(line) });
|
m_lines.emplace_back(std::move(line));
|
||||||
pos += m_lines.back().length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_changes.push_back({ Change::Insert, {0,0}, line_count(), true });
|
m_changes.push_back({ Change::Insert, {0,0}, line_count(), true });
|
||||||
|
@ -83,13 +81,11 @@ void Buffer::reload(std::vector<String> lines, time_t fs_timestamp)
|
||||||
if (lines.empty())
|
if (lines.empty())
|
||||||
lines.emplace_back("\n");
|
lines.emplace_back("\n");
|
||||||
|
|
||||||
ByteCount pos = 0;
|
|
||||||
m_lines.reserve(lines.size());
|
m_lines.reserve(lines.size());
|
||||||
for (auto& line : lines)
|
for (auto& line : lines)
|
||||||
{
|
{
|
||||||
kak_assert(not line.empty() and line.back() == '\n');
|
kak_assert(not line.empty() and line.back() == '\n');
|
||||||
m_lines.emplace_back(Line{ pos, std::move(line) });
|
m_lines.emplace_back(std::move(line));
|
||||||
pos += m_lines.back().length();
|
|
||||||
}
|
}
|
||||||
m_fs_timestamp = fs_timestamp;
|
m_fs_timestamp = fs_timestamp;
|
||||||
|
|
||||||
|
@ -135,7 +131,7 @@ ByteCoord Buffer::clamp(ByteCoord coord) const
|
||||||
|
|
||||||
ByteCoord Buffer::offset_coord(ByteCoord coord, CharCount offset)
|
ByteCoord Buffer::offset_coord(ByteCoord coord, CharCount offset)
|
||||||
{
|
{
|
||||||
auto& line = m_lines[coord.line].content;
|
auto& line = m_lines[coord.line];
|
||||||
auto character = std::max(0_char, std::min(line.char_count_to(coord.column) + offset,
|
auto character = std::max(0_char, std::min(line.char_count_to(coord.column) + offset,
|
||||||
line.char_length() - 1));
|
line.char_length() - 1));
|
||||||
return {coord.line, line.byte_count_to(character)};
|
return {coord.line, line.byte_count_to(character)};
|
||||||
|
@ -143,9 +139,9 @@ ByteCoord Buffer::offset_coord(ByteCoord coord, CharCount offset)
|
||||||
|
|
||||||
ByteCoord Buffer::offset_coord(ByteCoord coord, LineCount offset)
|
ByteCoord Buffer::offset_coord(ByteCoord coord, LineCount offset)
|
||||||
{
|
{
|
||||||
auto character = m_lines[coord.line].content.char_count_to(coord.column);
|
auto character = m_lines[coord.line].char_count_to(coord.column);
|
||||||
auto line = Kakoune::clamp(coord.line + offset, 0_line, line_count()-1);
|
auto line = Kakoune::clamp(coord.line + offset, 0_line, line_count()-1);
|
||||||
auto& content = m_lines[line].content;
|
auto& content = m_lines[line];
|
||||||
|
|
||||||
character = std::max(0_char, std::min(character, content.char_length() - 2));
|
character = std::max(0_char, std::min(character, content.char_length() - 2));
|
||||||
return {line, content.byte_count_to(character)};
|
return {line, content.byte_count_to(character)};
|
||||||
|
@ -162,7 +158,7 @@ String Buffer::string(ByteCoord begin, ByteCoord end) const
|
||||||
ByteCount count = -1;
|
ByteCount count = -1;
|
||||||
if (line == end.line)
|
if (line == end.line)
|
||||||
count = end.column - start;
|
count = end.column - start;
|
||||||
res += m_lines[line].content.substr(start, count);
|
res += m_lines[line].substr(start, count);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -423,14 +419,11 @@ bool Buffer::redo()
|
||||||
void Buffer::check_invariant() const
|
void Buffer::check_invariant() const
|
||||||
{
|
{
|
||||||
#ifdef KAK_DEBUG
|
#ifdef KAK_DEBUG
|
||||||
ByteCount start = 0;
|
|
||||||
kak_assert(not m_lines.empty());
|
kak_assert(not m_lines.empty());
|
||||||
for (auto& line : m_lines)
|
for (auto& line : m_lines)
|
||||||
{
|
{
|
||||||
kak_assert(line.start == start);
|
|
||||||
kak_assert(line.length() > 0);
|
kak_assert(line.length() > 0);
|
||||||
kak_assert(line.content.back() == '\n');
|
kak_assert(line.back() == '\n');
|
||||||
start += line.length();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -442,12 +435,6 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content)
|
||||||
if (content.empty())
|
if (content.empty())
|
||||||
return pos;
|
return pos;
|
||||||
|
|
||||||
ByteCount offset = this->offset(pos);
|
|
||||||
|
|
||||||
// all following lines advanced by length
|
|
||||||
for (LineCount i = pos.line+1; i < line_count(); ++i)
|
|
||||||
m_lines[i].start += content.length();
|
|
||||||
|
|
||||||
ByteCoord begin;
|
ByteCoord begin;
|
||||||
ByteCoord end;
|
ByteCoord end;
|
||||||
bool at_end = false;
|
bool at_end = false;
|
||||||
|
@ -460,23 +447,23 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content)
|
||||||
{
|
{
|
||||||
if (content[i] == '\n')
|
if (content[i] == '\n')
|
||||||
{
|
{
|
||||||
m_lines.push_back({ offset + start, content.substr(start, i + 1 - start) });
|
m_lines.push_back(content.substr(start, i + 1 - start));
|
||||||
start = i + 1;
|
start = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (start != content.length())
|
if (start != content.length())
|
||||||
m_lines.push_back({ offset + start, content.substr(start) });
|
m_lines.push_back(content.substr(start));
|
||||||
|
|
||||||
begin = pos.column == 0 ? pos : ByteCoord{ pos.line + 1, 0 };
|
begin = pos.column == 0 ? pos : ByteCoord{ pos.line + 1, 0 };
|
||||||
end = ByteCoord{ line_count()-1, m_lines.back().length() };
|
end = ByteCoord{ line_count(), 0 };
|
||||||
at_end = true;
|
at_end = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String prefix = m_lines[pos.line].content.substr(0, pos.column);
|
String prefix = m_lines[pos.line].substr(0, pos.column);
|
||||||
String suffix = m_lines[pos.line].content.substr(pos.column);
|
String suffix = m_lines[pos.line].substr(pos.column);
|
||||||
|
|
||||||
std::vector<Line> new_lines;
|
std::vector<String> new_lines;
|
||||||
|
|
||||||
ByteCount start = 0;
|
ByteCount start = 0;
|
||||||
for (ByteCount i = 0; i < content.length(); ++i)
|
for (ByteCount i = 0; i < content.length(); ++i)
|
||||||
|
@ -487,18 +474,17 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content)
|
||||||
if (start == 0)
|
if (start == 0)
|
||||||
{
|
{
|
||||||
line_content = prefix + line_content;
|
line_content = prefix + line_content;
|
||||||
new_lines.push_back({ offset + start - prefix.length(),
|
new_lines.push_back(std::move(line_content));
|
||||||
std::move(line_content) });
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
new_lines.push_back({ offset + start, std::move(line_content) });
|
new_lines.push_back(std::move(line_content));
|
||||||
start = i + 1;
|
start = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (start == 0)
|
if (start == 0)
|
||||||
new_lines.push_back({ offset + start - prefix.length(), prefix + content + suffix });
|
new_lines.push_back(prefix + content + suffix);
|
||||||
else if (start != content.length() or not suffix.empty())
|
else if (start != content.length() or not suffix.empty())
|
||||||
new_lines.push_back({ offset + start, content.substr(start) + suffix });
|
new_lines.push_back(content.substr(start) + suffix);
|
||||||
|
|
||||||
LineCount last_line = pos.line + new_lines.size() - 1;
|
LineCount last_line = pos.line + new_lines.size() - 1;
|
||||||
|
|
||||||
|
@ -520,10 +506,9 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end)
|
||||||
{
|
{
|
||||||
kak_assert(is_valid(begin));
|
kak_assert(is_valid(begin));
|
||||||
kak_assert(is_valid(end));
|
kak_assert(is_valid(end));
|
||||||
const ByteCount length = distance(begin, end);
|
String prefix = m_lines[begin.line].substr(0, begin.column);
|
||||||
String prefix = m_lines[begin.line].content.substr(0, begin.column);
|
String suffix = m_lines[end.line].substr(end.column);
|
||||||
String suffix = m_lines[end.line].content.substr(end.column);
|
String new_line = prefix + suffix;
|
||||||
Line new_line = { m_lines[begin.line].start, prefix + suffix };
|
|
||||||
|
|
||||||
ByteCoord next;
|
ByteCoord next;
|
||||||
if (new_line.length() != 0)
|
if (new_line.length() != 0)
|
||||||
|
@ -538,9 +523,6 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end)
|
||||||
next = is_end(begin) ? end_coord() : ByteCoord{begin.line, 0};
|
next = is_end(begin) ? end_coord() : ByteCoord{begin.line, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (LineCount i = begin.line+1; i < line_count(); ++i)
|
|
||||||
m_lines[i].start -= length;
|
|
||||||
|
|
||||||
m_changes.push_back({ Change::Erase, begin, end, is_end(begin) });
|
m_changes.push_back({ Change::Erase, begin, end, is_end(begin) });
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
@ -626,17 +608,38 @@ void Buffer::notify_saved()
|
||||||
|
|
||||||
ByteCoord Buffer::advance(ByteCoord coord, ByteCount count) const
|
ByteCoord Buffer::advance(ByteCoord coord, ByteCount count) const
|
||||||
{
|
{
|
||||||
ByteCount off = Kakoune::clamp(offset(coord) + count, 0_byte, byte_count());
|
if (count > 0)
|
||||||
auto it = std::upper_bound(m_lines.begin(), m_lines.end(), off,
|
{
|
||||||
[](ByteCount s, const Line& l) { return s < l.start; }) - 1;
|
auto line = coord.line;
|
||||||
return { LineCount{ (int)(it - m_lines.begin()) }, off - it->start };
|
count += coord.column;
|
||||||
|
while (count >= m_lines[line].length())
|
||||||
|
{
|
||||||
|
count -= m_lines[line++].length();
|
||||||
|
if (line == line_count())
|
||||||
|
return end_coord();
|
||||||
|
}
|
||||||
|
return { line, count };
|
||||||
|
}
|
||||||
|
else if (count < 0)
|
||||||
|
{
|
||||||
|
auto line = coord.line;
|
||||||
|
count += coord.column;
|
||||||
|
while (count < 0)
|
||||||
|
{
|
||||||
|
count += m_lines[--line].length();
|
||||||
|
if (line < 0)
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
return { line, count };
|
||||||
|
}
|
||||||
|
return coord;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteCoord Buffer::char_next(ByteCoord coord) const
|
ByteCoord Buffer::char_next(ByteCoord coord) const
|
||||||
{
|
{
|
||||||
if (coord.column < m_lines[coord.line].length() - 1)
|
if (coord.column < m_lines[coord.line].length() - 1)
|
||||||
{
|
{
|
||||||
auto& line = m_lines[coord.line].content;
|
auto& line = m_lines[coord.line];
|
||||||
coord.column += utf8::codepoint_size(line.begin() + (int)coord.column);
|
coord.column += utf8::codepoint_size(line.begin() + (int)coord.column);
|
||||||
// Handle invalid utf-8
|
// Handle invalid utf-8
|
||||||
if (coord.column >= line.length())
|
if (coord.column >= line.length())
|
||||||
|
@ -667,7 +670,7 @@ ByteCoord Buffer::char_prev(ByteCoord coord) const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto& line = m_lines[coord.line].content;
|
auto& line = m_lines[coord.line];
|
||||||
coord.column = (int)(utf8::character_start(line.begin() + (int)coord.column - 1) - line.begin());
|
coord.column = (int)(utf8::character_start(line.begin() + (int)coord.column - 1) - line.begin());
|
||||||
}
|
}
|
||||||
return coord;
|
return coord;
|
||||||
|
|
|
@ -105,7 +105,6 @@ public:
|
||||||
String string(ByteCoord begin, ByteCoord end) const;
|
String string(ByteCoord begin, ByteCoord end) const;
|
||||||
|
|
||||||
char byte_at(ByteCoord c) const;
|
char byte_at(ByteCoord c) const;
|
||||||
ByteCount offset(ByteCoord c) const;
|
|
||||||
ByteCount distance(ByteCoord begin, ByteCoord end) const;
|
ByteCount distance(ByteCoord begin, ByteCoord end) const;
|
||||||
ByteCoord advance(ByteCoord coord, ByteCount count) const;
|
ByteCoord advance(ByteCoord coord, ByteCount count) const;
|
||||||
ByteCoord next(ByteCoord coord) const;
|
ByteCoord next(ByteCoord coord) const;
|
||||||
|
@ -124,11 +123,10 @@ public:
|
||||||
|
|
||||||
BufferIterator begin() const;
|
BufferIterator begin() const;
|
||||||
BufferIterator end() const;
|
BufferIterator end() const;
|
||||||
ByteCount byte_count() const;
|
|
||||||
LineCount line_count() const;
|
LineCount line_count() const;
|
||||||
|
|
||||||
const String& operator[](LineCount line) const
|
const String& operator[](LineCount line) const
|
||||||
{ return m_lines[line].content; }
|
{ return m_lines[line]; }
|
||||||
|
|
||||||
// returns an iterator at given coordinates. clamp line_and_column
|
// returns an iterator at given coordinates. clamp line_and_column
|
||||||
BufferIterator iterator_at(ByteCoord coord) const;
|
BufferIterator iterator_at(ByteCoord coord) const;
|
||||||
|
@ -177,20 +175,13 @@ private:
|
||||||
|
|
||||||
void on_option_changed(const Option& option) override;
|
void on_option_changed(const Option& option) override;
|
||||||
|
|
||||||
struct Line
|
struct LineList : std::vector<String>
|
||||||
{
|
{
|
||||||
ByteCount start;
|
String& operator[](LineCount line)
|
||||||
String content;
|
{ return std::vector<String>::operator[]((int)line); }
|
||||||
|
|
||||||
ByteCount length() const { return content.length(); }
|
const String& operator[](LineCount line) const
|
||||||
};
|
{ return std::vector<String>::operator[]((int)line); }
|
||||||
struct LineList : std::vector<Line>
|
|
||||||
{
|
|
||||||
Line& operator[](LineCount line)
|
|
||||||
{ return std::vector<Line>::operator[]((int)line); }
|
|
||||||
|
|
||||||
const Line& operator[](LineCount line) const
|
|
||||||
{ return std::vector<Line>::operator[]((int)line); }
|
|
||||||
};
|
};
|
||||||
LineList m_lines;
|
LineList m_lines;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Kakoune
|
||||||
inline char Buffer::byte_at(ByteCoord c) const
|
inline char Buffer::byte_at(ByteCoord c) const
|
||||||
{
|
{
|
||||||
kak_assert(c.line < line_count() and c.column < m_lines[c.line].length());
|
kak_assert(c.line < line_count() and c.column < m_lines[c.line].length());
|
||||||
return m_lines[c.line].content[c.column];
|
return m_lines[c.line][c.column];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ByteCoord Buffer::next(ByteCoord coord) const
|
inline ByteCoord Buffer::next(ByteCoord coord) const
|
||||||
|
@ -40,14 +40,19 @@ inline ByteCoord Buffer::prev(ByteCoord coord) const
|
||||||
|
|
||||||
inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const
|
inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const
|
||||||
{
|
{
|
||||||
return offset(end) - offset(begin);
|
if (begin > end)
|
||||||
}
|
return -distance(end, begin);
|
||||||
|
ByteCount res = 0;
|
||||||
inline ByteCount Buffer::offset(ByteCoord c) const
|
for (LineCount l = begin.line; l <= end.line; ++l)
|
||||||
{
|
{
|
||||||
if (c.line == line_count())
|
ByteCount len = m_lines[l].length();
|
||||||
return m_lines.back().start + m_lines.back().length();
|
res += len;
|
||||||
return m_lines[c.line].start + c.column;
|
if (l == begin.line)
|
||||||
|
res -= begin.column;
|
||||||
|
if (l == end.line)
|
||||||
|
res -= len - end.column;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Buffer::is_valid(ByteCoord c) const
|
inline bool Buffer::is_valid(ByteCoord c) const
|
||||||
|
@ -77,13 +82,6 @@ inline BufferIterator Buffer::end() const
|
||||||
return BufferIterator(*this, { line_count() - 1, m_lines.back().length() });
|
return BufferIterator(*this, { line_count() - 1, m_lines.back().length() });
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ByteCount Buffer::byte_count() const
|
|
||||||
{
|
|
||||||
if (m_lines.empty())
|
|
||||||
return 0;
|
|
||||||
return m_lines.back().start + m_lines.back().length();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline LineCount Buffer::line_count() const
|
inline LineCount Buffer::line_count() const
|
||||||
{
|
{
|
||||||
return LineCount(m_lines.size());
|
return LineCount(m_lines.size());
|
||||||
|
|
|
@ -189,14 +189,13 @@ void InsertCompleter::select(int offset)
|
||||||
const auto& cursor_pos = selections.main().cursor();
|
const auto& cursor_pos = selections.main().cursor();
|
||||||
const auto prefix_len = buffer.distance(m_completions.begin, cursor_pos);
|
const auto prefix_len = buffer.distance(m_completions.begin, cursor_pos);
|
||||||
const auto suffix_len = std::max(0_byte, buffer.distance(cursor_pos, m_completions.end));
|
const auto suffix_len = std::max(0_byte, buffer.distance(cursor_pos, m_completions.end));
|
||||||
const auto buffer_len = buffer.byte_count();
|
|
||||||
|
|
||||||
auto ref = buffer.string(m_completions.begin, m_completions.end);
|
auto ref = buffer.string(m_completions.begin, m_completions.end);
|
||||||
for (auto& sel : selections)
|
for (auto& sel : selections)
|
||||||
{
|
{
|
||||||
auto offset = buffer.offset(sel.cursor());
|
const auto& cursor = sel.cursor();
|
||||||
auto pos = buffer.iterator_at(sel.cursor());
|
auto pos = buffer.iterator_at(cursor);
|
||||||
if (offset >= prefix_len and offset + suffix_len < buffer_len and
|
if (cursor.column >= prefix_len and (pos + suffix_len) != buffer.end() and
|
||||||
std::equal(ref.begin(), ref.end(), pos - prefix_len))
|
std::equal(ref.begin(), ref.end(), pos - prefix_len))
|
||||||
{
|
{
|
||||||
pos = buffer.erase(pos - prefix_len, pos + suffix_len);
|
pos = buffer.erase(pos - prefix_len, pos + suffix_len);
|
||||||
|
|
|
@ -288,7 +288,7 @@ Selection select_whole_paragraph(const Buffer& buffer, const Selection& selectio
|
||||||
{
|
{
|
||||||
BufferIterator first = buffer.iterator_at(selection.cursor());
|
BufferIterator first = buffer.iterator_at(selection.cursor());
|
||||||
|
|
||||||
if (not (flags & ObjectFlags::ToEnd) and buffer.offset(first.coord()) > 1 and
|
if (not (flags & ObjectFlags::ToEnd) and first.coord() > ByteCoord{0,1} and
|
||||||
*(first-1) == '\n' and *(first-2) == '\n')
|
*(first-1) == '\n' and *(first-2) == '\n')
|
||||||
--first;
|
--first;
|
||||||
else if ((flags & ObjectFlags::ToEnd) and
|
else if ((flags & ObjectFlags::ToEnd) and
|
||||||
|
|
|
@ -27,6 +27,9 @@ void test_buffer()
|
||||||
kak_assert(pos.coord() == ByteCoord{1 COMMA 0});
|
kak_assert(pos.coord() == ByteCoord{1 COMMA 0});
|
||||||
buffer.insert(pos, "tchou kanaky\n");
|
buffer.insert(pos, "tchou kanaky\n");
|
||||||
kak_assert(buffer.line_count() == 5);
|
kak_assert(buffer.line_count() == 5);
|
||||||
|
BufferIterator pos2 = buffer.end();
|
||||||
|
pos2 -= 9;
|
||||||
|
kak_assert(*pos2 == '?');
|
||||||
|
|
||||||
String str = buffer.string({ 4, 1 }, buffer.next({ 4, 5 }));
|
String str = buffer.string({ 4, 1 }, buffer.next({ 4, 5 }));
|
||||||
kak_assert(str == "youpi");
|
kak_assert(str == "youpi");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user