add initial cursor movement support
This commit is contained in:
parent
81e6a53c08
commit
3c5a7b7341
@ -27,18 +27,6 @@ void PieceTable::append_initial_line_piece(uint8_t * start, uint32_t length, boo
|
|||||||
m_num_lines++;
|
m_num_lines++;
|
||||||
}
|
}
|
||||||
|
|
||||||
PieceTable::Piece * PieceTable::get_start_of_line(PieceTable::Piece * start) const
|
|
||||||
{
|
|
||||||
Piece * piece = start;
|
|
||||||
|
|
||||||
while (piece->prev != start_piece && !piece->prev->eol())
|
|
||||||
{
|
|
||||||
piece = piece->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PieceTable::Cursor> PieceTable::add_cursor()
|
std::shared_ptr<PieceTable::Cursor> PieceTable::add_cursor()
|
||||||
{
|
{
|
||||||
auto cursor = std::make_shared<Cursor>();
|
auto cursor = std::make_shared<Cursor>();
|
||||||
@ -47,9 +35,182 @@ std::shared_ptr<PieceTable::Cursor> PieceTable::add_cursor()
|
|||||||
cursor->piece = start_piece->next;
|
cursor->piece = start_piece->next;
|
||||||
cursor->line_number = 0u;
|
cursor->line_number = 0u;
|
||||||
cursor->offset = 0u;
|
cursor->offset = 0u;
|
||||||
cursor->column = 0u;
|
|
||||||
|
|
||||||
m_cursors.push_back(cursor);
|
m_cursors.push_back(cursor);
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PieceTable::Cursor::go_start_of_line()
|
||||||
|
{
|
||||||
|
while ((!piece->prev->eol()) && (piece->prev != piece_table->start_piece))
|
||||||
|
{
|
||||||
|
piece = piece->prev;
|
||||||
|
}
|
||||||
|
offset = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PieceTable::Cursor::go_end_of_line()
|
||||||
|
{
|
||||||
|
/* TODO: Use Encoding */
|
||||||
|
while ((!piece->eol()) && (piece->next != piece_table->end_piece))
|
||||||
|
{
|
||||||
|
piece = piece->next;
|
||||||
|
}
|
||||||
|
offset = (piece->length > 0u) ? piece->length - 1u : 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PieceTable::Cursor::go_up(int n)
|
||||||
|
{
|
||||||
|
/* TODO: Use Encoding */
|
||||||
|
/* TODO: support tabs */
|
||||||
|
/* TODO: support n */
|
||||||
|
Piece * p = prev_line();
|
||||||
|
if (p == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t current_column = column();
|
||||||
|
piece = p;
|
||||||
|
offset = 0u;
|
||||||
|
line_number--;
|
||||||
|
forward_to_column(current_column);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PieceTable::Cursor::go_down(int n)
|
||||||
|
{
|
||||||
|
/* TODO: Use Encoding */
|
||||||
|
/* TODO: support tabs */
|
||||||
|
/* TODO: support n */
|
||||||
|
Piece * p = next_line();
|
||||||
|
if (p == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t current_column = column();
|
||||||
|
piece = p;
|
||||||
|
offset = 0u;
|
||||||
|
line_number++;
|
||||||
|
forward_to_column(current_column);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PieceTable::Cursor::go_left(int n)
|
||||||
|
{
|
||||||
|
/* TODO: Use Encoding */
|
||||||
|
/* 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 true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PieceTable::Cursor::go_right(int n)
|
||||||
|
{
|
||||||
|
/* TODO: Use Encoding */
|
||||||
|
/* 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 true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PieceTable::Piece * PieceTable::Cursor::prev_line() const
|
||||||
|
{
|
||||||
|
Piece * p = piece;
|
||||||
|
while ((!p->prev->eol()) && (p->prev != piece_table->start_piece))
|
||||||
|
{
|
||||||
|
p = p->prev;
|
||||||
|
}
|
||||||
|
if (p->prev == piece_table->start_piece)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
p = p->prev;
|
||||||
|
while ((!p->prev->eol()) && (p->prev != piece_table->start_piece))
|
||||||
|
{
|
||||||
|
p = p->prev;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
PieceTable::Piece * PieceTable::Cursor::next_line() const
|
||||||
|
{
|
||||||
|
Piece * p = piece;
|
||||||
|
while ((!p->eol()) && (p->next != piece_table->end_piece))
|
||||||
|
{
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
if (p->next == piece_table->end_piece)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
while ((!p->eol()) && (p->next != piece_table->end_piece))
|
||||||
|
{
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -61,14 +61,32 @@ public:
|
|||||||
/** Line number the cursor is on (0 based). */
|
/** Line number the cursor is on (0 based). */
|
||||||
uint32_t line_number;
|
uint32_t line_number;
|
||||||
|
|
||||||
/** Virtual column (0 based). */
|
/** Get the character pointed to by the cursor. */
|
||||||
uint32_t column;
|
|
||||||
|
|
||||||
uint32_t operator*() const
|
uint32_t operator*() const
|
||||||
{
|
{
|
||||||
/* TODO: Use Encoding */
|
/* TODO: Use Encoding */
|
||||||
return piece->start[offset];
|
return piece->start[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_end_of_line();
|
||||||
|
bool go_up(int n = 1);
|
||||||
|
bool go_down(int n = 1);
|
||||||
|
bool go_left(int n = 1);
|
||||||
|
bool go_right(int n = 1);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Piece * prev_line() const;
|
||||||
|
Piece * next_line() const;
|
||||||
|
void forward_to_column(uint32_t c);
|
||||||
};
|
};
|
||||||
|
|
||||||
Piece * start_piece;
|
Piece * start_piece;
|
||||||
@ -91,8 +109,6 @@ public:
|
|||||||
|
|
||||||
void append_initial_line_piece(uint8_t * start, uint32_t length, bool eol);
|
void append_initial_line_piece(uint8_t * start, uint32_t length, bool eol);
|
||||||
|
|
||||||
Piece * get_start_of_line(Piece * start) const;
|
|
||||||
|
|
||||||
std::shared_ptr<Cursor> add_cursor();
|
std::shared_ptr<Cursor> add_cursor();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -27,5 +27,17 @@ TEST(BufferTest, allows_navigating_using_cursors)
|
|||||||
Buffer b;
|
Buffer b;
|
||||||
ASSERT_TRUE(b.load_from_file("test/files/line_endings/lf_format.txt"));
|
ASSERT_TRUE(b.load_from_file("test/files/line_endings/lf_format.txt"));
|
||||||
std::shared_ptr<PieceTable::Cursor> cursor = b.piece_table->add_cursor();
|
std::shared_ptr<PieceTable::Cursor> cursor = b.piece_table->add_cursor();
|
||||||
EXPECT_EQ((uint32_t)'H', **cursor);
|
ASSERT_EQ((uint32_t)'H', **cursor);
|
||||||
|
cursor->go_up();
|
||||||
|
ASSERT_EQ((uint32_t)'H', **cursor);
|
||||||
|
cursor->go_right();
|
||||||
|
ASSERT_EQ((uint32_t)'e', **cursor);
|
||||||
|
cursor->go_down();
|
||||||
|
ASSERT_EQ((uint32_t)'h', **cursor);
|
||||||
|
cursor->go_left();
|
||||||
|
ASSERT_EQ((uint32_t)'T', **cursor);
|
||||||
|
cursor->go_left();
|
||||||
|
ASSERT_EQ((uint32_t)'T', **cursor);
|
||||||
|
cursor->go_down();
|
||||||
|
ASSERT_EQ((uint32_t)'T', **cursor);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user