Begin recording all buffer changes to prepare for undo tree
This commit is contained in:
parent
a8b39f8884
commit
21320d9ea7
@ -38,6 +38,7 @@ void Buffer::common_initialization()
|
|||||||
{
|
{
|
||||||
m_eof_iterator->go_forward();
|
m_eof_iterator->go_forward();
|
||||||
}
|
}
|
||||||
|
m_change_buffer = std::make_shared<GapBuffer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::load_empty_buffer()
|
void Buffer::load_empty_buffer()
|
||||||
@ -175,6 +176,7 @@ void Buffer::insert_code_point(const Buffer::Iterator & position, uint32_t code_
|
|||||||
uint8_t encoded[Encoding::MAX_CODE_POINT_SIZE];
|
uint8_t encoded[Encoding::MAX_CODE_POINT_SIZE];
|
||||||
uint8_t bytes = Encoding::encode(code_point, m_encoding, encoded);
|
uint8_t bytes = Encoding::encode(code_point, m_encoding, encoded);
|
||||||
m_gap_buffer->insert(local_position.offset(), encoded, bytes);
|
m_gap_buffer->insert(local_position.offset(), encoded, bytes);
|
||||||
|
record_change(encoded, bytes, local_position.offset(), true);
|
||||||
ssize_t lines = (code_point == '\n') ? 1 : 0;
|
ssize_t lines = (code_point == '\n') ? 1 : 0;
|
||||||
if (adjust_iterators)
|
if (adjust_iterators)
|
||||||
{
|
{
|
||||||
@ -196,6 +198,7 @@ void Buffer::erase_code_point(const Buffer::Iterator & position)
|
|||||||
Buffer::Iterator local_position = position;
|
Buffer::Iterator local_position = position;
|
||||||
uint8_t bytes = 0u;
|
uint8_t bytes = 0u;
|
||||||
uint32_t code_point = Encoding::decode(m_encoding, local_position.address(), &bytes);
|
uint32_t code_point = Encoding::decode(m_encoding, local_position.address(), &bytes);
|
||||||
|
record_change(local_position.address(), bytes, local_position.offset(), false);
|
||||||
m_gap_buffer->erase(local_position.offset(), bytes);
|
m_gap_buffer->erase(local_position.offset(), bytes);
|
||||||
ssize_t lines = (code_point == '\n') ? -1 : 0;
|
ssize_t lines = (code_point == '\n') ? -1 : 0;
|
||||||
for (auto iterator : m_iterators)
|
for (auto iterator : m_iterators)
|
||||||
@ -207,3 +210,72 @@ void Buffer::erase_code_point(const Buffer::Iterator & position)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::record_change(uint8_t data[], size_t length, size_t buffer_position, bool insert)
|
||||||
|
{
|
||||||
|
if (!m_current_change_operation)
|
||||||
|
{
|
||||||
|
m_current_change_operation = std::make_shared<ChangeOperation>();
|
||||||
|
}
|
||||||
|
if (m_current_change_operation->changes.size() > 0)
|
||||||
|
{
|
||||||
|
/* There is a previous change unit in progress. See if it can be
|
||||||
|
* modified to encompass the new change. */
|
||||||
|
ChangeUnit & cu = *m_current_change_operation->changes.rbegin();
|
||||||
|
if (insert && cu.insert &&
|
||||||
|
((buffer_position + length) >= cu.buffer_position) &&
|
||||||
|
(buffer_position <= (cu.buffer_position + cu.length)))
|
||||||
|
{
|
||||||
|
/* The new insertion can extend the previous insertion change unit. */
|
||||||
|
size_t change_buffer_offset = cu.change_buffer_offset + buffer_position - cu.buffer_position;
|
||||||
|
m_change_buffer->insert(change_buffer_offset, data, length);
|
||||||
|
cu.length += length;
|
||||||
|
cu.change_buffer_offset = std::min(cu.change_buffer_offset, change_buffer_offset);
|
||||||
|
cu.buffer_position = std::min(cu.buffer_position, buffer_position);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ((!insert) && (!cu.insert) &&
|
||||||
|
((buffer_position == cu.buffer_position) ||
|
||||||
|
((buffer_position + length) == cu.buffer_position)))
|
||||||
|
{
|
||||||
|
/* The new deletion can extend the previous deletion change unit. */
|
||||||
|
if (buffer_position == cu.buffer_position)
|
||||||
|
{
|
||||||
|
/* The new deletion immediately follows the previous. */
|
||||||
|
m_change_buffer->insert(cu.change_buffer_offset + cu.length, data, length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The new deletion immediately precedes the previous. */
|
||||||
|
m_change_buffer->insert(cu.change_buffer_offset, data, length);
|
||||||
|
}
|
||||||
|
cu.length += length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ((!insert) && cu.insert &&
|
||||||
|
(buffer_position >= cu.buffer_position) &&
|
||||||
|
((buffer_position + length) <= (cu.buffer_position + cu.length)))
|
||||||
|
{
|
||||||
|
/* The deletion is removing from the previous insertion change unit. */
|
||||||
|
m_change_buffer->erase(cu.change_buffer_offset + (buffer_position - cu.buffer_position), length);
|
||||||
|
if (cu.length <= length)
|
||||||
|
{
|
||||||
|
m_current_change_operation->changes.erase(--m_current_change_operation->changes.end());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cu.length -= length;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Start a new change unit. */
|
||||||
|
size_t change_buffer_offset = m_change_buffer->size();
|
||||||
|
m_change_buffer->insert(change_buffer_offset, data, length);
|
||||||
|
ChangeUnit cu;
|
||||||
|
cu.change_buffer_offset = change_buffer_offset;
|
||||||
|
cu.length = length;
|
||||||
|
cu.buffer_position = buffer_position;
|
||||||
|
cu.insert = insert;
|
||||||
|
m_current_change_operation->changes.push_back(cu);
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "Encoding.h"
|
#include "Encoding.h"
|
||||||
#include "GapBuffer.h"
|
#include "GapBuffer.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "ChangeOperation.h"
|
||||||
|
|
||||||
class Buffer
|
class Buffer
|
||||||
{
|
{
|
||||||
@ -121,18 +122,21 @@ protected:
|
|||||||
bool m_eol_at_eof;
|
bool m_eol_at_eof;
|
||||||
LineEndings::Type m_line_endings;
|
LineEndings::Type m_line_endings;
|
||||||
std::shared_ptr<GapBuffer> m_gap_buffer;
|
std::shared_ptr<GapBuffer> m_gap_buffer;
|
||||||
|
std::shared_ptr<GapBuffer> m_change_buffer;
|
||||||
Encoding::Type m_encoding;
|
Encoding::Type m_encoding;
|
||||||
uint8_t m_tabstop;
|
uint8_t m_tabstop;
|
||||||
bool m_insert_mode;
|
bool m_insert_mode;
|
||||||
std::list<std::shared_ptr<Iterator>> m_iterators;
|
std::list<std::shared_ptr<Iterator>> m_iterators;
|
||||||
std::shared_ptr<Iterator> m_eof_iterator;
|
std::shared_ptr<Iterator> m_eof_iterator;
|
||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
|
std::shared_ptr<ChangeOperation> m_current_change_operation;
|
||||||
|
|
||||||
void common_initialization();
|
void common_initialization();
|
||||||
bool load_from_file(const char * filename);
|
bool load_from_file(const char * filename);
|
||||||
void load_empty_buffer();
|
void load_empty_buffer();
|
||||||
bool load_from_memory(const uint8_t * data, size_t data_length);
|
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 load_text_in_buffer(uint8_t * buffer, size_t buffer_size, size_t data_length);
|
||||||
|
void record_change(uint8_t data[], size_t length, size_t buffer_position, bool insert);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
15
src/core/ChangeOperation.h
Normal file
15
src/core/ChangeOperation.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CHANGEOPERATION_H
|
||||||
|
#define CHANGEOPERATION_H
|
||||||
|
|
||||||
|
#include "ChangeUnit.h"
|
||||||
|
#include <list>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
class ChangeOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::list<ChangeUnit> changes;
|
||||||
|
std::list<size_t> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
src/core/ChangeUnit.h
Normal file
15
src/core/ChangeUnit.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CHANGEUNIT_H
|
||||||
|
#define CHANGEUNIT_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
class ChangeUnit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
size_t change_buffer_offset;
|
||||||
|
size_t length;
|
||||||
|
size_t buffer_position;
|
||||||
|
bool insert;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user