Skip to content

Commit

Permalink
Enable displaying ivar names for custom struct types
Browse files Browse the repository at this point in the history
FLEXMetadataExtras.h
  • Loading branch information
NSExceptional committed Apr 27, 2022
1 parent 9d97533 commit ba36647
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@

@interface FLEXArgumentInputStructView : FLEXArgumentInputView

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;

@end
74 changes: 41 additions & 33 deletions Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,41 @@ @interface FLEXArgumentInputStructView ()

@implementation FLEXArgumentInputStructView

static NSMutableDictionary<NSString *, NSArray<NSString *> *> *structFieldNameRegistrar = nil;
+ (void)initialize {
if (self == [FLEXArgumentInputStructView class]) {
structFieldNameRegistrar = [NSMutableDictionary new];
[self registerDefaultFieldNames];
}
}

+ (void)registerDefaultFieldNames {
NSDictionary *defaults = @{
@(@encode(CGRect)): @[@"CGPoint origin", @"CGSize size"],
@(@encode(CGPoint)): @[@"CGFloat x", @"CGFloat y"],
@(@encode(CGSize)): @[@"CGFloat width", @"CGFloat height"],
@(@encode(CGVector)): @[@"CGFloat dx", @"CGFloat dy"],
@(@encode(UIEdgeInsets)): @[@"CGFloat top", @"CGFloat left", @"CGFloat bottom", @"CGFloat right"],
@(@encode(UIOffset)): @[@"CGFloat horizontal", @"CGFloat vertical"],
@(@encode(NSRange)): @[@"NSUInteger location", @"NSUInteger length"],
@(@encode(CATransform3D)): @[@"CGFloat m11", @"CGFloat m12", @"CGFloat m13", @"CGFloat m14",
@"CGFloat m21", @"CGFloat m22", @"CGFloat m23", @"CGFloat m24",
@"CGFloat m31", @"CGFloat m32", @"CGFloat m33", @"CGFloat m34",
@"CGFloat m41", @"CGFloat m42", @"CGFloat m43", @"CGFloat m44"],
@(@encode(CGAffineTransform)): @[@"CGFloat a", @"CGFloat b",
@"CGFloat c", @"CGFloat d",
@"CGFloat tx", @"CGFloat ty"],
};

[structFieldNameRegistrar addEntriesFromDictionary:defaults];

if (@available(iOS 11.0, *)) {
structFieldNameRegistrar[@(@encode(NSDirectionalEdgeInsets))] = @[
@"CGFloat top", @"CGFloat leading", @"CGFloat bottom", @"CGFloat trailing"
];
}
}

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
self = [super initWithArgumentTypeEncoding:typeEncoding];
if (self) {
Expand Down Expand Up @@ -181,40 +216,13 @@ + (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
return NO;
}

+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
NSParameterAssert(typeEncoding); NSParameterAssert(names);
structFieldNameRegistrar[typeEncoding] = names;
}

+ (NSArray<NSString *> *)customFieldTitlesForTypeEncoding:(const char *)typeEncoding {
NSArray<NSString *> *customTitles = nil;
if (strcmp(typeEncoding, @encode(CGRect)) == 0) {
customTitles = @[@"CGPoint origin", @"CGSize size"];
} else if (strcmp(typeEncoding, @encode(CGPoint)) == 0) {
customTitles = @[@"CGFloat x", @"CGFloat y"];
} else if (strcmp(typeEncoding, @encode(CGSize)) == 0) {
customTitles = @[@"CGFloat width", @"CGFloat height"];
} else if (strcmp(typeEncoding, @encode(CGVector)) == 0) {
customTitles = @[@"CGFloat dx", @"CGFloat dy"];
} else if (strcmp(typeEncoding, @encode(UIEdgeInsets)) == 0) {
customTitles = @[@"CGFloat top", @"CGFloat left", @"CGFloat bottom", @"CGFloat right"];
} else if (strcmp(typeEncoding, @encode(UIOffset)) == 0) {
customTitles = @[@"CGFloat horizontal", @"CGFloat vertical"];
} else if (strcmp(typeEncoding, @encode(NSRange)) == 0) {
customTitles = @[@"NSUInteger location", @"NSUInteger length"];
} else if (strcmp(typeEncoding, @encode(CATransform3D)) == 0) {
customTitles = @[@"CGFloat m11", @"CGFloat m12", @"CGFloat m13", @"CGFloat m14",
@"CGFloat m21", @"CGFloat m22", @"CGFloat m23", @"CGFloat m24",
@"CGFloat m31", @"CGFloat m32", @"CGFloat m33", @"CGFloat m34",
@"CGFloat m41", @"CGFloat m42", @"CGFloat m43", @"CGFloat m44"];
} else if (strcmp(typeEncoding, @encode(CGAffineTransform)) == 0) {
customTitles = @[@"CGFloat a", @"CGFloat b",
@"CGFloat c", @"CGFloat d",
@"CGFloat tx", @"CGFloat ty"];
} else {
if (@available(iOS 11.0, *)) {
if (strcmp(typeEncoding, @encode(NSDirectionalEdgeInsets)) == 0) {
customTitles = @[@"CGFloat top", @"CGFloat leading",
@"CGFloat bottom", @"CGFloat trailing"];
}
}
}
return customTitles;
return structFieldNameRegistrar[@(typeEncoding)];
}

