Skip to content

Commit

Permalink
Added check to ensure newlines around block attachments are preserved
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdeep committed Jun 28, 2024
1 parent 293aec2 commit 31ee1a4
Showing 1 changed file with 79 additions and 3 deletions.
82 changes: 79 additions & 3 deletions Proton/Sources/ObjC/PRTextStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,27 @@ - (void)replaceCharactersInRange:(NSRange)range withAttributedString:(NSAttribut
// Out of bounds
return;
}

NSMutableAttributedString *replacementString = [attrString mutableCopy];
NSAttributedString *substring = [self attributedSubstringFromRange:range];

if (range.location > 0
&& [self attributedStringHasNewline:substring atStart:NO]
&& [self isCharacterAdjacentToRangeAnAttachment:self range:range checkBefore:NO]) {
replacementString = [self appendNewlineToAttributedString:[attrString mutableCopy] atStart:NO];
}

if (range.location > 0
&& [self attributedStringHasNewline:substring atStart:YES]
&& [self isCharacterAdjacentToRangeAnAttachment:self range:range checkBefore:YES]) {
replacementString = [self appendNewlineToAttributedString:[attrString mutableCopy] atStart:YES];
}

// Fix any missing attribute that is in the location being replaced, but not in the text that
// is coming in.
if (range.length > 0 && attrString.length > 0) {
if (range.length > 0 && replacementString.length > 0) {
NSDictionary<NSAttributedStringKey, id> *outgoingAttrs = [_storage attributesAtIndex:(range.location + range.length - 1) effectiveRange:nil];
NSDictionary<NSAttributedStringKey, id> *incomingAttrs = [attrString attributesAtIndex:0 effectiveRange:nil];
NSDictionary<NSAttributedStringKey, id> *incomingAttrs = [replacementString attributesAtIndex:0 effectiveRange:nil];

NSMutableDictionary<NSAttributedStringKey, id> *diff = [NSMutableDictionary dictionary];
for (NSAttributedStringKey outgoingKey in outgoingAttrs) {
Expand Down Expand Up @@ -215,6 +229,68 @@ - (void)removeAttribute:(NSAttributedStringKey)name range:(NSRange)range {

#pragma mark - Private

- (NSMutableAttributedString *)appendNewlineToAttributedString:(NSMutableAttributedString *)attributedString atStart:(BOOL)appendAtStart {
if (attributedString.length == 0) {
return [[NSMutableAttributedString alloc] initWithString:@"\n"]; // Return just a newline if the original string is empty.
}

// Create a new NSAttributedString with the newline character.
NSAttributedString *newlineAttributedString = [[NSAttributedString alloc] initWithString:@"\n"];

// Create a mutable copy of the original attributed string.
NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];

if (appendAtStart) {
// Append the attributed newline at the start.
[mutableAttributedString insertAttributedString:newlineAttributedString atIndex:0];
} else {
// Append the attributed newline at the end.
[mutableAttributedString appendAttributedString:newlineAttributedString];
}

return mutableAttributedString;
}

- (BOOL) attributedStringHasNewline:(NSAttributedString *) attributedString atStart: (BOOL)atStart {
NSString *string = [attributedString string];
if (string.length == 0) {
return NO;
}

unichar characterToVerify = [string characterAtIndex: 0];
if (atStart == NO) {
characterToVerify = [string characterAtIndex:string.length - 1];
}

return [[NSCharacterSet newlineCharacterSet] characterIsMember:characterToVerify];
}

-(BOOL) isCharacterAdjacentToRangeAnAttachment: (NSAttributedString *) attributedString range: (NSRange) range checkBefore: (BOOL) checkBefore {
NSUInteger positionToCheck;

if (checkBefore) {
if (range.location == 0) {
return NO; // No character before the start of the string
}
positionToCheck = range.location - 1;
} else {
positionToCheck = NSMaxRange(range);
if (positionToCheck >= attributedString.length) {
return NO; // No character after the end of the string
}
}

// Retrieve the attributes at the position to check
NSDictionary *attributes = [attributedString attributesAtIndex:positionToCheck effectiveRange:NULL];

// Check if these attributes contain the NSAttachmentAttributeName
if ([attributes objectForKey:@"_isBlockAttachment"] != nil) {
return YES; // There is an attachment
}

return NO; // No attachment found
}

- (void)fixMissingAttributesForDeletedAttributes:(NSArray<NSAttributedStringKey> *)attrs range:(NSRange)range {
if ((range.location + range.length) > _storage.length) {
// Out of bounds
Expand Down

0 comments on commit 31ee1a4

Please sign in to comment.