Skip to content

Commit

Permalink
Insert/Append text should use existing decoration (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhinayagarwal authored Feb 23, 2022
1 parent 3e45f56 commit 77fd317
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
21 changes: 13 additions & 8 deletions src/main/java/com/gluonhq/richtext/model/PieceTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ public void resetCharacterIterator() {
}

// internal append
Piece appendTextInternal(String text) {
Piece appendTextInternal(String text, TextDecoration decoration) {
int pos = additionBuffer.length();
additionBuffer += text;
textLengthProperty.set(getTextLength() + text.length());
return piece(Piece.BufferType.ADDITION, pos, text.length());
return new Piece(this, Piece.BufferType.ADDITION, pos, text.length(), decoration);
}

/**
Expand Down Expand Up @@ -208,6 +208,10 @@ static boolean inRange( int index, int start, int length ) {
return index >= start && index < start+length;
}

TextDecoration previousPieceDecoration(int index) {
return pieces.isEmpty() ? TextDecoration.builder().presets().build() : pieces.get(index > 0 ? index - 1 : 0).getDecoration();
}

@Override
public String toString() {
String p = pieces.stream().map(piece -> " - " + piece.toString()).collect(Collectors.joining("\n", "\n", ""));
Expand Down Expand Up @@ -374,7 +378,7 @@ protected void doUndo(PieceTable pt) {
protected void doRedo(PieceTable pt) {
if (!text.isEmpty()) {
int pos = pt.getTextLength();
newPiece = pt.appendTextInternal(text);
newPiece = pt.appendTextInternal(text, pt.previousPieceDecoration(pt.pieces.size()));
pt.pieces.add(newPiece);
pt.fire( new TextBuffer.InsertEvent(text, pos));
execSuccess = true;
Expand Down Expand Up @@ -422,19 +426,20 @@ protected void doRedo(PieceTable pt) {
pt.append(text);
} else {
pt.walkPieces((piece, pieceIndex, textPosition) -> {
if ( PieceTable.inRange(insertPosition, textPosition, piece.length)) {
if (PieceTable.inRange(insertPosition, textPosition, piece.length)) {
int pieceOffset = insertPosition - textPosition;
newPieces = PieceTable.normalize( List.of(
final TextDecoration decoration = pieceOffset > 0 ? piece.getDecoration() : pt.previousPieceDecoration(pieceIndex);
newPieces = PieceTable.normalize(List.of(
piece.pieceBefore(pieceOffset),
pt.appendTextInternal(text),
pt.appendTextInternal(text, decoration),
piece.pieceFrom(pieceOffset)
));
oldPiece = piece;
pt.pieces.addAll( pieceIndex, newPieces );
pt.pieces.addAll(pieceIndex, newPieces);
pt.pieces.remove(oldPiece);
opPieceIndex = pieceIndex;

pt.fire( new TextBuffer.InsertEvent(text, insertPosition));
pt.fire(new TextBuffer.InsertEvent(text, insertPosition));
execSuccess = true;
return true;
}
Expand Down
46 changes: 46 additions & 0 deletions src/test/java/com/gluonhq/richtext/model/PieceTableTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -447,4 +447,50 @@ public void multiBlockDecorateSizeAndColor() {
);
}

@Test
@DisplayName("Appended text should use existing decoration")
public void textAppendDecoration() {
String appended = " and some";
PieceTable pt = new PieceTable(originalText);
pt.decorate(0, originalText.length(), TextDecoration.builder().fontSize(20).build());
pt.append(appended);
Assertions.assertEquals(originalText+appended, pt.getText());
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getText().equals(appended))
.anyMatch(piece -> piece.getDecoration().getFontSize() == 20));
}

@Test
@DisplayName("Inserted text after decorated text")
public void textInsertAfterDecoration() {
String insert = "Bigger ";
PieceTable pt = new PieceTable(originalText);
pt.decorate(0, originalText.length(), TextDecoration.builder().fontSize(20).build());
pt.insert(insert, 9); // "Original Bigger Text"
Assertions.assertEquals(
new StringBuilder(originalText).insert(9, insert).toString(),
pt.getText()
);
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getText().equals(insert))
.anyMatch(piece -> piece.getDecoration().getFontSize() == 20));
}

@Test
@DisplayName("Inserted text after default decorated text")
public void textInsertAfterDefaultDecoratedText() {
String insert = "Bigger";
PieceTable pt = new PieceTable(originalText);
double defaultFontSize = TextDecoration.builder().presets().build().getFontSize();
pt.decorate(0, 8, TextDecoration.builder().fontSize(20).build());
pt.insert(insert, 11); // "Original TeBiggerxt"
Assertions.assertEquals(
new StringBuilder(originalText).insert(11, insert).toString(),
pt.getText()
);
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getText().equals(insert))
.anyMatch(piece -> piece.getDecoration().getFontSize() == defaultFontSize));
}

}

0 comments on commit 77fd317

Please sign in to comment.