204 lines
4.6 KiB
C++
204 lines
4.6 KiB
C++
#ifndef PIECETABLE_H
|
|
#define PIECETABLE_H
|
|
|
|
#include <stdint.h>
|
|
#include "PagedBuffer.h"
|
|
#include <utility>
|
|
#include <memory>
|
|
#include <list>
|
|
#include "Encoding.h"
|
|
|
|
class PieceTable
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
INTERNAL_EOL = '\n',
|
|
};
|
|
|
|
struct Piece
|
|
{
|
|
/** The previous piece in the chain. */
|
|
Piece * prev;
|
|
|
|
/** The next piece in the chain. */
|
|
Piece * next;
|
|
|
|
/** Text that the piece describes. */
|
|
uint8_t * start;
|
|
|
|
/** Length of the text (in bytes). */
|
|
uint32_t length;
|
|
|
|
/** Get whether this piece is the end of a line. */
|
|
bool eol() { return (length > 0u) && (start[length - 1u] == INTERNAL_EOL); }
|
|
};
|
|
|
|
struct Iterator
|
|
{
|
|
/** The piece table the cursor belongs to. */
|
|
PieceTable * piece_table;
|
|
|
|
/** The piece. */
|
|
Piece * piece;
|
|
|
|
/** Byte offset within the piece. */
|
|
uint32_t offset;
|
|
|
|
Iterator(PieceTable * pt);
|
|
|
|
/** Get the character pointed to by the cursor. */
|
|
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);
|
|
}
|
|
|
|
bool operator==(const Iterator & other) const
|
|
{
|
|
return (other.piece == piece) && (other.offset == offset);
|
|
}
|
|
|
|
bool operator!=(const Iterator & other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
};
|
|
|
|
struct Cursor
|
|
{
|
|
Iterator iterator;
|
|
|
|
uint32_t line;
|
|
|
|
uint32_t column;
|
|
|
|
/** Get the character pointed to by the cursor. */
|
|
uint32_t operator*() const
|
|
{
|
|
return *iterator;
|
|
}
|
|
|
|
Cursor(PieceTable * pt);
|
|
|
|
void go_start_of_line();
|
|
void go_end_of_line(bool allow_on_eol);
|
|
void go_up(int n, uint32_t desired_column);
|
|
void go_down(int n, uint32_t desired_column);
|
|
void go_left(int n);
|
|
void go_right(int n, bool allow_on_eol);
|
|
|
|
bool check_go_start_of_line();
|
|
bool check_go_end_of_line(bool allow_on_eol);
|
|
bool check_go_up(int n, uint32_t desired_column);
|
|
bool check_go_down(int n, uint32_t desired_column);
|
|
bool check_go_left(int n);
|
|
bool check_go_right(int n, bool allow_on_eol);
|
|
|
|
bool operator==(const Cursor & c) const
|
|
{
|
|
return (c.line == line) && (c.column == column);
|
|
}
|
|
bool operator!=(const Cursor & c) const
|
|
{
|
|
return !(*this == c);
|
|
}
|
|
void warp_to_inserted_piece(Piece * piece);
|
|
|
|
protected:
|
|
bool is_start_of_line();
|
|
bool is_end_of_line();
|
|
Piece * prev_line() const;
|
|
Piece * next_line() const;
|
|
void init_column();
|
|
void calculate_column();
|
|
void forward_to_column(uint32_t c);
|
|
};
|
|
|
|
struct Change
|
|
{
|
|
Piece * before;
|
|
Piece * after;
|
|
Piece * chains[2][2];
|
|
};
|
|
|
|
Piece * start_piece;
|
|
Piece * end_piece;
|
|
uint8_t tabstop;
|
|
Encoding::Type encoding;
|
|
|
|
PieceTable();
|
|
|
|
uint32_t get_num_lines() { return m_num_lines; }
|
|
|
|
void append_initial_line_piece(uint8_t * start, uint32_t length, bool eol);
|
|
|
|
std::shared_ptr<Cursor> add_cursor();
|
|
|
|
void begin_insert(const Cursor & cursor, bool before);
|
|
void insert_code_point(uint32_t code_point);
|
|
void end_insert();
|
|
void insertion_test(Cursor & c);
|
|
|
|
void undo();
|
|
|
|
protected:
|
|
Piece * add_piece()
|
|
{
|
|
return &m_pieces[m_piece_index++];
|
|
}
|
|
|
|
Piece & operator[](uint32_t index)
|
|
{
|
|
return m_pieces[index];
|
|
}
|
|
|
|
Change * add_change()
|
|
{
|
|
return &m_changes[m_changes_index++];
|
|
}
|
|
|
|
void apply_change(Change * change, uint8_t forward);
|
|
|
|
uint32_t m_num_lines;
|
|
|
|
PagedBuffer<uint8_t> m_append_buffer;
|
|
uint32_t m_append_buffer_index;
|
|
PagedBuffer<Piece> m_pieces;
|
|
/** Next available piece index. */
|
|
uint32_t m_piece_index;
|
|
PagedBuffer<Change> m_changes;
|
|
uint32_t m_changes_index;
|
|
Piece * m_insert_before_piece;
|
|
Piece * m_inserting_piece;
|
|
|
|
std::list<std::shared_ptr<Cursor>> m_cursors;
|
|
};
|
|
|
|
#endif
|