Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 18 additions & 33 deletions richtextfx/src/main/java/org/fxmisc/richtext/model/TextChange.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,14 @@

public abstract class TextChange<S, Self extends TextChange<S, Self>> {

/**
* Indicates whether this change can be merged with another change if they are both {@link #INSERTION} or
* both {@link #DELETION}.
*/
public static enum MergeType {
/** Indicates that the change will insert something but not remove anything */
INSERTION,
/** Indicates that the change will delete something but not insert anything */
DELETION,
/** Indicates that the change is a style change, a replacement or something other than the other two types */
NONE,
}


protected final int position;
protected final S removed;
protected final S inserted;
protected final MergeType mergeType;

public TextChange(int position, S removed, S inserted) {
this.position = position;
this.removed = removed;
this.inserted = inserted;

if (insertedLength() == 0) {
mergeType = removedLength() != 0
? MergeType.DELETION
: MergeType.NONE;
} else if (removedLength() == 0) {
mergeType = MergeType.INSERTION;
} else {
mergeType = MergeType.NONE;
}
}

public int getPosition() { return position; };
Expand All @@ -46,7 +21,6 @@ public TextChange(int position, S removed, S inserted) {
public Self invert() { return create(position, inserted, removed); }
public int getRemovalEnd() { return position + removedLength(); }
public int getInsertionEnd() { return position + insertedLength(); }
public final MergeType getMergeType() { return mergeType; };

protected abstract int removedLength();
protected abstract int insertedLength();
Expand All @@ -63,20 +37,32 @@ public final boolean isIdentity() {
}

/**
* Merges this change with the given change only if the end of this change's inserted text equals the
* latter's position and both are either {@link MergeType#INSERTION} or {@link MergeType#DELETION} changes.
*
* Merges this change with the given change, if possible.
* This change is considered to be the former and the given
* change is considered to be the latter.
* Changes can be merged if either
* <ul>
* <li>the latter's start matches the former's added text end; or</li>
* <li>the latter's removed text end matches the former's added text end.</li>
* </ul>
* @param latter change to merge with this change.
* @return a new merged change if changes can be merged,
* {@code null} otherwise.
*/
public Optional<Self> mergeWith(Self latter) {
if((this.mergeType == MergeType.INSERTION || this.mergeType == MergeType.DELETION)
&& this.mergeType == latter.mergeType
&& this.getInsertionEnd() == latter.position) {
if(latter.position == this.position + this.insertedLength()) {
S removedText = concat(this.removed, latter.removed);
S addedText = concat(this.inserted, latter.inserted);
return Optional.of(create(this.position, removedText, addedText));
} else if(latter.position + latter.removedLength() == this.position + this.insertedLength()) {
if(this.position <= latter.position) {
S addedText = concat(sub(this.inserted, 0, latter.position - this.position), latter.inserted);
return Optional.of(create(this.position, this.removed, addedText));
}
else {
S removedText = concat(sub(latter.removed, 0, this.position - latter.position), this.removed);
return Optional.of(create(latter.position, removedText, latter.inserted));
}
} else {
return Optional.empty();
}
Expand Down Expand Up @@ -104,7 +90,6 @@ public final String toString() {
return
this.getClass().getSimpleName() + "{\n" +
"\tposition: " + position + "\n" +
"\tmergeType: " + mergeType + "\n" +
"\tremoved: " + removed + "\n" +
"\tinserted: " + inserted + "\n" +
"}";
Expand Down