diff --git a/src/changes.cc b/src/changes.cc new file mode 100644 index 00000000..7feb82ec --- /dev/null +++ b/src/changes.cc @@ -0,0 +1,97 @@ +#include "changes.hh" + +namespace Kakoune +{ +void ForwardChangesTracker::update(const Buffer::Change& change) +{ + kak_assert(change.begin >= cur_pos); + + if (change.type == Buffer::Change::Insert) + { + old_pos = get_old_coord(change.begin); + cur_pos = change.end; + } + else if (change.type == Buffer::Change::Erase) + { + old_pos = get_old_coord(change.end); + cur_pos = change.begin; + } +} + +void ForwardChangesTracker::update(const Buffer& buffer, size_t& timestamp) +{ + for (auto& change : buffer.changes_since(timestamp)) + update(change); + timestamp = buffer.timestamp(); +} + +BufferCoord ForwardChangesTracker::get_old_coord(BufferCoord coord) const +{ + kak_assert(cur_pos <= coord); + auto pos_change = cur_pos - old_pos; + if (cur_pos.line == coord.line) + { + kak_assert(pos_change.column <= coord.column); + coord.column -= pos_change.column; + } + coord.line -= pos_change.line; + kak_assert(old_pos <= coord); + return coord; +} + +BufferCoord ForwardChangesTracker::get_new_coord(BufferCoord coord) const +{ + kak_assert(old_pos <= coord); + auto pos_change = cur_pos - old_pos; + if (old_pos.line == coord.line) + { + kak_assert(-pos_change.column <= coord.column); + coord.column += pos_change.column; + } + coord.line += pos_change.line; + kak_assert(cur_pos <= coord); + return coord; +} + +BufferCoord ForwardChangesTracker::get_new_coord_tolerant(BufferCoord coord) const +{ + if (coord < old_pos) + return cur_pos; + return get_new_coord(coord); +} + +bool ForwardChangesTracker::relevant(const Buffer::Change& change, BufferCoord old_coord) const +{ + auto new_coord = get_new_coord_tolerant(old_coord); + return change.type == Buffer::Change::Insert ? change.begin <= new_coord + : change.begin < new_coord; +} + +const Buffer::Change* forward_sorted_until(const Buffer::Change* first, const Buffer::Change* last) +{ + if (first != last) { + const Buffer::Change* next = first; + while (++next != last) { + const auto& ref = first->type == Buffer::Change::Insert ? first->end : first->begin; + if (next->begin <= ref) + return next; + first = next; + } + } + return last; +} + +const Buffer::Change* backward_sorted_until(const Buffer::Change* first, const Buffer::Change* last) +{ + if (first != last) { + const Buffer::Change* next = first; + while (++next != last) { + if (first->begin <= next->end) + return next; + first = next; + } + } + return last; +} + +} diff --git a/src/changes.hh b/src/changes.hh new file mode 100644 index 00000000..963ca786 --- /dev/null +++ b/src/changes.hh @@ -0,0 +1,89 @@ +#ifndef changes_hh_INCLUDED +#define changes_hh_INCLUDED + +#include "buffer.hh" +#include "coord.hh" + +namespace Kakoune +{ + +// This tracks position changes for changes that are done +// in a forward way (each change takes place at a position) +// *after* the previous one. +struct ForwardChangesTracker +{ + BufferCoord cur_pos; // last change position at current modification + BufferCoord old_pos; // last change position at start + + void update(const Buffer::Change& change); + void update(const Buffer& buffer, size_t& timestamp); + + BufferCoord get_old_coord(BufferCoord coord) const; + BufferCoord get_new_coord(BufferCoord coord) const; + BufferCoord get_new_coord_tolerant(BufferCoord coord) const; + + bool relevant(const Buffer::Change& change, BufferCoord old_coord) const; +}; + +const Buffer::Change* forward_sorted_until(const Buffer::Change* first, const Buffer::Change* last); +const Buffer::Change* backward_sorted_until(const Buffer::Change* first, const Buffer::Change* last); + +template +void update_forward(ConstArrayView changes, RangeContainer& ranges) +{ + ForwardChangesTracker changes_tracker; + + auto change_it = changes.begin(); + auto advance_while_relevant = [&](const BufferCoord& pos) mutable { + while (change_it != changes.end() and changes_tracker.relevant(*change_it, pos)) + changes_tracker.update(*change_it++); + }; + + for (auto& range : ranges) + { + auto& first = get_first(range); + auto& last = get_last(range); + advance_while_relevant(first); + first = changes_tracker.get_new_coord_tolerant(first); + + advance_while_relevant(last); + last = changes_tracker.get_new_coord_tolerant(last); + } +} + +template +void update_backward(ConstArrayView changes, RangeContainer& ranges) +{ + ForwardChangesTracker changes_tracker; + + using ReverseIt = std::reverse_iterator; + auto change_it = ReverseIt(changes.end()); + auto change_end = ReverseIt(changes.begin()); + auto advance_while_relevant = [&](const BufferCoord& pos) mutable { + while (change_it != change_end) + { + auto change = *change_it; + change.begin = changes_tracker.get_new_coord(change.begin); + change.end = changes_tracker.get_new_coord(change.end); + if (not changes_tracker.relevant(change, pos)) + break; + changes_tracker.update(change); + ++change_it; + } + }; + + for (auto& range : ranges) + { + auto& first = get_first(range); + auto& last = get_last(range); + advance_while_relevant(first); + first = changes_tracker.get_new_coord_tolerant(first); + + advance_while_relevant(last); + last = changes_tracker.get_new_coord_tolerant(last); + } +} + +} + +#endif // changes_hh_INCLUDED diff --git a/src/highlighters.cc b/src/highlighters.cc index fdb85c69..00f47297 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -2,6 +2,7 @@ #include "assert.hh" #include "buffer_utils.hh" +#include "changes.hh" #include "context.hh" #include "containers.hh" #include "command_manager.hh" @@ -992,6 +993,9 @@ HighlighterAndId create_flag_lines_highlighter(HighlighterParameters params) return {"hlflags_" + params[1], make_simple_highlighter(func) }; } +BufferCoord& get_first(RangeAndFace& r) { return std::get<0>(r).begin; } +BufferCoord& get_last(RangeAndFace& r) { return std::get<0>(r).end; } + HighlighterAndId create_ranges_highlighter(HighlighterParameters params) { if (params.size() != 1) @@ -1011,8 +1015,25 @@ HighlighterAndId create_ranges_highlighter(HighlighterParameters params) auto& buffer = context.buffer(); if (range_and_faces.prefix != buffer.timestamp()) { - // TODO: update ranges to current timestamp - return; + auto changes = buffer.changes_since(range_and_faces.prefix); + auto change_it = changes.begin(); + while (change_it != changes.end()) + { + auto forward_end = forward_sorted_until(change_it, changes.end()); + auto backward_end = backward_sorted_until(change_it, changes.end()); + + if (forward_end >= backward_end) + { + update_forward({ change_it, forward_end }, ranges); + change_it = forward_end; + } + else + { + update_backward({ change_it, backward_end }, ranges); + change_it = backward_end; + } + } + range_and_faces.prefix = buffer.timestamp(); } for (auto& range : ranges) diff --git a/src/selection.cc b/src/selection.cc index 5501bbd0..b0474e67 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -1,7 +1,8 @@ #include "selection.hh" -#include "utf8.hh" #include "buffer_utils.hh" +#include "changes.hh" +#include "utf8.hh" namespace Kakoune { @@ -96,164 +97,10 @@ Iterator merge_overlapping(Iterator begin, Iterator end, size_t& main, OverlapsF return begin + i + 1; } -// This tracks position changes for changes that are done -// in a forward way (each change takes place at a position) -// *after* the previous one. -struct ForwardChangesTracker -{ - BufferCoord cur_pos; // last change position at current modification - BufferCoord old_pos; // last change position at start - - void update(const Buffer::Change& change) - { - kak_assert(change.begin >= cur_pos); - - if (change.type == Buffer::Change::Insert) - { - old_pos = get_old_coord(change.begin); - cur_pos = change.end; - } - else if (change.type == Buffer::Change::Erase) - { - old_pos = get_old_coord(change.end); - cur_pos = change.begin; - } - } - - void update(const Buffer& buffer, size_t& timestamp) - { - for (auto& change : buffer.changes_since(timestamp)) - update(change); - timestamp = buffer.timestamp(); - } - - BufferCoord get_old_coord(BufferCoord coord) const - { - kak_assert(cur_pos <= coord); - auto pos_change = cur_pos - old_pos; - if (cur_pos.line == coord.line) - { - kak_assert(pos_change.column <= coord.column); - coord.column -= pos_change.column; - } - coord.line -= pos_change.line; - kak_assert(old_pos <= coord); - return coord; - } - - BufferCoord get_new_coord(BufferCoord coord) const - { - kak_assert(old_pos <= coord); - auto pos_change = cur_pos - old_pos; - if (old_pos.line == coord.line) - { - kak_assert(-pos_change.column <= coord.column); - coord.column += pos_change.column; - } - coord.line += pos_change.line; - kak_assert(cur_pos <= coord); - return coord; - } - - BufferCoord get_new_coord_tolerant(BufferCoord coord) const - { - if (coord < old_pos) - return cur_pos; - return get_new_coord(coord); - } - - bool relevant(const Buffer::Change& change, BufferCoord old_coord) const - { - auto new_coord = get_new_coord_tolerant(old_coord); - return change.type == Buffer::Change::Insert ? change.begin <= new_coord - : change.begin < new_coord; - } -}; - -const Buffer::Change* forward_sorted_until(const Buffer::Change* first, const Buffer::Change* last) -{ - if (first != last) { - const Buffer::Change* next = first; - while (++next != last) { - const auto& ref = first->type == Buffer::Change::Insert ? first->end : first->begin; - if (next->begin <= ref) - return next; - first = next; - } - } - return last; } -const Buffer::Change* backward_sorted_until(const Buffer::Change* first, const Buffer::Change* last) -{ - if (first != last) { - const Buffer::Change* next = first; - while (++next != last) { - if (first->begin <= next->end) - return next; - first = next; - } - } - return last; -} - -void update_forward(ConstArrayView changes, Vector& selections) -{ - ForwardChangesTracker changes_tracker; - - auto change_it = changes.begin(); - auto advance_while_relevant = [&](const BufferCoord& pos) mutable { - while (change_it != changes.end() and changes_tracker.relevant(*change_it, pos)) - changes_tracker.update(*change_it++); - }; - - for (auto& sel : selections) - { - auto& sel_min = sel.min(); - auto& sel_max = sel.max(); - advance_while_relevant(sel_min); - sel_min = changes_tracker.get_new_coord_tolerant(sel_min); - - advance_while_relevant(sel_max); - sel_max = changes_tracker.get_new_coord_tolerant(sel_max); - } - kak_assert(std::is_sorted(selections.begin(), selections.end(), compare_selections)); -} - -void update_backward(ConstArrayView changes, Vector& selections) -{ - ForwardChangesTracker changes_tracker; - - using ReverseIt = std::reverse_iterator; - auto change_it = ReverseIt(changes.end()); - auto change_end = ReverseIt(changes.begin()); - auto advance_while_relevant = [&](const BufferCoord& pos) mutable { - while (change_it != change_end) - { - auto change = *change_it; - change.begin = changes_tracker.get_new_coord(change.begin); - change.end = changes_tracker.get_new_coord(change.end); - if (not changes_tracker.relevant(change, pos)) - break; - changes_tracker.update(change); - ++change_it; - } - }; - - for (auto& sel : selections) - { - auto& sel_min = sel.min(); - auto& sel_max = sel.max(); - advance_while_relevant(sel_min); - sel_min = changes_tracker.get_new_coord_tolerant(sel_min); - - advance_while_relevant(sel_max); - sel_max = changes_tracker.get_new_coord_tolerant(sel_max); - } - kak_assert(std::is_sorted(selections.begin(), selections.end(), compare_selections)); -} - -} +BufferCoord& get_first(Selection& sel) { return sel.min(); } +BufferCoord& get_last(Selection& sel) { return sel.max(); } Vector compute_modified_ranges(Buffer& buffer, size_t timestamp) { @@ -367,11 +214,11 @@ void update_selections(Vector& selections, size_t& main, Buffer& buff update_backward({ change_it, backward_end }, selections); change_it = backward_end; } + kak_assert(std::is_sorted(selections.begin(), selections.end(), + compare_selections)); selections.erase( merge_overlapping(selections.begin(), selections.end(), main, overlaps), selections.end()); - kak_assert(std::is_sorted(selections.begin(), selections.end(), - compare_selections)); } for (auto& sel : selections) clamp(sel, buffer);