@end
3 changes: 3 additions & 0 deletions Classes/Editing/FLEXArgumentInputViewFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@
/// Useful when deciding whether to edit or explore a property, ivar, or NSUserDefaults value.
+ (BOOL)canEditFieldWithTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue;

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;

@end
5 changes: 5 additions & 0 deletions Classes/Editing/FLEXArgumentInputViewFactory.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,9 @@ + (BOOL)canEditFieldWithTypeEncoding:(const char *)typeEncoding currentValue:(id
return [self argumentInputViewSubclassForTypeEncoding:typeEncoding currentValue:currentValue] != nil;
}

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
[FLEXArgumentInputStructView registerFieldNames:names forTypeEncoding:typeEncoding];
}

@end
23 changes: 21 additions & 2 deletions Classes/Editing/FLEXFieldEditorViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXPropertyAttributes.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXMetadataExtras.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "UIBarButtonItem+FLEX.h"

@interface FLEXFieldEditorViewController () <FLEXArgumentInputViewDelegate>

@property (nonatomic, readonly) id<FLEXMetadataAuxiliaryInfo> auxiliaryInfoProvider;
@property (nonatomic) FLEXProperty *property;
@property (nonatomic) FLEXIvar *ivar;

Expand All @@ -30,14 +32,14 @@ @implementation FLEXFieldEditorViewController

#pragma mark - Initialization

+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^_Nullable)(void))onCommit {
+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^)(void))onCommit {
FLEXFieldEditorViewController *editor = [self target:target data:property commitHandler:onCommit];
editor.title = [@"Property: " stringByAppendingString:property.name];
editor.property = property;
return editor;
}

