Remove posB from information given by the diff algorithm
posB is always the sum of previous add len and previous keep len, so very easy to keep track of.
This commit is contained in:
parent
401ef84a4b
commit
3c265acd6c
|
@ -260,28 +260,31 @@ void Buffer::reload(StringView data, timespec fs_timestamp)
|
||||||
Vector<Diff> diff;
|
Vector<Diff> diff;
|
||||||
for_each_diff(m_lines.begin(), m_lines.size(),
|
for_each_diff(m_lines.begin(), m_lines.size(),
|
||||||
parsed_lines.lines.begin(), parsed_lines.lines.size(),
|
parsed_lines.lines.begin(), parsed_lines.lines.size(),
|
||||||
[&diff](DiffOp op, int len, int posB)
|
[&diff](DiffOp op, int len)
|
||||||
{ diff.push_back({op, len, posB}); },
|
{ diff.push_back({op, len}); },
|
||||||
[](const StringDataPtr& lhs, const StringDataPtr& rhs)
|
[](const StringDataPtr& lhs, const StringDataPtr& rhs)
|
||||||
{ return lhs->strview() == rhs->strview(); });
|
{ return lhs->strview() == rhs->strview(); });
|
||||||
|
|
||||||
auto it = m_lines.begin();
|
auto it = m_lines.begin();
|
||||||
|
auto new_it = parsed_lines.lines.begin();
|
||||||
for (auto& d : diff)
|
for (auto& d : diff)
|
||||||
{
|
{
|
||||||
if (d.op == DiffOp::Keep)
|
if (d.op == DiffOp::Keep)
|
||||||
|
{
|
||||||
it += d.len;
|
it += d.len;
|
||||||
|
new_it += d.len;
|
||||||
|
}
|
||||||
else if (d.op == DiffOp::Add)
|
else if (d.op == DiffOp::Add)
|
||||||
{
|
{
|
||||||
const LineCount cur_line = (int)(it - m_lines.begin());
|
const LineCount cur_line = (int)(it - m_lines.begin());
|
||||||
|
|
||||||
for (LineCount line = 0; line < d.len; ++line)
|
for (LineCount line = 0; line < d.len; ++line)
|
||||||
m_current_undo_group.push_back({
|
m_current_undo_group.push_back({Modification::Insert, cur_line + line, *(new_it + (int)line)});
|
||||||
Modification::Insert, cur_line + line,
|
|
||||||
parsed_lines.lines[(int)(d.posB + line)]});
|
|
||||||
|
|
||||||
m_changes.push_back({ Change::Insert, cur_line, cur_line + d.len });
|
m_changes.push_back({Change::Insert, cur_line, cur_line + d.len});
|
||||||
m_lines.insert(it, parsed_lines.lines.begin() + d.posB, parsed_lines.lines.begin() + d.posB + d.len);
|
m_lines.insert(it, new_it, new_it + d.len);
|
||||||
it = m_lines.begin() + (int)(cur_line + d.len);
|
it = m_lines.begin() + (int)(cur_line + d.len);
|
||||||
|
new_it += d.len;
|
||||||
}
|
}
|
||||||
else if (d.op == DiffOp::Remove)
|
else if (d.op == DiffOp::Remove)
|
||||||
{
|
{
|
||||||
|
|
37
src/diff.hh
37
src/diff.hh
|
@ -115,9 +115,9 @@ void find_diff_rec(IteratorA a, int begA, int endA,
|
||||||
int* V1, int* V2, int cost_limit,
|
int* V1, int* V2, int cost_limit,
|
||||||
Equal eq, OnDiff&& on_diff)
|
Equal eq, OnDiff&& on_diff)
|
||||||
{
|
{
|
||||||
auto on_diff_ifn = [&](DiffOp op, int len, int posB) {
|
auto on_diff_ifn = [&](DiffOp op, int len) {
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
on_diff(op, len, posB);
|
on_diff(op, len);
|
||||||
};
|
};
|
||||||
|
|
||||||
int prefix_len = 0;
|
int prefix_len = 0;
|
||||||
|
@ -128,14 +128,14 @@ void find_diff_rec(IteratorA a, int begA, int endA,
|
||||||
while (begA != endA and begB != endB and eq(a[endA-1], b[endB-1]))
|
while (begA != endA and begB != endB and eq(a[endA-1], b[endB-1]))
|
||||||
--endA, --endB, ++suffix_len;
|
--endA, --endB, ++suffix_len;
|
||||||
|
|
||||||
on_diff_ifn(DiffOp::Keep, prefix_len, 0);
|
on_diff_ifn(DiffOp::Keep, prefix_len);
|
||||||
|
|
||||||
const auto lenA = endA - begA, lenB = endB - begB;
|
const auto lenA = endA - begA, lenB = endB - begB;
|
||||||
|
|
||||||
if (lenA == 0)
|
if (lenA == 0)
|
||||||
on_diff_ifn(DiffOp::Add, lenB, begB);
|
on_diff_ifn(DiffOp::Add, lenB);
|
||||||
else if (lenB == 0)
|
else if (lenB == 0)
|
||||||
on_diff_ifn(DiffOp::Remove, lenA, 0);
|
on_diff_ifn(DiffOp::Remove, lenA);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto snake = find_middle_snake(a + begA, lenA, b + begB, lenB, V1, V2, cost_limit, eq);
|
auto snake = find_middle_snake(a + begA, lenA, b + begB, lenB, V1, V2, cost_limit, eq);
|
||||||
|
@ -146,30 +146,29 @@ void find_diff_rec(IteratorA a, int begA, int endA,
|
||||||
V1, V2, cost_limit, eq, on_diff);
|
V1, V2, cost_limit, eq, on_diff);
|
||||||
|
|
||||||
if (snake.op == Snake::Add)
|
if (snake.op == Snake::Add)
|
||||||
on_diff_ifn(DiffOp::Add, 1, begB + snake.y - 1);
|
on_diff_ifn(DiffOp::Add, 1);
|
||||||
if (snake.op == Snake::Del)
|
if (snake.op == Snake::Del)
|
||||||
on_diff_ifn(DiffOp::Remove, 1, 0);
|
on_diff_ifn(DiffOp::Remove, 1);
|
||||||
|
|
||||||
on_diff_ifn(DiffOp::Keep, snake.u - snake.x, 0);
|
on_diff_ifn(DiffOp::Keep, snake.u - snake.x);
|
||||||
|
|
||||||
if (snake.op == Snake::RevAdd)
|
if (snake.op == Snake::RevAdd)
|
||||||
on_diff_ifn(DiffOp::Add, 1, begB + snake.v);
|
on_diff_ifn(DiffOp::Add, 1);
|
||||||
if (snake.op == Snake::RevDel)
|
if (snake.op == Snake::RevDel)
|
||||||
on_diff_ifn(DiffOp::Remove, 1, 0);
|
on_diff_ifn(DiffOp::Remove, 1);
|
||||||
|
|
||||||
find_diff_rec(a, begA + snake.u + (int)(snake.op == Snake::RevDel), endA,
|
find_diff_rec(a, begA + snake.u + (int)(snake.op == Snake::RevDel), endA,
|
||||||
b, begB + snake.v + (int)(snake.op == Snake::RevAdd), endB,
|
b, begB + snake.v + (int)(snake.op == Snake::RevAdd), endB,
|
||||||
V1, V2, cost_limit, eq, on_diff);
|
V1, V2, cost_limit, eq, on_diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
on_diff_ifn(DiffOp::Keep, suffix_len, 0);
|
on_diff_ifn(DiffOp::Keep, suffix_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Diff
|
struct Diff
|
||||||
{
|
{
|
||||||
DiffOp op;
|
DiffOp op;
|
||||||
int len;
|
int len;
|
||||||
int posB;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IteratorA, typename IteratorB, typename OnDiff, typename Equal = std::equal_to<>>
|
template<typename IteratorA, typename IteratorB, typename OnDiff, typename Equal = std::equal_to<>>
|
||||||
|
@ -181,18 +180,18 @@ void for_each_diff(IteratorA a, int N, IteratorB b, int M, OnDiff&& on_diff, Equ
|
||||||
|
|
||||||
Diff last{};
|
Diff last{};
|
||||||
find_diff_rec(a, 0, N, b, 0, M, &data[N+M], &data[max + N+M], cost_limit, eq,
|
find_diff_rec(a, 0, N, b, 0, M, &data[N+M], &data[max + N+M], cost_limit, eq,
|
||||||
[&last, &on_diff](DiffOp op, int len, int posB) {
|
[&last, &on_diff](DiffOp op, int len) {
|
||||||
if (last.op == op and (op != DiffOp::Add or last.posB + last.len == posB))
|
if (last.op == op)
|
||||||
last.len += len;
|
last.len += len;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (last.op != DiffOp{} or last.len != 0 or last.posB != 0)
|
if (last.len != 0)
|
||||||
on_diff(last.op, last.len, last.posB);
|
on_diff(last.op, last.len);
|
||||||
last = Diff{op, len, posB};
|
last = Diff{op, len};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (last.op != DiffOp{} or last.len != 0 or last.posB != 0)
|
if (last.op != DiffOp{} or last.len != 0)
|
||||||
on_diff(last.op, last.len, last.posB);
|
on_diff(last.op, last.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -517,16 +517,18 @@ BufferCoord apply_diff(Buffer& buffer, BufferCoord pos, StringView before, Strin
|
||||||
|
|
||||||
for_each_diff(lines_before.begin(), (int)lines_before.size(),
|
for_each_diff(lines_before.begin(), (int)lines_before.size(),
|
||||||
lines_after.begin(), (int)lines_after.size(),
|
lines_after.begin(), (int)lines_after.size(),
|
||||||
[&, posA = 0](DiffOp op, int len, int posB) mutable {
|
[&, posA = 0, posB = 0](DiffOp op, int len) mutable {
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case DiffOp::Keep:
|
case DiffOp::Keep:
|
||||||
pos = buffer.advance(pos, byte_count(lines_before, posA, len));
|
pos = buffer.advance(pos, byte_count(lines_before, posA, len));
|
||||||
posA += len;
|
posA += len;
|
||||||
|
posB += len;
|
||||||
break;
|
break;
|
||||||
case DiffOp::Add:
|
case DiffOp::Add:
|
||||||
pos = buffer.insert(pos, {lines_after[posB].begin(),
|
pos = buffer.insert(pos, {lines_after[posB].begin(),
|
||||||
lines_after[posB + len - 1].end()}).end;
|
lines_after[posB + len - 1].end()}).end;
|
||||||
|
posB += len;
|
||||||
break;
|
break;
|
||||||
case DiffOp::Remove:
|
case DiffOp::Remove:
|
||||||
pos = buffer.erase(pos, buffer.advance(pos, byte_count(lines_before, posA, len)));
|
pos = buffer.erase(pos, buffer.advance(pos, byte_count(lines_before, posA, len)));
|
||||||
|
|
|
@ -17,29 +17,29 @@ UnitTest test_utf8{[]()
|
||||||
|
|
||||||
UnitTest test_diff{[]()
|
UnitTest test_diff{[]()
|
||||||
{
|
{
|
||||||
struct Diff{DiffOp op; int len; int posB = 0;};
|
struct Diff{DiffOp op; int len;};
|
||||||
auto check_diff = [](StringView a, StringView b, std::initializer_list<Diff> diffs) {
|
auto check_diff = [](StringView a, StringView b, std::initializer_list<Diff> diffs) {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for_each_diff(a.begin(), (int)a.length(), b.begin(), (int)b.length(),
|
for_each_diff(a.begin(), (int)a.length(), b.begin(), (int)b.length(),
|
||||||
[&](DiffOp op, int len, int posB) {
|
[&](DiffOp op, int len) {
|
||||||
kak_assert(count < diffs.size());
|
kak_assert(count < diffs.size());
|
||||||
auto& d = diffs.begin()[count++];
|
auto& d = diffs.begin()[count++];
|
||||||
kak_assert(d.op == op and d.len == len and d.posB == posB);
|
kak_assert(d.op == op and d.len == len);
|
||||||
});
|
});
|
||||||
kak_assert(count == diffs.size());
|
kak_assert(count == diffs.size());
|
||||||
};
|
};
|
||||||
check_diff("a?", "!", {{DiffOp::Remove, 1}, {DiffOp::Add, 1}, {DiffOp::Remove, 1}});
|
check_diff("a?", "!", {{DiffOp::Remove, 1}, {DiffOp::Add, 1}, {DiffOp::Remove, 1}});
|
||||||
check_diff("abcde", "cd", {{DiffOp::Remove, 2}, {DiffOp::Keep, 2}, {DiffOp::Remove, 1}});
|
check_diff("abcde", "cd", {{DiffOp::Remove, 2}, {DiffOp::Keep, 2}, {DiffOp::Remove, 1}});
|
||||||
check_diff("abcd", "cdef", {{DiffOp::Remove, 2}, {DiffOp::Keep, 2}, {DiffOp::Add, 2, 2}});
|
check_diff("abcd", "cdef", {{DiffOp::Remove, 2}, {DiffOp::Keep, 2}, {DiffOp::Add, 2}});
|
||||||
|
|
||||||
check_diff("mais que fais la police", "mais ou va la police",
|
check_diff("mais que fais la police", "mais ou va la police",
|
||||||
{{DiffOp::Keep, 5}, {DiffOp::Remove, 1}, {DiffOp::Add, 1, 5}, {DiffOp::Keep, 1},
|
{{DiffOp::Keep, 5}, {DiffOp::Remove, 1}, {DiffOp::Add, 1}, {DiffOp::Keep, 1},
|
||||||
{DiffOp::Remove, 1}, {DiffOp::Keep, 1}, {DiffOp::Add, 1, 8}, {DiffOp::Remove, 1},
|
{DiffOp::Remove, 1}, {DiffOp::Keep, 1}, {DiffOp::Add, 1}, {DiffOp::Remove, 1},
|
||||||
{DiffOp::Keep, 1}, {DiffOp::Remove, 2}, {DiffOp::Keep, 10}} );
|
{DiffOp::Keep, 1}, {DiffOp::Remove, 2}, {DiffOp::Keep, 10}} );
|
||||||
|
|
||||||
check_diff("abcdefghijk", "1cdef2hij34",
|
check_diff("abcdefghijk", "1cdef2hij34",
|
||||||
{{DiffOp::Remove, 2}, {DiffOp::Add, 1, 0}, {DiffOp::Keep, 4}, {DiffOp::Remove, 1},
|
{{DiffOp::Remove, 2}, {DiffOp::Add, 1}, {DiffOp::Keep, 4}, {DiffOp::Remove, 1},
|
||||||
{DiffOp::Add, 1, 5}, {DiffOp::Keep, 3}, {DiffOp::Add, 2, 9}, {DiffOp::Remove, 1}});
|
{DiffOp::Add, 1}, {DiffOp::Keep, 3}, {DiffOp::Add, 2}, {DiffOp::Remove, 1}});
|
||||||
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user