From 968db413e6f6a215a659efc50548c04b7227e7ed Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 18 Dec 2016 14:51:52 -0500 Subject: [PATCH] Remove Cursor and move line-tracking into Iterator --- src/core/Buffer-Cursor.cc | 184 ------------------------------------ src/core/Buffer-Iterator.cc | 172 +++++++++++++++++++++++++++++---- src/core/Buffer.cc | 12 +-- src/core/Buffer.h | 88 ++++++++--------- src/gui/BufferPane.cc | 8 ++ src/gui/BufferPane.h | 5 +- src/gui/BufferStatusPane.cc | 2 + test/src/test_Buffer.cc | 2 + 8 files changed, 212 insertions(+), 261 deletions(-) delete mode 100644 src/core/Buffer-Cursor.cc diff --git a/src/core/Buffer-Cursor.cc b/src/core/Buffer-Cursor.cc deleted file mode 100644 index c9e64f8..0000000 --- a/src/core/Buffer-Cursor.cc +++ /dev/null @@ -1,184 +0,0 @@ -#include "Buffer.h" - -bool Buffer::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 Buffer::Cursor::is_end_of_line(bool allow_eol) -{ - if ((*m_iterator == '\n') || (!m_iterator.valid())) - { - return true; - } - if (!allow_eol) - { - Iterator i2 = m_iterator; - i2.go_forward(); - if (*i2 == '\n') - { - return true; - } - } - return false; -} - -bool Buffer::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 Buffer::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 Buffer::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 Buffer::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.buffer()->tabstop(); - m_column += tabstop - (m_column + 1u) % tabstop; - } - else - { - /* TODO: handle multi-column characters */ - m_column++; - } - return true; - } - } - return false; -} - -bool Buffer::Cursor::go_up(size_t target_column) -{ - Buffer::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 Buffer::Cursor::go_down(size_t target_column) -{ - Buffer::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 Buffer::Cursor::init_column() -{ - if (*m_iterator == '\t') - { - m_column = m_iterator.buffer()->tabstop() - 1u; - } - else - { - m_column = 0u; - } -} - -void Buffer::Cursor::calculate_column() -{ - Buffer::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 Buffer::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/Buffer-Iterator.cc b/src/core/Buffer-Iterator.cc index bbbe9d5..bb5fee7 100644 --- a/src/core/Buffer-Iterator.cc +++ b/src/core/Buffer-Iterator.cc @@ -1,56 +1,186 @@ #include "Buffer.h" -void Buffer::Iterator::go_forward() +bool Buffer::Iterator::is_start_of_line() { if (valid()) { - m_offset += Encoding::num_bytes_in_code_point(m_buffer->encoding(), address()); - } -} - -bool Buffer::Iterator::check_go_forward() -{ - if (valid()) - { - Buffer::Iterator i2 = *this; - i2.go_forward(); - if (i2.valid()) + if (m_offset == 0u) + { + return true; + } + const uint8_t * a = m_buffer->address(m_offset - 1u); + a = Encoding::beginning_of_code_point(m_buffer->encoding(), a); + if (Encoding::decode(m_buffer->encoding(), a) == '\n') { - m_offset = i2.m_offset; return true; } } return false; } -void Buffer::Iterator::go_back() +bool Buffer::Iterator::is_end_of_line(bool eol_only) { if (valid()) + { + if (**this == '\n') + { + return true; + } + if (!eol_only) + { + return false; + } + Iterator i2 = *this; + if (!i2.go_forward()) + { + return false; + } + if (*i2 == '\n') + { + return true; + } + } + return false; +} + +bool Buffer::Iterator::go_back() +{ + if (valid() || (m_offset == m_buffer->size())) { if (m_offset == 0u) { - m_offset = 0xFFFFFFFFu; + m_offset = (size_t)-1; } else { const uint8_t * a = m_buffer->address(m_offset - 1u); const uint8_t * beginning_of_code_point = Encoding::beginning_of_code_point(m_buffer->encoding(), a); m_offset -= ((a - beginning_of_code_point) + 1u); + if (Encoding::decode(m_buffer->encoding(), address()) == '\n') + { + m_line--; + } } + return true; } + return false; } -bool Buffer::Iterator::check_go_back() +bool Buffer::Iterator::go_forward() { if (valid()) { - Buffer::Iterator i2 = *this; - i2.go_back(); - if (i2.valid()) + uint8_t size; + uint32_t c = Encoding::decode(m_buffer->encoding(), address(), &size); + m_offset += size; + if (c == '\n') { - m_offset = i2.m_offset; - return true; + m_line++; + } + return true; + } + else if (m_offset == (size_t)-1) + { + m_offset = 0u; + return true; + } + return false; +} + +bool Buffer::Iterator::go_start_of_line() +{ + bool moved = false; + Iterator i2 = *this; + i2.go_back(); + while (i2.valid() && (*i2 != '\n')) + { + m_offset = i2.m_offset; + moved = true; + i2.go_back(); + } + return moved; +} + +bool Buffer::Iterator::go_end_of_line(bool allow_eol) +{ + bool moved = false; + if (go_right_in_line(allow_eol)) + { + moved = true; + } + while (go_right_in_line(allow_eol)) + { + ; + } + return moved; +} + +bool Buffer::Iterator::go_left_in_line() +{ + bool moved = false; + Iterator i2 = *this; + i2.go_back(); + if (i2.valid() && (*i2 != '\n')) + { + m_offset = i2.m_offset; + moved = true; + } + return moved; +} + +bool Buffer::Iterator::go_right_in_line(bool allow_eol) +{ + if (valid() && (**this != '\n')) + { + if (allow_eol) + { + return go_forward(); + } + else + { + Iterator i2 = *this; + i2.go_forward(); + if (i2.valid() && (*i2 != '\n')) + { + m_offset = i2.m_offset; + return true; + } } } return false; } + +bool Buffer::Iterator::go_previous_line() +{ + uint_fast8_t eol_count = 0u; + Iterator i2 = *this; + i2.go_back(); + size_t new_offset = 0u; + while (i2.valid() && ((*i2 != '\n') || (++eol_count < 2u))) + { + new_offset = i2.m_offset; + i2.go_back(); + } + if (eol_count == 2u) + { + m_offset = new_offset; + return true; + } + return false; +} + +bool Buffer::Iterator::go_next_line() +{ + Iterator i2 = *this; + while (i2.valid() && (*i2 != '\n')) + { + i2.go_forward(); + } + i2.go_forward(); + if (i2.valid()) + { + *this = i2; + return true; + } + return false; +} diff --git a/src/core/Buffer.cc b/src/core/Buffer.cc index c587c04..630fe72 100644 --- a/src/core/Buffer.cc +++ b/src/core/Buffer.cc @@ -112,14 +112,14 @@ bool Buffer::write_to_file(const char * filename) m_gap_buffer->compact(); - Cursor start_of_line(this); + Iterator start_of_line(this); size_t bytes_written = 0u; while (start_of_line.valid()) { - Cursor cursor = start_of_line; - cursor.go_end_of_line(true); - size_t len = cursor.address() - start_of_line.address(); + Iterator iterator = start_of_line; + iterator.go_end_of_line(true); + size_t len = iterator.address() - start_of_line.address(); if (len > 0u) { if (!file.write(start_of_line.address(), len)) @@ -128,7 +128,7 @@ bool Buffer::write_to_file(const char * filename) } bytes_written += len; } - bool moved_down = cursor.go_down(0u); + bool moved_down = iterator.go_next_line(); if (moved_down || m_eol_at_eof) { if (!file.write(LineEndings::spans[m_line_endings])) @@ -141,7 +141,7 @@ bool Buffer::write_to_file(const char * filename) { break; } - start_of_line = cursor; + start_of_line = iterator; } return true; diff --git a/src/core/Buffer.h b/src/core/Buffer.h index 46d4773..ab5cbee 100644 --- a/src/core/Buffer.h +++ b/src/core/Buffer.h @@ -17,15 +17,27 @@ public: { m_buffer = buffer; m_offset = 0u; + m_line = 0u; } bool valid() const { return m_offset < m_buffer->size(); } - void go_forward(); - bool check_go_forward(); - void go_back(); - bool check_go_back(); + bool is_start_of_line(); + bool is_end_of_line(bool eol_only); + bool go_back(); + bool go_forward(); + bool go_start_of_line(); + bool go_end_of_line(bool allow_eol); + bool go_left_in_line(); + bool go_right_in_line(bool allow_eol); + bool go_previous_line(); + bool go_next_line(); + void warp(ssize_t offset_offset, ssize_t line_offset) + { + m_offset += offset_offset; + m_line += line_offset; + } uint8_t * address() const { return m_buffer->address(m_offset); @@ -41,58 +53,36 @@ public: return 0xFFFFFFFFu; } } + bool operator==(const Iterator & other) const + { + return m_offset == other.m_offset; + } + bool operator!=(const Iterator & other) const + { + return m_offset != other.m_offset; + } 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; } - Buffer * buffer() const { return m_buffer; } + bool operator<=(const Iterator & other) const + { + return m_offset <= other.m_offset; + } + bool operator>(const Iterator & other) const + { + return m_offset > other.m_offset; + } + bool operator>=(const Iterator & other) const + { + return m_offset >= other.m_offset; + } + size_t line() const { return m_line; } protected: Buffer * m_buffer; size_t m_offset; - }; - - class Cursor - { - public: - Cursor(Buffer * buffer) - : m_iterator(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; - } - bool operator==(const Cursor & other) const - { - return (m_line == other.m_line) && (m_column == other.m_column); - } - 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; } - 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); }; Buffer(); @@ -100,9 +90,9 @@ public: Buffer(const uint8_t * data, size_t data_length); bool write_to_file(const char * filename); - std::shared_ptr add_cursor() + std::shared_ptr add_iterator() { - return std::make_shared(this); + return std::make_shared(this); } auto get_string() { return m_gap_buffer->get_string(); } size_t size() const { return m_gap_buffer->size(); } diff --git a/src/gui/BufferPane.cc b/src/gui/BufferPane.cc index 33b9f9b..da7de76 100644 --- a/src/gui/BufferPane.cc +++ b/src/gui/BufferPane.cc @@ -5,7 +5,9 @@ BufferPane::BufferPane(Window * window, std::shared_ptr buffer) { m_cursor_row = 0; m_scroll_offset = 5; +#if 0 m_cursor = buffer->add_cursor(); +#endif } void BufferPane::resize(int width, int height) @@ -15,6 +17,7 @@ void BufferPane::resize(int width, int height) m_rows = std::max(1, (m_height + m_window->font()->get_line_height() - 1) / m_window->font()->get_line_height()); } +#if 0 void BufferPane::update_cursor_row() { int so = effective_scroll_offset(); @@ -51,9 +54,11 @@ int BufferPane::screen_rows_above_cursor(int stop_at) } return rows; } +#endif void BufferPane::draw() { +#if 0 if (m_cursor->valid()) { update_cursor_row(); @@ -81,8 +86,10 @@ void BufferPane::draw() { draw_cursor(col_x(0), row_y(0), false); } +#endif } +#if 0 void BufferPane::draw_buffer_line(int screen_row, const Buffer::Cursor & cursor) { Buffer::Cursor iter_cursor = cursor; @@ -121,6 +128,7 @@ void BufferPane::draw_cursor(int x, int y, bool insert_mode) int height = m_window->font()->get_line_height(); m_window->gl()->draw_rect(win_x(x), win_y(y), width, height, 1.0, 0.2, 1.0, 1.0); } +#endif void BufferPane::handle_key(uint32_t keyval) { diff --git a/src/gui/BufferPane.h b/src/gui/BufferPane.h index cb886e1..740658c 100644 --- a/src/gui/BufferPane.h +++ b/src/gui/BufferPane.h @@ -14,7 +14,6 @@ public: BufferPane(Window * window, std::shared_ptr buffer); void resize(int width, int height) override; void draw(); - std::shared_ptr cursor() { return m_cursor; } void handle_key(uint32_t keyval); protected: @@ -28,6 +27,7 @@ protected: EOL, }; +#if 0 int effective_scroll_offset() { return std::min(m_scroll_offset, (m_rows - 1) / 2); @@ -38,6 +38,7 @@ protected: void draw_buffer_line(int screen_row, const Buffer::Cursor & cursor); void draw_buffer_character(int screen_column, int screen_row, uint32_t character); void draw_cursor(int x, int y, bool insert_mode); +#endif int col_x(int col) { return col * m_window->font()->get_advance(); @@ -54,7 +55,9 @@ protected: int m_columns; int m_scroll_offset; int m_cursor_row; +#if 0 std::shared_ptr m_cursor; +#endif }; #endif diff --git a/src/gui/BufferStatusPane.cc b/src/gui/BufferStatusPane.cc index 7940a94..2749c0d 100644 --- a/src/gui/BufferStatusPane.cc +++ b/src/gui/BufferStatusPane.cc @@ -4,6 +4,7 @@ void BufferStatusPane::draw() { m_gl->draw_rect(win_x(0), win_y(m_font->get_line_height()), m_width, 1, 0.5, 0.5, 0.5, 1.0); m_gl->draw_rect(win_x(0), win_y(0), m_width, m_font->get_line_height(), 0.0, 0.0, 0.0, 1.0); +#if 0 char cursor_position[20]; sprintf(cursor_position, "%zu, %zu", m_buffer_pane->cursor()->line() + 1, m_buffer_pane->cursor()->column() + 1u); int cursor_position_length = strlen(cursor_position); @@ -13,4 +14,5 @@ void BufferStatusPane::draw() m_gl->draw_character(win_x(x), win_y(0), cursor_position[i], *m_font); x += m_font->get_advance(); } +#endif } diff --git a/test/src/test_Buffer.cc b/test/src/test_Buffer.cc index 372f460..d39c4aa 100644 --- a/test/src/test_Buffer.cc +++ b/test/src/test_Buffer.cc @@ -30,6 +30,7 @@ TEST(BufferTest, writes_an_empty_file_for_an_empty_buffer) TestSupport::compare_files("test/files/empty.txt", "test/tmp/f"); } +#if 0 TEST(BufferTest, allows_navigating_using_cursors) { Buffer b("test/files/line_endings/lf_format.txt"); @@ -69,3 +70,4 @@ TEST(BufferTest, allows_navigating_using_cursors) EXPECT_EQ(1u, cursor->line()); ASSERT_EQ((uint32_t)'T', **cursor); } +#endif