Split some PieceTable::Cursor functionality into PieceTable::Iterator

This commit is contained in:
Josh Holtrop 2016-08-27 15:20:08 -04:00
parent f659c14242
commit d6b3810a3c
2 changed files with 159 additions and 71 deletions

View File

@ -31,16 +31,89 @@ std::shared_ptr<PieceTable::Cursor> PieceTable::add_cursor()
{ {
auto cursor = std::make_shared<Cursor>(); auto cursor = std::make_shared<Cursor>();
cursor->piece_table = this; cursor->iterator.piece_table = this;
cursor->piece = start_piece->next; cursor->iterator.piece = start_piece->next;
cursor->line_number = 0u; cursor->iterator.offset = 0u;
cursor->offset = 0u;
m_cursors.push_back(cursor); m_cursors.push_back(cursor);
return 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 uint32_t PieceTable::Cursor::column() const
{ {
/* TODO: support tabs */ /* TODO: support tabs */
@ -58,119 +131,104 @@ uint32_t PieceTable::Cursor::column() const
} }
return c; return c;
} }
#endif
void PieceTable::Cursor::go_start_of_line() void PieceTable::Cursor::go_start_of_line()
{ {
while ((!piece->prev->eol()) && (piece->prev != piece_table->start_piece)) while (iterator.valid() && (!iterator.piece->prev->eol()))
{ {
piece = piece->prev; iterator.go_prev_piece();
} }
offset = 0u;
} }
void PieceTable::Cursor::go_end_of_line() void PieceTable::Cursor::go_end_of_line()
{ {
/* TODO: Use Encoding */ while (iterator.valid() && (!iterator.piece->eol()))
while ((!piece->eol()) && (piece->next != piece_table->end_piece))
{ {
piece = piece->next; iterator.go_next_piece();
} }
offset = (piece->length > 0u) ? piece->length - 1u : 0u; iterator.go_end_of_piece();
} }
bool PieceTable::Cursor::go_up(int n) bool PieceTable::Cursor::go_up(int n)
{ {
/* TODO: Use Encoding */
/* TODO: support tabs */
/* TODO: support n */
Piece * p = prev_line(); Piece * p = prev_line();
if (p == nullptr) if (p == nullptr)
{ {
return false; return false;
} }
iterator.piece = p;
iterator.offset = 0u;
#if 0
uint32_t current_column = column(); uint32_t current_column = column();
piece = p;
offset = 0u;
line_number--;
forward_to_column(current_column); forward_to_column(current_column);
#endif
return true; return true;
} }
bool PieceTable::Cursor::go_down(int n) bool PieceTable::Cursor::go_down(int n)
{ {
/* TODO: Use Encoding */
/* TODO: support tabs */
/* TODO: support n */
Piece * p = next_line(); Piece * p = next_line();
if (p == nullptr) if (p == nullptr)
{ {
return false; return false;
} }
iterator.piece = p;
iterator.offset = 0u;
#if 0
uint32_t current_column = column(); uint32_t current_column = column();
piece = p;
offset = 0u;
line_number++;
forward_to_column(current_column); forward_to_column(current_column);
#endif
return true; return true;
} }
bool PieceTable::Cursor::go_left(int n) bool PieceTable::Cursor::go_left(int n)
{ {
/* TODO: Use Encoding */ if (is_start_of_line())
/* TODO: support tabs */
/* TODO: support n */
if (offset > 0)
{
offset--;
}
else if ((piece->prev != piece_table->start_piece) &&
(!piece->prev->eol()))
{
piece = piece->prev;
offset = piece->length - 1u;
}
else
{ {
return false; return false;
} }
iterator.go_prev_position();
return true; return true;
} }
bool PieceTable::Cursor::go_right(int n) bool PieceTable::Cursor::go_right(int n)
{ {
/* TODO: Use Encoding */ if (is_end_of_line())
/* TODO: support tabs */
/* TODO: support n */
if (offset < piece->length - 1u)
{
offset++;
}
else if ((piece->next != piece_table->end_piece) &&
(!piece->eol()))
{
piece = piece->next;
offset = 0u;
}
else
{ {
return false; return false;
} }
iterator.go_next_position();
return true; 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 PieceTable::Piece * PieceTable::Cursor::prev_line() const
{ {
Piece * p = piece; Piece * p = iterator.piece;
while ((!p->prev->eol()) && (p->prev != piece_table->start_piece)) while ((!p->prev->eol()) && (p->prev != iterator.piece_table->start_piece))
{ {
p = p->prev; p = p->prev;
} }
if (p->prev == piece_table->start_piece) if (p->prev == iterator.piece_table->start_piece)
{ {
return nullptr; return nullptr;
} }
p = p->prev; p = p->prev;
while ((!p->prev->eol()) && (p->prev != piece_table->start_piece)) while ((!p->prev->eol()) && (p->prev != iterator.piece_table->start_piece))
{ {
p = p->prev; p = p->prev;
} }
@ -179,23 +237,24 @@ PieceTable::Piece * PieceTable::Cursor::prev_line() const
PieceTable::Piece * PieceTable::Cursor::next_line() const PieceTable::Piece * PieceTable::Cursor::next_line() const
{ {
Piece * p = piece; Piece * p = iterator.piece;
while ((!p->eol()) && (p->next != piece_table->end_piece)) while ((!p->eol()) && (p->next != iterator.piece_table->end_piece))
{ {
p = p->next; p = p->next;
} }
if (p->next == piece_table->end_piece) if (p->next == iterator.piece_table->end_piece)
{ {
return nullptr; return nullptr;
} }
p = p->next; p = p->next;
while ((!p->eol()) && (p->next != piece_table->end_piece)) while ((!p->eol()) && (p->next != iterator.piece_table->end_piece))
{ {
p = p->next; p = p->next;
} }
return p; return p;
} }
#if 0
void PieceTable::Cursor::forward_to_column(uint32_t c) void PieceTable::Cursor::forward_to_column(uint32_t c)
{ {
uint32_t current_column = column(); uint32_t current_column = column();
@ -214,3 +273,4 @@ void PieceTable::Cursor::forward_to_column(uint32_t c)
diff = new_diff; diff = new_diff;
} }
} }
#endif

View File

@ -48,7 +48,7 @@ public:
void toggle_eol() { flags ^= EOL_FLAG; } void toggle_eol() { flags ^= EOL_FLAG; }
}; };
struct Cursor struct Iterator
{ {
/** The piece table the cursor belongs to. */ /** The piece table the cursor belongs to. */
PieceTable * piece_table; PieceTable * piece_table;
@ -59,23 +59,49 @@ public:
/** Byte offset within the piece. */ /** Byte offset within the piece. */
uint32_t offset; uint32_t offset;
/** Line number the cursor is on (0 based). */ /** Get the character pointed to by the cursor. */
uint32_t line_number; uint32_t operator*() const
{
if (has_char())
{
return Encoding::decode(piece_table->encoding, &piece->start[offset]);
}
else
{
return 0xFFFFFFFFu;
}
}
uint8_t num_bytes_in_code_point() const;
void go_next_position();
void go_prev_position();
void go_end_of_piece();
void go_next_piece();
void go_prev_piece();
bool valid() const
{
return (piece != piece_table->start_piece) &&
(piece != piece_table->end_piece);
}
bool has_char() const
{
return valid() && (offset < piece->length);
}
};
struct Cursor
{
Iterator iterator;
/** Get the character pointed to by the cursor. */ /** Get the character pointed to by the cursor. */
uint32_t operator*() const uint32_t operator*() const
{ {
return Encoding::decode(piece_table->encoding, &piece->start[offset]); return *iterator;
} }
/**
* Get the screen column of the cursor (taking into account tabs).
*
* This function will return 0 only if the cursor is on an empty line.
* The first column of a line with at least one character is column 1.
*/
uint32_t column() const;
void go_start_of_line(); void go_start_of_line();
void go_end_of_line(); void go_end_of_line();
bool go_up(int n = 1); bool go_up(int n = 1);
@ -84,6 +110,8 @@ public:
bool go_right(int n = 1); bool go_right(int n = 1);
protected: protected:
bool is_start_of_line();
bool is_end_of_line();
Piece * prev_line() const; Piece * prev_line() const;
Piece * next_line() const; Piece * next_line() const;
void forward_to_column(uint32_t c); void forward_to_column(uint32_t c);