+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^_Nullable)(void))onCommit {
+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^)(void))onCommit {
FLEXFieldEditorViewController *editor = [self target:target data:ivar commitHandler:onCommit];
editor.title = [@"Ivar: " stringByAppendingString:ivar.name];
editor.ivar = ivar;
Expand All @@ -61,6 +63,8 @@ - (void)viewDidLoad {
self.toolbarItems = @[
UIBarButtonItem.flex_flexibleSpace, self.getterButton, self.actionButton
];

[self registerAuxiliaryInfo];

// Configure input view
self.fieldEditorView.fieldDescription = self.fieldDescription;
Expand Down Expand Up @@ -122,6 +126,17 @@ - (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputVi

#pragma mark - Private

- (void)registerAuxiliaryInfo {
// This is how Reflex will get Swift struct field names into the editor at runtime
NSDictionary<NSString *, NSArray *> *labels = [self.auxiliaryInfoProvider
auxiliaryInfoForKey:FLEXAuxiliarynfoKeyFieldLabels
];

for (NSString *type in labels) {
[FLEXArgumentInputViewFactory registerFieldNames:labels[type] forTypeEncoding:type];
}
}

- (id)currentValue {
if (self.property) {
return [self.property getValue:self.target];
Expand All @@ -130,6 +145,10 @@ - (id)currentValue {
}
}

- (id<FLEXMetadataAuxiliaryInfo>)auxiliaryInfoProvider {
return self.ivar ?: self.property;
}

- (const FLEXTypeEncoding *)typeEncoding {
if (self.property) {
return self.property.attributes.typeEncoding.UTF8String;
Expand Down
1 change: 1 addition & 0 deletions Classes/FLEX-Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import "FLEXPropertyAttributes.h"
#import "FLEXRuntime+Compare.h"
#import "FLEXRuntime+UIKitHelpers.h"
#import "FLEXMetadataExtras.h"

#import "FLEXProtocolBuilder.h"
#import "FLEXClassBuilder.h"
1 change: 1 addition & 0 deletions Classes/Headers/FLEXMetadataExtras.h
5 changes: 5 additions & 0 deletions Classes/Manager/FLEXManager+Extensibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ NS_ASSUME_NONNULL_BEGIN
/// Removes all registered global entries.
- (void)clearGlobalEntries;

#pragma mark - Editing

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;

#pragma mark - Simulator Shortcuts

/// Simulator keyboard shortcuts are enabled by default.
Expand Down
8 changes: 8 additions & 0 deletions Classes/Manager/FLEXManager+Extensibility.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#import "FLEXNetworkMITMViewController.h"
#import "FLEXKeyboardHelpViewController.h"
#import "FLEXFileBrowserController.h"
#import "FLEXArgumentInputStructView.h"
#import "FLEXUtility.h"

@interface FLEXManager (ExtensibilityPrivate)
Expand Down Expand Up @@ -75,6 +76,13 @@ - (void)clearGlobalEntries {
}


#pragma mark - Editing

+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
[FLEXArgumentInputStructView registerFieldNames:names forTypeEncoding:typeEncoding];
}


#pragma mark - Simulator Shortcuts

- (void)registerSimulatorShortcutWithKey:(NSString *)key modifiers:(UIKeyModifierFlags)modifiers action:(dispatch_block_t)action description:(NSString *)description {
Expand Down
30 changes: 30 additions & 0 deletions Classes/Utility/Runtime/Objc/Reflection/FLEXMetadataExtras.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// FLEXMetadataExtras.h
// FLEX
//
// Created by Tanner Bennett on 4/26/22.
//

#import <Foundation/Foundation.h>
#import "FLEXMethodBase.h"
#import "FLEXProperty.h"
#import "FLEXIvar.h"

NS_ASSUME_NONNULL_BEGIN

/// A dictionary mapping type encoding strings to an array of field titles
extern NSString * const FLEXAuxiliarynfoKeyFieldLabels;

@protocol FLEXMetadataAuxiliaryInfo <NSObject>

/// Used to supply arbitrary additional data that need not be exposed by their own properties
- (nullable id)auxiliaryInfoForKey:(NSString *)key;

@end

@interface FLEXMethodBase (Auxiliary) <FLEXMetadataAuxiliaryInfo> @end
@interface FLEXProperty (Auxiliary) <FLEXMetadataAuxiliaryInfo> @end
@interface FLEXIvar (Auxiliary) <FLEXMetadataAuxiliaryInfo> @end


NS_ASSUME_NONNULL_END
22 changes: 22 additions & 0 deletions Classes/Utility/Runtime/Objc/Reflection/FLEXMetadataExtras.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// FLEXMetadataExtras.m
// FLEX
//
// Created by Tanner Bennett on 4/26/22.
//

#import "FLEXMetadataExtras.h"

NSString * const FLEXAuxiliarynfoKeyFieldLabels = @"FLEXAuxiliarynfoKeyFieldLabels";

@implementation FLEXMethodBase (Auxiliary)
- (id)auxiliaryInfoForKey:(NSString *)key { return nil; }
@end

@implementation FLEXProperty (Auxiliary)
- (id)auxiliaryInfoForKey:(NSString *)key { return nil; }
@end

@implementation FLEXIvar (Auxiliary)
- (id)auxiliaryInfoForKey:(NSString *)key { return nil; }
@end
8 changes: 8 additions & 0 deletions FLEX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@
C387C87B22DFCD6A00750E58 /* FLEXCarouselCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C387C87922DFCD6A00750E58 /* FLEXCarouselCell.m */; };
C387C88322E0D24A00750E58 /* UIView+FLEX_Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = C387C88122E0D24A00750E58 /* UIView+FLEX_Layout.h */; settings = {ATTRIBUTES = (Private, ); }; };
C387C88422E0D24A00750E58 /* UIView+FLEX_Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = C387C88222E0D24A00750E58 /* UIView+FLEX_Layout.m */; };
C38D970228190C93008709D0 /* FLEXMetadataExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = C38D970028190C93008709D0 /* FLEXMetadataExtras.m */; };
C38D970328190C93008709D0 /* FLEXMetadataExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = C38D970128190C93008709D0 /* FLEXMetadataExtras.h */; };
C38DF0EA22CFE4370077B4AD /* FLEXTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38DF0E822CFE4370077B4AD /* FLEXTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38DF0EB22CFE4370077B4AD /* FLEXTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38DF0E922CFE4370077B4AD /* FLEXTableViewController.m */; };
C38EF26223A2FCD20047A7EC /* FLEXViewControllerShortcuts.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF26023A2FCD20047A7EC /* FLEXViewControllerShortcuts.m */; };
Expand Down Expand Up @@ -644,6 +646,8 @@
C387C87922DFCD6A00750E58 /* FLEXCarouselCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXCarouselCell.m; sourceTree = "<group>"; };
C387C88122E0D24A00750E58 /* UIView+FLEX_Layout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+FLEX_Layout.h"; sourceTree = "<group>"; };
C387C88222E0D24A00750E58 /* UIView+FLEX_Layout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+FLEX_Layout.m"; sourceTree = "<group>"; };
C38D970028190C93008709D0 /* FLEXMetadataExtras.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXMetadataExtras.m; sourceTree = "<group>"; };
C38D970128190C93008709D0 /* FLEXMetadataExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXMetadataExtras.h; sourceTree = "<group>"; };
C38DF0E822CFE4370077B4AD /* FLEXTableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXTableViewController.h; sourceTree = "<group>"; };
C38DF0E922CFE4370077B4AD /* FLEXTableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXTableViewController.m; sourceTree = "<group>"; };
C38EF26023A2FCD20047A7EC /* FLEXViewControllerShortcuts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXViewControllerShortcuts.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1282,6 +1286,8 @@
C36FBFC7230F3B98008D95D5 /* FLEXProtocolBuilder.m */,
C36FBFC9230F3B98008D95D5 /* FLEXClassBuilder.h */,
C36FBFBF230F3B98008D95D5 /* FLEXClassBuilder.m */,
C38D970128190C93008709D0 /* FLEXMetadataExtras.h */,
C38D970028190C93008709D0 /* FLEXMetadataExtras.m */,
);
path = Reflection;
sourceTree = "<group>";
Expand Down Expand Up @@ -1502,6 +1508,7 @@
3A4C94ED1B5B21410088C3F2 /* FLEXArgumentInputColorView.h in Headers */,
C3A9424523C641C1006871A3 /* SceneKit+Snapshot.h in Headers */,
3A4C94EB1B5B21410088C3F2 /* FLEXImagePreviewViewController.h in Headers */,
C38D970328190C93008709D0 /* FLEXMetadataExtras.h in Headers */,
C34D4EB823A2B17900C1F903 /* FLEXBundleShortcuts.h in Headers */,
C3694DC223EA147F006625D7 /* UIBarButtonItem+FLEX.h in Headers */,
C38F3F31230C958F004E3731 /* FLEXAlert.h in Headers */,
Expand Down Expand Up @@ -1827,6 +1834,7 @@
94AAF0391BAF2E1F00DE8760 /* FLEXKeyboardHelpViewController.m in Sources */,
C398624E23AD6C67007E6793 /* FLEXRuntimeKeyPath.m in Sources */,
C3694DC323EA147F006625D7 /* UIBarButtonItem+FLEX.m in Sources */,
C38D970228190C93008709D0 /* FLEXMetadataExtras.m in Sources */,
C36FBFD4230F3B98008D95D5 /* FLEXProtocol.m in Sources */,
C34D4EB123A2ABD900C1F903 /* FLEXLayerShortcuts.m in Sources */,
C38F3F32230C958F004E3731 /* FLEXAlert.m in Sources */,
Expand Down

0 comments on commit ba36647

Please sign in to comment.