#ifndef BUFFER_H #define BUFFER_H #include #include #include "LineEndings.h" #include "Encoding.h" #include "GapBuffer.h" #include #include "ChangeOperation.h" #include #include "EncodedString.h" class Buffer { public: enum : uint32_t { INVALID_CHANGE_OPERATION_INDEX = 0xFFFFFFFFu, }; struct Range; class Iterator { public: enum : uint32_t { INVALID_CODE_POINT = 0xFFFFFFFFu, }; Iterator(const Buffer * buffer) { m_buffer = buffer; m_offset = 0u; m_line = 0u; } bool valid() const { return m_offset < m_buffer->size(); } 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(); Iterator prev(); Iterator next(); void warp(ssize_t offset_offset, ssize_t line_offset) { m_offset += offset_offset; m_line += line_offset; } void warp_to_offset(size_t offset); uint8_t * address() const { return m_buffer->address(m_offset); } uint32_t operator*() const { if (valid()) { return Encoding::decode(m_buffer->encoding(), address()); } else { return INVALID_CODE_POINT; } } 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; } 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; } size_t offset() const { return m_offset; } protected: friend struct Range; const Buffer * m_buffer; size_t m_offset; size_t m_line; }; struct Range { std::shared_ptr start; std::shared_ptr end; Range(std::shared_ptr _start, std::shared_ptr _end) : start(_start), end(_end) { } bool valid() const { return start->valid() && (!end->valid() || (*start <= *end)); } size_t start_offset() const { return start->offset(); } size_t end_offset() const { if (end->valid()) { return end->offset(); } else { return start->m_buffer->size(); } } size_t size() const { return end_offset() - start_offset(); } }; Buffer(); Buffer(const char * filename); Buffer(const uint8_t * data, size_t data_length); bool write_to_file(const char * filename); std::shared_ptr add_iterator() { std::shared_ptr iterator = std::make_shared(this); m_iterators.push_back(iterator); return iterator; } std::shared_ptr add_cursor() { auto iterator = add_iterator(); m_cursors.push_back(iterator); return iterator; } void clear(); EncodedString get_string(); size_t size() const { return m_gap_buffer->size(); } uint8_t * address(size_t offset) const { return m_gap_buffer->address(offset); } Encoding::Type encoding() const { return m_encoding; } uint8_t tabstop() const { return m_tabstop; } void enter_insert_mode(); void exit_insert_mode(); bool insert_mode() const { return m_insert_mode; } void insert_code_point(const Buffer::Iterator & position, uint32_t code_point); void erase_code_point(const Buffer::Iterator & position); void erase_range(const Buffer::Iterator & start, const Buffer::Iterator & end); std::shared_ptr filename() const { return m_filename; } Iterator begin() const { return Iterator(this); } Iterator end() const { return *m_eof_iterator; } void push_operation() { m_operation_level++; } void pop_operation(); void undo(); void redo(); #ifndef ENABLE_TESTING protected: #endif bool m_eol_at_eof; LineEndings::Type m_line_endings; std::shared_ptr m_gap_buffer; std::shared_ptr m_change_buffer; Encoding::Type m_encoding; uint8_t m_tabstop; bool m_insert_mode; std::list> m_iterators; std::list> m_cursors; std::shared_ptr m_eof_iterator; std::shared_ptr m_filename; std::shared_ptr m_current_change_operation; int m_operation_level; size_t m_current_change_operation_index; std::vector> m_change_operations; void common_pre_load_initialization(); void common_post_load_initialization(); bool load_from_file(const char * filename); void load_empty_buffer(); bool load_from_memory(const uint8_t * data, size_t data_length); void load_text_in_buffer(uint8_t * buffer, size_t buffer_size, size_t data_length); void record_change(size_t offset, size_t length, bool insert); void save_current_operation(); void warp_iterators_after_insert(size_t offset, size_t length); void warp_iterators_before_delete(size_t offset, size_t length); void insert_data(size_t offset, const uint8_t data[], size_t length, bool do_record_change); void erase_data(size_t offset, size_t length, bool do_record_change); size_t lines_in_data(size_t offset, size_t length); void post_warp_cursors(); void apply_change_operation(const ChangeOperation & change_operation, bool forward); void apply_change_unit(const ChangeUnit & change_unit, bool forward); }; #endif