277 lines
5.8 KiB
C++
277 lines
5.8 KiB
C++
#include "PieceTable.h"
|
|
|
|
PieceTable::PieceTable(const uint8_t * file_buffer, unsigned long file_buffer_size)
|
|
{
|
|
m_file_buffer = file_buffer;
|
|
m_file_buffer_size = file_buffer_size;
|
|
start_piece = &m_pieces[PIECE_INDEX_START];
|
|
end_piece = &m_pieces[PIECE_INDEX_END];
|
|
start_piece->next = end_piece;
|
|
end_piece->prev = start_piece;
|
|
m_piece_index = 2u;
|
|
tabstop = 4u;
|
|
}
|
|
|
|
void PieceTable::append_initial_line_piece(uint8_t * start, uint32_t length, bool eol)
|
|
{
|
|
Piece * piece = add_piece();
|
|
piece->prev = end_piece->prev;
|
|
piece->next = end_piece;
|
|
piece->start = start;
|
|
piece->length = length;
|
|
piece->flags = 0u;
|
|
if (eol)
|
|
piece->flags |= Piece::EOL_FLAG;
|
|
end_piece->prev->next = piece;
|
|
end_piece->prev = piece;
|
|
m_num_lines++;
|
|
}
|
|
|
|
std::shared_ptr<PieceTable::Cursor> PieceTable::add_cursor()
|
|
{
|
|
auto cursor = std::make_shared<Cursor>();
|
|
|
|
cursor->iterator.piece_table = this;
|
|
cursor->iterator.piece = start_piece->next;
|
|
cursor->iterator.offset = 0u;
|
|
|
|
m_cursors.push_back(cursor);
|
|
|
|
return cursor;
|
|
}
|
|
|
|
uint8_t PieceTable::Iterator::num_bytes_in_code_point() const
|
|
{
|
|
if (offset >= piece->length)
|
|
{
|
|
return 0u;
|
|
}
|
|
else
|
|
{
|
|
return Encoding::num_bytes_in_code_point(piece_table->encoding, &piece->start[offset]);
|
|
}
|
|
}
|
|
|
|
void PieceTable::Iterator::go_next_position()
|
|
{
|
|
uint8_t code_point_size = num_bytes_in_code_point();
|
|
if ((offset + code_point_size) >= piece->length)
|
|
{
|
|
go_next_piece();
|
|
return;
|
|
}
|
|
offset += code_point_size;
|
|
}
|
|
|
|
void PieceTable::Iterator::go_prev_position()
|
|
{
|
|
if (offset > 0)
|
|
{
|
|
offset = Encoding::beginning_of_code_point(piece_table->encoding, &piece->start[offset - 1u]) - piece->start;
|
|
}
|
|
else if (piece != piece_table->start_piece)
|
|
{
|
|
piece = piece->prev;
|
|
if (piece->length > 0u)
|
|
{
|
|
offset = Encoding::beginning_of_code_point(piece_table->encoding, &piece->start[piece->length - 1u]) - piece->start;
|
|
}
|
|
else
|
|
{
|
|
offset = 0u;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PieceTable::Iterator::go_end_of_piece()
|
|
{
|
|
if (piece->length > 0u)
|
|
{
|
|
offset = Encoding::beginning_of_code_point(piece_table->encoding, &piece->start[piece->length - 1u]) - piece->start;
|
|
}
|
|
else
|
|
{
|
|
offset = 0u;
|
|
}
|
|
}
|
|
|
|
void PieceTable::Iterator::go_next_piece()
|
|
{
|
|
if (piece != piece_table->end_piece)
|
|
{
|
|
piece = piece->next;
|
|
offset = 0u;
|
|
}
|
|
}
|
|
|
|
void PieceTable::Iterator::go_prev_piece()
|
|
{
|
|
if (piece != piece_table->start_piece)
|
|
{
|
|
piece = piece->prev;
|
|
offset = 0u;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
uint32_t PieceTable::Cursor::column() const
|
|
{
|
|
/* TODO: support tabs */
|
|
Cursor sol = *this;
|
|
sol.go_start_of_line();
|
|
if (sol.piece->eol() && sol.piece->length == 0u)
|
|
{
|
|
return 0u;
|
|
}
|
|
uint32_t c = 1u;
|
|
while ((sol.piece != piece) || (sol.offset < offset))
|
|
{
|
|
sol.go_right();
|
|
c++;
|
|
}
|
|
return c;
|
|
}
|
|
#endif
|
|
|
|
void PieceTable::Cursor::go_start_of_line()
|
|
{
|
|
while (iterator.valid() && (!iterator.piece->prev->eol()))
|
|
{
|
|
iterator.go_prev_piece();
|
|
}
|
|
}
|
|
|
|
void PieceTable::Cursor::go_end_of_line()
|
|
{
|
|
while (iterator.valid() && (!iterator.piece->eol()))
|
|
{
|
|
iterator.go_next_piece();
|
|
}
|
|
iterator.go_end_of_piece();
|
|
}
|
|
|
|
bool PieceTable::Cursor::go_up(int n)
|
|
{
|
|
Piece * p = prev_line();
|
|
if (p == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
iterator.piece = p;
|
|
iterator.offset = 0u;
|
|
#if 0
|
|
uint32_t current_column = column();
|
|
forward_to_column(current_column);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool PieceTable::Cursor::go_down(int n)
|
|
{
|
|
Piece * p = next_line();
|
|
if (p == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
iterator.piece = p;
|
|
iterator.offset = 0u;
|
|
#if 0
|
|
uint32_t current_column = column();
|
|
forward_to_column(current_column);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool PieceTable::Cursor::go_left(int n)
|
|
{
|
|
if (is_start_of_line())
|
|
{
|
|
return false;
|
|
}
|
|
iterator.go_prev_position();
|
|
return true;
|
|
}
|
|
|
|
bool PieceTable::Cursor::go_right(int n)
|
|
{
|
|
if (is_end_of_line())
|
|
{
|
|
return false;
|
|
}
|
|
iterator.go_next_position();
|
|
return true;
|
|
}
|
|
|
|
bool PieceTable::Cursor::is_start_of_line()
|
|
{
|
|
return iterator.valid() &&
|
|
(iterator.offset == 0u) &&
|
|
(iterator.piece->prev->eol());
|
|
}
|
|
|
|
bool PieceTable::Cursor::is_end_of_line()
|
|
{
|
|
return iterator.valid() &&
|
|
((iterator.offset + iterator.num_bytes_in_code_point()) >= iterator.piece->length) &&
|
|
iterator.piece->eol();
|
|
}
|
|
|
|
PieceTable::Piece * PieceTable::Cursor::prev_line() const
|
|
{
|
|
Piece * p = iterator.piece;
|
|
while ((!p->prev->eol()) && (p->prev != iterator.piece_table->start_piece))
|
|
{
|
|
p = p->prev;
|
|
}
|
|
if (p->prev == iterator.piece_table->start_piece)
|
|
{
|
|
return nullptr;
|
|
}
|
|
p = p->prev;
|
|
while ((!p->prev->eol()) && (p->prev != iterator.piece_table->start_piece))
|
|
{
|
|
p = p->prev;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
PieceTable::Piece * PieceTable::Cursor::next_line() const
|
|
{
|
|
Piece * p = iterator.piece;
|
|
while ((!p->eol()) && (p->next != iterator.piece_table->end_piece))
|
|
{
|
|
p = p->next;
|
|
}
|
|
if (p->next == iterator.piece_table->end_piece)
|
|
{
|
|
return nullptr;
|
|
}
|
|
p = p->next;
|
|
while ((!p->eol()) && (p->next != iterator.piece_table->end_piece))
|
|
{
|
|
p = p->next;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
#if 0
|
|
void PieceTable::Cursor::forward_to_column(uint32_t c)
|
|
{
|
|
uint32_t current_column = column();
|
|
/* TODO: support tabs */
|
|
/* TODO: Use Encoding */
|
|
int32_t diff = abs((int32_t)(c - current_column));
|
|
while (go_right())
|
|
{
|
|
current_column++;
|
|
int32_t new_diff = abs((int32_t)(c - current_column));
|
|
if (new_diff > diff)
|
|
{
|
|
go_left();
|
|
return;
|
|
}
|
|
diff = new_diff;
|
|
}
|
|
}
|
|
#endif
|