Skip to content

Commit

Permalink
Use NSTextStorageDelegate instead of method swizzling
Browse files Browse the repository at this point in the history
  • Loading branch information
tomekzaw committed Oct 17, 2024
1 parent 0ea1e73 commit edce693
Show file tree
Hide file tree
Showing 16 changed files with 81 additions and 444 deletions.
8 changes: 4 additions & 4 deletions apple/MarkdownCommitHook.mm
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@
}

// apply markdown
auto newString = [utils parseMarkdown:nsAttributedString
withAttributes:defaultNSTextAttributes];
NSMutableAttributedString *newString = [nsAttributedString mutableCopy];
[utils applyFormatting:newString withDefaultTextAttributes:defaultNSTextAttributes];

// create a clone of the old TextInputState and update the
// attributed string box to point to the string with markdown
Expand Down Expand Up @@ -217,8 +217,8 @@
stateData.attributedStringBox);

// apply markdown
auto newString = [utils parseMarkdown:nsAttributedString
withAttributes:defaultNSTextAttributes];
NSMutableAttributedString *newString = [nsAttributedString mutableCopy];
[utils applyFormatting:newString withDefaultTextAttributes:defaultNSTextAttributes];

// create a clone of the old TextInputState and update the
// attributed string box to point to the string with markdown
Expand Down
74 changes: 28 additions & 46 deletions apple/MarkdownTextInputDecoratorView.mm
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
#import <React/RCTUITextField.h>
#import <React/RCTUITextView.h>
#import <React/RCTTextInputComponentView.h>
#import "react_native_assert.h"

#import <RNLiveMarkdown/MarkdownLayoutManager.h>
#import <RNLiveMarkdown/MarkdownTextInputDecoratorView.h>
#import <RNLiveMarkdown/RCTBackedTextFieldDelegateAdapter+Markdown.h>
#import <RNLiveMarkdown/RCTUITextView+Markdown.h>

#ifdef RCT_NEW_ARCH_ENABLED
#import <RNLiveMarkdown/RCTTextInputComponentView+Markdown.h>
#else
#import <RNLiveMarkdown/RCTBaseTextInputView+Markdown.h>
#endif /* RCT_NEW_ARCH_ENABLED */
#import <RNLiveMarkdown/MarkdownTextStorageDelegate.h>

#import <objc/runtime.h>

@implementation MarkdownTextInputDecoratorView {
RCTMarkdownUtils *_markdownUtils;
RCTMarkdownStyle *_markdownStyle;
#ifdef RCT_NEW_ARCH_ENABLED
__weak RCTTextInputComponentView *_textInput;
#else
__weak RCTBaseTextInputView *_textInput;
#endif /* RCT_NEW_ARCH_ENABLED */
__weak UIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
__weak RCTBackedTextFieldDelegateAdapter *_adapter;
MarkdownTextStorageDelegate *_markdownTextStorageDelegate;
__weak RCTUITextView *_textView;
}

