From 7d32953b9d77831750c049e777e48b7d53ab431d Mon Sep 17 00:00:00 2001 From: JacobCXDev Date: Thu, 26 Mar 2020 05:06:53 +0000 Subject: [PATCH 1/2] SyntaxHighlighting started? See commit description. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Working: @property Not working: Everything else! Also, there's a crash (which currently has a workaround implemented) in FLEXMetadataSection.m — see the FIXME. --- .../FLEXFilteringTableViewController.m | 2 +- Classes/Core/FLEXSingleRowSection.m | 14 +-- Classes/Core/FLEXTableViewSection.h | 8 +- Classes/Core/FLEXTableViewSection.m | 17 +-- .../Editing/FLEXDefaultEditorViewController.m | 3 +- Classes/Editing/FLEXFieldEditorView.h | 2 +- Classes/Editing/FLEXFieldEditorView.m | 4 +- .../Editing/FLEXFieldEditorViewController.m | 7 +- .../Editing/FLEXMethodCallingViewController.m | 7 +- .../Bookmarks/FLEXBookmarksViewController.m | 2 +- Classes/FLEX-Categories.h | 2 + .../FLEXObjectListViewController.m | 4 +- Classes/GlobalStateExplorers/FLEXObjectRef.h | 2 +- Classes/GlobalStateExplorers/FLEXObjectRef.m | 2 +- Classes/ObjectExplorers/FLEXObjectExplorer.h | 2 +- Classes/ObjectExplorers/FLEXObjectExplorer.m | 21 ++-- .../FLEXObjectExplorerViewController.m | 16 ++- .../Sections/FLEXCollectionContentSection.m | 14 +-- .../Sections/FLEXMetadataSection.m | 19 +-- .../Sections/Shortcuts/FLEXBlockShortcuts.m | 6 +- .../Sections/Shortcuts/FLEXBundleShortcuts.m | 3 +- .../Sections/Shortcuts/FLEXClassShortcuts.m | 10 +- .../Sections/Shortcuts/FLEXLayerShortcuts.m | 3 +- .../Sections/Shortcuts/FLEXShortcut.h | 12 +- .../Sections/Shortcuts/FLEXShortcut.m | 34 +++--- .../Sections/Shortcuts/FLEXShortcutsSection.h | 6 +- .../Sections/Shortcuts/FLEXShortcutsSection.m | 34 +++--- .../Shortcuts/FLEXViewControllerShortcuts.m | 6 +- .../Sections/Shortcuts/FLEXViewShortcuts.m | 6 +- .../Categories/FLEXRuntime+UIKitHelpers.h | 8 +- .../Categories/FLEXRuntime+UIKitHelpers.m | 58 ++++----- .../Categories/NSAttributedString+FLEX.h | 16 +++ .../Categories/NSAttributedString+FLEX.m | 66 +++++++++++ .../Categories/NSDictionary+ObjcRuntime.h | 2 +- .../Categories/NSDictionary+ObjcRuntime.m | 77 +++++++----- .../NSMutableAttributedString+FLEX.h | 14 +++ .../NSMutableAttributedString+FLEX.m | 25 ++++ .../Categories/NSObject+SyntaxHighlighting.h | 15 +++ .../Categories/NSObject+SyntaxHighlighting.m | 18 +++ .../Categories/NSString+SyntaxHighlighting.h | 41 +++++++ .../Categories/NSString+SyntaxHighlighting.m | 99 ++++++++++++++++ Classes/Utility/FLEXColor.h | 29 +++++ Classes/Utility/FLEXColor.m | 110 ++++++++++++++++++ Classes/Utility/FLEXUtility.h | 4 +- Classes/Utility/FLEXUtility.m | 9 +- Classes/Utility/Runtime/FLEXRuntimeUtility.h | 6 +- Classes/Utility/Runtime/FLEXRuntimeUtility.m | 37 +++--- .../Objc/Reflection/FLEXClassBuilder.m | 7 ++ .../Runtime/Objc/Reflection/FLEXIvar.m | 6 +- .../Runtime/Objc/Reflection/FLEXMethod.m | 34 +++--- .../Runtime/Objc/Reflection/FLEXMethodBase.h | 2 +- .../Runtime/Objc/Reflection/FLEXMethodBase.m | 12 +- .../Runtime/Objc/Reflection/FLEXProperty.h | 2 +- .../Runtime/Objc/Reflection/FLEXProperty.m | 45 ++++--- .../Objc/Reflection/FLEXPropertyAttributes.h | 7 +- .../Objc/Reflection/FLEXPropertyAttributes.m | 54 ++++++--- .../Runtime/Objc/Reflection/FLEXProtocol.m | 21 ++++ .../Objc/Reflection/FLEXProtocolBuilder.m | 7 ++ FLEX.xcodeproj/project.pbxproj | 34 +++++- .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++ 60 files changed, 867 insertions(+), 274 deletions(-) create mode 100644 Classes/Utility/Categories/NSAttributedString+FLEX.h create mode 100644 Classes/Utility/Categories/NSAttributedString+FLEX.m create mode 100644 Classes/Utility/Categories/NSMutableAttributedString+FLEX.h create mode 100644 Classes/Utility/Categories/NSMutableAttributedString+FLEX.m create mode 100644 Classes/Utility/Categories/NSObject+SyntaxHighlighting.h create mode 100644 Classes/Utility/Categories/NSObject+SyntaxHighlighting.m create mode 100644 Classes/Utility/Categories/NSString+SyntaxHighlighting.h create mode 100644 Classes/Utility/Categories/NSString+SyntaxHighlighting.m create mode 100644 FLEX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/Classes/Core/Controllers/FLEXFilteringTableViewController.m b/Classes/Core/Controllers/FLEXFilteringTableViewController.m index 69f1a049d1..33b8467468 100644 --- a/Classes/Core/Controllers/FLEXFilteringTableViewController.m +++ b/Classes/Core/Controllers/FLEXFilteringTableViewController.m @@ -182,7 +182,7 @@ - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexP - (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point __IOS_AVAILABLE(13.0) { FLEXTableViewSection *section = self.filterDelegate.sections[indexPath.section]; - NSString *title = [section menuTitleForRow:indexPath.row]; + NSString *title = [section menuTitleForRow:indexPath.row].string; NSArray *menuItems = [section menuItemsForRow:indexPath.row sender:self]; if (menuItems.count) { diff --git a/Classes/Core/FLEXSingleRowSection.m b/Classes/Core/FLEXSingleRowSection.m index 95f557e8a4..6d56ee1641 100644 --- a/Classes/Core/FLEXSingleRowSection.m +++ b/Classes/Core/FLEXSingleRowSection.m @@ -13,8 +13,8 @@ @interface FLEXSingleRowSection () @property (nonatomic, readonly) NSString *reuseIdentifier; @property (nonatomic, readonly) void (^cellConfiguration)(__kindof UITableViewCell *cell); -@property (nonatomic) NSString *lastTitle; -@property (nonatomic) NSString *lastSubitle; +@property (nonatomic) NSAttributedString *lastTitle; +@property (nonatomic) NSAttributedString *lastSubtitle; @end @implementation FLEXSingleRowSection @@ -72,16 +72,16 @@ - (void)configureCell:(__kindof UITableViewCell *)cell forRow:(NSInteger)row { cell.accessoryType = UITableViewCellAccessoryNone; self.cellConfiguration(cell); - self.lastTitle = cell.textLabel.text; - self.lastSubitle = cell.detailTextLabel.text; + self.lastTitle = cell.textLabel.attributedText; + self.lastSubtitle = cell.detailTextLabel.attributedText; } -- (NSString *)titleForRow:(NSInteger)row { +- (NSAttributedString *)titleForRow:(NSInteger)row { return self.lastTitle; } -- (NSString *)subtitleForRow:(NSInteger)row { - return self.lastSubitle; +- (NSAttributedString *)subtitleForRow:(NSInteger)row { + return self.lastSubtitle; } @end diff --git a/Classes/Core/FLEXTableViewSection.h b/Classes/Core/FLEXTableViewSection.h index 4c3f7599a4..e313de3e80 100644 --- a/Classes/Core/FLEXTableViewSection.h +++ b/Classes/Core/FLEXTableViewSection.h @@ -90,13 +90,13 @@ NS_ASSUME_NONNULL_BEGIN /// By default, this is the title of the row. /// @return The title of the context menu, if any. -- (nullable NSString *)menuTitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); +- (nullable NSAttributedString *)menuTitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); /// Protected, not intended for public use. \c menuTitleForRow: /// already includes the value returned from this method. /// /// By default, this returns \c @"". Subclasses may override to /// provide a detailed description of the target of the context menu. -- (NSString *)menuSubtitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); +- (NSAttributedString *)menuSubtitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); /// The context menu items, if any. Subclasses may override. /// By default, only inludes items for \c copyMenuItemsForRow:. - (nullable NSArray *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13.0)); @@ -124,10 +124,10 @@ NS_ASSUME_NONNULL_BEGIN /// For use by whatever view controller uses your section. Not required. /// @return An optional title. -- (nullable NSString *)titleForRow:(NSInteger)row; +- (nullable NSAttributedString *)titleForRow:(NSInteger)row; /// For use by whatever view controller uses your section. Not required. /// @return An optional subtitle. -- (nullable NSString *)subtitleForRow:(NSInteger)row; +- (nullable NSAttributedString *)subtitleForRow:(NSInteger)row; @end diff --git a/Classes/Core/FLEXTableViewSection.m b/Classes/Core/FLEXTableViewSection.m index 9090f99e6d..8e12899a62 100644 --- a/Classes/Core/FLEXTableViewSection.m +++ b/Classes/Core/FLEXTableViewSection.m @@ -10,6 +10,7 @@ #import "FLEXTableView.h" #import "FLEXUtility.h" #import "UIMenu+FLEX.h" +#import "NSString+SyntaxHighlighting.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-implementation" @@ -53,19 +54,19 @@ - (NSString *)reuseIdentifierForRow:(NSInteger)row { #if FLEX_AT_LEAST_IOS13_SDK -- (NSString *)menuTitleForRow:(NSInteger)row { - NSString *title = [self titleForRow:row]; - NSString *subtitle = [self menuSubtitleForRow:row]; +- (NSAttributedString *)menuTitleForRow:(NSInteger)row { + NSAttributedString *title = [self titleForRow:row]; + NSAttributedString *subtitle = [self menuSubtitleForRow:row]; if (subtitle.length) { - return [NSString stringWithFormat:@"%@\n\n%@", title, subtitle]; + return [NSString stringWithFormat:@"%@\n\n%@", title, subtitle].attributedString; } return title; } -- (NSString *)menuSubtitleForRow:(NSInteger)row { - return @""; +- (NSAttributedString *)menuSubtitleForRow:(NSInteger)row { + return @"".attributedString; } - (NSArray *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13)) { @@ -120,8 +121,8 @@ - (NSString *)menuSubtitleForRow:(NSInteger)row { return nil; } -- (NSString *)titleForRow:(NSInteger)row { return nil; } -- (NSString *)subtitleForRow:(NSInteger)row { return nil; } +- (NSAttributedString *)titleForRow:(NSInteger)row { return nil; } +- (NSAttributedString *)subtitleForRow:(NSInteger)row { return nil; } @end diff --git a/Classes/Editing/FLEXDefaultEditorViewController.m b/Classes/Editing/FLEXDefaultEditorViewController.m index 739aa988ba..484c582436 100644 --- a/Classes/Editing/FLEXDefaultEditorViewController.m +++ b/Classes/Editing/FLEXDefaultEditorViewController.m @@ -11,6 +11,7 @@ #import "FLEXRuntimeUtility.h" #import "FLEXArgumentInputView.h" #import "FLEXArgumentInputViewFactory.h" +#import "NSString+SyntaxHighlighting.h" @interface FLEXDefaultEditorViewController () @@ -37,7 +38,7 @@ - (NSUserDefaults *)defaults { - (void)viewDidLoad { [super viewDidLoad]; - self.fieldEditorView.fieldDescription = self.key; + self.fieldEditorView.fieldDescription = self.key.attributedString; id currentValue = [self.defaults objectForKey:self.key]; FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory diff --git a/Classes/Editing/FLEXFieldEditorView.h b/Classes/Editing/FLEXFieldEditorView.h index 1345805af3..7ea9479b11 100644 --- a/Classes/Editing/FLEXFieldEditorView.h +++ b/Classes/Editing/FLEXFieldEditorView.h @@ -13,7 +13,7 @@ @interface FLEXFieldEditorView : UIView @property (nonatomic, copy) NSString *targetDescription; -@property (nonatomic, copy) NSString *fieldDescription; +@property (nonatomic, copy) NSAttributedString *fieldDescription; @property (nonatomic, copy) NSArray *argumentInputViews; diff --git a/Classes/Editing/FLEXFieldEditorView.m b/Classes/Editing/FLEXFieldEditorView.m index 5295261e1b..3bf4ff9ac0 100644 --- a/Classes/Editing/FLEXFieldEditorView.m +++ b/Classes/Editing/FLEXFieldEditorView.m @@ -90,10 +90,10 @@ - (void)setTargetDescription:(NSString *)targetDescription { } } -- (void)setFieldDescription:(NSString *)fieldDescription { +- (void)setFieldDescription:(NSAttributedString *)fieldDescription { if (![_fieldDescription isEqual:fieldDescription]) { _fieldDescription = fieldDescription; - self.fieldDescriptionLabel.text = fieldDescription; + self.fieldDescriptionLabel.attributedText = fieldDescription; [self setNeedsLayout]; } } diff --git a/Classes/Editing/FLEXFieldEditorViewController.m b/Classes/Editing/FLEXFieldEditorViewController.m index 7a5db17de3..343fce14c6 100644 --- a/Classes/Editing/FLEXFieldEditorViewController.m +++ b/Classes/Editing/FLEXFieldEditorViewController.m @@ -14,6 +14,7 @@ #import "FLEXUtility.h" #import "FLEXColor.h" #import "UIBarButtonItem+FLEX.h" +#import "NSString+SyntaxHighlighting.h" @interface FLEXFieldEditorViewController () @@ -22,7 +23,7 @@ @interface FLEXFieldEditorViewController () @property (nonatomic, readonly) id currentValue; @property (nonatomic, readonly) const FLEXTypeEncoding *typeEncoding; -@property (nonatomic, readonly) NSString *fieldDescription; +@property (nonatomic, readonly) NSAttributedString *fieldDescription; @end @@ -142,11 +143,11 @@ - (const FLEXTypeEncoding *)typeEncoding { } } -- (NSString *)fieldDescription { +- (NSAttributedString *)fieldDescription { if (self.property) { return self.property.fullDescription; } else { - return self.ivar.description; + return self.ivar.description.attributedString; } } diff --git a/Classes/Editing/FLEXMethodCallingViewController.m b/Classes/Editing/FLEXMethodCallingViewController.m index cc4a3eb44b..3165b3b0b6 100644 --- a/Classes/Editing/FLEXMethodCallingViewController.m +++ b/Classes/Editing/FLEXMethodCallingViewController.m @@ -14,6 +14,8 @@ #import "FLEXArgumentInputView.h" #import "FLEXArgumentInputViewFactory.h" #import "FLEXUtility.h" +#import "NSAttributedString+FLEX.h" +#import "NSString+SyntaxHighlighting.h" @interface FLEXMethodCallingViewController () @property (nonatomic) FLEXMethod *method; @@ -45,10 +47,7 @@ - (void)viewDidLoad { // Configure field editor view self.fieldEditorView.argumentInputViews = [self argumentInputViews]; - self.fieldEditorView.fieldDescription = [NSString stringWithFormat: - @"Signature:\n%@\n\nReturn Type:\n%s", - self.method.description, (char *)self.method.returnType - ]; + self.fieldEditorView.fieldDescription = [NSAttributedString stringWithFormat:@"Signature:\n%@\n\nReturn Type:\n%s", self.method.description, [NSString stringWithFormat:@"%s", (char *)self.method.returnType].attributedString]; } - (NSArray *)argumentInputViews { diff --git a/Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.m b/Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.m index 85af331dcc..8a4a5b96c5 100644 --- a/Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.m +++ b/Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.m @@ -186,7 +186,7 @@ - (UITableViewCell *)tableView:(FLEXTableView *)tableView cellForRowAtIndexPath: UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kFLEXDetailCell forIndexPath:indexPath]; id object = self.bookmarks[indexPath.row]; - cell.textLabel.text = [FLEXRuntimeUtility safeDescriptionForObject:object]; + cell.textLabel.attributedText = [FLEXRuntimeUtility safeDescriptionForObject:object]; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ — %p", [object class], object]; return cell; diff --git a/Classes/FLEX-Categories.h b/Classes/FLEX-Categories.h index fe534539c7..d825771d43 100644 --- a/Classes/FLEX-Categories.h +++ b/Classes/FLEX-Categories.h @@ -25,3 +25,5 @@ #import #import #import +#import +#import diff --git a/Classes/GlobalStateExplorers/FLEXObjectListViewController.m b/Classes/GlobalStateExplorers/FLEXObjectListViewController.m index e6ae8f3255..89866a2065 100644 --- a/Classes/GlobalStateExplorers/FLEXObjectListViewController.m +++ b/Classes/GlobalStateExplorers/FLEXObjectListViewController.m @@ -229,10 +229,10 @@ - (FLEXMutableListSection *)makeSection:(NSArray *)rows title:(NSString *)title FLEXMutableListSection *section = [FLEXMutableListSection list:rows cellConfiguration:^(FLEXTableViewCell *cell, FLEXObjectRef *ref, NSInteger row) { cell.textLabel.text = ref.reference; - cell.detailTextLabel.text = ref.summary; + cell.detailTextLabel.attributedText = ref.summary; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } filterMatcher:^BOOL(NSString *filterText, FLEXObjectRef *ref) { - if (ref.summary && [ref.summary localizedCaseInsensitiveContainsString:filterText]) { + if (ref.summary && [ref.summary.string localizedCaseInsensitiveContainsString:filterText]) { return YES; } diff --git a/Classes/GlobalStateExplorers/FLEXObjectRef.h b/Classes/GlobalStateExplorers/FLEXObjectRef.h index 3a9e225804..f8d6bc2bfb 100644 --- a/Classes/GlobalStateExplorers/FLEXObjectRef.h +++ b/Classes/GlobalStateExplorers/FLEXObjectRef.h @@ -21,7 +21,7 @@ @property (nonatomic, readonly) NSString *reference; /// For instances, this is the result of -[FLEXRuntimeUtility summaryForObject:] /// For classes, there is no summary. -@property (nonatomic, readonly) NSString *summary; +@property (nonatomic, readonly) NSAttributedString *summary; @property (nonatomic, readonly) id object; @end diff --git a/Classes/GlobalStateExplorers/FLEXObjectRef.m b/Classes/GlobalStateExplorers/FLEXObjectRef.m index 67c5822bdb..cd52faa2af 100644 --- a/Classes/GlobalStateExplorers/FLEXObjectRef.m +++ b/Classes/GlobalStateExplorers/FLEXObjectRef.m @@ -60,7 +60,7 @@ - (id)initWithObject:(id)object ivarName:(NSString *)ivar showSummary:(BOOL)show return self; } -- (NSString *)summary { +- (NSAttributedString *)summary { if (self.wantsSummary) { if (!_summary) { _summary = [FLEXRuntimeUtility summaryForObject:self.object]; diff --git a/Classes/ObjectExplorers/FLEXObjectExplorer.h b/Classes/ObjectExplorers/FLEXObjectExplorer.h index 0995e4dd92..0e75c5a075 100644 --- a/Classes/ObjectExplorers/FLEXObjectExplorer.h +++ b/Classes/ObjectExplorers/FLEXObjectExplorer.h @@ -14,7 +14,7 @@ @property (nonatomic, readonly) id object; /// Subclasses can override to provide a more useful description -@property (nonatomic, readonly) NSString *objectDescription; +@property (nonatomic, readonly) NSAttributedString *objectDescription; /// @return \c YES if \c object is an instance of a class, /// or \c NO if \c object is a class itself. diff --git a/Classes/ObjectExplorers/FLEXObjectExplorer.m b/Classes/ObjectExplorers/FLEXObjectExplorer.m index 8d56c90b24..4675266f50 100644 --- a/Classes/ObjectExplorers/FLEXObjectExplorer.m +++ b/Classes/ObjectExplorers/FLEXObjectExplorer.m @@ -16,6 +16,7 @@ #import "NSObject+Reflection.h" #import "FLEXMetadataSection.h" #import "NSUserDefaults+FLEX.h" +#import "NSAttributedString+FLEX.h" @interface FLEXObjectExplorer () { NSMutableArray *> *_allProperties; @@ -26,7 +27,7 @@ @interface FLEXObjectExplorer () { NSMutableArray *> *_allConformedProtocols; NSMutableArray *_allInstanceSizes; NSMutableArray *_allImageNames; - NSString *_objectDescription; + NSAttributedString *_objectDescription; } @end @@ -55,7 +56,7 @@ - (id)initWithObject:(id)objectOrClass { #pragma mark - Public -- (NSString *)objectDescription { +- (NSAttributedString *)objectDescription { if (!_objectDescription) { // Hard-code UIColor description if ([self.object isKindOfClass:[UIColor class]]) { @@ -63,21 +64,21 @@ - (NSString *)objectDescription { [self.object getRed:&r green:&g blue:&b alpha:&a]; [self.object getHue:&h saturation:&s brightness:&l alpha:nil]; - return [NSString stringWithFormat: - @"HSL: (%.3f, %.3f, %.3f)\nRGB: (%.3f, %.3f, %.3f)\nAlpha: %.3f", - h, s, l, r, g, b, a - ]; + NSAttributedString *rString = [NSAttributedString stringWithAttributes:@{ NSForegroundColorAttributeName: UIColor.redColor } format:@"%.3f", r]; + NSAttributedString *gString = [NSAttributedString stringWithAttributes:@{ NSForegroundColorAttributeName: UIColor.greenColor } format:@"%.3f", g]; + NSAttributedString *bString = [NSAttributedString stringWithAttributes:@{ NSForegroundColorAttributeName: UIColor.blueColor } format:@"%.3f", b]; + return [NSAttributedString stringWithFormat:@"HSL: (%.3f, %.3f, %.3f)\nRGB: (%@, %@, %@)\nAlpha: %.3f", h, s, l, rString, gString, bString, a]; } - NSString *description = [FLEXRuntimeUtility safeDescriptionForObject:self.object]; + NSAttributedString *description = [FLEXRuntimeUtility safeDescriptionForObject:self.object]; if (!description.length) { - NSString *address = [FLEXUtility addressOfObject:self.object]; - return [NSString stringWithFormat:@"Object at %@ returned empty description", address]; + NSAttributedString *address = [FLEXUtility addressOfObject:self.object]; + return [NSAttributedString stringWithFormat:@"Object at %@ returned empty description", address]; } if (description.length > 10000) { - description = [description substringToIndex:10000]; + description = [description attributedSubstringFromRange:NSMakeRange(0, 10000)]; } _objectDescription = description; diff --git a/Classes/ObjectExplorers/FLEXObjectExplorerViewController.m b/Classes/ObjectExplorers/FLEXObjectExplorerViewController.m index 33c3ff1839..188843b926 100644 --- a/Classes/ObjectExplorers/FLEXObjectExplorerViewController.m +++ b/Classes/ObjectExplorers/FLEXObjectExplorerViewController.m @@ -164,11 +164,11 @@ - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { _descriptionSection = [FLEXSingleRowSection title:@"Description" reuse:kFLEXMultilineCell cell:^(FLEXTableViewCell *cell) { cell.titleLabel.font = UIFont.flex_defaultTableCellFont; - cell.titleLabel.text = explorer.objectDescription; + cell.titleLabel.attributedText = explorer.objectDescription; } ]; self.descriptionSection.filterMatcher = ^BOOL(NSString *filterText) { - return [explorer.objectDescription localizedCaseInsensitiveContainsString:filterText]; + return [explorer.objectDescription.string localizedCaseInsensitiveContainsString:filterText]; }; } @@ -227,10 +227,10 @@ - (void)shareButtonPressed { [FLEXBookmarkManager.bookmarks addObject:self.object]; }); make.button(@"Copy Description").handler(^(NSArray *strings) { - UIPasteboard.generalPasteboard.string = self.explorer.objectDescription; + UIPasteboard.generalPasteboard.string = self.explorer.objectDescription.string; }); make.button(@"Copy Address").handler(^(NSArray *strings) { - UIPasteboard.generalPasteboard.string = [FLEXUtility addressOfObject:self.object]; + UIPasteboard.generalPasteboard.string = [FLEXUtility addressOfObject:self.object].string; }); make.button(@"Cancel").cancelStyle(); } showFrom:self]; @@ -345,10 +345,8 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa FLEXTableViewSection *section = self.filterDelegate.sections[indexPath.section]; if (section == self.descriptionSection) { - NSAttributedString *attributedText = [[NSAttributedString alloc] - initWithString:self.explorer.objectDescription - attributes:@{ NSFontAttributeName : UIFont.flex_defaultTableCellFont } - ]; + NSMutableAttributedString *attributedText = self.explorer.objectDescription.mutableCopy; + [attributedText addAttribute:NSFontAttributeName value:UIFont.flex_defaultTableCellFont range:NSMakeRange(0, attributedText.length)]; return [FLEXMultilineTableViewCell preferredHeightWithAttributedText:attributedText @@ -376,7 +374,7 @@ - (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAt - (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { if (action == @selector(copy:)) { - UIPasteboard.generalPasteboard.string = self.explorer.objectDescription; + UIPasteboard.generalPasteboard.string = self.explorer.objectDescription.string; } } diff --git a/Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.m b/Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.m index d481d44667..715d38a5c2 100644 --- a/Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.m +++ b/Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.m @@ -76,11 +76,11 @@ + (FLEXCollectionType)typeForCollection:(id)collection { /// - Ordered: the index /// - Unordered: the object /// - Keyed: the key -- (NSString *)titleForRow:(NSInteger)row { +- (NSAttributedString *)titleForRow:(NSInteger)row { switch (self.collectionType) { case FLEXOrderedCollection: if (!self.hideOrderIndexes) { - return @(row).stringValue; + return @(row).stringValue.attributedString; } // Fall-through case FLEXUnorderedCollection: @@ -97,7 +97,7 @@ - (NSString *)titleForRow:(NSInteger)row { /// - Ordered: the object /// - Unordered: nothing /// - Keyed: the value -- (NSString *)subtitleForRow:(NSInteger)row { +- (NSAttributedString *)subtitleForRow:(NSInteger)row { switch (self.collectionType) { case FLEXOrderedCollection: if (!self.hideOrderIndexes) { @@ -114,7 +114,7 @@ - (NSString *)subtitleForRow:(NSInteger)row { } } -- (NSString *)describe:(id)object { +- (NSAttributedString *)describe:(id)object { return [FLEXRuntimeUtility summaryForObject:object]; } @@ -156,7 +156,7 @@ - (void)setFilterText:(NSString *)filterText { if (filterText.length) { BOOL (^matcher)(id, id) = self.customFilter ?: ^BOOL(NSString *query, id obj) { - return [[self describe:obj] localizedCaseInsensitiveContainsString:query]; + return [[self describe:obj].string localizedCaseInsensitiveContainsString:query]; }; NSPredicate *filter = [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) { @@ -192,8 +192,8 @@ - (NSString *)reuseIdentifierForRow:(NSInteger)row { } - (void)configureCell:(__kindof FLEXTableViewCell *)cell forRow:(NSInteger)row { - cell.titleLabel.text = [self titleForRow:row]; - cell.subtitleLabel.text = [self subtitleForRow:row]; + cell.titleLabel.attributedText = [self titleForRow:row]; + cell.subtitleLabel.attributedText = [self subtitleForRow:row]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } diff --git a/Classes/ObjectExplorers/Sections/FLEXMetadataSection.m b/Classes/ObjectExplorers/Sections/FLEXMetadataSection.m index 698f532671..0bf06d06e4 100644 --- a/Classes/ObjectExplorers/Sections/FLEXMetadataSection.m +++ b/Classes/ObjectExplorers/Sections/FLEXMetadataSection.m @@ -70,12 +70,15 @@ - (void)setExcludedMetadata:(NSSet *)excludedMetadata { #pragma mark - Overrides -- (NSString *)titleForRow:(NSInteger)row { - return [self.metadata[row] description]; +- (NSAttributedString *)titleForRow:(NSInteger)row { + return [self.metadata[row] attributedDescription]; } -- (NSString *)subtitleForRow:(NSInteger)row { - return [self.metadata[row] previewWithTarget:self.explorer.object]; +- (NSAttributedString *)subtitleForRow:(NSInteger)row { + id str = [self.metadata[row] previewWithTarget:self.explorer.object]; // FIXME: Should always be NSAttributedString + if ([str isKindOfClass:NSString.class]) + return ((NSString *)str).attributedString; + return str; } - (NSString *)title { @@ -146,7 +149,7 @@ - (void)reloadData { // Remove excluded metadata if (self.excludedMetadata.count) { id filterBlock = ^BOOL(id obj, NSUInteger idx) { - return ![self.excludedMetadata containsObject:obj.name]; + return ![self.excludedMetadata containsObject:obj.name.string]; }; // Filter exclusions and sort @@ -184,14 +187,14 @@ - (UIViewController *)editorForRow:(NSInteger)row { } - (void)configureCell:(__kindof FLEXTableViewCell *)cell forRow:(NSInteger)row { - cell.titleLabel.text = [self titleForRow:row]; - cell.subtitleLabel.text = [self subtitleForRow:row]; + cell.titleLabel.attributedText = [self titleForRow:row]; + cell.subtitleLabel.attributedText = [self subtitleForRow:row]; cell.accessoryType = [self accessoryTypeForRow:row]; } #if FLEX_AT_LEAST_IOS13_SDK -- (NSString *)menuSubtitleForRow:(NSInteger)row { +- (NSAttributedString *)menuSubtitleForRow:(NSInteger)row { return [self.metadata[row] contextualSubtitleWithTarget:self.explorer.object]; } diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBlockShortcuts.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBlockShortcuts.m index 201d092689..6dd4494e12 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBlockShortcuts.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBlockShortcuts.m @@ -28,9 +28,9 @@ + (instancetype)forObject:(id)block { blockInfo.summary, blockInfo.sourceDeclaration, signature.debugDescription, - [FLEXActionShortcut title:@"View Method Signature" - subtitle:^NSString *(id block) { - return signature.description ?: @"unsupported signature"; + [FLEXActionShortcut title:@"View Method Signature".attributedString + subtitle:^NSAttributedString *(id block) { + return signature.attributedDescription ?: @"unsupported signature".attributedString; } viewer:^UIViewController *(id block) { return [FLEXObjectExplorerFactory explorerViewControllerForObject:signature]; diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBundleShortcuts.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBundleShortcuts.m index 9c99991a06..9c5cb20451 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBundleShortcuts.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXBundleShortcuts.m @@ -9,6 +9,7 @@ #import "FLEXBundleShortcuts.h" #import "FLEXShortcut.h" #import "FLEXFileBrowserTableViewController.h" +#import "NSString+SyntaxHighlighting.h" #pragma mark - @implementation FLEXBundleShortcuts @@ -16,7 +17,7 @@ @implementation FLEXBundleShortcuts + (instancetype)forObject:(NSBundle *)bundle { return [self forObject:bundle additionalRows:@[ - [FLEXActionShortcut title:@"Browse Bundle Directory" subtitle:nil + [FLEXActionShortcut title:@"Browse Bundle Directory".attributedString subtitle:nil viewer:^UIViewController *(id view) { return [FLEXFileBrowserTableViewController path:bundle.bundlePath]; } diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXClassShortcuts.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXClassShortcuts.m index d1e2886824..09640c5ea9 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXClassShortcuts.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXClassShortcuts.m @@ -23,7 +23,7 @@ + (instancetype)forObject:(Class)cls { // The methods below are written in such a way that they will not interfere // with properties/etc being registered alongside these return [self forObject:cls additionalRows:@[ - [FLEXActionShortcut title:@"Find Live Instances" subtitle:nil + [FLEXActionShortcut title:@"Find Live Instances".attributedString subtitle:nil viewer:^UIViewController *(id obj) { return [FLEXObjectListViewController instancesOfClassWithName:NSStringFromClass(obj) @@ -33,7 +33,7 @@ + (instancetype)forObject:(Class)cls { return UITableViewCellAccessoryDisclosureIndicator; } ], - [FLEXActionShortcut title:@"List Subclasses" subtitle:nil + [FLEXActionShortcut title:@"List Subclasses".attributedString subtitle:nil viewer:^UIViewController *(id obj) { NSString *name = NSStringFromClass(obj); return [FLEXObjectListViewController subclassesOfClassWithName:name]; @@ -42,9 +42,9 @@ + (instancetype)forObject:(Class)cls { return UITableViewCellAccessoryDisclosureIndicator; } ], - [FLEXActionShortcut title:@"Explore Bundle for Class" - subtitle:^NSString *(id obj) { - return [self shortNameForBundlePath:[NSBundle bundleForClass:obj].executablePath]; + [FLEXActionShortcut title:@"Explore Bundle for Class".attributedString + subtitle:^NSAttributedString *(id obj) { + return [self shortNameForBundlePath:[NSBundle bundleForClass:obj].executablePath].attributedString; } viewer:^UIViewController *(id obj) { NSBundle *bundle = [NSBundle bundleForClass:obj]; diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXLayerShortcuts.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXLayerShortcuts.m index b6ee84c9e7..355de93b2c 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXLayerShortcuts.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXLayerShortcuts.m @@ -9,12 +9,13 @@ #import "FLEXLayerShortcuts.h" #import "FLEXShortcut.h" #import "FLEXImagePreviewViewController.h" +#import "NSString+SyntaxHighlighting.h" @implementation FLEXLayerShortcuts + (instancetype)forObject:(CALayer *)layer { return [self forObject:layer additionalRows:@[ - [FLEXActionShortcut title:@"Preview Image" subtitle:nil + [FLEXActionShortcut title:@"Preview Image".attributedString subtitle:nil viewer:^UIViewController *(id layer) { return [FLEXImagePreviewViewController previewForLayer:layer]; } diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h index cce67dd3c9..5a6f32c4ff 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h @@ -20,8 +20,8 @@ NS_ASSUME_NONNULL_BEGIN /// them to the existing list of shortcuts for a class. @protocol FLEXShortcut -- (nonnull NSString *)titleWith:(id)object; -- (nullable NSString *)subtitleWith:(id)object; +- (nonnull NSAttributedString *)titleWith:(id)object; +- (nullable NSAttributedString *)subtitleWith:(id)object; - (nullable void (^)(UIViewController *host))didSelectActionWith:(id)object; /// Called when the row is selected - (nullable UIViewController *)viewerWith:(id)object; @@ -56,13 +56,13 @@ NS_ASSUME_NONNULL_BEGIN /// Does not support the \c -editorWith: method. @interface FLEXActionShortcut : NSObject -+ (instancetype)title:(NSString *)title - subtitle:(nullable NSString *(^)(id object))subtitleFuture ++ (instancetype)title:(NSAttributedString *)title + subtitle:(nullable NSAttributedString *(^)(id object))subtitleFuture viewer:(nullable UIViewController *(^)(id object))viewerFuture accessoryType:(nullable UITableViewCellAccessoryType(^)(id object))accessoryTypeFuture; -+ (instancetype)title:(NSString *)title - subtitle:(nullable NSString *(^)(id object))subtitleFuture ++ (instancetype)title:(NSAttributedString *)title + subtitle:(nullable NSAttributedString *(^)(id object))subtitleFuture selectionHandler:(nullable void (^)(UIViewController *host, id object))tapAction accessoryType:(nullable UITableViewCellAccessoryType(^)(id object))accessoryTypeFuture; diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.m index f2d5eec1c5..4452f3e5cb 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.m @@ -17,7 +17,7 @@ #import "FLEXMethodCallingViewController.h" #import "FLEXMetadataSection.h" #import "FLEXTableView.h" - +#import "NSAttributedString+FLEX.h" #pragma mark - FLEXShortcut @@ -64,15 +64,15 @@ - (id)propertyOrIvarValue:(id)object { return [self.metadata currentValueWithTarget:object]; } -- (NSString *)titleWith:(id)object { +- (NSAttributedString *)titleWith:(id)object { switch (self.metadataKind) { case FLEXMetadataKindClassProperties: case FLEXMetadataKindProperties: // Since we're outside of the "properties" section, prepend @property for clarity. - return [@"@property " stringByAppendingString:[_item description]]; + return [@"@property ".keywordsAttributedString stringByAppendingAttributedString:[_item attributedDescription]]; default: - return [_item description]; + return [_item attributedDescription]; } NSAssert( @@ -80,18 +80,18 @@ - (NSString *)titleWith:(id)object { @"Unexpected type: %@", [_item class] ); - return _item; + return ((NSString *)_item).attributedString; } -- (NSString *)subtitleWith:(id)object { +- (NSAttributedString *)subtitleWith:(id)object { if (self.metadataKind) { - return [self.metadata previewWithTarget:object] ?: @"nil"; + return [self.metadata previewWithTarget:object] ?: @"nil".keywordsAttributedString; } // Item is probably a string; must return empty string since // these will be gathered into an array. If the object is a // just a string, it doesn't get a subtitle. - return @""; + return @"".attributedString; } - (void (^)(UIViewController *))didSelectActionWith:(id)object { @@ -137,8 +137,8 @@ - (FLEXIvar *)ivar { return _item; } #pragma mark - FLEXActionShortcut @interface FLEXActionShortcut () -@property (nonatomic, readonly) NSString *title; -@property (nonatomic, readonly) NSString *(^subtitleFuture)(id); +@property (nonatomic, readonly) NSAttributedString *title; +@property (nonatomic, readonly) NSAttributedString *(^subtitleFuture)(id); @property (nonatomic, readonly) UIViewController *(^viewerFuture)(id); @property (nonatomic, readonly) void (^selectionHandler)(UIViewController *, id); @property (nonatomic, readonly) UITableViewCellAccessoryType (^accessoryTypeFuture)(id); @@ -146,21 +146,21 @@ @interface FLEXActionShortcut () @implementation FLEXActionShortcut -+ (instancetype)title:(NSString *)title - subtitle:(NSString *(^)(id))subtitle ++ (instancetype)title:(NSAttributedString *)title + subtitle:(NSAttributedString *(^)(id))subtitle viewer:(UIViewController *(^)(id))viewer accessoryType:(UITableViewCellAccessoryType (^)(id))type { return [[self alloc] initWithTitle:title subtitle:subtitle viewer:viewer selectionHandler:nil accessoryType:type]; } -+ (instancetype)title:(NSString *)title - subtitle:(NSString * (^)(id))subtitle ++ (instancetype)title:(NSAttributedString *)title + subtitle:(NSAttributedString * (^)(id))subtitle selectionHandler:(void (^)(UIViewController *, id))tapAction accessoryType:(UITableViewCellAccessoryType (^)(id))type { return [[self alloc] initWithTitle:title subtitle:subtitle viewer:nil selectionHandler:tapAction accessoryType:type]; } -- (id)initWithTitle:(NSString *)title +- (id)initWithTitle:(NSAttributedString *)title subtitle:(id)subtitleFuture viewer:(id)viewerFuture selectionHandler:(id)tapAction @@ -181,11 +181,11 @@ - (id)initWithTitle:(NSString *)title return self; } -- (NSString *)titleWith:(id)object { +- (NSAttributedString *)titleWith:(id)object { return self.title; } -- (NSString *)subtitleWith:(id)object { +- (NSAttributedString *)subtitleWith:(id)object { return self.subtitleFuture(object); } diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h index 6084cda719..60dda186b3 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h @@ -25,11 +25,11 @@ @interface FLEXShortcutsSection : FLEXTableViewSection /// Uses \c kFLEXDefaultCell -+ (instancetype)forObject:(id)objectOrClass rowTitles:(NSArray *)titles; ++ (instancetype)forObject:(id)objectOrClass rowTitles:(NSArray *)titles; /// Uses \c kFLEXDetailCell for non-empty subtitles, otherwise uses \c kFLEXDefaultCell + (instancetype)forObject:(id)objectOrClass - rowTitles:(NSArray *)titles - rowSubtitles:(NSArray *)subtitles; + rowTitles:(NSArray *)titles + rowSubtitles:(NSArray *)subtitles; /// Uses \c kFLEXDefaultCell for rows that are given a title, otherwise /// this uses \c kFLEXDetailCell for any other allowed object. diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.m index 0402178c7d..a33c451d99 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.m @@ -20,11 +20,11 @@ #pragma mark Private @interface FLEXShortcutsSection () -@property (nonatomic, copy) NSArray *titles; -@property (nonatomic, copy) NSArray *subtitles; +@property (nonatomic, copy) NSArray *titles; +@property (nonatomic, copy) NSArray *subtitles; -@property (nonatomic, copy) NSArray *allTitles; -@property (nonatomic, copy) NSArray *allSubtitles; +@property (nonatomic, copy) NSArray *allTitles; +@property (nonatomic, copy) NSArray *allSubtitles; // Shortcuts are not used if initialized with static titles and subtitles @property (nonatomic, copy) NSArray> *shortcuts; @@ -35,13 +35,13 @@ @implementation FLEXShortcutsSection #pragma mark Initialization -+ (instancetype)forObject:(id)objectOrClass rowTitles:(NSArray *)titles { ++ (instancetype)forObject:(id)objectOrClass rowTitles:(NSArray *)titles { return [self forObject:objectOrClass rowTitles:titles rowSubtitles:nil]; } + (instancetype)forObject:(id)objectOrClass - rowTitles:(NSArray *)titles - rowSubtitles:(NSArray *)subtitles { + rowTitles:(NSArray *)titles + rowSubtitles:(NSArray *)subtitles { return [[self alloc] initWithObject:objectOrClass titles:titles subtitles:subtitles]; } @@ -60,8 +60,8 @@ + (instancetype)forObject:(id)objectOrClass { } - (id)initWithObject:(id)object - titles:(NSArray *)titles - subtitles:(NSArray *)subtitles { + titles:(NSArray *)titles + subtitles:(NSArray *)subtitles { NSParameterAssert(titles.count == subtitles.count || !subtitles); NSParameterAssert(titles.count); @@ -130,8 +130,8 @@ - (void)setFilterText:(NSString *)filterText { if (filterText.length) { // Tally up indexes of titles and subtitles matching the filter NSMutableIndexSet *filterMatches = [NSMutableIndexSet new]; - id filterBlock = ^BOOL(NSString *obj, NSUInteger idx) { - if ([obj localizedCaseInsensitiveContainsString:filterText]) { + id filterBlock = ^BOOL(NSAttributedString *obj, NSUInteger idx) { + if ([obj.string localizedCaseInsensitiveContainsString:filterText]) { [filterMatches addIndex:idx]; return YES; } @@ -149,7 +149,7 @@ - (void)setFilterText:(NSString *)filterText { } else { self.shortcuts = self.allShortcuts; self.titles = self.allTitles; - self.subtitles = [self.allSubtitles flex_filtered:^BOOL(NSString *sub, NSUInteger idx) { + self.subtitles = [self.allSubtitles flex_filtered:^BOOL(NSAttributedString *sub, NSUInteger idx) { return sub.length > 0; }]; } @@ -218,21 +218,21 @@ - (NSString *)reuseIdentifierForRow:(NSInteger)row { } - (void)configureCell:(__kindof FLEXTableViewCell *)cell forRow:(NSInteger)row { - cell.titleLabel.text = [self titleForRow:row]; + cell.titleLabel.attributedText = [self titleForRow:row]; cell.titleLabel.numberOfLines = self.numberOfLines; - cell.subtitleLabel.text = [self subtitleForRow:row]; + cell.subtitleLabel.attributedText = [self subtitleForRow:row]; cell.subtitleLabel.numberOfLines = self.numberOfLines; cell.accessoryType = [self accessoryTypeForRow:row]; } -- (NSString *)titleForRow:(NSInteger)row { +- (NSAttributedString *)titleForRow:(NSInteger)row { return self.titles[row]; } -- (NSString *)subtitleForRow:(NSInteger)row { +- (NSAttributedString *)subtitleForRow:(NSInteger)row { // Case: dynamic, uncached subtitles if (!self.cacheSubtitles) { - NSString *subtitle = [self.shortcuts[row] subtitleWith:self.object]; + NSAttributedString *subtitle = [self.shortcuts[row] subtitleWith:self.object]; return subtitle.length ? subtitle : nil; } diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewControllerShortcuts.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewControllerShortcuts.m index bdcde4c371..b836aabbc5 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewControllerShortcuts.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewControllerShortcuts.m @@ -48,9 +48,9 @@ + (instancetype)forObject:(UIViewController *)viewController { }; return [self forObject:viewController additionalRows:@[ - [FLEXActionShortcut title:@"Push View Controller" - subtitle:^NSString *(UIViewController *controller) { - return vcIsInuse(controller) ? @"In use, cannot push" : nil; + [FLEXActionShortcut title:@"Push View Controller".attributedString + subtitle:^NSAttributedString *(UIViewController *controller) { + return vcIsInuse(controller) ? @"In use, cannot push".attributedString : nil; } selectionHandler:^void(UIViewController *host, UIViewController *controller) { if (!vcIsInuse(controller)) { diff --git a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewShortcuts.m b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewShortcuts.m index 63152860e2..18a5216d5e 100644 --- a/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewShortcuts.m +++ b/Classes/ObjectExplorers/Sections/Shortcuts/FLEXViewShortcuts.m @@ -62,8 +62,8 @@ + (instancetype)forObject:(UIView *)view { UIViewController *controller = [FLEXViewShortcuts nearestViewControllerForView:view]; return [self forObject:view additionalRows:@[ - [FLEXActionShortcut title:@"Nearest View Controller" - subtitle:^NSString *(id view) { + [FLEXActionShortcut title:@"Nearest View Controller".attributedString + subtitle:^NSAttributedString *(id view) { return [FLEXRuntimeUtility safeDescriptionForObject:controller]; } viewer:^UIViewController *(id view) { @@ -73,7 +73,7 @@ + (instancetype)forObject:(UIView *)view { return controller ? UITableViewCellAccessoryDisclosureIndicator : 0; } ], - [FLEXActionShortcut title:@"Preview Image" subtitle:nil + [FLEXActionShortcut title:@"Preview Image".attributedString subtitle:nil viewer:^UIViewController *(id view) { return [FLEXImagePreviewViewController previewForView:view]; } diff --git a/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h b/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h index cd07f3c992..31ea702292 100644 --- a/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h +++ b/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h @@ -11,12 +11,14 @@ #import "FLEXIvar.h" #import "FLEXMethod.h" #import "FLEXProtocol.h" +#import "NSObject+SyntaxHighlighting.h" @protocol FLEXRuntimeMetadata /// Used as the main title of the row - (NSString *)description; +- (NSAttributedString *)attributedDescription; /// Used to compare metadata objects for uniqueness -@property (nonatomic, readonly) NSString *name; +@property (nonatomic, readonly) NSAttributedString *name; /// YES for properties and ivars which surely support editing, NO for all methods. @property (nonatomic, readonly) BOOL isEditable; /// NO for ivars, YES for supported methods and properties @@ -28,7 +30,7 @@ /// Should return \c nil if not applicable - (id)currentValueWithTarget:(id)object; /// Used as the subtitle or description of a property, ivar, or method -- (NSString *)previewWithTarget:(id)object; +- (NSAttributedString *)previewWithTarget:(id)object; /// For methods, a method calling screen. For all else, an object explorer. - (UIViewController *)viewerWithTarget:(id)object; /// For methods and protocols, nil. For all else, an a field editor screen. @@ -46,7 +48,7 @@ /// of what to copy like "Name" and the values are what will be copied. - (NSArray *)copiableMetadataWithTarget:(id)object; /// Properties and ivars return the address of an object, if they hold one. -- (NSString *)contextualSubtitleWithTarget:(id)object; +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object; #endif diff --git a/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.m b/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.m index 0ac807bf71..daf6de49e7 100644 --- a/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.m +++ b/Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.m @@ -64,13 +64,11 @@ - (id)currentValueBeforeUnboxingWithTarget:(id)object { ]; } -- (NSString *)previewWithTarget:(id)object { +- (NSAttributedString *)previewWithTarget:(id)object { if (object_isClass(object) && !self.isClassProperty) { return self.attributes.fullDeclaration; } else { - return [FLEXRuntimeUtility - summaryForObject:[self currentValueWithTarget:object] - ]; + return [FLEXRuntimeUtility summaryForObject:[self currentValueWithTarget:object]]; } } @@ -161,7 +159,7 @@ - (NSString *)reuseIdentifierWithTarget:(id)object { return nil; } return items; } -- (NSString *)contextualSubtitleWithTarget:(id)object { +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object { id target = [self appropriateTargetForPropertyType:object]; if (target && self.attributes.typeEncoding.flex_typeIsObjectOrClass) { return [FLEXUtility addressOfObject:[self currentValueBeforeUnboxingWithTarget:target]]; @@ -195,13 +193,11 @@ - (id)currentValueWithTarget:(id)object { return nil; } -- (NSString *)previewWithTarget:(id)object { +- (NSAttributedString *)previewWithTarget:(id)object { if (object_isClass(object)) { - return self.details; + return self.details.attributedString; } - return [FLEXRuntimeUtility - summaryForObject:[self currentValueWithTarget:object] - ]; + return [FLEXRuntimeUtility summaryForObject:[self currentValueWithTarget:object]]; } - (UIViewController *)viewerWithTarget:(id)object { @@ -286,7 +282,7 @@ - (NSString *)reuseIdentifierWithTarget:(id)object { return nil; } return items; } -- (NSString *)contextualSubtitleWithTarget:(id)object { +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object { if (!object_isClass(object) && self.typeEncoding.flex_typeIsObjectOrClass) { return [FLEXUtility addressOfObject:[self getValue:object]]; } @@ -315,8 +311,8 @@ - (id)currentValueWithTarget:(id)object { return nil; } -- (NSString *)previewWithTarget:(id)object { - return [self.selectorString stringByAppendingFormat:@" — %@", self.typeEncoding]; +- (NSAttributedString *)previewWithTarget:(id)object { + return [self.selectorString stringByAppendingFormat:@" — %@", self.typeEncoding].attributedString; } - (UIViewController *)viewerWithTarget:(id)object { @@ -353,7 +349,7 @@ - (NSString *)reuseIdentifierWithTarget:(id)object { return nil; } ]; } -- (NSString *)contextualSubtitleWithTarget:(id)object { +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object { return nil; } @@ -388,12 +384,12 @@ - (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object { - (NSArray *)copiableMetadataWithTarget:(id)object { return [[super copiableMetadataWithTarget:object] arrayByAddingObjectsFromArray:@[ - @"NSMethodSignature *", [FLEXUtility addressOfObject:self.signature], + @"NSMethodSignature *", [FLEXUtility addressOfObject:self.signature].string, @"Signature String", self.signatureString ?: @"", @"Number of Arguments", @(self.numberOfArguments).stringValue, @"Return Type", @(self.returnType ?: ""), @"Return Size", @(self.returnSize).stringValue, - @"objc_method", [FLEXUtility pointerToString:self.objc_method], + @"objc_method", [FLEXUtility pointerToString:self.objc_method].string, ]]; } @@ -415,7 +411,7 @@ - (id)currentValueWithTarget:(id)object { return nil; } -- (NSString *)previewWithTarget:(id)object { +- (NSAttributedString *)previewWithTarget:(id)object { return nil; } @@ -448,7 +444,7 @@ - (NSString *)reuseIdentifierWithTarget:(id)object { return nil; } ]; } -- (NSString *)contextualSubtitleWithTarget:(id)object { +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object { return nil; } @@ -460,10 +456,10 @@ - (NSString *)contextualSubtitleWithTarget:(id)object { #pragma mark FLEXStaticMetadata @interface FLEXStaticMetadata () { @protected - NSString *_name; + NSAttributedString *_name; } @property (nonatomic) FLEXTableViewCellReuseIdentifier reuse; -@property (nonatomic) NSString *subtitle; +@property (nonatomic) NSAttributedString *subtitle; @property (nonatomic) id metadata; @end @@ -498,14 +494,18 @@ - (id)initWithStyle:(FLEXStaticMetadataRowStyle)style title:(NSString *)title su _reuse = kFLEXMultilineDetailCell; } - _name = title; - _subtitle = subtitle; + _name = title.attributedString; + _subtitle = subtitle.attributedString; } return self; } - (NSString *)description { + return self.name.string; +} + +- (NSAttributedString *)attributedDescription { return self.name; } @@ -525,7 +525,7 @@ - (id)currentValueWithTarget:(id)object { return nil; } -- (NSString *)previewWithTarget:(id)object { +- (NSAttributedString *)previewWithTarget:(id)object { return self.subtitle; } @@ -548,10 +548,10 @@ - (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object { } - (NSArray *)copiableMetadataWithTarget:(id)object { - return @[self.name, self.subtitle]; + return @[self.name.string, self.subtitle.string]; } -- (NSString *)contextualSubtitleWithTarget:(id)object { +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object { return nil; } @@ -568,7 +568,7 @@ + (instancetype)withClass:(Class)cls { FLEXStaticMetadata_Class *metadata = [self new]; metadata.metadata = cls; - metadata->_name = NSStringFromClass(cls); + metadata->_name = NSStringFromClass(cls).attributedString; metadata.reuse = kFLEXDefaultCell; return metadata; } @@ -588,12 +588,12 @@ - (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object { - (NSArray *)copiableMetadataWithTarget:(id)object { return @[ - @"Class Name", self.name, - @"Class", [FLEXUtility addressOfObject:self.metadata] + @"Class Name", self.name.string, + @"Class", [FLEXUtility addressOfObject:self.metadata].string ]; } -- (NSString *)contextualSubtitleWithTarget:(id)object { +- (NSAttributedString *)contextualSubtitleWithTarget:(id)object { return [FLEXUtility addressOfObject:self.metadata]; } diff --git a/Classes/Utility/Categories/NSAttributedString+FLEX.h b/Classes/Utility/Categories/NSAttributedString+FLEX.h new file mode 100644 index 0000000000..1c03d02c21 --- /dev/null +++ b/Classes/Utility/Categories/NSAttributedString+FLEX.h @@ -0,0 +1,16 @@ +// +// NSAttributedString+FLEX.h +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import + +@interface NSAttributedString (FLEX) ++ (instancetype)stringByJoiningArray:(NSArray *)array withSeparator:(NSAttributedString *)separator; ++ (instancetype)stringWithFormat:(NSString *)format, ...; ++ (instancetype)stringWithAttributes:(NSDictionary *)attributes format:(NSString *)format, ...; +- (instancetype)stringByAppendingAttributedString:(NSAttributedString *)aString; +@end diff --git a/Classes/Utility/Categories/NSAttributedString+FLEX.m b/Classes/Utility/Categories/NSAttributedString+FLEX.m new file mode 100644 index 0000000000..685097cb39 --- /dev/null +++ b/Classes/Utility/Categories/NSAttributedString+FLEX.m @@ -0,0 +1,66 @@ +// +// NSAttributedString+FLEX.m +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import "NSAttributedString+FLEX.h" + +@implementation NSAttributedString (FLEX) ++ (instancetype)stringByJoiningArray:(NSArray *)array withSeparator:(NSAttributedString *)separator { + NSMutableAttributedString *attributedString = [NSMutableAttributedString new]; + for (int i = 0; i < array.count; i++) { + [attributedString appendAttributedString:array[i]]; + if (i != array.count - 1) + [attributedString appendAttributedString:separator]; + } + return attributedString; +} ++ (instancetype)stringWithFormat:(NSString *)format, ... { + va_list arguments; + va_start(arguments, format); + + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@""]; + NSScanner *scanner = [NSScanner scannerWithString:format]; + scanner.charactersToBeSkipped = [NSCharacterSet new]; + while (![scanner isAtEnd]) { + NSString *discarded; + [scanner scanUpToString:@"%" intoString:&discarded]; + if (discarded) { + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:discarded]]; + } + if ([scanner scanString:@"%%" intoString:NULL]) { + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"%"]]; + } else if ([scanner scanString:@"%@" intoString:NULL]) { + id object = va_arg(arguments, id); + if(![object isKindOfClass:NSAttributedString.class]) { + object = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@", object]]; + } + [attributedString appendAttributedString:object]; + } else if ([scanner scanString:@"%" intoString:NULL]) { + NSString *specifier = [format substringFromIndex:scanner.scanLocation]; + if(specifier.length > 1) { + specifier = [specifier substringToIndex:1]; + } + NSAssert(NO, @"Unsupported format specifier '%@'", specifier); + } + } + return attributedString; +} ++ (instancetype)stringWithAttributes:(NSDictionary *)attributes format:(NSString *)format, ... { + va_list arguments; + va_start(arguments, format); + + NSMutableAttributedString *attributedString = [NSMutableAttributedString stringWithFormat:format, arguments]; + [attributedString setAttributes:attributes range:NSMakeRange(0, attributedString.length)]; + return attributedString; +} +- (instancetype)stringByAppendingAttributedString:(NSAttributedString *)aString { + NSMutableAttributedString *attributedString = self.mutableCopy; + [attributedString appendAttributedString:aString]; + return attributedString; +} +@end + diff --git a/Classes/Utility/Categories/NSDictionary+ObjcRuntime.h b/Classes/Utility/Categories/NSDictionary+ObjcRuntime.h index 2d5f0fcab1..d8eb6dbaf6 100644 --- a/Classes/Utility/Categories/NSDictionary+ObjcRuntime.h +++ b/Classes/Utility/Categories/NSDictionary+ObjcRuntime.h @@ -14,7 +14,7 @@ /// \c kFLEXPropertyAttributeKeyTypeEncoding is the only required key. /// Keys representing a boolean value should have a value of \c @YES instead of an empty string. -- (NSString *)propertyAttributesString; +- (NSAttributedString *)propertyAttributesString; + (instancetype)attributesDictionaryForProperty:(objc_property_t)property; diff --git a/Classes/Utility/Categories/NSDictionary+ObjcRuntime.m b/Classes/Utility/Categories/NSDictionary+ObjcRuntime.m index bb0d5ff5d1..f5a9e4dc1b 100644 --- a/Classes/Utility/Categories/NSDictionary+ObjcRuntime.m +++ b/Classes/Utility/Categories/NSDictionary+ObjcRuntime.m @@ -9,16 +9,18 @@ #import "NSDictionary+ObjcRuntime.h" #import "FLEXRuntimeUtility.h" +#import "NSMutableAttributedString+FLEX.h" +#import "NSString+SyntaxHighlighting.h" @implementation NSDictionary (ObjcRuntime) /// See this link on how to construct a proper attributes string: /// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html -- (NSString *)propertyAttributesString { +- (NSAttributedString *)propertyAttributesString { if (!self[kFLEXPropertyAttributeKeyTypeEncoding]) return nil; - NSMutableString *attributes = [NSMutableString new]; - [attributes appendFormat:@"T%@,", self[kFLEXPropertyAttributeKeyTypeEncoding]]; + NSMutableAttributedString *attributes = [NSMutableAttributedString new]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"T%@,", self[kFLEXPropertyAttributeKeyTypeEncoding]]]; for (NSString *attribute in self.allKeys) { FLEXPropertyAttribute c = (FLEXPropertyAttribute)[attribute characterAtIndex:0]; @@ -26,55 +28,66 @@ - (NSString *)propertyAttributesString { case FLEXPropertyAttributeTypeEncoding: break; case FLEXPropertyAttributeBackingIvarName: - [attributes appendFormat:@"%@%@,", - kFLEXPropertyAttributeKeyBackingIvarName, - self[kFLEXPropertyAttributeKeyBackingIvarName] - ]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@%@", + kFLEXPropertyAttributeKeyBackingIvarName, + self[kFLEXPropertyAttributeKeyBackingIvarName] + ]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeCopy: if ([self[kFLEXPropertyAttributeKeyCopy] boolValue]) - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyCopy]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyCopy]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeCustomGetter: - [attributes appendFormat:@"%@%@,", - kFLEXPropertyAttributeKeyCustomGetter, - self[kFLEXPropertyAttributeKeyCustomGetter] - ]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@%@", + kFLEXPropertyAttributeKeyCustomGetter, + self[kFLEXPropertyAttributeKeyCustomGetter] + ]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeCustomSetter: - [attributes appendFormat:@"%@%@,", - kFLEXPropertyAttributeKeyCustomSetter, - self[kFLEXPropertyAttributeKeyCustomSetter] - ]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@%@", + kFLEXPropertyAttributeKeyCustomSetter, + self[kFLEXPropertyAttributeKeyCustomSetter] + ]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeDynamic: if ([self[kFLEXPropertyAttributeKeyDynamic] boolValue]) - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyDynamic]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyDynamic]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeGarbageCollectible: - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyGarbageCollectable]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyGarbageCollectable]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeNonAtomic: if ([self[kFLEXPropertyAttributeKeyNonAtomic] boolValue]) - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyNonAtomic]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyNonAtomic]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeOldTypeEncoding: - [attributes appendFormat:@"%@%@,", - kFLEXPropertyAttributeKeyOldStyleTypeEncoding, - self[kFLEXPropertyAttributeKeyOldStyleTypeEncoding] - ]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@%@", + kFLEXPropertyAttributeKeyOldStyleTypeEncoding, + self[kFLEXPropertyAttributeKeyOldStyleTypeEncoding] + ]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeReadOnly: if ([self[kFLEXPropertyAttributeKeyReadOnly] boolValue]) - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyReadOnly]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyReadOnly]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeRetain: if ([self[kFLEXPropertyAttributeKeyRetain] boolValue]) - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyRetain]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyRetain]]; + [attributes appendAttributedString:@",".attributedString]; break; case FLEXPropertyAttributeWeak: if ([self[kFLEXPropertyAttributeKeyWeak] boolValue]) - [attributes appendFormat:@"%@,", kFLEXPropertyAttributeKeyWeak]; + [attributes appendAttributedString:[NSAttributedString stringWithFormat:@"%@", kFLEXPropertyAttributeKeyWeak]]; + [attributes appendAttributedString:@",".attributedString]; break; default: return nil; @@ -82,7 +95,7 @@ - (NSString *)propertyAttributesString { } } - [attributes deleteCharactersInRange:NSMakeRange(attributes.length-1, 1)]; + [attributes deleteCharactersInRange:NSMakeRange(attributes.length - 1, 1)]; return attributes.copy; } @@ -93,11 +106,11 @@ + (instancetype)attributesDictionaryForProperty:(objc_property_t)property { char *value = property_copyAttributeValue(property, key.UTF8String); if (value) { attrs[key] = [[NSString alloc] - initWithBytesNoCopy:value - length:strlen(value) - encoding:NSUTF8StringEncoding - freeWhenDone:YES - ]; + initWithBytesNoCopy:value + length:strlen(value) + encoding:NSUTF8StringEncoding + freeWhenDone:YES + ]; } } diff --git a/Classes/Utility/Categories/NSMutableAttributedString+FLEX.h b/Classes/Utility/Categories/NSMutableAttributedString+FLEX.h new file mode 100644 index 0000000000..f0492ba8c3 --- /dev/null +++ b/Classes/Utility/Categories/NSMutableAttributedString+FLEX.h @@ -0,0 +1,14 @@ +// +// NSMutableAttributedString+FLEX.h +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import +#import "NSAttributedString+FLEX.h" + +@interface NSMutableAttributedString (FLEX) +- (void)replaceOccurencesOfString:(NSAttributedString *)aString withString:(NSAttributedString *)replacement; +@end diff --git a/Classes/Utility/Categories/NSMutableAttributedString+FLEX.m b/Classes/Utility/Categories/NSMutableAttributedString+FLEX.m new file mode 100644 index 0000000000..c6d8a0445a --- /dev/null +++ b/Classes/Utility/Categories/NSMutableAttributedString+FLEX.m @@ -0,0 +1,25 @@ +// +// NSMutableAttributedString+FLEX.m +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import "NSMutableAttributedString+FLEX.h" + +@implementation NSMutableAttributedString (FLEX) +- (void)replaceOccurencesOfString:(NSAttributedString *)aString withString:(NSAttributedString *)replacement { + NSRange searchRange = NSMakeRange(0, aString.length); + while (searchRange.location < self.string.length) { + searchRange.length = self.length - searchRange.location; + NSRange foundRange = [self.string rangeOfString:aString.string options:0 range:searchRange]; + if (foundRange.location != NSNotFound) { + searchRange.location = foundRange.location + foundRange.length; + [self replaceCharactersInRange:foundRange withAttributedString:replacement]; + } else { + break; + } + } +} +@end diff --git a/Classes/Utility/Categories/NSObject+SyntaxHighlighting.h b/Classes/Utility/Categories/NSObject+SyntaxHighlighting.h new file mode 100644 index 0000000000..d4c432db06 --- /dev/null +++ b/Classes/Utility/Categories/NSObject+SyntaxHighlighting.h @@ -0,0 +1,15 @@ +// +// NSObject+SyntaxHighlighting.h +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import +#import "NSString+SyntaxHighlighting.h" + +@interface NSObject (SyntaxHighlighting) +@property (readonly, copy) NSAttributedString *attributedDescription; +@property (readonly, copy) NSAttributedString *attributedDebugDescription; +@end diff --git a/Classes/Utility/Categories/NSObject+SyntaxHighlighting.m b/Classes/Utility/Categories/NSObject+SyntaxHighlighting.m new file mode 100644 index 0000000000..2b9d489be4 --- /dev/null +++ b/Classes/Utility/Categories/NSObject+SyntaxHighlighting.m @@ -0,0 +1,18 @@ +// +// NSObject+SyntaxHighlighting.m +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import "NSObject+SyntaxHighlighting.h" + +@implementation NSObject (SyntaxHighlighting) +- (NSAttributedString *)attributedDescription { + return self.description.attributedString; +} +- (NSAttributedString *)attributedDebugDescription { + return self.debugDescription.attributedString; +} +@end diff --git a/Classes/Utility/Categories/NSString+SyntaxHighlighting.h b/Classes/Utility/Categories/NSString+SyntaxHighlighting.h new file mode 100644 index 0000000000..5b3592a144 --- /dev/null +++ b/Classes/Utility/Categories/NSString+SyntaxHighlighting.h @@ -0,0 +1,41 @@ +// +// NSString+SyntaxHighlighting.h +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import "FLEXColor.h" + +@interface NSString (SyntaxHighlighting) +- (NSAttributedString *)attributedString; +- (NSMutableAttributedString *)mutableAttributedString; +- (NSAttributedString *)plainTextAttributedString; +- (NSAttributedString *)commentsAttributedString; +- (NSAttributedString *)documentationMarkupAttributedString; +- (NSAttributedString *)documentationMarkupKeywordsAttributedString; +- (NSAttributedString *)marksAttributedString; +- (NSAttributedString *)stringsAttributedString; +- (NSAttributedString *)charactersAttributedString; +- (NSAttributedString *)numbersAttributedString; +- (NSAttributedString *)keywordsAttributedString; +- (NSAttributedString *)preprocessorStatementsAttributedString; +- (NSAttributedString *)URLsAttributedString; +- (NSAttributedString *)attributesAttributedString; +- (NSAttributedString *)typeDeclarationsAttributedString; +- (NSAttributedString *)otherDeclarationsAttributedString; +- (NSAttributedString *)projectClassNamesAttributedString; +- (NSAttributedString *)projectFunctionAndMethodNamesAttributedString; +- (NSAttributedString *)projectConstantsAttributedString; +- (NSAttributedString *)projectTypeNamesAttributedString; +- (NSAttributedString *)projectInstanceVariablesAndGlobalsAttributedString; +- (NSAttributedString *)projectPreprocessorMacrosAttributedString; +- (NSAttributedString *)otherClassNamesAttributedString; +- (NSAttributedString *)otherFunctionAndMethodNamesAttributedString; +- (NSAttributedString *)otherConstantsAttributedString; +- (NSAttributedString *)otherTypeNamesAttributedString; +- (NSAttributedString *)otherInstanceVariablesAndGlobalsAttributedString; +- (NSAttributedString *)otherPreprocessorMacrosAttributedString; +- (NSAttributedString *)headingAttributedString; +@end diff --git a/Classes/Utility/Categories/NSString+SyntaxHighlighting.m b/Classes/Utility/Categories/NSString+SyntaxHighlighting.m new file mode 100644 index 0000000000..a91f1730f4 --- /dev/null +++ b/Classes/Utility/Categories/NSString+SyntaxHighlighting.m @@ -0,0 +1,99 @@ +// +// NSString+SyntaxHighlighting.m +// FLEX +// +// Created by Jacob Clayden on 25/03/2020. +// Copyright © 2020 Flipboard. All rights reserved. +// + +#import "NSString+SyntaxHighlighting.h" + +@implementation NSString (SyntaxHighlighting) +- (NSAttributedString *)attributedString { + return [[NSAttributedString alloc] initWithString:self]; +} +- (NSAttributedString *)mutableAttributedString { + return [[NSMutableAttributedString alloc] initWithString:self]; +} +- (NSAttributedString *)plainTextAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.plainTextColor }]; +} +- (NSAttributedString *)commentsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.commentsColor }]; +} +- (NSAttributedString *)documentationMarkupAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.documentationMarkupColor }]; +} +- (NSAttributedString *)documentationMarkupKeywordsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.documentationMarkupKeywordsColor }]; +} +- (NSAttributedString *)marksAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.marksColor }]; +} +- (NSAttributedString *)stringsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.stringsColor }]; +} +- (NSAttributedString *)charactersAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.charactersColor }]; +} +- (NSAttributedString *)numbersAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.numbersColor }]; +} +- (NSAttributedString *)keywordsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.keywordsColor }]; +} +- (NSAttributedString *)preprocessorStatementsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.preprocessorStatementsColor }]; +} +- (NSAttributedString *)URLsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.URLsColor }]; +} +- (NSAttributedString *)attributesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.attributesColor }]; +} +- (NSAttributedString *)typeDeclarationsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.typeDeclarationsColor }]; +} +- (NSAttributedString *)otherDeclarationsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherDeclarationsColor }]; +} +- (NSAttributedString *)projectClassNamesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.projectClassNamesColor }]; +} +- (NSAttributedString *)projectFunctionAndMethodNamesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.projectFunctionAndMethodNamesColor }]; +} +- (NSAttributedString *)projectConstantsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.projectConstantsColor }]; +} +- (NSAttributedString *)projectTypeNamesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.projectTypeNamesColor }]; +} +- (NSAttributedString *)projectInstanceVariablesAndGlobalsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.projectInstanceVariablesAndGlobalsColor }]; +} +- (NSAttributedString *)projectPreprocessorMacrosAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.projectPreprocessorMacrosColor }]; +} +- (NSAttributedString *)otherClassNamesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherClassNamesColor }]; +} +- (NSAttributedString *)otherFunctionAndMethodNamesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherFunctionAndMethodNamesColor }]; +} +- (NSAttributedString *)otherConstantsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherConstantsColor }]; +} +- (NSAttributedString *)otherTypeNamesAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherTypeNamesColor }]; +} +- (NSAttributedString *)otherInstanceVariablesAndGlobalsAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherInstanceVariablesAndGlobalsColor }]; +} +- (NSAttributedString *)otherPreprocessorMacrosAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.otherPreprocessorMacrosColor }]; +} +- (NSAttributedString *)headingAttributedString { + return [[NSAttributedString alloc] initWithString:self attributes:@{ NSForegroundColorAttributeName: FLEXColor.headingColor }]; +} +@end diff --git a/Classes/Utility/FLEXColor.h b/Classes/Utility/FLEXColor.h index 45d9dafe99..ab16d86209 100644 --- a/Classes/Utility/FLEXColor.h +++ b/Classes/Utility/FLEXColor.h @@ -42,6 +42,35 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly, class) UIColor *hairlineColor; @property (readonly, class) UIColor *destructiveColor; +// Syntax Colours +@property (readonly, class) UIColor *plainTextColor; +@property (readonly, class) UIColor *commentsColor; +@property (readonly, class) UIColor *documentationMarkupColor; +@property (readonly, class) UIColor *documentationMarkupKeywordsColor; +@property (readonly, class) UIColor *marksColor; +@property (readonly, class) UIColor *stringsColor; +@property (readonly, class) UIColor *charactersColor; +@property (readonly, class) UIColor *numbersColor; +@property (readonly, class) UIColor *keywordsColor; +@property (readonly, class) UIColor *preprocessorStatementsColor; +@property (readonly, class) UIColor *URLsColor; +@property (readonly, class) UIColor *attributesColor; +@property (readonly, class) UIColor *typeDeclarationsColor; +@property (readonly, class) UIColor *otherDeclarationsColor; +@property (readonly, class) UIColor *projectClassNamesColor; +@property (readonly, class) UIColor *projectFunctionAndMethodNamesColor; +@property (readonly, class) UIColor *projectConstantsColor; +@property (readonly, class) UIColor *projectTypeNamesColor; +@property (readonly, class) UIColor *projectInstanceVariablesAndGlobalsColor; +@property (readonly, class) UIColor *projectPreprocessorMacrosColor; +@property (readonly, class) UIColor *otherClassNamesColor; +@property (readonly, class) UIColor *otherFunctionAndMethodNamesColor; +@property (readonly, class) UIColor *otherConstantsColor; +@property (readonly, class) UIColor *otherTypeNamesColor; +@property (readonly, class) UIColor *otherInstanceVariablesAndGlobalsColor; +@property (readonly, class) UIColor *otherPreprocessorMacrosColor; +@property (readonly, class) UIColor *headingColor; + @end NS_ASSUME_NONNULL_END diff --git a/Classes/Utility/FLEXColor.m b/Classes/Utility/FLEXColor.m index edaa645f24..7e53ffe792 100644 --- a/Classes/Utility/FLEXColor.m +++ b/Classes/Utility/FLEXColor.m @@ -137,4 +137,114 @@ + (UIColor *)destructiveColor { return FLEXDynamicColor(systemRedColor, redColor); } +#pragma mark - Syntax Colours + ++ (UIColor *)plainTextColor { + return FLEXDynamicColor(labelColor, whiteColor); +} + ++ (UIColor *)commentsColor { + return FLEXDynamicColor(colorWithRed:0.42353 green:0.47451 blue:0.52549 alpha:1.00000, colorWithRed:0.36471 green:0.42353 blue:0.47451 alpha:1.00000); +} + ++ (UIColor *)documentationMarkupColor { + return FLEXDynamicColor(colorWithRed:0.42353 green:0.47451 blue:0.52549 alpha:1.00000, colorWithRed:0.36471 green:0.42353 blue:0.47451 alpha:1.00000); +} + ++ (UIColor *)documentationMarkupKeywordsColor { + return FLEXDynamicColor(colorWithRed:0.57255 green:0.63137 blue:0.69412 alpha:1.00000, colorWithRed:0.29020 green:0.33333 blue:0.37647 alpha:1.00000); +} + ++ (UIColor *)marksColor { + return FLEXDynamicColor(colorWithRed:0.57255 green:0.63137 blue:0.69412 alpha:1.00000, colorWithRed:0.29020 green:0.33333 blue:0.37647 alpha:1.00000); +} + ++ (UIColor *)stringsColor { + return FLEXDynamicColor(colorWithRed:0.98824 green:0.41569 blue:0.36471 alpha:1.00000, colorWithRed:0.76863 green:0.10196 blue:0.08627 alpha:1.00000); +} + ++ (UIColor *)charactersColor { + return FLEXDynamicColor(colorWithRed:0.81569 green:0.74902 blue:0.41176 alpha:1.00000, colorWithRed:0.10980 green:0.00000 blue:0.81176 alpha:1.00000); +} + ++ (UIColor *)numbersColor { + return FLEXDynamicColor(colorWithRed:0.81569 green:0.74902 blue:0.41176 alpha:1.00000, colorWithRed:0.10980 green:0.00000 blue:0.81176 alpha:1.00000); +} + ++ (UIColor *)keywordsColor { + return FLEXDynamicColor(colorWithRed:0.98824 green:0.37255 blue:0.63922 alpha:1.00000, colorWithRed:0.60784 green:0.13725 blue:0.57647 alpha:1.00000); +} + ++ (UIColor *)preprocessorStatementsColor { + return FLEXDynamicColor(colorWithRed:0.99216 green:0.56078 blue:0.24706 alpha:1.00000, colorWithRed:0.39216 green:0.21961 blue:0.12549 alpha:1.00000); +} + ++ (UIColor *)URLsColor { + return FLEXDynamicColor(colorWithRed:0.32941 green:0.50980 blue:1.00000 alpha:1.00000, colorWithRed:0.05490 green:0.05490 blue:1.00000 alpha:1.00000); +} + ++ (UIColor *)attributesColor { + return FLEXDynamicColor(colorWithRed:0.74902 green:0.52157 blue:0.33333 alpha:1.00000, colorWithRed:0.42745 green:0.30196 blue:0.02353 alpha:1.00000); +} + ++ (UIColor *)typeDeclarationsColor { + return FLEXDynamicColor(colorWithRed:0.36471 green:0.84706 blue:1.00000 alpha:1.00000, colorWithRed:0.04314 green:0.30980 blue:0.47451 alpha:1.00000); +} + ++ (UIColor *)otherDeclarationsColor { + return FLEXDynamicColor(colorWithRed:0.25490 green:0.63137 blue:0.75294 alpha:1.00000, colorWithRed:0.05882 green:0.40784 blue:0.62745 alpha:1.00000); +} + ++ (UIColor *)projectClassNamesColor { + return FLEXDynamicColor(colorWithRed:0.61961 green:0.94510 blue:0.86667 alpha:1.00000, colorWithRed:0.10980 green:0.27451 blue:0.29020 alpha:1.00000); +} + ++ (UIColor *)projectFunctionAndMethodNamesColor { + return FLEXDynamicColor(colorWithRed:0.40392 green:0.71765 blue:0.64314 alpha:1.00000, colorWithRed:0.19608 green:0.42745 blue:0.45490 alpha:1.00000); +} + ++ (UIColor *)projectConstantsColor { + return FLEXDynamicColor(colorWithRed:0.40392 green:0.71765 blue:0.64314 alpha:1.00000, colorWithRed:0.19608 green:0.42745 blue:0.45490 alpha:1.00000); +} + ++ (UIColor *)projectTypeNamesColor { + return FLEXDynamicColor(colorWithRed:0.61961 green:0.94510 blue:0.86667 alpha:1.00000, colorWithRed:0.10980 green:0.27451 blue:0.29020 alpha:1.00000); +} + ++ (UIColor *)projectInstanceVariablesAndGlobalsColor { + return FLEXDynamicColor(colorWithRed:0.40392 green:0.71765 blue:0.64314 alpha:1.00000, colorWithRed:0.19608 green:0.42745 blue:0.45490 alpha:1.00000); +} + ++ (UIColor *)projectPreprocessorMacrosColor { + return FLEXDynamicColor(colorWithRed:0.99216 green:0.56078 blue:0.24706 alpha:1.00000, colorWithRed:0.39216 green:0.21961 blue:0.12549 alpha:1.00000); +} + ++ (UIColor *)otherClassNamesColor { + return FLEXDynamicColor(colorWithRed:0.81569 green:0.65882 blue:1.00000 alpha:1.00000, colorWithRed:0.22353 green:0.00000 blue:0.62745 alpha:1.00000); +} + ++ (UIColor *)otherFunctionAndMethodNamesColor { + return FLEXDynamicColor(colorWithRed:0.63137 green:0.40392 blue:0.90196 alpha:1.00000, colorWithRed:0.42353 green:0.21176 blue:0.66275 alpha:1.00000); +} + ++ (UIColor *)otherConstantsColor { + return FLEXDynamicColor(colorWithRed:0.63137 green:0.40392 blue:0.90196 alpha:1.00000, colorWithRed:0.42353 green:0.21176 blue:0.66275 alpha:1.00000); +} + ++ (UIColor *)otherTypeNamesColor { + return FLEXDynamicColor(colorWithRed:0.81569 green:0.65882 blue:1.00000 alpha:1.00000, colorWithRed:0.22353 green:0.00000 blue:0.62745 alpha:1.00000); +} + ++ (UIColor *)otherInstanceVariablesAndGlobalsColor { + return FLEXDynamicColor(colorWithRed:0.63137 green:0.40392 blue:0.90196 alpha:1.00000, colorWithRed:0.42353 green:0.21176 blue:0.66275 alpha:1.00000); +} + ++ (UIColor *)otherPreprocessorMacrosColor { + return FLEXDynamicColor(colorWithRed:0.99216 green:0.56078 blue:0.24706 alpha:1.00000, colorWithRed:0.39216 green:0.21961 blue:0.12549 alpha:1.00000); +} + ++ (UIColor *)headingColor { + return FLEXDynamicColor(colorWithRed:0.66667 green:0.05098 blue:0.56863 alpha:1.00000, colorWithRed:0.66667 green:0.05098 blue:0.56863 alpha:1.00000); +} + @end diff --git a/Classes/Utility/FLEXUtility.h b/Classes/Utility/FLEXUtility.h index 385fffe20a..9636c82af7 100644 --- a/Classes/Utility/FLEXUtility.h +++ b/Classes/Utility/FLEXUtility.h @@ -44,8 +44,8 @@ + (NSString *)detailDescriptionForView:(UIView *)view; + (UIImage *)circularImageWithColor:(UIColor *)color radius:(CGFloat)radius; + (UIColor *)hierarchyIndentPatternColor; -+ (NSString *)pointerToString:(void *)ptr; -+ (NSString *)addressOfObject:(id)object; ++ (NSAttributedString *)pointerToString:(void *)ptr; ++ (NSAttributedString *)addressOfObject:(id)object; + (NSString *)stringByEscapingHTMLEntitiesInString:(NSString *)originalString; + (UIInterfaceOrientationMask)infoPlistSupportedInterfaceOrientationsMask; + (UIImage *)thumbnailedImageWithMaxPixelDimension:(NSInteger)dimension fromImageData:(NSData *)data; diff --git a/Classes/Utility/FLEXUtility.m b/Classes/Utility/FLEXUtility.m index 79e99f56b4..ded779f9f9 100644 --- a/Classes/Utility/FLEXUtility.m +++ b/Classes/Utility/FLEXUtility.m @@ -13,6 +13,7 @@ #import #import #import +#import "NSString+SyntaxHighlighting.h" @implementation FLEXUtility @@ -197,12 +198,12 @@ + (NSString *)applicationName { return FLEXUtility.applicationImageName.lastPathComponent; } -+ (NSString *)pointerToString:(void *)ptr { - return [NSString stringWithFormat:@"%p", ptr]; ++ (NSAttributedString *)pointerToString:(void *)ptr { + return [NSString stringWithFormat:@"%p", ptr].attributedString; } -+ (NSString *)addressOfObject:(id)object { - return [NSString stringWithFormat:@"%p", object]; ++ (NSAttributedString *)addressOfObject:(id)object { + return [NSString stringWithFormat:@"%p", object].attributedString; } + (NSString *)stringByEscapingHTMLEntitiesInString:(NSString *)originalString { diff --git a/Classes/Utility/Runtime/FLEXRuntimeUtility.h b/Classes/Utility/Runtime/FLEXRuntimeUtility.h index ce34797e6c..ea18618312 100644 --- a/Classes/Utility/Runtime/FLEXRuntimeUtility.h +++ b/Classes/Utility/Runtime/FLEXRuntimeUtility.h @@ -52,9 +52,9 @@ + (NSArray *)classHierarchyOfObject:(id)objectOrClass; /// Used to describe an object in brief within an explorer row -+ (NSString *)summaryForObject:(id)value; -+ (NSString *)safeDescriptionForObject:(id)object; -+ (NSString *)safeDebugDescriptionForObject:(id)object; ++ (NSAttributedString *)summaryForObject:(id)value; ++ (NSAttributedString *)safeDescriptionForObject:(id)object; ++ (NSAttributedString *)safeDebugDescriptionForObject:(id)object; // Property Helpers + (BOOL)tryAddPropertyWithName:(const char *)name diff --git a/Classes/Utility/Runtime/FLEXRuntimeUtility.m b/Classes/Utility/Runtime/FLEXRuntimeUtility.m index 8591e972c4..fde3c00337 100644 --- a/Classes/Utility/Runtime/FLEXRuntimeUtility.m +++ b/Classes/Utility/Runtime/FLEXRuntimeUtility.m @@ -10,6 +10,9 @@ #import "FLEXRuntimeUtility.h" #import "FLEXObjcInternal.h" #import "FLEXTypeEncodingParser.h" +#import "NSString+SyntaxHighlighting.h" +#import "NSMutableAttributedString+FLEX.h" +#import "NSObject+SyntaxHighlighting.h" static NSString *const FLEXRuntimeUtilityErrorDomain = @"FLEXRuntimeUtilityErrorDomain"; typedef NS_ENUM(NSInteger, FLEXRuntimeUtilityErrorCode) { @@ -97,42 +100,42 @@ + (NSUInteger)fieldNameOffsetForTypeEncoding:(const FLEXTypeEncoding *)typeEncod } /// Could be nil -+ (NSString *)safeDescriptionForObject:(id)object { ++ (NSAttributedString *)safeDescriptionForObject:(id)object { // Don't assume that we have an NSObject subclass. // Check to make sure the object responds to the description method if ([object respondsToSelector:@selector(description)]) { - return [object description]; + return [object description].attributedString; } return nil; } /// Never nil -+ (NSString *)safeDebugDescriptionForObject:(id)object { - NSString *description = nil; ++ (NSAttributedString *)safeDebugDescriptionForObject:(id)object { + NSAttributedString *description = nil; // Don't assume that we have an NSObject subclass. // Check to make sure the object responds to the description method if ([object respondsToSelector:@selector(debugDescription)]) { - description = [object debugDescription]; + description = [object debugDescription].attributedString; } else { description = [self safeDescriptionForObject:object]; } if (!description.length) { - NSString *cls = NSStringFromClass(object_getClass(object)); + NSMutableAttributedString *cls = NSStringFromClass(object_getClass(object)).mutableAttributedString; if (object_isClass(object)) { - description = [cls stringByAppendingString:@" class (no description)"]; + description = [cls stringByAppendingAttributedString:@" class (no description)".attributedString]; } else { - description = [cls stringByAppendingString:@" instance (no description)"]; + description = [cls stringByAppendingAttributedString:@" instance (no description)".attributedString]; } } return description; } -+ (NSString *)summaryForObject:(id)value { - NSString *description = nil; ++ (NSAttributedString *)summaryForObject:(id)value { + NSAttributedString *description = nil; // Special case BOOL for better readability. if ([value isKindOfClass:[NSValue class]]) { @@ -140,24 +143,26 @@ + (NSString *)summaryForObject:(id)value { if (strcmp(type, @encode(BOOL)) == 0) { BOOL boolValue = NO; [value getValue:&boolValue]; - return boolValue ? @"YES" : @"NO"; + return boolValue ? @"YES".keywordsAttributedString : @"NO".keywordsAttributedString; } else if (strcmp(type, @encode(SEL)) == 0) { SEL selector = NULL; [value getValue:&selector]; - return NSStringFromSelector(selector); + return NSStringFromSelector(selector).attributedString; } } @try { // Single line display - replace newlines and tabs with spaces. - description = [[self safeDescriptionForObject:value] stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; - description = [description stringByReplacingOccurrencesOfString:@"\t" withString:@" "]; + NSMutableAttributedString *safeDescription = [self safeDescriptionForObject:value].mutableCopy; + [safeDescription replaceOccurencesOfString:@"\n".attributedString withString:@" ".attributedString]; + [safeDescription replaceOccurencesOfString:@"\t".attributedString withString:@" ".attributedString]; + description = safeDescription.copy; } @catch (NSException *e) { - description = [@"Thrown: " stringByAppendingString:e.reason ?: @"(nil exception reason)"]; + description = [@"Thrown: " stringByAppendingString:e.reason ?: @"(nil exception reason)"].attributedString; } if (!description) { - description = @"nil"; + description = @"nil".keywordsAttributedString; } return description; diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.m index adeb4a415c..b1a14d899e 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.m @@ -12,6 +12,8 @@ #import "FLEXMethodBase.h" #import "FLEXProtocol.h" #import +#import "NSAttributedString+FLEX.h" +#import "NSObject+SyntaxHighlighting.h" #pragma mark FLEXClassBuilder @@ -70,6 +72,11 @@ - (NSString *)description { NSStringFromClass(self.class), self.name, self.isRegistered]; } +- (NSAttributedString *)attributedDescription { + return [NSAttributedString stringWithFormat:@"<%@ name=%@, registered=%d>", + NSStringFromClass(self.class), self.name, self.isRegistered]; +} + #pragma mark Building - (NSArray *)addMethods:(NSArray *)methods { NSParameterAssert(methods.count); diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.m index a76052f7dc..f1a154472b 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.m @@ -11,6 +11,7 @@ #import "FLEXRuntimeUtility.h" #import "FLEXRuntimeSafety.h" #import "FLEXTypeEncodingParser.h" +#import "NSAttributedString+FLEX.h" @interface FLEXIvar () { NSString *_flex_description; @@ -83,10 +84,7 @@ - (void)examine { sizeForDetails = @"unknown size"; } - _details = [NSString stringWithFormat: - @"%@, offset %@ — %@", - sizeForDetails, @(_offset), typeForDetails - ]; + _details = [NSString stringWithFormat:@"%@, offset %@ — %@", sizeForDetails, @(_offset), typeForDetails]; } - (id)getValue:(id)target { diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m index cbcd9eefb0..d64ef6ce4e 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m @@ -11,6 +11,8 @@ #import "FLEXMirror.h" #import "FLEXTypeEncodingParser.h" #import "FLEXRuntimeUtility.h" +#import "NSAttributedString+FLEX.h" +#import "NSString+SyntaxHighlighting.h" @implementation FLEXMethod @dynamic implementation; @@ -88,6 +90,14 @@ - (NSString *)description { _flex_description = [self prettyName]; } + return _flex_description.string; +} + +- (NSAttributedString *)attributedDescription { + if (!_flex_description) { + _flex_description = [self prettyName]; + } + return _flex_description; } @@ -100,17 +110,17 @@ - (NSString *)debugNameGivenClassName:(NSString *)name { return string; } -- (NSString *)prettyName { - NSString *methodTypeString = self.isInstanceMethod ? @"-" : @"+"; - NSString *readableReturnType = [FLEXRuntimeUtility readableTypeForEncoding:@(self.signature.methodReturnType ?: "")]; +- (NSAttributedString *)prettyName { + NSAttributedString *methodTypeString = (self.isInstanceMethod ? @"-" : @"+").attributedString; + NSAttributedString *readableReturnType = [FLEXRuntimeUtility readableTypeForEncoding:@(self.signature.methodReturnType ?: "")].attributedString; - NSString *prettyName = [NSString stringWithFormat:@"%@ (%@)", methodTypeString, readableReturnType]; + NSMutableAttributedString *prettyName = [NSMutableAttributedString stringWithFormat:@"%@ (%@)", methodTypeString, readableReturnType]; NSArray *components = [self prettyArgumentComponents]; if (components.count) { - return [prettyName stringByAppendingString:[components componentsJoinedByString:@" "]]; + return [prettyName stringByAppendingAttributedString:[NSAttributedString stringByJoiningArray:components withSeparator:@" ".attributedString]]; } else { - return [prettyName stringByAppendingString:self.selectorString]; + return [prettyName stringByAppendingAttributedString:self.selectorString.otherFunctionAndMethodNamesAttributedString]; } } @@ -123,19 +133,15 @@ - (NSArray *)prettyArgumentComponents { NSMutableArray *components = [NSMutableArray new]; - NSArray *selectorComponents = [self.selectorString componentsSeparatedByString:@":"]; + NSArray *selectorComponents = [self.selectorString componentsSeparatedByString:@":"]; NSUInteger numberOfArguments = self.numberOfArguments; for (NSUInteger argIndex = 2; argIndex < numberOfArguments; argIndex++) { assert(argIndex < self.signature.numberOfArguments); const char *argType = [self.signature getArgumentTypeAtIndex:argIndex] ?: "?"; - NSString *readableArgType = [FLEXRuntimeUtility readableTypeForEncoding:@(argType)]; - NSString *prettyComponent = [NSString - stringWithFormat:@"%@:(%@) ", - selectorComponents[argIndex - 2], - readableArgType - ]; + NSAttributedString *readableArgType = [FLEXRuntimeUtility readableTypeForEncoding:@(argType)].attributedString; + NSAttributedString *prettyComponent = [NSAttributedString stringWithFormat:@"%@:(%@) ", selectorComponents[argIndex - 2].otherFunctionAndMethodNamesAttributedString, readableArgType]; [components addObject:prettyComponent]; } @@ -145,7 +151,7 @@ - (NSArray *)prettyArgumentComponents { - (NSString *)debugDescription { return [NSString stringWithFormat:@"<%@ selector=%@, signature=%@>", - NSStringFromClass(self.class), self.selectorString, self.signatureString]; + NSStringFromClass(self.class), self.selectorString.otherFunctionAndMethodNamesAttributedString, self.signatureString]; } - (void)examine { diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h index 96d838be7c..2f83ea06d1 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h @@ -20,7 +20,7 @@ NSString *_typeEncoding; IMP _implementation; - NSString *_flex_description; + NSAttributedString *_flex_description; } /// Constructs and returns an \c FLEXSimpleMethod instance with the given name, type encoding, and implementation. diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.m index 7e33daa7f1..3ba1e0527b 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.m @@ -8,6 +8,8 @@ // #import "FLEXMethodBase.h" +#import "NSAttributedString+FLEX.h" +#import "NSString+SyntaxHighlighting.h" @implementation FLEXMethodBase @@ -40,7 +42,15 @@ - (NSString *)selectorString { - (NSString *)description { if (!_flex_description) { - _flex_description = [NSString stringWithFormat:@"%@ '%@'", _name, _typeEncoding]; + _flex_description = [NSString stringWithFormat:@"%@ '%@'", _name, _typeEncoding].attributedString; + } + + return _flex_description.string; +} + +- (NSAttributedString *)attributedDescription { + if (!_flex_description) { + _flex_description = [NSString stringWithFormat:@"%@ '%@'", _name, _typeEncoding].attributedString; } return _flex_description; diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h index 89c4549635..04f233605a 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h @@ -67,7 +67,7 @@ /// @return The value of this property on \c target as given by \c -valueForKey: /// A source-like description of the property, with all of its attributes. -@property (nonatomic, readonly) NSString *fullDescription; +@property (nonatomic, readonly) NSAttributedString *fullDescription; /// If this is a class property, you must class the class object. - (id)getValue:(id)target; diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m index 16bbe0bf4a..294f25a473 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m @@ -11,11 +11,14 @@ #import "FLEXPropertyAttributes.h" #import "FLEXMethodBase.h" #import "FLEXRuntimeUtility.h" +#import "NSAttributedString+FLEX.h" +#import "NSObject+SyntaxHighlighting.h" +#import "NSString+SyntaxHighlighting.h" #include @interface FLEXProperty () { - NSString *_flex_description; + NSAttributedString *_flex_description; } @property (nonatomic ) BOOL uniqueCheckFlag; @property (nonatomic, readonly) Class cls; @@ -54,34 +57,34 @@ + (instancetype)propertyWithName:(NSString *)name attributes:(FLEXPropertyAttrib - (id)initWithProperty:(objc_property_t)property onClass:(Class)cls { NSParameterAssert(property); - + self = [super init]; if (self) { _objc_property = property; _attributes = [FLEXPropertyAttributes attributesForProperty:property]; _name = @(property_getName(property) ?: "(nil)"); _cls = cls; - + if (!_attributes) [NSException raise:NSInternalInconsistencyException format:@"Error retrieving property attributes"]; if (!_name) [NSException raise:NSInternalInconsistencyException format:@"Error retrieving property name"]; - + [self examine]; } - + return self; } - (id)initWithName:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes { NSParameterAssert(name); NSParameterAssert(attributes); - + self = [super init]; if (self) { _attributes = attributes; _name = name; - + [self examine]; } - + return self; } @@ -127,7 +130,16 @@ - (void)examine { - (NSString *)description { if (!_flex_description) { NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding]; - _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType]; + _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType].attributedString; + } + + return _flex_description.string; +} + +- (NSAttributedString *)attributedDescription { + if (!_flex_description) { + NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding]; + _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType].attributedString; } return _flex_description; @@ -175,7 +187,7 @@ - (NSString *)imageName { return _imageName; } -- (NSString *)fullDescription { +- (NSAttributedString *)fullDescription { NSMutableArray *attributesStrings = [NSMutableArray new]; FLEXPropertyAttributes *attributes = self.attributes; @@ -203,7 +215,7 @@ - (NSString *)fullDescription { } else { [attributesStrings addObject:@"readwrite"]; } - + // Class or not if (self.isClassProperty) { [attributesStrings addObject:@"class"]; @@ -219,13 +231,18 @@ - (NSString *)fullDescription { [attributesStrings addObject:[NSString stringWithFormat:@"setter=%s", sel_getName(customSetter)]]; } - NSString *attributesString = [attributesStrings componentsJoinedByString:@", "]; - return [NSString stringWithFormat:@"@property (%@) %@", attributesString, self.description]; + NSMutableAttributedString *attributesString = [NSMutableAttributedString new]; + for (int i = 0; i < attributesStrings.count; i++) { + [attributesString appendAttributedString:attributesStrings[i].keywordsAttributedString]; + if (i != attributesStrings.count - 1) + [attributesString appendAttributedString:@", ".attributedString]; + } + return [NSAttributedString stringWithFormat:@"%@ (%@) %@", @"@property".keywordsAttributedString, attributesString, self.attributedDescription]; } - (id)getValue:(id)target { if (!target) return nil; - + // We don't care about checking dynamically whether the getter // _now_ exists on this object. If the getter doesn't exist // when this property is initialized, it will never call it. diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h b/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h index b9bac2eb38..73479068e1 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h @@ -21,7 +21,8 @@ NS_ASSUME_NONNULL_BEGIN // These are necessary for the mutable subclass to function @protected NSUInteger _count; - NSString *_string, *_backingIvar, *_typeEncoding, *_oldTypeEncoding, *_fullDeclaration; + NSString *_backingIvar, *_typeEncoding, *_oldTypeEncoding; + NSAttributedString *_string, *_fullDeclaration; NSDictionary *_dictionary; objc_property_attribute_t *_list; SEL _customGetter, _customSetter; @@ -42,9 +43,9 @@ NS_ASSUME_NONNULL_BEGIN /// For use with \c class_replaceProperty and the like. @property (nonatomic, readonly) objc_property_attribute_t *list; /// The string value of the property attributes. -@property (nonatomic, readonly) NSString *string; +@property (nonatomic, readonly) NSAttributedString *string; /// A human-readable version of the property attributes. -@property (nonatomic, readonly) NSString *fullDeclaration; +@property (nonatomic, readonly) NSAttributedString *fullDeclaration; /// A dictionary of the property attributes. /// Values are either a string or \c @YES. Boolean attributes /// which are false will not be present in the dictionary. diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m index f9af3b05cb..8865988582 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m @@ -11,6 +11,10 @@ #import "FLEXRuntimeUtility.h" #import "NSString+ObjcRuntime.h" #import "NSDictionary+ObjcRuntime.h" +#import "NSAttributedString+FLEX.h" +#import "NSMutableAttributedString+FLEX.h" +#import "NSString+SyntaxHighlighting.h" +#import "NSObject+SyntaxHighlighting.h" #pragma mark FLEXPropertyAttributes @@ -30,7 +34,7 @@ @interface FLEXPropertyAttributes () @property (nonatomic) BOOL isWeak; @property (nonatomic) BOOL isGarbageCollectable; -- (NSString *)buildFullDeclaration; +- (NSAttributedString *)buildFullDeclaration; @end @@ -88,8 +92,21 @@ - (NSString *)description { ]; } +- (NSAttributedString *)attributedDescription { + return [NSAttributedString + stringWithFormat:@"<%@ \"%@\", ivar=%@, readonly=%d, nonatomic=%d, getter=%@, setter=%@>", + NSStringFromClass(self.class), + self.string, + self.backingIvar ?: @"none", + self.isReadOnly, + self.isNonatomic, + NSStringFromSelector(self.customGetter) ?: @"none", + NSStringFromSelector(self.customSetter) ?: @"none" + ]; +} + - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount { - NSDictionary *attrs = self.string.propertyAttributes; + NSDictionary *attrs = self.string.string.propertyAttributes; objc_property_attribute_t *propertyAttributes = malloc(attrs.count * sizeof(objc_property_attribute_t)); if (attributesCount) { @@ -190,36 +207,43 @@ - (objc_property_attribute_t *)list { return _list; } -- (NSString *)buildFullDeclaration { - NSMutableString *decl = [NSMutableString new]; +- (NSAttributedString *)buildFullDeclaration { + NSMutableAttributedString *decl = [NSMutableAttributedString new]; - [decl appendFormat:@"%@, ", _isNonatomic ? @"nonatomic" : @"atomic"]; - [decl appendFormat:@"%@, ", _isReadOnly ? @"readonly" : @"readwrite"]; + [decl appendAttributedString:[NSAttributedString stringWithFormat:@"%@, ", _isNonatomic ? @"nonatomic".keywordsAttributedString : @"atomic".keywordsAttributedString]]; + [decl appendAttributedString:[NSAttributedString stringWithFormat:@"%@, ", _isReadOnly ? @"readonly".keywordsAttributedString : @"readwrite".keywordsAttributedString]]; BOOL noExplicitMemorySemantics = YES; if (_isCopy) { noExplicitMemorySemantics = NO; - [decl appendString:@"copy, "]; + [decl appendAttributedString:@"copy".keywordsAttributedString]; + [decl appendAttributedString:@", ".attributedString]; } if (_isRetained) { noExplicitMemorySemantics = NO; - [decl appendString:@"strong, "]; + [decl appendAttributedString:@"strong".keywordsAttributedString]; + [decl appendAttributedString:@", ".attributedString]; } if (_isWeak) { noExplicitMemorySemantics = NO; - [decl appendString:@"weak, "]; + [decl appendAttributedString:@"weak".keywordsAttributedString]; + [decl appendAttributedString:@", ".attributedString]; } if ([_typeEncoding hasPrefix:@"@"] && noExplicitMemorySemantics) { // *probably* strong if this is an object; strong is the default. - [decl appendString:@"strong, "]; + [decl appendAttributedString:@"strong".keywordsAttributedString]; + [decl appendAttributedString:@", ".attributedString]; } else if (noExplicitMemorySemantics) { // *probably* assign if this is not an object - [decl appendString:@"assign, "]; + [decl appendAttributedString:@"assign".keywordsAttributedString]; + [decl appendAttributedString:@", ".attributedString]; } if (_customGetter) { - [decl appendFormat:@"getter=%@, ", NSStringFromSelector(_customGetter)]; + [decl appendAttributedString:[NSAttributedString stringWithFormat:@"getter=%@", NSStringFromSelector(_customGetter)]]; + [decl appendAttributedString:@", ".attributedString]; } if (_customSetter) { - [decl appendFormat:@"setter=%@, ", NSStringFromSelector(_customSetter)]; + [decl appendAttributedString:[NSAttributedString stringWithFormat:@"setter=%@", NSStringFromSelector(_customSetter)]]; + [decl appendAttributedString:@", ".attributedString]; } [decl deleteCharactersInRange:NSMakeRange(decl.length-2, 2)]; @@ -312,7 +336,7 @@ - (objc_property_attribute_t *)list { return super.list; } -- (NSString *)string { +- (NSAttributedString *)string { // Regenerate string after mutations if (self.stringDelta || !_string) { self.stringDelta = NO; @@ -354,7 +378,7 @@ - (NSDictionary *)dictionary { return _dictionary; } -- (NSString *)fullDeclaration { +- (NSAttributedString *)fullDeclaration { if (self.declDelta || !_fullDeclaration) { _declDelta = NO; _fullDeclaration = [self buildFullDeclaration]; diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.m index b17b3fbc18..b0c17e33cd 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.m @@ -10,6 +10,8 @@ #import "FLEXProtocol.h" #import "FLEXProperty.h" #import "FLEXRuntimeUtility.h" +#import "NSAttributedString+FLEX.h" +#import "NSObject+SyntaxHighlighting.h" @implementation FLEXProtocol @@ -58,12 +60,22 @@ - (NSString *)description { return self.name; } +- (NSAttributedString *)attributedDescription { + return self.name.attributedString; +} + - (NSString *)debugDescription { return [NSString stringWithFormat:@"<%@ name=%@, %lu properties, %lu required methods, %lu optional methods, %lu protocols>", NSStringFromClass(self.class), self.name, (unsigned long)self.properties.count, (unsigned long)self.requiredMethods.count, (unsigned long)self.optionalMethods.count, (unsigned long)self.protocols.count]; } +- (NSAttributedString *)attributedDebugDescription { + return [NSAttributedString stringWithFormat:@"<%@ name=%@, %lu properties, %lu required methods, %lu optional methods, %lu protocols>", + NSStringFromClass(self.class), self.name, (unsigned long)self.properties.count, + (unsigned long)self.requiredMethods.count, (unsigned long)self.optionalMethods.count, (unsigned long)self.protocols.count]; +} + - (void)examine { _name = @(protocol_getName(self.objc_protocol)); unsigned int prcount, pccount, mdrcount, mdocount; @@ -139,9 +151,18 @@ - (NSString *)description { return NSStringFromSelector(self.selector); } +- (NSAttributedString *)attributedDescription { + return NSStringFromSelector(self.selector).attributedString; +} + - (NSString *)debugDescription { return [NSString stringWithFormat:@"<%@ name=%@, type=%@>", NSStringFromClass(self.class), NSStringFromSelector(self.selector), self.typeEncoding]; } +- (NSAttributedString *)attributedDebugDescription { + return [NSAttributedString stringWithFormat:@"<%@ name=%@, type=%@>", + NSStringFromClass(self.class), NSStringFromSelector(self.selector), self.typeEncoding]; +} + @end diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m index 5e5f6ed04c..abeaae2d0a 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m @@ -11,6 +11,8 @@ #import "FLEXProtocol.h" #import "FLEXProperty.h" #import +#import "NSAttributedString+FLEX.h" +#import "NSObject+SyntaxHighlighting.h" #define MutationAssertion(msg) if (self.isRegistered) { \ [NSException \ @@ -58,6 +60,11 @@ - (NSString *)description { NSStringFromClass(self.class), self.name, self.isRegistered]; } +- (NSAttributedString *)attributedDescription { + return [NSAttributedString stringWithFormat:@"<%@ name=%@, registered=%d>", + NSStringFromClass(self.class), self.name, self.isRegistered]; +} + #pragma mark Building - (void)addProperty:(FLEXProperty *)property isRequired:(BOOL)isRequired { diff --git a/FLEX.xcodeproj/project.pbxproj b/FLEX.xcodeproj/project.pbxproj index 67e8b10a99..aaa94f42dc 100644 --- a/FLEX.xcodeproj/project.pbxproj +++ b/FLEX.xcodeproj/project.pbxproj @@ -8,6 +8,14 @@ /* Begin PBXBuildFile section */ 04F1CA191C137CF1000A52B0 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 04F1CA181C137CF1000A52B0 /* LICENSE */; }; + 16A1B3FF242C021D00B8BE4B /* NSAttributedString+FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = 16A1B39C242BB9FE00B8BE4B /* NSAttributedString+FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 16A1B400242C021D00B8BE4B /* NSAttributedString+FLEX.m in Sources */ = {isa = PBXBuildFile; fileRef = 16A1B39D242BB9FE00B8BE4B /* NSAttributedString+FLEX.m */; }; + 16A1B401242C021D00B8BE4B /* NSMutableAttributedString+FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = 16A1B3F8242BF2F300B8BE4B /* NSMutableAttributedString+FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 16A1B402242C021D00B8BE4B /* NSMutableAttributedString+FLEX.m in Sources */ = {isa = PBXBuildFile; fileRef = 16A1B3F9242BF2F300B8BE4B /* NSMutableAttributedString+FLEX.m */; }; + 16A1B403242C021D00B8BE4B /* NSObject+SyntaxHighlighting.h in Headers */ = {isa = PBXBuildFile; fileRef = 16A1B3A4242BBB3400B8BE4B /* NSObject+SyntaxHighlighting.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 16A1B404242C021D00B8BE4B /* NSObject+SyntaxHighlighting.m in Sources */ = {isa = PBXBuildFile; fileRef = 16A1B3A5242BBB3400B8BE4B /* NSObject+SyntaxHighlighting.m */; }; + 16A1B405242C021D00B8BE4B /* NSString+SyntaxHighlighting.h in Headers */ = {isa = PBXBuildFile; fileRef = 16A1B394242BB26F00B8BE4B /* NSString+SyntaxHighlighting.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 16A1B406242C021D00B8BE4B /* NSString+SyntaxHighlighting.m in Sources */ = {isa = PBXBuildFile; fileRef = 16A1B395242BB26F00B8BE4B /* NSString+SyntaxHighlighting.m */; }; 1C27A8B91F0E5A0400F0D02D /* FLEXTestsMethodsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C27A8B81F0E5A0400F0D02D /* FLEXTestsMethodsList.m */; }; 1C27A8BB1F0E5A0400F0D02D /* FLEX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4C941F1B5B20570088C3F2 /* FLEX.framework */; }; 222C88221C7339DC007CA15F /* FLEXRealmDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222C88211C7339DC007CA15F /* FLEXRealmDefines.h */; }; @@ -110,7 +118,7 @@ 71E1C2172307FBB800F5032A /* FLEXKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C20F2307FBB700F5032A /* FLEXKeychain.m */; }; 71E1C2182307FBB800F5032A /* FLEXKeychainTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C2102307FBB700F5032A /* FLEXKeychainTableViewController.m */; }; 71E1C2192307FBB800F5032A /* FLEXKeychainQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 71E1C2112307FBB700F5032A /* FLEXKeychainQuery.m */; }; - 7349FD6A22B93CDF00051810 /* FLEXColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7349FD6822B93CDF00051810 /* FLEXColor.h */; }; + 7349FD6A22B93CDF00051810 /* FLEXColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7349FD6822B93CDF00051810 /* FLEXColor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7349FD6B22B93CDF00051810 /* FLEXColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 7349FD6922B93CDF00051810 /* FLEXColor.m */; }; 779B1ECE1C0C4D7C001F5E49 /* FLEXDatabaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC01C0C4D7C001F5E49 /* FLEXDatabaseManager.h */; }; 779B1ED01C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC21C0C4D7C001F5E49 /* FLEXMultiColumnTableView.h */; }; @@ -358,6 +366,14 @@ /* Begin PBXFileReference section */ 04F1CA181C137CF1000A52B0 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + 16A1B394242BB26F00B8BE4B /* NSString+SyntaxHighlighting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+SyntaxHighlighting.h"; sourceTree = ""; }; + 16A1B395242BB26F00B8BE4B /* NSString+SyntaxHighlighting.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+SyntaxHighlighting.m"; sourceTree = ""; }; + 16A1B39C242BB9FE00B8BE4B /* NSAttributedString+FLEX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+FLEX.h"; sourceTree = ""; }; + 16A1B39D242BB9FE00B8BE4B /* NSAttributedString+FLEX.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+FLEX.m"; sourceTree = ""; }; + 16A1B3A4242BBB3400B8BE4B /* NSObject+SyntaxHighlighting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+SyntaxHighlighting.h"; sourceTree = ""; }; + 16A1B3A5242BBB3400B8BE4B /* NSObject+SyntaxHighlighting.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SyntaxHighlighting.m"; sourceTree = ""; }; + 16A1B3F8242BF2F300B8BE4B /* NSMutableAttributedString+FLEX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSMutableAttributedString+FLEX.h"; sourceTree = ""; }; + 16A1B3F9242BF2F300B8BE4B /* NSMutableAttributedString+FLEX.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSMutableAttributedString+FLEX.m"; sourceTree = ""; }; 1C27A8B61F0E5A0300F0D02D /* FLEXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FLEXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1C27A8B81F0E5A0400F0D02D /* FLEXTestsMethodsList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXTestsMethodsList.m; sourceTree = ""; }; 1C27A8BA1F0E5A0400F0D02D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -1244,6 +1260,14 @@ C3694DC123EA147F006625D7 /* UIBarButtonItem+FLEX.m */, C30199482409B38A00759E8E /* CALayer+FLEX.h */, C30199492409B38A00759E8E /* CALayer+FLEX.m */, + 16A1B39C242BB9FE00B8BE4B /* NSAttributedString+FLEX.h */, + 16A1B39D242BB9FE00B8BE4B /* NSAttributedString+FLEX.m */, + 16A1B3F8242BF2F300B8BE4B /* NSMutableAttributedString+FLEX.h */, + 16A1B3F9242BF2F300B8BE4B /* NSMutableAttributedString+FLEX.m */, + 16A1B3A4242BBB3400B8BE4B /* NSObject+SyntaxHighlighting.h */, + 16A1B3A5242BBB3400B8BE4B /* NSObject+SyntaxHighlighting.m */, + 16A1B394242BB26F00B8BE4B /* NSString+SyntaxHighlighting.h */, + 16A1B395242BB26F00B8BE4B /* NSString+SyntaxHighlighting.m */, ); path = Categories; sourceTree = ""; @@ -1415,6 +1439,7 @@ 3A4C94EB1B5B21410088C3F2 /* FLEXImagePreviewViewController.h in Headers */, C34D4EB823A2B17900C1F903 /* FLEXBundleShortcuts.h in Headers */, C3694DC223EA147F006625D7 /* UIBarButtonItem+FLEX.h in Headers */, + 16A1B405242C021D00B8BE4B /* NSString+SyntaxHighlighting.h in Headers */, C38F3F31230C958F004E3731 /* FLEXAlert.h in Headers */, C398624D23AD6C67007E6793 /* FLEXKeyPathSearchController.h in Headers */, 3A4C95381B5B21410088C3F2 /* FLEXNetworkRecorder.h in Headers */, @@ -1484,6 +1509,7 @@ C398682923AC370100E9E391 /* FLEXViewShortcuts.h in Headers */, C3474C4023DA496400466532 /* FLEXKeyValueTableViewCell.h in Headers */, 779B1ED61C0C4D7C001F5E49 /* FLEXTableContentViewController.h in Headers */, + 16A1B401242C021D00B8BE4B /* NSMutableAttributedString+FLEX.h in Headers */, C3DFCDB82418336D00BB7084 /* NSUserDefaults+FLEX.h in Headers */, 3A4C95221B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h in Headers */, C33E46AF223B02CD004BD0E6 /* FLEXASLLogController.h in Headers */, @@ -1540,6 +1566,7 @@ C3A9423C23C54010006871A3 /* FHSSnapshotView.h in Headers */, 3A4C95261B5B21410088C3F2 /* FLEXGlobalsViewController.h in Headers */, C398625923AD6C88007E6793 /* FLEXSearchToken.h in Headers */, + 16A1B3FF242C021D00B8BE4B /* NSAttributedString+FLEX.h in Headers */, C33C825E2316DC8600DD2451 /* FLEXObjectExplorer.h in Headers */, C34D4EB423A2AF2A00C1F903 /* FLEXColorPreviewSection.h in Headers */, C383C3BE23B6B398007A321B /* UITextField+Range.h in Headers */, @@ -1548,6 +1575,7 @@ C386D6ED24199EC600699085 /* FLEX-Runtime.h in Headers */, C398682623AC359600E9E391 /* FLEXShortcutsFactory+Defaults.h in Headers */, C397E318240EC98F0091E4EC /* FLEXSQLResult.h in Headers */, + 16A1B403242C021D00B8BE4B /* NSObject+SyntaxHighlighting.h in Headers */, 7349FD6A22B93CDF00051810 /* FLEXColor.h in Headers */, C36FBFD3230F3B98008D95D5 /* FLEXMethod.h in Headers */, C36FBFD8230F3B98008D95D5 /* FLEXPropertyAttributes.h in Headers */, @@ -1694,6 +1722,7 @@ files = ( C398682823AC36EC00E9E391 /* FLEXViewShortcuts.m in Sources */, C3DFCDB92418336D00BB7084 /* NSUserDefaults+FLEX.m in Sources */, + 16A1B402242C021D00B8BE4B /* NSMutableAttributedString+FLEX.m in Sources */, C3878DBE23A74A8F0038FDBE /* FLEXNetworkRecorder.m in Sources */, C3878DBC23A749F70038FDBE /* FLEXFieldEditorViewController.m in Sources */, 942DCD871BAE0CA300DB5DC2 /* FLEXKeyboardShortcutManager.m in Sources */, @@ -1716,6 +1745,7 @@ 3A4C94F61B5B21410088C3F2 /* FLEXArgumentInputObjectView.m in Sources */, 3A4C94EC1B5B21410088C3F2 /* FLEXImagePreviewViewController.m in Sources */, C383C3BA23B6A62A007A321B /* FLEXRuntimeSafety.m in Sources */, + 16A1B404242C021D00B8BE4B /* NSObject+SyntaxHighlighting.m in Sources */, 3A4C94F21B5B21410088C3F2 /* FLEXArgumentInputFontsPickerView.m in Sources */, C3BFD071233C23ED0015FB82 /* NSArray+Functional.m in Sources */, 7349FD6B22B93CDF00051810 /* FLEXColor.m in Sources */, @@ -1726,6 +1756,7 @@ C36FBFD4230F3B98008D95D5 /* FLEXProtocol.m in Sources */, C34D4EB123A2ABD900C1F903 /* FLEXLayerShortcuts.m in Sources */, C38F3F32230C958F004E3731 /* FLEXAlert.m in Sources */, + 16A1B406242C021D00B8BE4B /* NSString+SyntaxHighlighting.m in Sources */, C301994B2409B38A00759E8E /* CALayer+FLEX.m in Sources */, 3A4C95081B5B21410088C3F2 /* FLEXDefaultEditorViewController.m in Sources */, 779B1ED11C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m in Sources */, @@ -1771,6 +1802,7 @@ 3A4C94D61B5B21410088C3F2 /* FLEXObjectExplorerViewController.m in Sources */, C383C3BD23B6B398007A321B /* UITextField+Range.m in Sources */, 3A4C94DE1B5B21410088C3F2 /* FLEXHeapEnumerator.m in Sources */, + 16A1B400242C021D00B8BE4B /* NSAttributedString+FLEX.m in Sources */, 3A4C95251B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m in Sources */, C36FBFD1230F3B98008D95D5 /* FLEXClassBuilder.m in Sources */, 779B1ED51C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m in Sources */, diff --git a/FLEX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/FLEX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/FLEX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + From c75e4c979c07020f137ceecbaf514fe2ebcdd8eb Mon Sep 17 00:00:00 2001 From: JacobCXDev Date: Thu, 26 Mar 2020 16:20:04 +0000 Subject: [PATCH 2/2] Shortcuts (mostly) done --- .../Editing/FLEXFieldEditorViewController.m | 4 +- .../Editing/FLEXMethodCallingViewController.m | 2 +- .../Utility/Categories/FLEXRuntime+Compare.m | 4 +- .../Categories/NSAttributedString+FLEX.h | 2 + .../Categories/NSAttributedString+FLEX.m | 5 + .../Utility/Categories/NSObject+Reflection.m | 2 +- Classes/Utility/Runtime/FLEXRuntimeUtility.h | 4 +- Classes/Utility/Runtime/FLEXRuntimeUtility.m | 198 ++++++++++-------- .../Objc/Reflection/FLEXBlockDescription.h | 2 +- .../Objc/Reflection/FLEXBlockDescription.m | 18 +- .../Objc/Reflection/FLEXClassBuilder.m | 2 +- .../Runtime/Objc/Reflection/FLEXIvar.h | 2 +- .../Runtime/Objc/Reflection/FLEXIvar.m | 26 ++- .../Runtime/Objc/Reflection/FLEXMethod.m | 4 +- .../Runtime/Objc/Reflection/FLEXProperty.h | 2 +- .../Runtime/Objc/Reflection/FLEXProperty.m | 26 +-- .../Objc/Reflection/FLEXPropertyAttributes.m | 1 - .../Objc/Reflection/FLEXProtocolBuilder.m | 2 +- 18 files changed, 168 insertions(+), 138 deletions(-) diff --git a/Classes/Editing/FLEXFieldEditorViewController.m b/Classes/Editing/FLEXFieldEditorViewController.m index 343fce14c6..d232752f2c 100644 --- a/Classes/Editing/FLEXFieldEditorViewController.m +++ b/Classes/Editing/FLEXFieldEditorViewController.m @@ -38,14 +38,14 @@ + (instancetype)target:(id)target property:(FLEXProperty *)property { } FLEXFieldEditorViewController *editor = [self target:target]; - editor.title = [@"Property: " stringByAppendingString:property.name]; + editor.title = [@"Property: " stringByAppendingString:property.name.string]; editor.property = property; return editor; } + (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar { FLEXFieldEditorViewController *editor = [self target:target]; - editor.title = [@"Ivar: " stringByAppendingString:ivar.name]; + editor.title = [@"Ivar: " stringByAppendingString:ivar.name.string]; editor.ivar = ivar; return editor; } diff --git a/Classes/Editing/FLEXMethodCallingViewController.m b/Classes/Editing/FLEXMethodCallingViewController.m index 3165b3b0b6..26a01c7e68 100644 --- a/Classes/Editing/FLEXMethodCallingViewController.m +++ b/Classes/Editing/FLEXMethodCallingViewController.m @@ -47,7 +47,7 @@ - (void)viewDidLoad { // Configure field editor view self.fieldEditorView.argumentInputViews = [self argumentInputViews]; - self.fieldEditorView.fieldDescription = [NSAttributedString stringWithFormat:@"Signature:\n%@\n\nReturn Type:\n%s", self.method.description, [NSString stringWithFormat:@"%s", (char *)self.method.returnType].attributedString]; + self.fieldEditorView.fieldDescription = [NSAttributedString stringWithFormat:@"Signature:\n%@\n\nReturn Type:\n%@", self.method.description, [NSString stringWithFormat:@"%s", (char *)self.method.returnType].attributedString]; } - (NSArray *)argumentInputViews { diff --git a/Classes/Utility/Categories/FLEXRuntime+Compare.m b/Classes/Utility/Categories/FLEXRuntime+Compare.m index 8889bbf3f2..1404f6ec70 100644 --- a/Classes/Utility/Categories/FLEXRuntime+Compare.m +++ b/Classes/Utility/Categories/FLEXRuntime+Compare.m @@ -11,7 +11,7 @@ @implementation FLEXProperty (Compare) - (NSComparisonResult)compare:(FLEXProperty *)other { - NSComparisonResult r = [self.name caseInsensitiveCompare:other.name]; + NSComparisonResult r = [self.name.string caseInsensitiveCompare:other.name.string]; if (r == NSOrderedSame) { // TODO make sure empty image name sorts above an image name return [self.imageName ?: @"" compare:other.imageName]; @@ -25,7 +25,7 @@ - (NSComparisonResult)compare:(FLEXProperty *)other { @implementation FLEXIvar (Compare) - (NSComparisonResult)compare:(FLEXIvar *)other { - return [self.name caseInsensitiveCompare:other.name]; + return [self.name.string caseInsensitiveCompare:other.name.string]; } @end diff --git a/Classes/Utility/Categories/NSAttributedString+FLEX.h b/Classes/Utility/Categories/NSAttributedString+FLEX.h index 1c03d02c21..684a16f6dc 100644 --- a/Classes/Utility/Categories/NSAttributedString+FLEX.h +++ b/Classes/Utility/Categories/NSAttributedString+FLEX.h @@ -7,10 +7,12 @@ // #import +#import "NSMutableAttributedString+FLEX.h" @interface NSAttributedString (FLEX) + (instancetype)stringByJoiningArray:(NSArray *)array withSeparator:(NSAttributedString *)separator; + (instancetype)stringWithFormat:(NSString *)format, ...; + (instancetype)stringWithAttributes:(NSDictionary *)attributes format:(NSString *)format, ...; - (instancetype)stringByAppendingAttributedString:(NSAttributedString *)aString; +- (instancetype)stringByReplacingOccurrencesOfString:(NSAttributedString *)aString withString:(NSAttributedString *)replacement; @end diff --git a/Classes/Utility/Categories/NSAttributedString+FLEX.m b/Classes/Utility/Categories/NSAttributedString+FLEX.m index 685097cb39..d4df22b4a5 100644 --- a/Classes/Utility/Categories/NSAttributedString+FLEX.m +++ b/Classes/Utility/Categories/NSAttributedString+FLEX.m @@ -62,5 +62,10 @@ - (instancetype)stringByAppendingAttributedString:(NSAttributedString *)aString [attributedString appendAttributedString:aString]; return attributedString; } +- (instancetype)stringByReplacingOccurrencesOfString:(NSAttributedString *)aString withString:(NSAttributedString *)replacement { + NSMutableAttributedString *attributedString = self.mutableCopy; + [attributedString replaceOccurencesOfString:aString withString:replacement]; + return attributedString; +} @end diff --git a/Classes/Utility/Categories/NSObject+Reflection.m b/Classes/Utility/Categories/NSObject+Reflection.m index 105e834fcf..004f2abda7 100644 --- a/Classes/Utility/Categories/NSObject+Reflection.m +++ b/Classes/Utility/Categories/NSObject+Reflection.m @@ -424,7 +424,7 @@ + (FLEXProperty *)flex_classPropertyNamed:(NSString *)name { } + (void)flex_replaceProperty:(FLEXProperty *)property { - [self flex_replaceProperty:property.name attributes:property.attributes]; + [self flex_replaceProperty:property.name.string attributes:property.attributes]; } + (void)flex_replaceProperty:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes { diff --git a/Classes/Utility/Runtime/FLEXRuntimeUtility.h b/Classes/Utility/Runtime/FLEXRuntimeUtility.h index ea18618312..8dc2039f5c 100644 --- a/Classes/Utility/Runtime/FLEXRuntimeUtility.h +++ b/Classes/Utility/Runtime/FLEXRuntimeUtility.h @@ -45,7 +45,7 @@ + (NSUInteger)fieldNameOffsetForTypeEncoding:(const FLEXTypeEncoding *)typeEncoding; /// Given name "foo" and type "int" this would return "int foo", but /// given name "foo" and type "T *" it would return "T *foo" -+ (NSString *)appendName:(NSString *)name toType:(NSString *)typeEncoding; ++ (NSAttributedString *)appendName:(NSAttributedString *)name toType:(NSAttributedString *)typeEncoding; /// @return The class hierarchy for the given object or class, /// from the current class to the root-most class. @@ -84,6 +84,6 @@ #pragma mark - Metadata Helpers -+ (NSString *)readableTypeForEncoding:(NSString *)encodingString; ++ (NSAttributedString *)readableTypeForEncoding:(NSString *)encodingString; @end diff --git a/Classes/Utility/Runtime/FLEXRuntimeUtility.m b/Classes/Utility/Runtime/FLEXRuntimeUtility.m index fde3c00337..29d8fe267c 100644 --- a/Classes/Utility/Runtime/FLEXRuntimeUtility.m +++ b/Classes/Utility/Runtime/FLEXRuntimeUtility.m @@ -103,6 +103,9 @@ + (NSUInteger)fieldNameOffsetForTypeEncoding:(const FLEXTypeEncoding *)typeEncod + (NSAttributedString *)safeDescriptionForObject:(id)object { // Don't assume that we have an NSObject subclass. // Check to make sure the object responds to the description method + if ([object respondsToSelector:@selector(attributedDescription)]) { + return [object attributedDescription]; + } if ([object respondsToSelector:@selector(description)]) { return [object description].attributedString; } @@ -147,16 +150,15 @@ + (NSAttributedString *)summaryForObject:(id)value { } else if (strcmp(type, @encode(SEL)) == 0) { SEL selector = NULL; [value getValue:&selector]; - return NSStringFromSelector(selector).attributedString; + return NSStringFromSelector(selector).otherFunctionAndMethodNamesAttributedString; } } @try { // Single line display - replace newlines and tabs with spaces. - NSMutableAttributedString *safeDescription = [self safeDescriptionForObject:value].mutableCopy; - [safeDescription replaceOccurencesOfString:@"\n".attributedString withString:@" ".attributedString]; - [safeDescription replaceOccurencesOfString:@"\t".attributedString withString:@" ".attributedString]; - description = safeDescription.copy; + NSAttributedString *safeDescription = [self safeDescriptionForObject:value]; + safeDescription = [safeDescription stringByReplacingOccurrencesOfString:@"\n".attributedString withString:@" ".attributedString]; + safeDescription = [safeDescription stringByReplacingOccurrencesOfString:@"\t".attributedString withString:@" ".attributedString]; } @catch (NSException *e) { description = [@"Thrown: " stringByAppendingString:e.reason ?: @"(nil exception reason)"].attributedString; } @@ -224,8 +226,8 @@ + (BOOL)tryAddPropertyWithName:(const char *)name #pragma mark - Method Helpers (Public) -+ (NSArray *)prettyArgumentComponentsForMethod:(Method)method { - NSMutableArray *components = [NSMutableArray new]; ++ (NSArray *)prettyArgumentComponentsForMethod:(Method)method { + NSMutableArray *components = [NSMutableArray new]; NSString *selectorName = NSStringFromSelector(method_getName(method)); NSMutableArray *selectorComponents = [selectorName componentsSeparatedByString:@":"].mutableCopy; @@ -241,13 +243,9 @@ + (BOOL)tryAddPropertyWithName:(const char *)name for (unsigned int argIndex = 0; argIndex < selectorComponents.count; argIndex++) { char *argType = method_copyArgumentType(method, argIndex + kFLEXNumberOfImplicitArgs); - NSString *readableArgType = (argType != NULL) ? [self readableTypeForEncoding:@(argType)] : nil; + NSAttributedString *readableArgType = (argType != NULL) ? [self readableTypeForEncoding:@(argType)] : nil; free(argType); - NSString *prettyComponent = [NSString - stringWithFormat:@"%@:(%@) ", - selectorComponents[argIndex], - readableArgType - ]; + NSAttributedString *prettyComponent = [NSAttributedString stringWithFormat:@"%@:(%@) ", selectorComponents[argIndex].otherFunctionAndMethodNamesAttributedString, readableArgType]; [components addObject:prettyComponent]; } @@ -600,13 +598,7 @@ + (void)enumerateTypesInStructEncoding:(const char *)structEncoding runningFieldOffset += fieldAlignment - currentSizeSum; } - typeBlock( - structName, - typeEncoding.UTF8String, - [self readableTypeForEncoding:typeEncoding], - runningFieldIndex, - runningFieldOffset - ); + typeBlock(structName, typeEncoding.UTF8String, [self readableTypeForEncoding:typeEncoding].string, runningFieldIndex, runningFieldOffset); runningFieldOffset += fieldSize; runningFieldIndex++; typeStart = nextTypeStart; @@ -630,23 +622,23 @@ + (void)enumerateTypesInStructEncoding:(const char *)structEncoding return attributesDictionary; } -+ (NSString *)appendName:(NSString *)name toType:(NSString *)type { ++ (NSAttributedString *)appendName:(NSAttributedString *)name toType:(NSAttributedString *)type { if (!type.length) { - type = @"(?)"; + type = [NSAttributedString stringWithFormat:@"(%@)", @"?".keywordsAttributedString]; } - NSString *combined = nil; - if ([type characterAtIndex:type.length - 1] == FLEXTypeEncodingCString) { - combined = [type stringByAppendingString:name]; + NSAttributedString *combined = nil; + if ([type.string characterAtIndex:type.length - 1] == FLEXTypeEncodingCString) { + combined = [type stringByAppendingAttributedString:name]; } else { - combined = [type stringByAppendingFormat:@" %@", name]; + combined = [type stringByAppendingAttributedString:[NSAttributedString stringWithFormat:@" %@", name]]; } return combined; } -+ (NSString *)readableTypeForEncoding:(NSString *)encodingString { ++ (NSAttributedString *)readableTypeForEncoding:(NSString *)encodingString { if (!encodingString.length) { - return @"?"; + return @"?".keywordsAttributedString; } // See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html @@ -674,18 +666,18 @@ + (NSString *)readableTypeForEncoding:(NSString *)encodingString { [finalFieldNamesString appendString:fieldName]; } } - NSString *const recursiveType = [self readableTypeForEncoding:[encodingString substringFromIndex:fieldNameOffset]]; - return [NSString stringWithFormat:@"%@ %@", recursiveType, finalFieldNamesString]; + NSAttributedString *const recursiveType = [self readableTypeForEncoding:[encodingString substringFromIndex:fieldNameOffset]]; + return [NSAttributedString stringWithFormat:@"%@ %@", recursiveType, finalFieldNamesString.otherFunctionAndMethodNamesAttributedString]; } // Objects if (encodingCString[0] == FLEXTypeEncodingObjcObject) { - NSString *class = [encodingString substringFromIndex:1]; - class = [class stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - if (class.length == 0 || (class.length == 1 && [class characterAtIndex:0] == FLEXTypeEncodingUnknown)) { - class = @"id"; + NSAttributedString *class = [encodingString substringFromIndex:1].otherClassNamesAttributedString.mutableCopy; + class = [class stringByReplacingOccurrencesOfString:@"\"".attributedString withString:@"".attributedString]; + if (class.length == 0 || (class.length == 1 && [class.string characterAtIndex:0] == FLEXTypeEncodingUnknown)) { + class = @"id".keywordsAttributedString.mutableCopy; } else { - class = [class stringByAppendingString:@" *"]; + class = [class stringByAppendingAttributedString:@" *".attributedString]; } return class; } @@ -694,73 +686,95 @@ + (NSString *)readableTypeForEncoding:(NSString *)encodingString { // Do this first since some of the direct translations (i.e. Method) contain a prefix. #define RECURSIVE_TRANSLATE(prefix, formatString) \ if (encodingCString[0] == prefix) { \ - NSString *recursiveType = [self readableTypeForEncoding:[encodingString substringFromIndex:1]]; \ - return [NSString stringWithFormat:formatString, recursiveType]; \ + NSAttributedString *recursiveType = [self readableTypeForEncoding:[encodingString substringFromIndex:1]]; \ + return [NSAttributedString stringWithFormat:formatString, recursiveType]; \ + } + +#define RECURSIVE_TRANSLATE_KEYWORD(prefix, keyword, formatString) \ + if (encodingCString[0] == prefix) { \ + NSAttributedString *recursiveType = [self readableTypeForEncoding:[encodingString substringFromIndex:1]]; \ + return [NSAttributedString stringWithFormat:formatString, keyword.keywordsAttributedString, recursiveType]; \ } // If there's a qualifier prefix on the encoding, translate it and then // recursively call this method with the rest of the encoding string. RECURSIVE_TRANSLATE('^', @"%@ *"); - RECURSIVE_TRANSLATE('r', @"const %@"); - RECURSIVE_TRANSLATE('n', @"in %@"); - RECURSIVE_TRANSLATE('N', @"inout %@"); - RECURSIVE_TRANSLATE('o', @"out %@"); - RECURSIVE_TRANSLATE('O', @"bycopy %@"); - RECURSIVE_TRANSLATE('R', @"byref %@"); - RECURSIVE_TRANSLATE('V', @"oneway %@"); - RECURSIVE_TRANSLATE('b', @"bitfield(%@)"); + RECURSIVE_TRANSLATE_KEYWORD('r', @"const", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('n', @"in", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('N', @"inout", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('o', @"out", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('O', @"bycopy", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('R', @"byref", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('V', @"oneway", @"%@ %@"); + RECURSIVE_TRANSLATE_KEYWORD('b', @"bitfield", @"%@(%@)"); #undef RECURSIVE_TRANSLATE // C Types -#define TRANSLATE(ctype) \ + +#define TRANSLATE_OTHER_TYPE(ctype) \ + if (strcmp(encodingCString, @encode(ctype)) == 0) { \ + return ((NSString *)CFSTR(#ctype)).otherTypeNamesAttributedString; \ + } + +#define TRANSLATE_OTHER_TYPE_PTR(ctype) \ + if (strcmp(encodingCString, @encode(ctype)) == 0) { \ + return [NSAttributedString stringWithFormat:@"%@ *", [(NSString *)CFSTR(#ctype) stringByReplacingOccurrencesOfString:@" *" withString:@""].keywordsAttributedString]; \ + } + +#define TRANSLATE_KEYWORD(ctype) \ + if (strcmp(encodingCString, @encode(ctype)) == 0) { \ + return ((NSString *)CFSTR(#ctype)).keywordsAttributedString; \ + } + +#define TRANSLATE_KEYWORD_PTR(ctype) \ if (strcmp(encodingCString, @encode(ctype)) == 0) { \ - return (NSString *)CFSTR(#ctype); \ + return [NSAttributedString stringWithFormat:@"%@ *", ((NSString *)CFSTR(#ctype)).keywordsAttributedString]; \ } // Order matters here since some of the cocoa types are typedefed to c types. // We can't recover the exact mapping, but we choose to prefer the cocoa types. // This is not an exhaustive list, but it covers the most common types - TRANSLATE(CGRect); - TRANSLATE(CGPoint); - TRANSLATE(CGSize); - TRANSLATE(CGVector); - TRANSLATE(UIEdgeInsets); + TRANSLATE_OTHER_TYPE(CGRect); + TRANSLATE_OTHER_TYPE(CGPoint); + TRANSLATE_OTHER_TYPE(CGSize); + TRANSLATE_OTHER_TYPE(CGVector); + TRANSLATE_OTHER_TYPE(UIEdgeInsets); if (@available(iOS 11.0, *)) { - TRANSLATE(NSDirectionalEdgeInsets); - } - TRANSLATE(UIOffset); - TRANSLATE(NSRange); - TRANSLATE(CGAffineTransform); - TRANSLATE(CATransform3D); - TRANSLATE(CGColorRef); - TRANSLATE(CGPathRef); - TRANSLATE(CGContextRef); - TRANSLATE(NSInteger); - TRANSLATE(NSUInteger); - TRANSLATE(CGFloat); - TRANSLATE(BOOL); - TRANSLATE(int); - TRANSLATE(short); - TRANSLATE(long); - TRANSLATE(long long); - TRANSLATE(unsigned char); - TRANSLATE(unsigned int); - TRANSLATE(unsigned short); - TRANSLATE(unsigned long); - TRANSLATE(unsigned long long); - TRANSLATE(float); - TRANSLATE(double); - TRANSLATE(long double); - TRANSLATE(char *); - TRANSLATE(Class); - TRANSLATE(objc_property_t); - TRANSLATE(Ivar); - TRANSLATE(Method); - TRANSLATE(Category); - TRANSLATE(NSZone *); - TRANSLATE(SEL); - TRANSLATE(void); + TRANSLATE_OTHER_TYPE(NSDirectionalEdgeInsets); + } + TRANSLATE_OTHER_TYPE(UIOffset); + TRANSLATE_OTHER_TYPE(NSRange); + TRANSLATE_OTHER_TYPE(CGAffineTransform); + TRANSLATE_OTHER_TYPE(CATransform3D); + TRANSLATE_OTHER_TYPE(CGColorRef); + TRANSLATE_OTHER_TYPE(CGPathRef); + TRANSLATE_OTHER_TYPE(CGContextRef); + TRANSLATE_OTHER_TYPE(NSInteger); + TRANSLATE_OTHER_TYPE(NSUInteger); + TRANSLATE_OTHER_TYPE(CGFloat); + TRANSLATE_KEYWORD(BOOL); + TRANSLATE_KEYWORD(int); + TRANSLATE_KEYWORD(short); + TRANSLATE_KEYWORD(long); + TRANSLATE_KEYWORD(long long); + TRANSLATE_KEYWORD(unsigned char); + TRANSLATE_KEYWORD(unsigned int); + TRANSLATE_KEYWORD(unsigned short); + TRANSLATE_KEYWORD(unsigned long); + TRANSLATE_KEYWORD(unsigned long long); + TRANSLATE_KEYWORD(float); + TRANSLATE_KEYWORD(double); + TRANSLATE_KEYWORD(long double); + TRANSLATE_KEYWORD_PTR(char); + TRANSLATE_OTHER_TYPE(Class); + TRANSLATE_OTHER_TYPE(objc_property_t); + TRANSLATE_OTHER_TYPE(Ivar); + TRANSLATE_OTHER_TYPE(Method); + TRANSLATE_OTHER_TYPE(Category); + TRANSLATE_OTHER_TYPE_PTR(NSZone *); + TRANSLATE_KEYWORD(SEL); + TRANSLATE_KEYWORD(void); #undef TRANSLATE @@ -768,7 +782,7 @@ + (NSString *)readableTypeForEncoding:(NSString *)encodingString { if (encodingCString[0] == FLEXTypeEncodingStructBegin) { // Special case: std::string if ([encodingString hasPrefix:@"{basic_string", - NSStringFromClass(self.class), self.name, self.typeEncoding, (long)self.offset]; + return [NSString stringWithFormat:@"<%@ name=%@, encoding=%@, offset=%ld>", NSStringFromClass(self.class), self.name, self.typeEncoding, (long)self.offset]; +} + +- (NSAttributedString *)attributedDebugDescription { + return [NSAttributedString stringWithFormat:@"<%@ name=%@, encoding=%@, offset=%@>", NSStringFromClass(self.class).otherClassNamesAttributedString, self.name, self.typeEncoding.otherTypeNamesAttributedString, [NSString stringWithFormat:@"%ld", (long)self.offset].numbersAttributedString]; } - (void)examine { - _name = @(ivar_getName(self.objc_ivar) ?: "(nil)"); + _name = ivar_getName(self.objc_ivar) ? [NSString stringWithCString:ivar_getName(self.objc_ivar) encoding:NSUTF8StringEncoding].otherInstanceVariablesAndGlobalsAttributedString : [NSAttributedString stringWithFormat:@"(%@)", @"nil".keywordsAttributedString]; _offset = ivar_getOffset(self.objc_ivar); _typeEncoding = @(ivar_getTypeEncoding(self.objc_ivar) ?: ""); @@ -95,7 +109,7 @@ - (id)getValue:(id)target { #ifdef __arm64__ // See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html - if (self.type == FLEXTypeEncodingObjcClass && [self.name isEqualToString:@"isa"]) { + if (self.type == FLEXTypeEncodingObjcClass && [self.name.string isEqualToString:@"isa"]) { value = object_getClass(target); } else #endif diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m index d64ef6ce4e..df93c2f678 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m @@ -112,7 +112,7 @@ - (NSString *)debugNameGivenClassName:(NSString *)name { - (NSAttributedString *)prettyName { NSAttributedString *methodTypeString = (self.isInstanceMethod ? @"-" : @"+").attributedString; - NSAttributedString *readableReturnType = [FLEXRuntimeUtility readableTypeForEncoding:@(self.signature.methodReturnType ?: "")].attributedString; + NSAttributedString *readableReturnType = [FLEXRuntimeUtility readableTypeForEncoding:@(self.signature.methodReturnType ?: "")]; NSMutableAttributedString *prettyName = [NSMutableAttributedString stringWithFormat:@"%@ (%@)", methodTypeString, readableReturnType]; NSArray *components = [self prettyArgumentComponents]; @@ -140,7 +140,7 @@ - (NSArray *)prettyArgumentComponents { assert(argIndex < self.signature.numberOfArguments); const char *argType = [self.signature getArgumentTypeAtIndex:argIndex] ?: "?"; - NSAttributedString *readableArgType = [FLEXRuntimeUtility readableTypeForEncoding:@(argType)].attributedString; + NSAttributedString *readableArgType = [FLEXRuntimeUtility readableTypeForEncoding:@(argType)]; NSAttributedString *prettyComponent = [NSAttributedString stringWithFormat:@"%@:(%@) ", selectorComponents[argIndex - 2].otherFunctionAndMethodNamesAttributedString, readableArgType]; [components addObject:prettyComponent]; diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h index 04f233605a..1d516bdd2e 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h @@ -35,7 +35,7 @@ @property (nonatomic, readonly) BOOL isClassProperty; /// The name of the property. -@property (nonatomic, readonly) NSString *name; +@property (nonatomic, readonly) NSAttributedString *name; /// The type of the property. Get the full type from the attributes. @property (nonatomic, readonly) FLEXTypeEncoding type; /// The property's attributes. diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m index 294f25a473..f8b18e47aa 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m @@ -62,7 +62,7 @@ - (id)initWithProperty:(objc_property_t)property onClass:(Class)cls { if (self) { _objc_property = property; _attributes = [FLEXPropertyAttributes attributesForProperty:property]; - _name = @(property_getName(property) ?: "(nil)"); + _name = property_getName(property) ? [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding].otherInstanceVariablesAndGlobalsAttributedString : [NSAttributedString stringWithFormat:@"(%@)", @"nil".keywordsAttributedString]; _cls = cls; if (!_attributes) [NSException raise:NSInternalInconsistencyException format:@"Error retrieving property attributes"]; @@ -80,7 +80,7 @@ - (id)initWithName:(NSString *)name attributes:(FLEXPropertyAttributes *)attribu self = [super init]; if (self) { _attributes = attributes; - _name = name; + _name = name.otherInstanceVariablesAndGlobalsAttributedString; [self examine]; } @@ -102,12 +102,8 @@ - (void)examine { SEL customGetter = self.attributes.customGetter; SEL customSetter = self.attributes.customSetter; - SEL defaultGetter = NSSelectorFromString(self.name); - SEL defaultSetter = NSSelectorFromString([NSString - stringWithFormat:@"set%c%@:", - (char)toupper([self.name characterAtIndex:0]), - [self.name substringFromIndex:1] - ]); + SEL defaultGetter = NSSelectorFromString(self.name.string); + SEL defaultSetter = NSSelectorFromString([NSString stringWithFormat:@"set%c%@:", (char)toupper([self.name.string characterAtIndex:0]), [self.name.string substringFromIndex:1]]); // Check if the likely getters/setters exist SEL validGetter = selectorIfValid(customGetter) ?: selectorIfValid(defaultGetter); @@ -129,8 +125,8 @@ - (void)examine { - (NSString *)description { if (!_flex_description) { - NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding]; - _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType].attributedString; + NSAttributedString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding]; + _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType]; } return _flex_description.string; @@ -138,8 +134,8 @@ - (NSString *)description { - (NSAttributedString *)attributedDescription { if (!_flex_description) { - NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding]; - _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType].attributedString; + NSAttributedString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding]; + _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType]; } return _flex_description; @@ -161,12 +157,12 @@ - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCoun } - (void)replacePropertyOnClass:(Class)cls { - class_replaceProperty(cls, self.name.UTF8String, self.attributes.list, (unsigned int)self.attributes.count); + class_replaceProperty(cls, self.name.string.UTF8String, self.attributes.list, (unsigned int)self.attributes.count); } - (void)computeSymbolInfo:(BOOL)forceBundle { if ((!_multiple || !_uniqueCheckFlag) && _cls) { - _multiple = _objc_property != class_getProperty(_cls, self.name.UTF8String); + _multiple = _objc_property != class_getProperty(_cls, self.name.string.UTF8String); if (_multiple || forceBundle) { Dl_info exeInfo; @@ -280,7 +276,7 @@ - (FLEXMethodBase *)getterWithImplementation:(IMP)implementation { - (FLEXMethodBase *)setterWithImplementation:(IMP)implementation { NSString *types = [NSString stringWithFormat:@"%s%s%s%@", @encode(void), @encode(id), @encode(SEL), self.attributes.typeEncoding]; - NSString *name = [NSString stringWithFormat:@"set%@:", self.name.capitalizedString]; + NSString *name = [NSString stringWithFormat:@"set%@:", self.name.string.capitalizedString]; FLEXMethodBase *setter = [FLEXMethodBase buildMethodNamed:name withTypes:types implementation:implementation]; return setter; } diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m index 8865988582..9b775a334d 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m @@ -11,7 +11,6 @@ #import "FLEXRuntimeUtility.h" #import "NSString+ObjcRuntime.h" #import "NSDictionary+ObjcRuntime.h" -#import "NSAttributedString+FLEX.h" #import "NSMutableAttributedString+FLEX.h" #import "NSString+SyntaxHighlighting.h" #import "NSObject+SyntaxHighlighting.h" diff --git a/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m b/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m index abeaae2d0a..5a324dbc76 100644 --- a/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m +++ b/Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.m @@ -72,7 +72,7 @@ - (void)addProperty:(FLEXProperty *)property isRequired:(BOOL)isRequired { unsigned int count; objc_property_attribute_t *attributes = [property copyAttributesList:&count]; - protocol_addProperty(self.workingProtocol, property.name.UTF8String, attributes, count, isRequired, YES); + protocol_addProperty(self.workingProtocol, property.name.string.UTF8String, attributes, count, isRequired, YES); free(attributes); }