summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2016-03-16 13:48:11 +0000
committerMaxime Coste <frrrwww@gmail.com>2016-03-16 13:48:11 +0000
commitde1433d30ade30c6768cefb085ff69ef7387fa2f (patch)
treece7161d346db680e96cb80ed22928810e45655c4 /src
parentc5b24e2a8a783fda939c6576158e0d9d591d632b (diff)
Avoid the spurious newline insertion when replacing at end of buffer
Add a Buffer::replace method to handle the replacements properly Fixes #633
Diffstat (limited to 'src')
-rw-r--r--src/buffer.cc24
-rw-r--r--src/buffer.hh1
-rw-r--r--src/buffer_utils.hh7
-rw-r--r--src/selection.cc24
4 files changed, 45 insertions, 11 deletions
diff --git a/src/buffer.cc b/src/buffer.cc
index a28b81cb..ee250aba 100644
--- a/src/buffer.cc
+++ b/src/buffer.cc
@@ -343,8 +343,9 @@ ByteCoord Buffer::do_insert(ByteCoord pos, StringView content)
return 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)
- pos = line_count();
+ pos = append_lines ? line_count() : end_coord();
const StringView prefix = at_end ?
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 new_lines_it = new_lines.begin();
- if (not at_end)
+ if (not append_lines)
*line_it++ = std::move(*new_lines_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())};
}
+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
{
size_t history_cursor_index = m_history_cursor - m_history.begin();
diff --git a/src/buffer.hh b/src/buffer.hh
index a7ab127c..6b99ab1d 100644
--- a/src/buffer.hh
+++ b/src/buffer.hh
@@ -123,6 +123,7 @@ public:
BufferIterator insert(const BufferIterator& pos, StringView content);
BufferIterator erase(BufferIterator begin, BufferIterator end);
+ BufferIterator replace(const BufferIterator& begin, const BufferIterator& end, StringView content);
size_t timestamp() const;
timespec fs_timestamp() const;
diff --git a/src/buffer_utils.hh b/src/buffer_utils.hh
index 543e2357..97c5374d 100644
--- a/src/buffer_utils.hh
+++ b/src/buffer_utils.hh
@@ -21,6 +21,13 @@ inline BufferIterator erase(Buffer& buffer, const Selection& range)
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)
{
return utf8::distance(buffer.iterator_at(range.min()),
diff --git a/src/selection.cc b/src/selection.cc
index 90580bdd..95d466df 100644
--- a/src/selection.cc
+++ b/src/selection.cc
@@ -439,7 +439,7 @@ BufferIterator prepare_insert(Buffer& buffer, const Selection& sel, InsertMode m
case InsertMode::InsertCursor:
return buffer.iterator_at(sel.cursor());
case InsertMode::Replace:
- return erase(buffer, sel);
+ return {}; // replace is handled specially, by calling Buffer::replace
case InsertMode::Append:
{
// 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);
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;
- }
- pos = m_buffer->insert(pos, str);
+ if (mode == InsertMode::Replace)
+ pos = replace(*m_buffer, sel, str);
+ else
+ pos = m_buffer->insert(pos, str);
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();
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
auto& min = sel.min();
auto& max = sel.max();
@@ -505,6 +508,9 @@ void SelectionList::insert(ConstArrayView<String> strings, InsertMode mode,
}
else
{
+ if (str.empty())
+ continue;
+
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));
}