Expand Down Expand Up @@ -51,26 +40,33 @@ - (void)didMoveToWindow {

#ifdef RCT_NEW_ARCH_ENABLED
react_native_assert([view isKindOfClass:[RCTTextInputComponentView class]] && "Previous sibling component is not an instance of RCTTextInputComponentView.");
_textInput = (RCTTextInputComponentView *)view;
_backedTextInputView = [_textInput valueForKey:@"_backedTextInputView"];
RCTTextInputComponentView *textInputComponentView = (RCTTextInputComponentView *)view;
UIView<RCTBackedTextInputViewProtocol> *backedTextInputView = [textInputComponentView valueForKey:@"_backedTextInputView"];
#else
react_native_assert([view isKindOfClass:[RCTBaseTextInputView class]] && "Previous sibling component is not an instance of RCTBaseTextInputView.");
_textInput = (RCTBaseTextInputView *)view;
_backedTextInputView = _textInput.backedTextInputView;
// TODO: implement on Paper
react_native_assert(false && "Not implemented on Paper yet");
#endif /* RCT_NEW_ARCH_ENABLED */

_markdownUtils = [[RCTMarkdownUtils alloc] init];
react_native_assert(_markdownStyle != nil);
[_markdownUtils setMarkdownStyle:_markdownStyle];

[_textInput setMarkdownUtils:_markdownUtils];
if ([_backedTextInputView isKindOfClass:[RCTUITextField class]]) {
RCTUITextField *textField = (RCTUITextField *)_backedTextInputView;
_adapter = [textField valueForKey:@"textInputDelegateAdapter"];
[_adapter setMarkdownUtils:_markdownUtils];
} else if ([_backedTextInputView isKindOfClass:[RCTUITextView class]]) {
_textView = (RCTUITextView *)_backedTextInputView;
[_textView setMarkdownUtils:_markdownUtils];
if ([backedTextInputView isKindOfClass:[RCTUITextField class]]) {
// TODO: implement for singleline input
react_native_assert(false && "Not implemented for singleline input yet");
} else if ([backedTextInputView isKindOfClass:[RCTUITextView class]]) {
_textView = (RCTUITextView *)backedTextInputView;

_markdownTextStorageDelegate = [[MarkdownTextStorageDelegate alloc] init];
_markdownTextStorageDelegate.markdownUtils = _markdownUtils;
_markdownTextStorageDelegate.textView = _textView;

// register delegate for future edits
_textView.textStorage.delegate = _markdownTextStorageDelegate;

// format initial value
[_textView.textStorage setAttributedString:_textView.attributedText];

NSLayoutManager *layoutManager = _textView.layoutManager; // switching to TextKit 1 compatibility mode

// Correct content height in TextKit 1 compatibility mode. (See https://github.com/Expensify/App/issues/41567)
Expand All @@ -90,14 +86,9 @@ - (void)didMoveToWindow {

- (void)willMoveToWindow:(UIWindow *)newWindow
{
if (_textInput != nil) {
[_textInput setMarkdownUtils:nil];
}
if (_adapter != nil) {
[_adapter setMarkdownUtils:nil];
}
if (_textView != nil) {
[_textView setMarkdownUtils:nil];
_textView.textStorage.delegate = nil;

if (_textView.layoutManager != nil && [object_getClass(_textView.layoutManager) isEqual:[MarkdownLayoutManager class]]) {
[_textView.layoutManager setValue:nil forKey:@"markdownUtils"];
object_setClass(_textView.layoutManager, [NSLayoutManager class]);
Expand All @@ -110,17 +101,8 @@ - (void)setMarkdownStyle:(RCTMarkdownStyle *)markdownStyle
_markdownStyle = markdownStyle;
[_markdownUtils setMarkdownStyle:markdownStyle];

if (_textView != nil) {
// We want to use `textStorage` for applying markdown when possible. Currently it's only available for UITextView
[_textView textDidChange];
} else {
// apply new styles
#ifdef RCT_NEW_ARCH_ENABLED
[_textInput _setAttributedString:_backedTextInputView.attributedText];
#else
[_textInput setAttributedText:_textInput.attributedText];
#endif /* RCT_NEW_ARCH_ENABLED */
}
// trigger reformatting
[_textView.textStorage setAttributedString:_textView.attributedText];
}

@end
15 changes: 15 additions & 0 deletions apple/MarkdownTextStorageDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import <UIKit/UIKit.h>
#import <React/RCTUITextView.h>
#import <RNLiveMarkdown/RCTMarkdownUtils.h>

NS_ASSUME_NONNULL_BEGIN

@interface MarkdownTextStorageDelegate : NSObject <NSTextStorageDelegate>

@property(nonatomic, nullable) RCTMarkdownUtils *markdownUtils;

@property(nonatomic, nullable, strong) RCTUITextView *textView;

@end

NS_ASSUME_NONNULL_END
15 changes: 15 additions & 0 deletions apple/MarkdownTextStorageDelegate.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import <RNLiveMarkdown/MarkdownTextStorageDelegate.h>

@implementation MarkdownTextStorageDelegate

- (void)textStorage:(NSTextStorage *)textStorage didProcessEditing:(NSTextStorageEditActions)editedMask range:(NSRange)editedRange changeInLength:(NSInteger)delta {
react_native_assert(_markdownUtils != nil);
react_native_assert(_textView != nil);
react_native_assert(_textView.defaultTextAttributes != nil);

[_markdownUtils applyFormatting:textStorage withDefaultTextAttributes:_textView.defaultTextAttributes];

// TODO: fix cursor position when adding newline after a blockquote (probably not here though)
}

@end
14 changes: 0 additions & 14 deletions apple/RCTBackedTextFieldDelegateAdapter+Markdown.h

This file was deleted.

43 changes: 0 additions & 43 deletions apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm

This file was deleted.

18 changes: 0 additions & 18 deletions apple/RCTBaseTextInputView+Markdown.h

This file was deleted.

101 changes: 0 additions & 101 deletions apple/RCTBaseTextInputView+Markdown.mm

This file was deleted.

2 changes: 1 addition & 1 deletion apple/RCTMarkdownUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) RCTMarkdownStyle *markdownStyle;
@property (nonatomic) NSMutableArray<NSDictionary *> *blockquoteRangesAndLevels;

- (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withAttributes:(nullable NSDictionary<NSAttributedStringKey, id>*)attributes;
- (void)applyFormatting:(nonnull NSMutableAttributedString *)attributedString withDefaultTextAttributes:(nonnull NSDictionary<NSAttributedStringKey,id> *)defaultTextAttributes;

@end

Expand Down
Loading

0 comments on commit edce693

Please sign in to comment.