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())
|
||||
lines.emplace_back("\n");
|
||||
|
||||
ByteCount pos = 0;
|
||||
m_lines.reserve(lines.size());
|
||||
for (auto& line : lines)
|
||||
{
|
||||
kak_assert(not line.empty() and line.back() == '\n');
|
||||
m_lines.emplace_back(Line{ pos, std::move(line) });
|
||||
pos += m_lines.back().length();
|
||||
m_lines.emplace_back(std::move(line));
|
||||
}
|
||||
|
||||
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())
|
||||
lines.emplace_back("\n");
|
||||
|
||||
ByteCount pos = 0;
|
||||
m_lines.reserve(lines.size());
|
||||
for (auto& line : lines)
|
||||
{
|
||||
kak_assert(not line.empty() and line.back() == '\n');
|
||||
m_lines.emplace_back(Line{ pos, std::move(line) });
|
||||
pos += m_lines.back().length();
|
||||
m_lines.emplace_back(std::move(line));
|
||||
}
|
||||
m_fs_timestamp = fs_timestamp;
|
||||
|
||||
|
@ -135,7 +131,7 @@ ByteCoord Buffer::clamp(ByteCoord coord) const
|
|||
|
||||
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,
|
||||
line.char_length() - 1));
|
||||
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)
|
||||
{
|
||||
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& content = m_lines[line].content;
|
||||
auto& content = m_lines[line];
|
||||
|
||||
character = std::max(0_char, std::min(character, content.char_length() - 2));
|
||||
return {line, content.byte_count_to(character)};
|
||||
|
@ -162,7 +158,7 @@ String Buffer::string(ByteCoord begin, ByteCoord end) const
|
|||
ByteCount count = -1;
|
||||
if (line == end.line)
|
||||
count = end.column - start;
|
||||
res += m_lines[line].content.substr(start, count);
|
||||
res += m_lines[line].substr(start, count);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -423,14 +419,11 @@ bool Buffer::redo()
|
|||
void Buffer::check_invariant() const
|
||||
{
|
||||
#ifdef KAK_DEBUG
|
||||
ByteCount start = 0;
|
||||
kak_assert(not m_lines.empty());
|
||||
for (auto& line : m_lines)
|
||||
{
|
||||
kak_assert(line.start == start);
|
||||
kak_assert(line.length() > 0);
|
||||
kak_assert(line.content.back() == '\n');
|
||||
start += line.length();
|
||||
kak_assert(line.back() == '\n');
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -442,12 +435,6 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content)
|
|||
if (content.empty())
|
||||
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 end;
|
||||
bool at_end = false;
|
||||
|
@ -460,23 +447,23 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content)
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 };
|
||||
end = ByteCoord{ line_count()-1, m_lines.back().length() };
|
||||
end = ByteCoord{ line_count(), 0 };
|
||||
at_end = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
String prefix = m_lines[pos.line].content.substr(0, pos.column);
|
||||
String suffix = m_lines[pos.line].content.substr(pos.column);
|
||||
String prefix = m_lines[pos.line].substr(0, pos.column);
|
||||
String suffix = m_lines[pos.line].substr(pos.column);
|
||||
|
||||
std::vector<Line> new_lines;
|
||||
std::vector<String> new_lines;
|
||||
|
||||
ByteCount start = 0;
|
||||
for (ByteCount i = 0; i < content.length(); ++i)
|
||||
|
@ -487,18 +474,17 @@ ByteCoord Buffer::do_insert(ByteCoord pos, const String& content)
|
|||
if (start == 0)
|
||||
{
|
||||
line_content = prefix + line_content;
|
||||
new_lines.push_back({ offset + start - prefix.length(),
|
||||
std::move(line_content) });
|
||||
new_lines.push_back(std::move(line_content));
|
||||
}
|
||||
else
|
||||
new_lines.push_back({ offset + start, std::move(line_content) });
|
||||
new_lines.push_back(std::move(line_content));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
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())
|
||||
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;
|
||||
|
||||
|
@ -520,10 +506,9 @@ ByteCoord Buffer::do_erase(ByteCoord begin, ByteCoord end)
|
|||
{
|
||||
kak_assert(is_valid(begin));
|
||||
kak_assert(is_valid(end));
|
||||
const ByteCount length = distance(begin, end);
|
||||
String prefix = m_lines[begin.line].content.substr(0, begin.column);
|
||||
String suffix = m_lines[end.line].content.substr(end.column);
|
||||
Line new_line = { m_lines[begin.line].start, prefix + suffix };
|
||||
String prefix = m_lines[begin.line].substr(0, begin.column);
|
||||
String suffix = m_lines[end.line].substr(end.column);
|
||||
String new_line = prefix + suffix;
|
||||
|
||||
ByteCoord next;
|
||||
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};
|
||||
}
|
||||
|
||||
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) });
|
||||
return next;
|
||||
}
|
||||
|
@ -626,17 +608,38 @@ void Buffer::notify_saved()
|
|||
|
||||
ByteCoord Buffer::advance(ByteCoord coord, ByteCount count) const
|
||||
{
|
||||
ByteCount off = Kakoune::clamp(offset(coord) + count, 0_byte, byte_count());
|
||||
auto it = std::upper_bound(m_lines.begin(), m_lines.end(), off,
|
||||
[](ByteCount s, const Line& l) { return s < l.start; }) - 1;
|
||||
return { LineCount{ (int)(it - m_lines.begin()) }, off - it->start };
|
||||
if (count > 0)
|
||||
{
|
||||
auto line = coord.line;
|
||||
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
|
||||
{
|
||||
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);
|
||||
// Handle invalid utf-8
|
||||
if (coord.column >= line.length())
|
||||
|
@ -667,7 +670,7 @@ ByteCoord Buffer::char_prev(ByteCoord coord) const
|
|||
}
|
||||
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());
|
||||
}
|
||||
return coord;
|
||||
|
|
|
@ -105,7 +105,6 @@ public:
|
|||
String string(ByteCoord begin, ByteCoord end) const;
|
||||
|
||||
char byte_at(ByteCoord c) const;
|
||||
ByteCount offset(ByteCoord c) const;
|
||||
ByteCount distance(ByteCoord begin, ByteCoord end) const;
|
||||
ByteCoord advance(ByteCoord coord, ByteCount count) const;
|
||||
ByteCoord next(ByteCoord coord) const;
|
||||
|
@ -124,11 +123,10 @@ public:
|
|||
|
||||
BufferIterator begin() const;
|
||||
BufferIterator end() const;
|
||||
ByteCount byte_count() const;
|
||||
LineCount line_count() 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
|
||||
BufferIterator iterator_at(ByteCoord coord) const;
|
||||
|
@ -177,20 +175,13 @@ private:
|
|||
|
||||
void on_option_changed(const Option& option) override;
|
||||
|
||||
struct Line
|
||||
struct LineList : std::vector<String>
|
||||
{
|
||||
ByteCount start;
|
||||
String content;
|
||||
String& operator[](LineCount line)
|
||||
{ return std::vector<String>::operator[]((int)line); }
|
||||
|
||||
ByteCount length() const { return content.length(); }
|
||||
};
|
||||
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); }
|
||||
const String& operator[](LineCount line) const
|
||||
{ return std::vector<String>::operator[]((int)line); }
|
||||
};
|
||||
LineList m_lines;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Kakoune
|
|||
inline char Buffer::byte_at(ByteCoord c) const
|
||||
{
|
||||
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
|
||||
|
@ -40,14 +40,19 @@ inline ByteCoord Buffer::prev(ByteCoord coord) const
|
|||
|
||||
inline ByteCount Buffer::distance(ByteCoord begin, ByteCoord end) const
|
||||
{
|
||||
return offset(end) - offset(begin);
|
||||
}
|
||||
|
||||
inline ByteCount Buffer::offset(ByteCoord c) const
|
||||
{
|
||||
if (c.line == line_count())
|
||||
return m_lines.back().start + m_lines.back().length();
|
||||
return m_lines[c.line].start + c.column;
|
||||
if (begin > end)
|
||||
return -distance(end, begin);
|
||||
ByteCount res = 0;
|
||||
for (LineCount l = begin.line; l <= end.line; ++l)
|
||||
{
|
||||
ByteCount len = m_lines[l].length();
|
||||
res += len;
|
||||
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
|
||||
|
@ -77,13 +82,6 @@ inline BufferIterator Buffer::end() const
|
|||
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
|
||||
{
|
||||
return LineCount(m_lines.size());
|
||||
|
|
|
@ -189,14 +189,13 @@ void InsertCompleter::select(int offset)
|
|||
const auto& cursor_pos = selections.main().cursor();
|
||||
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 buffer_len = buffer.byte_count();
|
||||
|
||||
auto ref = buffer.string(m_completions.begin, m_completions.end);
|
||||
for (auto& sel : selections)
|
||||
{
|
||||
auto offset = buffer.offset(sel.cursor());
|
||||
auto pos = buffer.iterator_at(sel.cursor());
|
||||
if (offset >= prefix_len and offset + suffix_len < buffer_len and
|
||||
const auto& cursor = sel.cursor();
|
||||
auto pos = buffer.iterator_at(cursor);
|
||||
if (cursor.column >= prefix_len and (pos + suffix_len) != buffer.end() and
|
||||
std::equal(ref.begin(), ref.end(), pos - prefix_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());
|
||||
|
||||
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;
|
||||
else if ((flags & ObjectFlags::ToEnd) and
|
||||
|
|
|
@ -27,6 +27,9 @@ void test_buffer()
|
|||
kak_assert(pos.coord() == ByteCoord{1 COMMA 0});
|
||||
buffer.insert(pos, "tchou kanaky\n");
|
||||
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 }));
|
||||
kak_assert(str == "youpi");
|
||||
|
|
Loading…
Reference in New Issue
Block a user