Skip to content

Commit

Permalink
Batching fixup for reduced computation
Browse files Browse the repository at this point in the history
  • Loading branch information
harshad1 committed Aug 27, 2024
1 parent 1ca5698 commit 0d037ef
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ public HighlightingEditor(Context context, AttributeSet attrs) {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (_hlEnabled && _hl != null) {
_hl.fixup(start, before, count);
_textUnchangedWhileHighlighting.set(false);
_hl.fixup(start, before, count);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ public SyntaxHighlighterBase configure(@Nullable final Paint paint) {
* A class representing any span
*/
public static class SpanGroup implements Comparable<SpanGroup> {
int start, end;
int start, length;
final Object span;
final boolean isStatic;

SpanGroup(Object o, int s, int e) {
SpanGroup(Object o, int s, int l) {
span = o;
start = s;
end = e;
length = l;
isStatic = o instanceof UpdateLayout;
}

Expand All @@ -132,6 +132,7 @@ private static class ForceUpdateLayout implements UpdateLayout {
private final List<SpanGroup> _groups, _groupBuffer;
private final NavigableSet<Integer> _appliedDynamic;
private boolean _staticApplied = false;
private int _fixupAfter = -1, _fixupDelta = 0;

protected Spannable _spannable;
protected final AppSettings _appSettings;
Expand All @@ -141,7 +142,6 @@ public SyntaxHighlighterBase(final AppSettings as) {
_groups = new ArrayList<>();
_groupBuffer = new ArrayList<>();
_appliedDynamic = new TreeSet<>();

_layoutUpdater = new ForceUpdateLayout();
}

Expand Down Expand Up @@ -225,30 +225,63 @@ public SyntaxHighlighterBase fixup(final int start, final int before, final int
return fixup(start + before, count - before);
}

// Adjust all spans after a change in the text

/**
* Adjust all currently computed spans. Use to adjust spans after text edited.
* We internally buffer / batch these fixes for increased performance
*
* @param after Apply to spans with region starting after 'after'
* @param delta Apply to
* @return this
*/
public SyntaxHighlighterBase fixup(final int after, final int delta) {
for (int i = _groups.size() - 1; i >= 0; i--) {
final SpanGroup group = _groups.get(i);
// Very simple fixup. If the group is entirely after 'after', adjust it's region
if (group.start <= after) {
// We iterate backwards. As groups are sorted, if start is before after, can break out
break;
} else {
group.start += delta;
group.end += delta;
if (_fixupAfter == -1) {
_fixupAfter = after;
_fixupDelta = delta;
} else if (isFixupOverlap(after, delta)) {
_fixupAfter = Math.min(_fixupAfter, after);
_fixupDelta += delta;
} else {
applyFixup();
}
return this;
}

// Test if fixup region overlaps with the current fixup
private boolean isFixupOverlap(final int after, final int delta) {
return (after >= _fixupAfter && after <= _fixupAfter + Math.abs(_fixupDelta)) ||
(_fixupAfter >= after && _fixupAfter <= after + Math.abs(delta));
}

private SyntaxHighlighterBase applyFixup() {
if (_fixupAfter >= 0 && _fixupDelta != 0) {
for (int i = _groups.size() - 1; i >= 0; i--) {
final SpanGroup group = _groups.get(i);
// Very simple fixup. If the group is entirely after 'after', adjust it's region
if (group.start <= _fixupAfter) {
// We iterate backwards. As groups are sorted, if start is before after, can break out
break;
} else {
group.start += _fixupDelta;
}
}
clearFixup();
}
return this;
}

private void clearFixup() {
_fixupAfter = -1;
_fixupDelta = 0;
}

// The fixup logic offsets all spans after a certain point by a delta
// All spans after = (start + before) are offset by (count - before)
// If we are typing text or deleting text naturally, we can batch these changes
// The delta will be 1 or -1 for each character added or removed
// The start would move back if we are deleting text
// The delta would increase if we are adding text


public SyntaxHighlighterBase applyAll() {
return applyDynamic().applyStatic();
}
Expand All @@ -267,6 +300,8 @@ public SyntaxHighlighterBase applyDynamic(final int[] range) {
return this;
}

applyFixup();

final int length = _spannable.length();
for (int i = 0; i < _groups.size(); i++) {
final SpanGroup group = _groups.get(i);
Expand All @@ -280,9 +315,10 @@ public SyntaxHighlighterBase applyDynamic(final int[] range) {
break;
}

final boolean valid = group.start >= 0 && group.end > range[0] && group.end <= length;
final int end = group.start + group.length;
final boolean valid = group.start >= 0 && end > range[0] && end <= length;
if (valid && !_appliedDynamic.contains(i)) {
_spannable.setSpan(group.span, group.start, group.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
_spannable.setSpan(group.span, group.start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
_appliedDynamic.add(i);
}
}
Expand All @@ -295,9 +331,11 @@ public SyntaxHighlighterBase applyStatic() {
return this;
}

applyFixup();

for (final SpanGroup group : _groups) {
if (group.isStatic) {
_spannable.setSpan(group.span, group.start, group.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
_spannable.setSpan(group.span, group.start, group.start + group.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}

Expand Down Expand Up @@ -335,6 +373,7 @@ public final SyntaxHighlighterBase setComputed() {
_staticApplied = false;
_groups.addAll(_groupBuffer);
_groupBuffer.clear();
clearFixup();
return this;
}

Expand Down Expand Up @@ -370,7 +409,7 @@ public final SyntaxHighlighterBase compute() {

protected final void addSpanGroup(final Object span, final int start, final int end) {
if (end > start && span != null) {
_groupBuffer.add(new SpanGroup(span, start, end));
_groupBuffer.add(new SpanGroup(span, start, end - start));
}
}

Expand Down

0 comments on commit 0d037ef

Please sign in to comment.