diff options
| author | Maxime Coste <frrrwww@gmail.com> | 2016-03-16 13:48:11 +0000 |
|---|---|---|
| committer | Maxime Coste <frrrwww@gmail.com> | 2016-03-16 13:48:11 +0000 |
| commit | de1433d30ade30c6768cefb085ff69ef7387fa2f (patch) | |
| tree | ce7161d346db680e96cb80ed22928810e45655c4 /src | |
| parent | c5b24e2a8a783fda939c6576158e0d9d591d632b (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.cc | 24 | ||||
| -rw-r--r-- | src/buffer.hh | 1 | ||||
| -rw-r--r-- | src/buffer_utils.hh | 7 | ||||
| -rw-r--r-- | src/selection.cc | 24 |
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)); } |
