Refuse modification of ReadOnly buffers and make Debug buffer readonly
The debug buffer is a bit special as lots of events might mutate it, permitting it to be modified leads to some buggy behaviour: For example, `pipe` uses a ForwardChangeTracker to track buffer changes, but when applied on a debug buffer with the profile flag on, each shell execution will trigger an additional modification of the buffer while applying the changes, leading to an assertion failing as changes might not be happening in a forward way anymore. Trying to modify a debug buffer will now raise an error immediatly.
This commit is contained in:
parent
3584e00d19
commit
66fe2d84da
|
@ -158,6 +158,12 @@ bool Buffer::set_name(String name)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::throw_if_read_only() const
|
||||||
|
{
|
||||||
|
if (m_flags & Flags::ReadOnly)
|
||||||
|
throw runtime_error("Buffer is read-only");
|
||||||
|
}
|
||||||
|
|
||||||
void Buffer::update_display_name()
|
void Buffer::update_display_name()
|
||||||
{
|
{
|
||||||
if (m_flags & Flags::File)
|
if (m_flags & Flags::File)
|
||||||
|
@ -315,8 +321,10 @@ void Buffer::commit_undo_group()
|
||||||
m_history_cursor = node;
|
m_history_cursor = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::undo(size_t count) noexcept
|
bool Buffer::undo(size_t count)
|
||||||
{
|
{
|
||||||
|
throw_if_read_only();
|
||||||
|
|
||||||
commit_undo_group();
|
commit_undo_group();
|
||||||
|
|
||||||
if (not m_history_cursor->parent)
|
if (not m_history_cursor->parent)
|
||||||
|
@ -333,8 +341,10 @@ bool Buffer::undo(size_t count) noexcept
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::redo(size_t count) noexcept
|
bool Buffer::redo(size_t count)
|
||||||
{
|
{
|
||||||
|
throw_if_read_only();
|
||||||
|
|
||||||
if (not m_history_cursor->redo_child)
|
if (not m_history_cursor->redo_child)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -350,8 +360,10 @@ bool Buffer::redo(size_t count) noexcept
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::move_to(HistoryNode* history_node) noexcept
|
void Buffer::move_to(HistoryNode* history_node)
|
||||||
{
|
{
|
||||||
|
throw_if_read_only();
|
||||||
|
|
||||||
commit_undo_group();
|
commit_undo_group();
|
||||||
|
|
||||||
auto find_lowest_common_parent = [](HistoryNode* a, HistoryNode* b) {
|
auto find_lowest_common_parent = [](HistoryNode* a, HistoryNode* b) {
|
||||||
|
@ -419,7 +431,7 @@ Buffer::HistoryNode* Buffer::find_history_node(HistoryNode* node, const Func& fu
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::move_to(size_t history_id) noexcept
|
bool Buffer::move_to(size_t history_id)
|
||||||
{
|
{
|
||||||
auto* target_node = find_history_node(&m_history, [history_id](auto* node)
|
auto* target_node = find_history_node(&m_history, [history_id](auto* node)
|
||||||
{ return node->id == history_id; });
|
{ return node->id == history_id; });
|
||||||
|
@ -548,6 +560,8 @@ void Buffer::apply_modification(const Modification& modification)
|
||||||
|
|
||||||
BufferCoord Buffer::insert(BufferCoord pos, StringView content)
|
BufferCoord Buffer::insert(BufferCoord pos, StringView content)
|
||||||
{
|
{
|
||||||
|
throw_if_read_only();
|
||||||
|
|
||||||
kak_assert(is_valid(pos));
|
kak_assert(is_valid(pos));
|
||||||
if (content.empty())
|
if (content.empty())
|
||||||
return pos;
|
return pos;
|
||||||
|
@ -568,6 +582,8 @@ BufferCoord Buffer::insert(BufferCoord pos, StringView content)
|
||||||
|
|
||||||
BufferCoord Buffer::erase(BufferCoord begin, BufferCoord end)
|
BufferCoord Buffer::erase(BufferCoord begin, BufferCoord end)
|
||||||
{
|
{
|
||||||
|
throw_if_read_only();
|
||||||
|
|
||||||
kak_assert(is_valid(begin) and is_valid(end));
|
kak_assert(is_valid(begin) and is_valid(end));
|
||||||
// do not erase last \n except if we erase from the start of a line, and normalize
|
// do not erase last \n except if we erase from the start of a line, and normalize
|
||||||
// end coord
|
// end coord
|
||||||
|
@ -585,6 +601,8 @@ BufferCoord Buffer::erase(BufferCoord begin, BufferCoord end)
|
||||||
|
|
||||||
BufferCoord Buffer::replace(BufferCoord begin, BufferCoord end, StringView content)
|
BufferCoord Buffer::replace(BufferCoord begin, BufferCoord end, StringView content)
|
||||||
{
|
{
|
||||||
|
throw_if_read_only();
|
||||||
|
|
||||||
if (is_end(end) and not content.empty() and content.back() == '\n')
|
if (is_end(end) and not content.empty() and content.back() == '\n')
|
||||||
{
|
{
|
||||||
end = back_coord();
|
end = back_coord();
|
||||||
|
|
|
@ -139,9 +139,9 @@ public:
|
||||||
void set_fs_timestamp(timespec ts);
|
void set_fs_timestamp(timespec ts);
|
||||||
|
|
||||||
void commit_undo_group();
|
void commit_undo_group();
|
||||||
bool undo(size_t count = 1) noexcept;
|
bool undo(size_t count = 1);
|
||||||
bool redo(size_t count = 1) noexcept;
|
bool redo(size_t count = 1);
|
||||||
bool move_to(size_t history_id) noexcept;
|
bool move_to(size_t history_id);
|
||||||
size_t current_history_id() const noexcept;
|
size_t current_history_id() const noexcept;
|
||||||
size_t next_history_id() const noexcept { return m_next_history_id; }
|
size_t next_history_id() const noexcept { return m_next_history_id; }
|
||||||
|
|
||||||
|
@ -218,6 +218,7 @@ public:
|
||||||
void on_registered();
|
void on_registered();
|
||||||
void on_unregistered();
|
void on_unregistered();
|
||||||
|
|
||||||
|
void throw_if_read_only() const;
|
||||||
private:
|
private:
|
||||||
void on_option_changed(const Option& option) override;
|
void on_option_changed(const Option& option) override;
|
||||||
|
|
||||||
|
@ -272,7 +273,7 @@ private:
|
||||||
SafePtr<HistoryNode> m_last_save_history_cursor;
|
SafePtr<HistoryNode> m_last_save_history_cursor;
|
||||||
UndoGroup m_current_undo_group;
|
UndoGroup m_current_undo_group;
|
||||||
|
|
||||||
void move_to(HistoryNode* history_node) noexcept;
|
void move_to(HistoryNode* history_node);
|
||||||
|
|
||||||
template<typename Func> HistoryNode* find_history_node(HistoryNode* node, const Func& func);
|
template<typename Func> HistoryNode* find_history_node(HistoryNode* node, const Func& func);
|
||||||
|
|
||||||
|
|
|
@ -181,12 +181,17 @@ void write_to_debug_buffer(StringView str)
|
||||||
// where the user can put its cursor to scroll with new messages
|
// where the user can put its cursor to scroll with new messages
|
||||||
const bool eol_back = not str.empty() and str.back() == '\n';
|
const bool eol_back = not str.empty() and str.back() == '\n';
|
||||||
if (Buffer* buffer = BufferManager::instance().get_buffer_ifp(debug_buffer_name))
|
if (Buffer* buffer = BufferManager::instance().get_buffer_ifp(debug_buffer_name))
|
||||||
|
{
|
||||||
|
buffer->flags() &= ~Buffer::Flags::ReadOnly;
|
||||||
|
auto restore = on_scope_end([buffer] { buffer->flags() |= Buffer::Flags::ReadOnly; });
|
||||||
|
|
||||||
buffer->insert(buffer->back_coord(), eol_back ? str : str + "\n");
|
buffer->insert(buffer->back_coord(), eol_back ? str : str + "\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String line = str + (eol_back ? "\n" : "\n\n");
|
String line = str + (eol_back ? "\n" : "\n\n");
|
||||||
BufferManager::instance().create_buffer(
|
BufferManager::instance().create_buffer(
|
||||||
debug_buffer_name.str(), Buffer::Flags::NoUndo | Buffer::Flags::Debug,
|
debug_buffer_name.str(), Buffer::Flags::NoUndo | Buffer::Flags::Debug | Buffer::Flags::ReadOnly,
|
||||||
line, InvalidTime);
|
line, InvalidTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1061,6 +1061,8 @@ public:
|
||||||
context().hooks().run_hook("InsertIdle", "", context());
|
context().hooks().run_hook("InsertIdle", "", context());
|
||||||
}}
|
}}
|
||||||
{
|
{
|
||||||
|
context().buffer().throw_if_read_only();
|
||||||
|
|
||||||
last_insert().recording.set();
|
last_insert().recording.set();
|
||||||
last_insert().mode = mode;
|
last_insert().mode = mode;
|
||||||
last_insert().keys.clear();
|
last_insert().keys.clear();
|
||||||
|
@ -1068,11 +1070,6 @@ public:
|
||||||
last_insert().count = count;
|
last_insert().count = count;
|
||||||
context().hooks().run_hook("InsertBegin", "", context());
|
context().hooks().run_hook("InsertBegin", "", context());
|
||||||
prepare(mode, count);
|
prepare(mode, count);
|
||||||
|
|
||||||
if (context().has_client() and
|
|
||||||
context().options()["readonly"].get<bool>())
|
|
||||||
context().print_status({ "Warning: This buffer is readonly",
|
|
||||||
get_face("Error") });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_enabled() override
|
void on_enabled() override
|
||||||
|
|
Loading…
Reference in New Issue
Block a user