Avoid the spurious newline insertion when replacing at end of buffer
Add a Buffer::replace method to handle the replacements properly Fixes #633
This commit is contained in:
parent
c5b24e2a8a
commit
de1433d30a
|
@ -343,8 +343,9 @@ ByteCoord Buffer::do_insert(ByteCoord pos, StringView content)
|
||||||
return pos;
|
return pos;
|
||||||
|
|
||||||
const bool at_end = is_end(pos);
|
const bool at_end = is_end(pos);
|
||||||
|
const bool append_lines = at_end and (m_lines.empty() or byte_at(back_coord()) == '\n');
|
||||||
if (at_end)
|
if (at_end)
|
||||||
pos = line_count();
|
pos = append_lines ? line_count() : end_coord();
|
||||||
|
|
||||||
const StringView prefix = at_end ?
|
const StringView prefix = at_end ?
|
||||||
StringView{} : m_lines[pos.line].substr(0, pos.column);
|
StringView{} : m_lines[pos.line].substr(0, pos.column);
|
||||||
|
@ -369,7 +370,7 @@ ByteCoord Buffer::do_insert(ByteCoord pos, StringView content)
|
||||||
|
|
||||||
auto line_it = m_lines.begin() + (int)pos.line;
|
auto line_it = m_lines.begin() + (int)pos.line;
|
||||||
auto new_lines_it = new_lines.begin();
|
auto new_lines_it = new_lines.begin();
|
||||||
if (not at_end)
|
if (not append_lines)
|
||||||
*line_it++ = std::move(*new_lines_it++);
|
*line_it++ = std::move(*new_lines_it++);
|
||||||
|
|
||||||
m_lines.insert(line_it,
|
m_lines.insert(line_it,
|
||||||
|
@ -473,6 +474,25 @@ BufferIterator Buffer::erase(BufferIterator begin, BufferIterator end)
|
||||||
return {*this, do_erase(begin.coord(), end.coord())};
|
return {*this, do_erase(begin.coord(), end.coord())};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufferIterator Buffer::replace(const BufferIterator& begin, const BufferIterator& end, StringView content)
|
||||||
|
{
|
||||||
|
if (not (m_flags & Flags::NoUndo))
|
||||||
|
m_current_undo_group.emplace_back(Modification::Erase, begin.coord(),
|
||||||
|
intern(string(begin.coord(), end.coord())));
|
||||||
|
auto pos = do_erase(begin.coord(), end.coord());
|
||||||
|
|
||||||
|
StringDataPtr real_content;
|
||||||
|
if (is_end(pos) and content.back() != '\n')
|
||||||
|
real_content = intern(content + "\n");
|
||||||
|
else
|
||||||
|
real_content = intern(content);
|
||||||
|
|
||||||
|
auto coord = is_end(pos) ? ByteCoord{line_count()} : pos;
|
||||||
|
if (not (m_flags & Flags::NoUndo))
|
||||||
|
m_current_undo_group.emplace_back(Modification::Insert, coord, real_content);
|
||||||
|
return {*this, do_insert(pos, real_content->strview())};
|
||||||
|
}
|
||||||
|
|
||||||
bool Buffer::is_modified() const
|
bool Buffer::is_modified() const
|
||||||
{
|
{
|
||||||
size_t history_cursor_index = m_history_cursor - m_history.begin();
|
size_t history_cursor_index = m_history_cursor - m_history.begin();
|
||||||
|
|
|
@ -123,6 +123,7 @@ public:
|
||||||
|
|
||||||
BufferIterator insert(const BufferIterator& pos, StringView content);
|
BufferIterator insert(const BufferIterator& pos, StringView content);
|
||||||
BufferIterator erase(BufferIterator begin, BufferIterator end);
|
BufferIterator erase(BufferIterator begin, BufferIterator end);
|
||||||
|
BufferIterator replace(const BufferIterator& begin, const BufferIterator& end, StringView content);
|
||||||
|
|
||||||
size_t timestamp() const;
|
size_t timestamp() const;
|
||||||
timespec fs_timestamp() const;
|
timespec fs_timestamp() const;
|
||||||
|
|
|
@ -21,6 +21,13 @@ inline BufferIterator erase(Buffer& buffer, const Selection& range)
|
||||||
buffer.iterator_at(buffer.char_next(range.max())));
|
buffer.iterator_at(buffer.char_next(range.max())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline BufferIterator replace(Buffer& buffer, const Selection& range, StringView content)
|
||||||
|
{
|
||||||
|
return buffer.replace(buffer.iterator_at(range.min()),
|
||||||
|
buffer.iterator_at(buffer.char_next(range.max())),
|
||||||
|
content);
|
||||||
|
}
|
||||||
|
|
||||||
inline CharCount char_length(const Buffer& buffer, const Selection& range)
|
inline CharCount char_length(const Buffer& buffer, const Selection& range)
|
||||||
{
|
{
|
||||||
return utf8::distance(buffer.iterator_at(range.min()),
|
return utf8::distance(buffer.iterator_at(range.min()),
|
||||||
|
|
|
@ -439,7 +439,7 @@ BufferIterator prepare_insert(Buffer& buffer, const Selection& sel, InsertMode m
|
||||||
case InsertMode::InsertCursor:
|
case InsertMode::InsertCursor:
|
||||||
return buffer.iterator_at(sel.cursor());
|
return buffer.iterator_at(sel.cursor());
|
||||||
case InsertMode::Replace:
|
case InsertMode::Replace:
|
||||||
return erase(buffer, sel);
|
return {}; // replace is handled specially, by calling Buffer::replace
|
||||||
case InsertMode::Append:
|
case InsertMode::Append:
|
||||||
{
|
{
|
||||||
// special case for end of lines, append to current line instead
|
// special case for end of lines, append to current line instead
|
||||||
|
@ -482,21 +482,24 @@ void SelectionList::insert(ConstArrayView<String> strings, InsertMode mode,
|
||||||
changes_tracker.update(*m_buffer, m_timestamp);
|
changes_tracker.update(*m_buffer, m_timestamp);
|
||||||
|
|
||||||
const String& str = strings[std::min(index, strings.size()-1)];
|
const String& str = strings[std::min(index, strings.size()-1)];
|
||||||
if (str.empty())
|
|
||||||
{
|
|
||||||
if (mode == InsertMode::Replace)
|
|
||||||
sel.anchor() = sel.cursor() = m_buffer->clamp(pos.coord());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (mode == InsertMode::Replace)
|
||||||
|
pos = replace(*m_buffer, sel, str);
|
||||||
|
else
|
||||||
pos = m_buffer->insert(pos, str);
|
pos = m_buffer->insert(pos, str);
|
||||||
|
|
||||||
auto& change = m_buffer->changes_since(m_timestamp).back();
|
auto& change = m_buffer->changes_since(m_timestamp).back();
|
||||||
changes_tracker.update(change);
|
changes_tracker.update(*m_buffer, m_timestamp);
|
||||||
m_timestamp = m_buffer->timestamp();
|
m_timestamp = m_buffer->timestamp();
|
||||||
|
|
||||||
if (select_inserted or mode == InsertMode::Replace)
|
if (select_inserted or mode == InsertMode::Replace)
|
||||||
{
|
{
|
||||||
|
if (str.empty())
|
||||||
|
{
|
||||||
|
sel.anchor() = sel.cursor() = m_buffer->clamp(pos.coord());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// we want min and max from *before* we do any change
|
// we want min and max from *before* we do any change
|
||||||
auto& min = sel.min();
|
auto& min = sel.min();
|
||||||
auto& max = sel.max();
|
auto& max = sel.max();
|
||||||
|
@ -505,6 +508,9 @@ void SelectionList::insert(ConstArrayView<String> strings, InsertMode mode,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (str.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
sel.anchor() = m_buffer->clamp(update_insert(sel.anchor(), change.begin, change.end));
|
sel.anchor() = m_buffer->clamp(update_insert(sel.anchor(), change.begin, change.end));
|
||||||
sel.cursor() = m_buffer->clamp(update_insert(sel.cursor(), change.begin, change.end));
|
sel.cursor() = m_buffer->clamp(update_insert(sel.cursor(), change.begin, change.end));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
x~
|
|
@ -0,0 +1 @@
|
||||||
|
blah
|
|
@ -0,0 +1 @@
|
||||||
|
BLAH
|
Loading…
Reference in New Issue
Block a user