diff --git a/src/core/Buffer.cc b/src/core/Buffer.cc index ad305ee..4d9a5b5 100644 --- a/src/core/Buffer.cc +++ b/src/core/Buffer.cc @@ -103,12 +103,12 @@ bool Buffer::write_to_file(const char * filename) m_gap_buffer->compact(); - GapBuffer::Cursor start_of_line(&*m_gap_buffer); + Cursor start_of_line(&*m_gap_buffer); size_t bytes_written = 0u; while (start_of_line.valid()) { - GapBuffer::Cursor cursor = start_of_line; + Cursor cursor = start_of_line; cursor.go_end_of_line(true); size_t len = cursor.address() - start_of_line.address(); if (len > 0u) diff --git a/src/core/Buffer.h b/src/core/Buffer.h index 75ae05e..01b7e81 100644 --- a/src/core/Buffer.h +++ b/src/core/Buffer.h @@ -6,6 +6,7 @@ #include "LineEndings.h" #include "Encoding.h" #include "GapBuffer.h" +#include "Cursor.h" class Buffer { @@ -15,7 +16,6 @@ public: Buffer(const uint8_t * data, size_t data_length); bool write_to_file(const char * filename); - typedef GapBuffer::Cursor Cursor; auto add_cursor() { return m_gap_buffer->add_cursor(); } auto get_string() { return m_gap_buffer->get_string(); } void insert(Cursor & insert_cursor, uint32_t code_point) diff --git a/src/core/Cursor.cc b/src/core/Cursor.cc new file mode 100644 index 0000000..f96e7a6 --- /dev/null +++ b/src/core/Cursor.cc @@ -0,0 +1,240 @@ +#include "Cursor.h" + +void Iterator::go_forward() +{ + if (valid()) + { + m_offset += Encoding::num_bytes_in_code_point(m_gap_buffer->encoding(), address()); + } +} + +bool Iterator::check_go_forward() +{ + if (valid()) + { + Iterator i2 = *this; + i2.go_forward(); + if (i2.valid()) + { + m_offset = i2.m_offset; + return true; + } + } + return false; +} + +void Iterator::go_back() +{ + if (valid()) + { + if (m_offset == 0u) + { + m_offset = 0xFFFFFFFFu; + } + else + { + const uint8_t * a = m_gap_buffer->address(m_offset - 1u); + const uint8_t * beginning_of_code_point = Encoding::beginning_of_code_point(m_gap_buffer->encoding(), a); + m_offset -= ((a - beginning_of_code_point) + 1u); + } + } +} + +bool Iterator::check_go_back() +{ + if (valid()) + { + Iterator i2 = *this; + i2.go_back(); + if (i2.valid()) + { + m_offset = i2.m_offset; + return true; + } + } + return false; +} + + +bool Cursor::is_start_of_line() +{ + Iterator i2 = m_iterator; + if (!i2.check_go_back()) + { + /* Iterator cannot go backwards so it is at beginning of buffer. */ + return true; + } + return *i2 == '\n'; +} + +bool Cursor::is_end_of_line(bool allow_eol) +{ + if (*m_iterator == '\n') + { + return true; + } + if (!allow_eol) + { + Iterator i2 = m_iterator; + i2.go_forward(); + if (*i2 == '\n') + { + return true; + } + } + return false; +} + +bool Cursor::go_start_of_line() +{ + bool moved = false; + Iterator i2 = m_iterator; + for (;;) + { + i2.go_back(); + if (i2.valid() && (*i2 != '\n')) + { + moved = true; + m_iterator = i2; + } + else + { + break; + } + } + if (moved) + { + init_column(); + } + return moved; +} + +bool Cursor::go_end_of_line(bool allow_eol) +{ + bool moved = false; + if (go_right(allow_eol)) + { + moved = true; + } + while (go_right(allow_eol)) + { + ; + } + return moved; +} + +bool Cursor::go_left() +{ + if (!is_start_of_line()) + { + uint32_t chr = *m_iterator; + if (m_iterator.check_go_back()) + { + if (chr == '\t') + { + calculate_column(); + } + else + { + /* TODO: handle multi-column characters */ + m_column--; + } + return true; + } + } + return false; +} + +bool Cursor::go_right(bool allow_eol) +{ + if (!is_end_of_line(allow_eol)) + { + if (m_iterator.check_go_forward()) + { + uint32_t chr = *m_iterator; + if (chr == '\t') + { + uint8_t tabstop = m_iterator.gap_buffer()->tabstop; + m_column += tabstop - (m_column + 1u) % tabstop; + } + else + { + /* TODO: handle multi-column characters */ + m_column++; + } + return true; + } + } + return false; +} + +bool Cursor::go_up(size_t target_column) +{ + Cursor c2 = *this; + c2.go_start_of_line(); + if (!c2.m_iterator.check_go_back()) + { + return false; + } + c2.go_start_of_line(); + *this = c2; + m_line--; + m_column = 0u; + forward_to_column(target_column); + return true; +} + +bool Cursor::go_down(size_t target_column) +{ + Cursor c2 = *this; + c2.go_end_of_line(true); + if (!c2.m_iterator.check_go_forward()) + { + return false; + } + *this = c2; + m_line++; + m_column = 0u; + forward_to_column(target_column); + return true; +} + +void Cursor::init_column() +{ + if (*m_iterator == '\t') + { + m_column = m_iterator.gap_buffer()->tabstop - 1u; + } + else + { + m_column = 0u; + } +} + +void Cursor::calculate_column() +{ + Cursor tmp_cursor = *this; + tmp_cursor.go_start_of_line(); + while (tmp_cursor < *this) + { + tmp_cursor.go_right(true); + } + m_column = tmp_cursor.m_column; +} + +void Cursor::forward_to_column(size_t target_column) +{ + int32_t diff = abs((int32_t)(target_column - m_column)); + if (diff == 0) + return; + while (go_right(false)) + { + int32_t new_diff = abs((int32_t)(target_column - m_column)); + if (new_diff > diff) + { + go_left(); + return; + } + diff = new_diff; + } +} diff --git a/src/core/Cursor.h b/src/core/Cursor.h new file mode 100644 index 0000000..9c11beb --- /dev/null +++ b/src/core/Cursor.h @@ -0,0 +1,92 @@ +#ifndef CURSOR_H +#define CURSOR_H + +#include +#include +#include "Encoding.h" +#include "GapBuffer.h" + +class Iterator +{ +public: + Iterator(GapBuffer * gap_buffer) + { + m_gap_buffer = gap_buffer; + m_offset = 0u; + } + bool valid() const + { + return m_offset < m_gap_buffer->size(); + } + void go_forward(); + bool check_go_forward(); + void go_back(); + bool check_go_back(); + uint8_t * address() const + { + return m_gap_buffer->address(m_offset); + } + uint32_t operator*() const + { + if (valid()) + { + return Encoding::decode(m_gap_buffer->encoding(), address()); + } + else + { + return 0xFFFFFFFFu; + } + } + GapBuffer * gap_buffer() const { return m_gap_buffer; } + bool operator<(const Iterator & other) const + { + return m_offset < other.m_offset; + } + size_t offset() { return m_offset; } + void set_offset(size_t new_offset) { m_offset = new_offset; } + +protected: + GapBuffer * m_gap_buffer; + size_t m_offset; +}; + +class Cursor +{ +public: + Cursor(GapBuffer * gap_buffer) + : m_iterator(gap_buffer) + { + m_line = 0u; + init_column(); + } + bool is_start_of_line(); + bool is_end_of_line(bool allow_eol); + bool go_start_of_line(); + bool go_end_of_line(bool allow_eol); + bool go_left(); + bool go_right(bool allow_eol); + bool go_up(size_t target_column); + bool go_down(size_t target_column); + bool operator<(const Cursor & other) const + { + return m_iterator < other.m_iterator; + } + uint32_t operator*() const { return *m_iterator; } + uint8_t * address() const { return m_iterator.address(); } + bool valid() const { return m_iterator.valid(); } + size_t line() const { return m_line; } + size_t column() const { return m_column; } + Iterator & iterator() { return m_iterator; } + void set_line(size_t line) { m_line = line; } + void calculate_column(); + +protected: + Iterator m_iterator; + size_t m_line; + size_t m_column; + + void init_column(); + void forward_to_column(size_t target_column); +}; + +#endif diff --git a/src/core/GapBuffer.cc b/src/core/GapBuffer.cc index 550a1eb..803da50 100644 --- a/src/core/GapBuffer.cc +++ b/src/core/GapBuffer.cc @@ -1,6 +1,7 @@ #include "GapBuffer.h" #include "System.h" #include +#include "Cursor.h" GapBuffer::GapBuffer(Encoding::Type encoding) { @@ -27,7 +28,7 @@ GapBuffer::~GapBuffer() System::free_pages(m_buffer, m_buffer_size >> System::page_size_log); } -std::shared_ptr GapBuffer::add_cursor() +std::shared_ptr GapBuffer::add_cursor() { std::shared_ptr cursor = std::make_shared(this); m_cursors.push_back(cursor); @@ -131,243 +132,3 @@ void GapBuffer::move_gap(size_t position) } } } - - -void GapBuffer::Iterator::go_forward() -{ - if (valid()) - { - m_offset += Encoding::num_bytes_in_code_point(m_gap_buffer->m_encoding, address()); - } -} - -bool GapBuffer::Iterator::check_go_forward() -{ - if (valid()) - { - Iterator i2 = *this; - i2.go_forward(); - if (i2.valid()) - { - m_offset = i2.m_offset; - return true; - } - } - return false; -} - -void GapBuffer::Iterator::go_back() -{ - if (valid()) - { - if (m_offset == 0u) - { - m_offset = 0xFFFFFFFFu; - } - else - { - const uint8_t * a = m_gap_buffer->address(m_offset - 1u); - const uint8_t * beginning_of_code_point = Encoding::beginning_of_code_point(m_gap_buffer->m_encoding, a); - m_offset -= ((a - beginning_of_code_point) + 1u); - } - } -} - -bool GapBuffer::Iterator::check_go_back() -{ - if (valid()) - { - Iterator i2 = *this; - i2.go_back(); - if (i2.valid()) - { - m_offset = i2.m_offset; - return true; - } - } - return false; -} - - -bool GapBuffer::Cursor::is_start_of_line() -{ - Iterator i2 = m_iterator; - if (!i2.check_go_back()) - { - /* Iterator cannot go backwards so it is at beginning of buffer. */ - return true; - } - return *i2 == '\n'; -} - -bool GapBuffer::Cursor::is_end_of_line(bool allow_eol) -{ - if (*m_iterator == '\n') - { - return true; - } - if (!allow_eol) - { - Iterator i2 = m_iterator; - i2.go_forward(); - if (*i2 == '\n') - { - return true; - } - } - return false; -} - -bool GapBuffer::Cursor::go_start_of_line() -{ - bool moved = false; - Iterator i2 = m_iterator; - for (;;) - { - i2.go_back(); - if (i2.valid() && (*i2 != '\n')) - { - moved = true; - m_iterator = i2; - } - else - { - break; - } - } - if (moved) - { - init_column(); - } - return moved; -} - -bool GapBuffer::Cursor::go_end_of_line(bool allow_eol) -{ - bool moved = false; - if (go_right(allow_eol)) - { - moved = true; - } - while (go_right(allow_eol)) - { - ; - } - return moved; -} - -bool GapBuffer::Cursor::go_left() -{ - if (!is_start_of_line()) - { - uint32_t chr = *m_iterator; - if (m_iterator.check_go_back()) - { - if (chr == '\t') - { - calculate_column(); - } - else - { - /* TODO: handle multi-column characters */ - m_column--; - } - return true; - } - } - return false; -} - -bool GapBuffer::Cursor::go_right(bool allow_eol) -{ - if (!is_end_of_line(allow_eol)) - { - if (m_iterator.check_go_forward()) - { - uint32_t chr = *m_iterator; - if (chr == '\t') - { - uint8_t tabstop = m_iterator.gap_buffer()->tabstop; - m_column += tabstop - (m_column + 1u) % tabstop; - } - else - { - /* TODO: handle multi-column characters */ - m_column++; - } - return true; - } - } - return false; -} - -bool GapBuffer::Cursor::go_up(size_t target_column) -{ - Cursor c2 = *this; - c2.go_start_of_line(); - if (!c2.m_iterator.check_go_back()) - { - return false; - } - c2.go_start_of_line(); - *this = c2; - m_line--; - m_column = 0u; - forward_to_column(target_column); - return true; -} - -bool GapBuffer::Cursor::go_down(size_t target_column) -{ - Cursor c2 = *this; - c2.go_end_of_line(true); - if (!c2.m_iterator.check_go_forward()) - { - return false; - } - *this = c2; - m_line++; - m_column = 0u; - forward_to_column(target_column); - return true; -} - -void GapBuffer::Cursor::init_column() -{ - if (*m_iterator == '\t') - { - m_column = m_iterator.gap_buffer()->tabstop - 1u; - } - else - { - m_column = 0u; - } -} - -void GapBuffer::Cursor::calculate_column() -{ - Cursor tmp_cursor = *this; - tmp_cursor.go_start_of_line(); - while (tmp_cursor < *this) - { - tmp_cursor.go_right(true); - } - m_column = tmp_cursor.m_column; -} - -void GapBuffer::Cursor::forward_to_column(size_t target_column) -{ - int32_t diff = abs((int32_t)(target_column - m_column)); - if (diff == 0) - return; - while (go_right(false)) - { - int32_t new_diff = abs((int32_t)(target_column - m_column)); - if (new_diff > diff) - { - go_left(); - return; - } - diff = new_diff; - } -} diff --git a/src/core/GapBuffer.h b/src/core/GapBuffer.h index fb631d3..1c63440 100644 --- a/src/core/GapBuffer.h +++ b/src/core/GapBuffer.h @@ -8,92 +8,11 @@ #include #include +class Cursor; + class GapBuffer { public: - class Iterator - { - public: - Iterator(GapBuffer * gap_buffer) - { - m_gap_buffer = gap_buffer; - m_offset = 0u; - } - bool valid() const - { - return m_offset < m_gap_buffer->size(); - } - void go_forward(); - bool check_go_forward(); - void go_back(); - bool check_go_back(); - uint8_t * address() const - { - return m_gap_buffer->address(m_offset); - } - uint32_t operator*() const - { - if (valid()) - { - return Encoding::decode(m_gap_buffer->m_encoding, address()); - } - else - { - return 0xFFFFFFFFu; - } - } - GapBuffer * gap_buffer() const { return m_gap_buffer; } - bool operator<(const Iterator & other) const - { - return m_offset < other.m_offset; - } - size_t offset() { return m_offset; } - void set_offset(size_t new_offset) { m_offset = new_offset; } - - protected: - GapBuffer * m_gap_buffer; - size_t m_offset; - }; - - class Cursor - { - public: - Cursor(GapBuffer * gap_buffer) - : m_iterator(gap_buffer) - { - m_line = 0u; - init_column(); - } - bool is_start_of_line(); - bool is_end_of_line(bool allow_eol); - bool go_start_of_line(); - bool go_end_of_line(bool allow_eol); - bool go_left(); - bool go_right(bool allow_eol); - bool go_up(size_t target_column); - bool go_down(size_t target_column); - bool operator<(const Cursor & other) const - { - return m_iterator < other.m_iterator; - } - uint32_t operator*() const { return *m_iterator; } - uint8_t * address() const { return m_iterator.address(); } - bool valid() const { return m_iterator.valid(); } - size_t line() const { return m_line; } - size_t column() const { return m_column; } - Iterator & iterator() { return m_iterator; } - void set_line(size_t line) { m_line = line; } - void calculate_column(); - - protected: - Iterator m_iterator; - size_t m_line; - size_t m_column; - - void init_column(); - void forward_to_column(size_t target_column); - }; - uint8_t tabstop; GapBuffer(Encoding::Type encoding); @@ -117,6 +36,7 @@ public: void compact(); void insert(Cursor & insert_cursor, uint32_t code_point); std::string get_string(); + Encoding::Type encoding() { return m_encoding; } protected: uint8_t * m_buffer; diff --git a/src/gui/BufferPane.cc b/src/gui/BufferPane.cc index 7e545cb..d828cb5 100644 --- a/src/gui/BufferPane.cc +++ b/src/gui/BufferPane.cc @@ -29,7 +29,7 @@ void BufferPane::update_cursor_row() int BufferPane::screen_rows_below_cursor(int stop_at) { - Buffer::Cursor cursor = *m_cursor; + Cursor cursor = *m_cursor; size_t column = cursor.column(); cursor.go_end_of_line(false); int rows = (cursor.column() / m_columns) - (column / m_columns); @@ -43,11 +43,11 @@ int BufferPane::screen_rows_below_cursor(int stop_at) int BufferPane::screen_rows_above_cursor(int stop_at) { - Buffer::Cursor cursor = *m_cursor; + Cursor cursor = *m_cursor; int rows = cursor.column() / m_columns; while ((rows < stop_at) && cursor.go_up(0u)) { - Buffer::Cursor cursor2 = cursor; + Cursor cursor2 = cursor; cursor2.go_end_of_line(false); rows += (cursor2.column() / m_columns) + 1; } @@ -58,11 +58,11 @@ void BufferPane::draw() { update_cursor_row(); int screen_row = m_cursor_row - m_cursor->column() / m_columns; - Buffer::Cursor iter_cursor = *m_cursor; + Cursor iter_cursor = *m_cursor; iter_cursor.go_start_of_line(); while ((screen_row > 0) && iter_cursor.go_up(0u)) { - Buffer::Cursor cursor2 = iter_cursor; + Cursor cursor2 = iter_cursor; cursor2.go_end_of_line(false); screen_row -= (1 + cursor2.column() / m_columns); } @@ -78,9 +78,9 @@ void BufferPane::draw() } } -void BufferPane::draw_buffer_line(int screen_row, const Buffer::Cursor & cursor) +void BufferPane::draw_buffer_line(int screen_row, const Cursor & cursor) { - Buffer::Cursor iter_cursor = cursor; + Cursor iter_cursor = cursor; while (!iter_cursor.is_end_of_line(true)) { int draw_row = screen_row + (iter_cursor.column() / m_columns); diff --git a/src/gui/BufferPane.h b/src/gui/BufferPane.h index 2d2d926..a118189 100644 --- a/src/gui/BufferPane.h +++ b/src/gui/BufferPane.h @@ -15,7 +15,7 @@ public: std::shared_ptr gl); void resize(int width, int height) override; void draw(); - std::shared_ptr cursor() { return m_cursor; } + std::shared_ptr cursor() { return m_cursor; } protected: int effective_scroll_offset() @@ -25,7 +25,7 @@ protected: int screen_rows_below_cursor(int stop_at); int screen_rows_above_cursor(int stop_at); void update_cursor_row(); - void draw_buffer_line(int screen_row, const Buffer::Cursor & cursor); + void draw_buffer_line(int screen_row, const Cursor & cursor); void draw_buffer_character(int screen_column, int screen_row, uint32_t character); void draw_cursor(int screen_column, int screen_row, bool insert_mode); void colrow_to_xy(int col, int row, int * x, int * y); @@ -37,7 +37,7 @@ protected: int m_columns; int m_scroll_offset; int m_cursor_row; - std::shared_ptr m_cursor; + std::shared_ptr m_cursor; }; #endif