jes/src-c/core/Buffer.h
2018-07-25 20:47:02 -04:00

235 lines
7.0 KiB
C++

#ifndef BUFFER_H
#define BUFFER_H
#include <list>
#include <memory>
#include "LineEndings.h"
#include "Encoding.h"
#include "GapBuffer.h"
#include <string>
#include "ChangeOperation.h"
#include <vector>
#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();
bool go_forward_in_line_up_to_char(uint32_t c);
bool go_forward_in_line_on_to_char(uint32_t c);
bool go_backward_in_line_up_to_char(uint32_t c);
bool go_backward_in_line_on_to_char(uint32_t c);
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; }
std::shared_ptr<Iterator> clonep()
{
return std::make_shared<Iterator>(*this);
}
protected:
friend struct Range;
const Buffer * m_buffer;
size_t m_offset;
size_t m_line;
};
struct Range
{
std::shared_ptr<Iterator> start;
std::shared_ptr<Iterator> end;
Range(std::shared_ptr<Iterator> _start, std::shared_ptr<Iterator> _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, size_t * n_lines = nullptr, size_t * n_bytes = nullptr);
std::shared_ptr<Iterator> add_iterator()
{
std::shared_ptr<Iterator> iterator = std::make_shared<Iterator>(this);
m_iterators.push_back(iterator);
return iterator;
}
std::shared_ptr<Iterator> 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::Range & range);
std::shared_ptr<std::string> filename() const { return m_filename; }
void set_filename(const std::string & filename);
Iterator begin() const { return Iterator(this); }
std::shared_ptr<Iterator> beginp() const { return std::make_shared<Iterator>(this); }
Iterator end() const { return *m_eof_iterator; }
std::shared_ptr<Iterator> endp() const { return std::make_shared<Iterator>(*m_eof_iterator); }
void push_operation() { m_operation_level++; }
void pop_operation();
void undo();
void redo();
size_t n_lines() const;
#ifndef ENABLE_TESTING
protected:
#endif
bool m_eol_at_eof;
LineEndings::Type m_line_endings;
std::shared_ptr<GapBuffer> m_gap_buffer;
std::shared_ptr<GapBuffer> m_change_buffer;
Encoding::Type m_encoding;
uint8_t m_tabstop;
bool m_insert_mode;
std::list<std::shared_ptr<Iterator>> m_iterators;
std::list<std::shared_ptr<Iterator>> m_cursors;
std::shared_ptr<Iterator> m_eof_iterator;
std::shared_ptr<std::string> m_filename;
std::shared_ptr<ChangeOperation> m_current_change_operation;
int m_operation_level;
size_t m_current_change_operation_index;
std::vector<std::shared_ptr<ChangeOperation>> 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