├── .gitignore
├── CreateFile.png
├── README.md
├── SuggestedColors.png
├── SuggestedColors.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ └── SuggestedColors.xcscheme
├── SuggestedColors
├── Aspects.h
├── Aspects.m
├── ColorCell.h
├── ColorCell.m
├── ColorsViewController.h
├── ColorsViewController.m
├── ColorsViewController.xib
├── IBHeaders
│ └── Headers.h
├── Info.plist
├── Storyboard.storyboard
├── SuggestedColors.h
├── SuggestedColors.m
├── SuggestedColors.plist
├── View.xib
└── XCodeEditor
│ ├── Utils
│ ├── XCKeyBuilder.h
│ └── XCKeyBuilder.m
│ ├── XCAbstractDefinition.h
│ ├── XCAbstractDefinition.m
│ ├── XCBuildConfig.h
│ ├── XCBuildConfig.m
│ ├── XCClassDefinition.h
│ ├── XCClassDefinition.m
│ ├── XCFileOperationQueue.h
│ ├── XCFileOperationQueue.m
│ ├── XCFrameworkDefinition.h
│ ├── XCFrameworkDefinition.m
│ ├── XCGroup.h
│ ├── XCGroup.m
│ ├── XCProject+SubProject.h
│ ├── XCProject+SubProject.m
│ ├── XCProject.h
│ ├── XCProject.m
│ ├── XCSourceFile.h
│ ├── XCSourceFile.m
│ ├── XCSourceFileDefinition.h
│ ├── XCSourceFileDefinition.m
│ ├── XCSubProjectDefinition.h
│ ├── XCSubProjectDefinition.m
│ ├── XCTarget.h
│ ├── XCTarget.m
│ ├── XCXibDefinition.h
│ ├── XCXibDefinition.m
│ ├── XcodeEditor.h
│ ├── XcodeGroupMember.h
│ ├── XcodeMemberType.h
│ ├── XcodeMemberType.m
│ ├── XcodeSourceFileType.h
│ └── XcodeSourceFileType.m
└── SuggestedColorsTests
├── Info.plist
└── SuggestedColorsTests.m
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### Xcode ###
4 | build/
5 | *.pbxuser
6 | !default.pbxuser
7 | *.mode1v3
8 | !default.mode1v3
9 | *.mode2v3
10 | !default.mode2v3
11 | *.perspectivev3
12 | !default.perspectivev3
13 | xcuserdata
14 | *.xccheckout
15 | *.moved-aside
16 | DerivedData
17 | *.xcuserstate
18 |
19 |
--------------------------------------------------------------------------------
/CreateFile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwaitzel/SuggestedColors/0c6bd60c66c71fc16eeee94c308eeb4746d5dd79/CreateFile.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SuggestedColors
2 | ---
3 |
4 | Xcode plugin for replace the suggested colors in xcode.
5 |
6 | 
7 |
8 | ## Use
9 |
10 | 
11 |
12 | Go to Edit->Create SuggestedColors file and a plist will be created. Add colors there with NAME and HEX VALUE
13 |
14 | Change useMyColors entry to activate/deactivate it
15 |
16 | ## Important - Do not change plist file name
17 |
18 | ## Installation
19 | Either
20 |
21 | - Install it via [Alcatraz](http://alcatraz.io/)
22 |
23 | or
24 |
25 | - Clone and build the plugin yourself, it will be installed to the right location automatically by building it.
26 |
27 |
28 | In any case, relaunch Xcode to load it.
29 |
30 | ## Known Issues
31 | 1- I change useMyColors to NO/YES but the Interface Builder doesn't update
32 | FIX: Alt-tab to another window and it should refresh
33 |
34 |
35 |
--------------------------------------------------------------------------------
/SuggestedColors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwaitzel/SuggestedColors/0c6bd60c66c71fc16eeee94c308eeb4746d5dd79/SuggestedColors.png
--------------------------------------------------------------------------------
/SuggestedColors.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SuggestedColors.xcodeproj/xcshareddata/xcschemes/SuggestedColors.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
58 |
61 |
62 |
63 |
69 |
70 |
71 |
72 |
73 |
74 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/SuggestedColors/Aspects.h:
--------------------------------------------------------------------------------
1 | //
2 | // Aspects.h
3 | // Aspects - A delightful, simple library for aspect oriented programming.
4 | //
5 | // Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license.
6 | //
7 |
8 | #import
9 |
10 | typedef NS_OPTIONS(NSUInteger, AspectOptions) {
11 | AspectPositionAfter = 0, /// Called after the original implementation (default)
12 | AspectPositionInstead = 1, /// Will replace the original implementation.
13 | AspectPositionBefore = 2, /// Called before the original implementation.
14 |
15 | AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
16 | };
17 |
18 | /// Opaque Aspect Token that allows to deregister the hook.
19 | @protocol AspectToken
20 |
21 | /// Deregisters an aspect.
22 | /// @return YES if deregistration is successful, otherwise NO.
23 | - (BOOL)remove;
24 |
25 | @end
26 |
27 | /// The AspectInfo protocol is the first parameter of our block syntax.
28 | @protocol AspectInfo
29 |
30 | /// The instance that is currently hooked.
31 | - (id)instance;
32 |
33 | /// The original invocation of the hooked method.
34 | - (NSInvocation *)originalInvocation;
35 |
36 | /// All method arguments, boxed. This is lazily evaluated.
37 | - (NSArray *)arguments;
38 |
39 | @end
40 |
41 | /**
42 | Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called a 1000 times per second.
43 |
44 | Adding aspects returns an opaque token which can be used to deregister again. All calls are thread safe.
45 | */
46 | @interface NSObject (Aspects)
47 |
48 | /// Adds a block of code before/instead/after the current `selector` for a specific class.
49 | ///
50 | /// @param block Aspects replicates the type signature of the method being hooked.
51 | /// The first parameter will be `id`, followed by all parameters of the method.
52 | /// These parameters are optional and will be filled to match the block signature.
53 | /// You can even use an empty block, or one that simple gets `id`.
54 | ///
55 | /// @note Hooking static methods is not supported.
56 | /// @return A token which allows to later deregister the aspect.
57 | + (id)aspect_hookSelector:(SEL)selector
58 | withOptions:(AspectOptions)options
59 | usingBlock:(id)block
60 | error:(NSError **)error;
61 |
62 | /// Adds a block of code before/instead/after the current `selector` for a specific instance.
63 | - (id)aspect_hookSelector:(SEL)selector
64 | withOptions:(AspectOptions)options
65 | usingBlock:(id)block
66 | error:(NSError **)error;
67 |
68 | @end
69 |
70 |
71 | typedef NS_ENUM(NSUInteger, AspectErrorCode) {
72 | AspectErrorSelectorBlacklisted, /// Selectors like release, retain, autorelease are blacklisted.
73 | AspectErrorDoesNotRespondToSelector, /// Selector could not be found.
74 | AspectErrorSelectorDeallocPosition, /// When hooking dealloc, only AspectPositionBefore is allowed.
75 | AspectErrorSelectorAlreadyHookedInClassHierarchy, /// Statically hooking the same method in subclasses is not allowed.
76 | AspectErrorFailedToAllocateClassPair, /// The runtime failed creating a class pair.
77 | AspectErrorMissingBlockSignature, /// The block misses compile time signature info and can't be called.
78 | AspectErrorIncompatibleBlockSignature, /// The block signature does not match the method or is too large.
79 |
80 | AspectErrorRemoveObjectAlreadyDeallocated = 100 /// (for removing) The object hooked is already deallocated.
81 | };
82 |
83 | extern NSString *const AspectErrorDomain;
84 |
--------------------------------------------------------------------------------
/SuggestedColors/ColorCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // ColorCell.h
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/20/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ColorCell : NSTableCellView
12 | @property (weak) IBOutlet NSColorWell *colorWell;
13 | @end
14 |
--------------------------------------------------------------------------------
/SuggestedColors/ColorCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // ColorCell.m
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/20/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import "ColorCell.h"
10 |
11 | @interface ColorCell ()
12 |
13 | @end
14 |
15 | @implementation ColorCell
16 |
17 |
18 | - (void)drawRect:(NSRect)dirtyRect {
19 | [super drawRect:dirtyRect];
20 |
21 | // Drawing code here.
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/SuggestedColors/ColorsViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ColorsViewController.h
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/20/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ColorsViewController : NSWindowController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/SuggestedColors/ColorsViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ColorsViewController.m
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/20/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import "ColorsViewController.h"
10 | #import "ColorCell.h"
11 |
12 | @interface ColorsViewController ()
13 | @property (weak) IBOutlet NSTableView *colorsTableView;
14 |
15 | @end
16 |
17 | @implementation ColorsViewController
18 |
19 | - (void)windowDidLoad {
20 | [super windowDidLoad];
21 |
22 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
23 |
24 | }
25 |
26 | - (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
27 | {
28 | return 5;
29 | }
30 |
31 | - (NSView *)tableView:(NSTableView *)tableView
32 | viewForTableColumn:(NSTableColumn *)tableColumn
33 | row:(NSInteger)row {
34 |
35 |
36 | // Get an existing cell with the MyView identifier if it exists
37 | ColorCell *colorCell = [tableView makeViewWithIdentifier:@"ColorCell" owner:self];
38 | colorCell.textField.stringValue = [NSString stringWithFormat:@"%zd", row];
39 | colorCell.colorWell.color = [NSColor redColor];
40 |
41 | // Return the result
42 | return colorCell;
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/SuggestedColors/ColorsViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/SuggestedColors/IBHeaders/Headers.h:
--------------------------------------------------------------------------------
1 | //
2 | // Headers.h
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/20/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 | #import
9 | #import
10 |
11 | @class DVTMapTable, DVTMutableOrderedSet;
12 |
13 | @interface DVTMutableOrderedDictionary : NSMutableDictionary
14 | {
15 | DVTMutableOrderedSet *set;
16 | DVTMapTable *backingMapTable;
17 | }
18 |
19 | - (id)mutableCopyWithZone:(struct _NSZone *)arg1;
20 | - (id)copyWithZone:(struct _NSZone *)arg1;
21 | - (id)allKeys;
22 | - (id)lastValue;
23 | - (id)lastKey;
24 | - (id)firstValue;
25 | - (id)firstKey;
26 | - (void)removeObjectForKey:(id)arg1;
27 | - (void)setObject:(id)arg1 forKey:(id)arg2;
28 | - (id)keyEnumerator;
29 | - (id)objectForKey:(id)arg1;
30 | - (unsigned long long)count;
31 | - (Class)classForCoder;
32 | - (void)encodeWithCoder:(id)arg1;
33 | - (id)initWithCoder:(id)arg1;
34 | - (id)initWithObjects:(id)arg1 forKeys:(id)arg2;
35 | - (id)initWithCapacity:(unsigned long long)arg1;
36 |
37 | @end
38 |
39 |
40 | @class DVTMutableOrderedDictionary, DVTObservingToken, NSColor, NSMenu, NSString;
41 |
42 | @interface DVTAbstractColorPicker : NSView
43 | {
44 | NSMenu *_colorsMenu;
45 | id _colorValueBindingController;
46 | NSString *_colorValueBindingKeyPath;
47 | DVTObservingToken *_colorListBindingObservation;
48 | DVTObservingToken *_colorValueBindingObservation;
49 | DVTObservingToken *_supportsNilColorBindingObservation;
50 | // id _windowActivationObservation;
51 | BOOL _supportsNilColor;
52 | BOOL _showingMultipleValues;
53 | BOOL _enabled;
54 | BOOL _active;
55 | BOOL _highlighted;
56 | int _defaultColorMode;
57 | NSColor *_color;
58 | DVTMutableOrderedDictionary *_suggestedColors;
59 | NSColor *_defaultColor;
60 | id _target;
61 | SEL _action;
62 | unsigned long long _controlSize;
63 | }
64 |
65 | @property(nonatomic, getter=isHighlighted) BOOL highlighted; // @synthesize highlighted=_highlighted;
66 | @property(nonatomic, getter=isActive) BOOL active; // @synthesize active=_active;
67 | @property(nonatomic, getter=isEnabled) BOOL enabled; // @synthesize enabled=_enabled;
68 | @property(nonatomic) unsigned long long controlSize; // @synthesize controlSize=_controlSize;
69 | @property SEL action; // @synthesize action=_action;
70 | @property __weak id target; // @synthesize target=_target;
71 | @property(getter=isShowingMultipleValues) BOOL showingMultipleValues; // @synthesize showingMultipleValues=_showingMultipleValues;
72 | @property BOOL supportsNilColor; // @synthesize supportsNilColor=_supportsNilColor;
73 | @property(nonatomic) int defaultColorMode; // @synthesize defaultColorMode=_defaultColorMode;
74 | @property(retain, nonatomic) NSColor *defaultColor; // @synthesize defaultColor=_defaultColor;
75 | @property(retain) DVTMutableOrderedDictionary *suggestedColors; // @synthesize suggestedColors=_suggestedColors;
76 | @property(retain, nonatomic) NSColor *color; // @synthesize color=_color;
77 |
78 | - (void)unbind:(id)arg1;
79 | - (void)bind:(id)arg1 toObject:(id)arg2 withKeyPath:(id)arg3 options:(id)arg4;
80 | - (void)observedColorValueDidChangeToValue:(id)arg1;
81 | - (void)displayColorPanel:(id)arg1;
82 | - (void)takeDrawnColorFrom:(id)arg1;
83 | - (void)takeDrawnColorFromPopUpMenu:(id)arg1;
84 | - (void)sendAction;
85 | - (void)beginColorDragForEvent:(id)arg1;
86 | - (id)imageForDraggedColor:(id)arg1;
87 | - (BOOL)performDragOperation:(id)arg1;
88 | - (unsigned long long)draggingEntered:(id)arg1;
89 | - (void)colorPanelColorChanged:(id)arg1;
90 | - (void)colorPanelWillClose:(id)arg1;
91 | - (void)window:(id)arg1 didChangeActivationState:(long long)arg2;
92 | - (void)colorPickerDidBecomeActive:(id)arg1;
93 | - (void)colorChosenFromColorChooser:(id)arg1;
94 | - (void)moveUp:(id)arg1;
95 | - (void)moveDown:(id)arg1;
96 | - (void)performClick:(id)arg1;
97 | - (void)displayColorPanel;
98 | - (BOOL)canBecomeKeyView;
99 | - (BOOL)becomeFirstResponder;
100 | - (BOOL)resignFirstResponder;
101 | - (BOOL)acceptsFirstResponder;
102 | - (BOOL)acceptsFirstMouse:(id)arg1;
103 | - (void)viewWillMoveToWindow:(id)arg1;
104 | - (void)showColorsMenu;
105 | - (double)minimumPopUpMenuWidth;
106 | - (struct CGPoint)popUpMenuLocation;
107 | - (id)effectiveSwatchFillColor;
108 | - (void)putIntoMultipleValuesState;
109 | - (void)populateColorsMenu;
110 | - (double)swatchHeight;
111 | - (id)swatchImageForColor:(id)arg1 withSize:(struct CGSize)arg2;
112 | - (id)effectiveSwatchBorderColor;
113 | - (id)effectiveTextColor;
114 | - (BOOL)isShowingTitle;
115 | - (BOOL)isShowingDefaultColor;
116 | - (BOOL)isShowingNamedColor;
117 | - (BOOL)supportsDefaultColor;
118 | - (double)noColorStrokeWidth;
119 | - (id)titleFont;
120 | - (void)setSuggestedColorsUsingColorList:(id)arg1;
121 | - (BOOL)isOnActiveWindow;
122 | - (id)nameForColor:(id)arg1;
123 | - (BOOL)containsColor:(id)arg1;
124 | - (void)encodeWithCoder:(id)arg1;
125 | - (id)initWithCoder:(id)arg1;
126 | - (id)initWithFrame:(struct CGRect)arg1 colorList:(id)arg2 defaultColor:(id)arg3 defaultColorMode:(int)arg4;
127 | - (id)initWithFrame:(struct CGRect)arg1;
128 | - (void)commonInit;
129 |
130 | @end
131 |
132 | @interface DVTColorPickerPopUpButton : DVTAbstractColorPicker
133 |
134 | @end
135 |
136 |
137 |
138 | @interface IDEInspectorColorProperty : NSObject
139 | {
140 | DVTColorPickerPopUpButton *_popUpButton;
141 | }
142 |
143 | @end
144 |
145 |
146 |
147 |
148 |
149 | //// IDE WORKSPACe
150 | @class DVTFilePath;
151 | @class DVTFilePath, DVTHashTable, DVTMapTable, DVTObservingToken, DVTStackBacktrace, IDEActivityLogSection, IDEBatchFindManager, IDEBreakpointManager, IDEConcreteClientTracker, IDEContainer, IDEContainer, IDEContainerQuery, IDEDeviceInstallWorkspaceMonitor, IDEExecutionEnvironment, IDEIndex, IDEIssueManager, IDELogManager, IDERefactoring, IDERunContextManager, IDESourceControlWorkspaceMonitor, IDETestManager, IDETextIndex, IDEWorkspaceArena, IDEWorkspaceBotMonitor, IDEWorkspaceSharedSettings, IDEWorkspaceSnapshotManager, IDEWorkspaceUserSettings, NSDictionary, NSHashTable, NSMapTable, NSMutableArray, NSMutableOrderedSet, NSMutableSet, NSSet, NSString;
152 |
153 | @interface IDEWorkspace : NSObject
154 | {
155 | NSString *_untitledName;
156 | DVTFilePath *_headerMapFilePath;
157 | IDEExecutionEnvironment *_executionEnvironment;
158 | IDEContainerQuery *_containerQuery;
159 | DVTObservingToken *_containerQueryObservingToken;
160 | NSMutableSet *_referencedContainers;
161 | DVTHashTable *_fileRefsWithContainerLoadingIssues;
162 | IDEActivityLogSection *_containerLoadingIntegrityLog;
163 | NSMutableSet *_customDataStores;
164 | IDEWorkspaceUserSettings *_userSettings;
165 | IDEWorkspaceSharedSettings *_sharedSettings;
166 | DVTMapTable *_blueprintProviderObserverMap;
167 | NSMutableSet *_referencedBlueprints;
168 | DVTMapTable *_testableProviderObserverMap;
169 | NSMutableSet *_referencedTestables;
170 | BOOL _initialContainerScanComplete;
171 | NSMutableArray *_referencedRunnableBuildableProducts;
172 | IDERunContextManager *_runContextManager;
173 | IDELogManager *_logManager;
174 | IDEIssueManager *_issueManager;
175 | IDEBreakpointManager *_breakpointManager;
176 | IDEBatchFindManager *_batchFindManager;
177 | IDETestManager *_testManager;
178 | IDEContainerQuery *_indexableSourceQuery;
179 | DVTObservingToken *_indexableSourceQueryObservingToken;
180 | NSMutableArray *_observedIndexableSources;
181 | IDEContainerQuery *_indexableFileQuery;
182 | DVTObservingToken *_indexableFileQueryObservingToken;
183 | id _indexableFileUpdateNotificationToken;
184 | IDEIndex *_index;
185 | IDERefactoring *_refactoring;
186 | DVTMapTable *_fileRefsToResolvedFilePaths;
187 | NSMutableSet *_fileRefsToRegisterForIndexing;
188 | IDETextIndex *_textIndex;
189 | IDEDeviceInstallWorkspaceMonitor *_deviceInstallWorkspaceMonitor;
190 | IDESourceControlWorkspaceMonitor *_sourceControlWorkspaceMonitor;
191 | IDEWorkspaceSnapshotManager *_snapshotManager;
192 | DVTFilePath *_wrappedXcode3ProjectPath;
193 | DVTObservingToken *_wrappedXcode3ProjectValidObservingToken;
194 | DVTObservingToken *_newWrappedXcode3ProjectObservingToken;
195 | NSHashTable *_pendingReferencedFileReferences;
196 | NSHashTable *_pendingReferencedContainers;
197 | IDEConcreteClientTracker *_clientTracker;
198 | DVTHashTable *_fileReferencesForProblem8727051;
199 | DVTObservingToken *_finishedLoadingObservingToken;
200 | NSDictionary *_Problem9887530_preferredStructurePaths;
201 | BOOL _simpleFilesFocused;
202 | DVTHashTable *_sourceControlStatusUpdatePendingFileReferences;
203 | id _openingPerformanceMetricIdentifier;
204 | DVTStackBacktrace *_finishedLoadingBacktrace;
205 | NSMutableOrderedSet *_initialOrderedReferencedBlueprintProviders;
206 | BOOL _hasPostedIndexingRegistrationBatchNotification;
207 | BOOL _didFinishLoadingFirstStage;
208 | BOOL _finishedLoading;
209 | BOOL _postLoadingPerformanceMetricsAllowed;
210 | BOOL _willInvalidate;
211 | BOOL _pendingFileReferencesAndContainers;
212 | BOOL _didProcessFileReferencesForProblem8727051;
213 | BOOL _isCleaningBuildFolder;
214 | BOOL _indexingAndRefactoringRestartScheduled;
215 | BOOL _sourceControlStatusUpdatePending;
216 | BOOL _didFinishBuildingInitialBlueprintProviderOrderedSet;
217 | NSMapTable *_pendingExecutionNotificationTokens;
218 | IDEWorkspaceBotMonitor *_workspaceBotMonitor;
219 | }
220 | @property (readonly) DVTFilePath *representingFilePath;
221 | @property(retain, nonatomic) IDEWorkspaceUserSettings *userSettings; // @synthesize userSettings=_userSettings;
222 |
223 | - (id)_wrappingContainerPath;
224 | + (id)rootElementName;
225 |
226 | @end
227 |
228 | @interface DVTFilePath : NSObject
229 | @property (readonly) NSString *fileName;
230 | @property (readonly) NSURL *fileURL;
231 | @property (readonly) NSArray *pathComponents;
232 | @property (readonly) NSString *pathString;
233 | @end
234 |
235 |
236 | @interface DVTDualProxyWindow : NSWindow
237 | @end
238 |
239 | @interface IDEWorkspaceWindow : DVTDualProxyWindow
240 | @end
241 |
242 |
243 | @class DVTObservingToken, DVTStackBacktrace, DVTStateToken, DVTTabBarEnclosureView, DVTTabBarView, DVTTabSwitcher, IDEEditorArea, IDESourceControlWorkspaceUIHandler, IDEToolbarDelegate, IDEWorkspace, IDEWorkspaceTabController, IDEWorkspaceWindow, NSMapTable, NSMutableArray, NSString, NSTimer, _IDEWindowFullScreenSavedDebuggerTransitionValues;
244 |
245 | @interface IDEWorkspaceWindowController : NSWindowController
246 | {
247 |
248 | }
249 |
250 |
251 | @end
252 |
253 |
254 | @interface IDEEditorDocument : NSDocument
255 | @property(retain) DVTFilePath *filePath; // @synthesize filePath=_filePath;
256 | @end
257 |
258 |
259 | @interface IDEPlistDocument : IDEEditorDocument
260 |
261 | @end
262 |
--------------------------------------------------------------------------------
/SuggestedColors/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | MonstersInc.$(PRODUCT_NAME:rfc1034identifier)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | BNDL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.1.1
25 | DVTPlugInCompatibilityUUIDs
26 |
27 | C4A681B0-4A26-480E-93EC-1218098B9AA0
28 | AD68E85B-441B-4301-B564-A45E4919A6AD
29 | A16FF353-8441-459E-A50C-B071F53F51B7
30 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7
31 | 8DC44374-2B35-4C57-A6FE-2AD66A36AAD9
32 | E969541F-E6F9-4D25-8158-72DC3545A6C6
33 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90
34 |
35 | LSMinimumSystemVersion
36 | $(MACOSX_DEPLOYMENT_TARGET)
37 | NSPrincipalClass
38 | SuggestedColors
39 | XC4Compatible
40 |
41 | XCPluginHasUI
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/SuggestedColors/Storyboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/SuggestedColors/SuggestedColors.h:
--------------------------------------------------------------------------------
1 | //
2 | // Plugin.h
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/16/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SuggestedColors : NSObject
12 |
13 | + (instancetype)sharedPlugin;
14 |
15 | @property (nonatomic, strong, readonly) NSBundle* bundle;
16 | @end
--------------------------------------------------------------------------------
/SuggestedColors/SuggestedColors.m:
--------------------------------------------------------------------------------
1 | //
2 | // Plugin.m
3 | // Plugin
4 | //
5 | // Created by Javi Waitzel on 10/16/14.
6 | // Copyright (c) 2014 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "SuggestedColors.h"
12 | #import "Aspects.h"
13 | #import
14 | #import "Headers.h"
15 | #import "ColorsViewController.h"
16 | #import "XcodeEditor.h"
17 |
18 | static NSString*const IDEEditorDocumentDidChangeNotification = @"IDEEditorDocumentDidChangeNotification";
19 |
20 | static NSString*const SuggestedColorsPlistName = @"SuggestedColors.plist";
21 |
22 |
23 |
24 | #define NSColorFromRGBA(rgbValue, alpha_) [NSColor colorWithCalibratedRed: ( (float) ( (rgbValue & 0xFF0000) >> 16 ) ) / 255.0 green: ( (float) ( (rgbValue & 0xFF00) >> 8 ) ) / 255.0 blue: ( (float) (rgbValue & 0xFF) ) / 255.0 alpha: alpha_]
25 |
26 | #define NSColorFromRGB(rgbValue) NSColorFromRGBA(rgbValue, 1.0)
27 |
28 | static SuggestedColors *sharedPlugin;
29 | NSMutableDictionary *suggestedColorsDic;
30 |
31 | @interface SuggestedColors ()
32 |
33 | @property (nonatomic, strong, readwrite) NSBundle *bundle;
34 | @property (nonatomic, strong) NSString *projectBundlePath;
35 | @property (nonatomic, strong) NSString *projectWorkspacePath;
36 | @property (nonatomic, assign) BOOL menuItemAlreadyCreated;
37 | @property (nonatomic, strong) NSMenuItem *createFileMenuItem;
38 | @property (nonatomic, strong) NSMenuItem *separatorItem;
39 | @end
40 |
41 | @implementation SuggestedColors
42 |
43 | + (void)pluginDidLoad:(NSBundle*)plugin
44 | {
45 | static dispatch_once_t onceToken;
46 | NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"];
47 |
48 | if ([currentApplicationName isEqual:@"Xcode"])
49 | {
50 | dispatch_once(&onceToken, ^{
51 | sharedPlugin = [[self alloc] initWithBundle:plugin];
52 | });
53 | }
54 | } /* pluginDidLoad */
55 |
56 | + (instancetype)sharedPlugin
57 | {
58 | return sharedPlugin;
59 | }
60 |
61 | - (id)initWithBundle:(NSBundle*)plugin
62 | {
63 | if (self = [super init])
64 | {
65 | // reference to plugin's bundle, for resource access
66 | self.bundle = plugin;
67 |
68 | // Register to notification center
69 | [[NSNotificationCenter defaultCenter] addObserver:self
70 | selector:@selector(workspaceWindowDidBecomeMain:)
71 | name:NSWindowDidBecomeMainNotification
72 | object:nil];
73 |
74 | // [[NSNotificationCenter defaultCenter] addObserver:self
75 | // selector:@selector(notificationListener:)
76 | // name:nil
77 | // object:nil];
78 |
79 |
80 | [[NSNotificationCenter defaultCenter] addObserver:self
81 | selector:@selector(documentDidChange:)
82 | name:IDEEditorDocumentDidChangeNotification
83 | object:nil];
84 |
85 | NSError *error;
86 | [objc_getClass("DVTAbstractColorPicker") aspect_hookSelector:@selector(setSuggestedColors:) withOptions:AspectPositionAfter usingBlock: ^(id < AspectInfo > par){
87 | if (suggestedColorsDic)
88 | {
89 | if( ( [suggestedColorsDic objectForKey:@"useMyColors"] == nil) || [[suggestedColorsDic objectForKey:@"useMyColors"] boolValue] )
90 | {
91 | DVTAbstractColorPicker *colorPicker = (DVTAbstractColorPicker*) par.instance;
92 | DVTMutableOrderedDictionary *dic = [[objc_getClass("DVTMutableOrderedDictionary") alloc]
93 | initWithObjects:[[suggestedColorsDic objectForKey:@"colors"] allObjects]
94 | forKeys:[[suggestedColorsDic objectForKey:@"colors"] allKeys]];
95 |
96 | [colorPicker setValue:dic forKey:@"_suggestedColors"];
97 | }
98 | }
99 | } error:&error];
100 | }
101 | return self;
102 | } /* initWithBundle */
103 |
104 | // Get current Workspace
105 | - (void)workspaceWindowDidBecomeMain:(NSNotification*)notification
106 | {
107 | if ([[notification object] isKindOfClass:[IDEWorkspaceWindow class]])
108 | {
109 | NSWindow *workspaceWindow = (NSWindow*) [notification object];
110 | NSWindowController *workspaceWindowController = (NSWindowController*) workspaceWindow.windowController;
111 | IDEWorkspace *workspace = (IDEWorkspace*) [workspaceWindowController valueForKey:@"_workspace"];
112 | DVTFilePath *representingFilePath = workspace.representingFilePath;
113 |
114 | self.projectWorkspacePath = [representingFilePath.pathString stringByReplacingOccurrencesOfString:@".xcworkspace"
115 | withString:@".xcodeproj"];
116 |
117 | self.projectBundlePath = [representingFilePath.pathString stringByReplacingOccurrencesOfString:@".xcodeproj"
118 | withString:@"/"];
119 | [self reloadColors:nil];
120 | }
121 | } /* workspaceWindowDidBecomeMain */
122 |
123 | - (void)reloadColors:(id)sender
124 | {
125 | if(self.projectBundlePath == nil)
126 | {
127 | return;
128 | }
129 |
130 | XCProject *proj = [[XCProject alloc] initWithFilePath:self.projectWorkspacePath];
131 | XCSourceFile *suggestedColorsFile = [proj fileWithName:SuggestedColorsPlistName];
132 |
133 | if(suggestedColorsFile)
134 | {
135 | NSString *pathFile = [[[proj filePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:[suggestedColorsFile pathRelativeToProjectRoot]];
136 | suggestedColorsDic = [NSMutableDictionary dictionaryWithDictionary:[NSDictionary dictionaryWithContentsOfFile:pathFile]];
137 |
138 | NSMutableDictionary *newDic = [NSMutableDictionary dictionary];
139 |
140 | for (NSString *color in [suggestedColorsDic objectForKey:@"colors"])
141 | {
142 | NSString *colorString = [[suggestedColorsDic objectForKey:@"colors"] objectForKey:color];
143 |
144 | // [self parseColorString:@"rgb(121,122,123)"];
145 | // [self parseColorString:@"rgba(121,122,123, 0.5)"];
146 | // [self parseColorString:@"123456"];
147 | // [self parseColorString:@"123456,0.5"];
148 |
149 | NSColor *colorValue = [self parseColorString:colorString];
150 | [newDic setObject:colorValue forKey:color];
151 | }
152 |
153 | // [newDic setObject:[NSColor whiteColor] forKey:@"White color"];
154 | // [newDic setObject:[NSColor clearColor] forKey:@"Clear color"];
155 |
156 | [suggestedColorsDic setObject:newDic forKey:@"colors"];
157 | }
158 | else
159 | {
160 | // Create menu items, initialize UI, etc.
161 | // Sample Menu Item:
162 | if(!self.menuItemAlreadyCreated)
163 | {
164 | NSMenuItem *editMenuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
165 |
166 | if(editMenuItem)
167 | {
168 | self.separatorItem = [NSMenuItem separatorItem];
169 | [editMenuItem.submenu addItem:self.separatorItem];
170 |
171 | self.createFileMenuItem = [[NSMenuItem alloc] initWithTitle:@"Create SuggestedColors file" action:@selector(createSuggestedColorsFile:) keyEquivalent:@""];
172 | [self.createFileMenuItem setTarget:self];
173 | [[editMenuItem submenu] addItem:self.createFileMenuItem];
174 |
175 | self.menuItemAlreadyCreated = YES;
176 | }
177 | }
178 |
179 | NSLog(@"Suggested colors file not found...");
180 | }
181 | } /* reloadColors */
182 |
183 | - (NSColor*)parseColorString:(NSString*)colorString
184 | {
185 | NSColor *colorValue = [NSColor whiteColor];
186 |
187 | colorString = [colorString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
188 |
189 | // Color in rgb(x,x,x) format
190 | if ([colorString rangeOfString:@"rgb("].length > 0)
191 | {
192 | colorString = [colorString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
193 | char *rgbChars = (char*) [[[colorString stringByReplacingOccurrencesOfString:@"rgb(" withString:@""] stringByReplacingOccurrencesOfString:@")" withString:@""] cStringUsingEncoding:NSUTF8StringEncoding];
194 | int r = atoi( strtok(rgbChars, ",") );
195 | int g = atoi( strtok(NULL, ",") );
196 | int b = atoi( strtok(NULL, ",") );
197 |
198 | // NSLog(@"r:%i, g:%i, b:%i", r,g,b);
199 | colorValue = [NSColor colorWithCalibratedRed:r / 255.0
200 | green:g / 255.0
201 | blue:b / 255.0
202 | alpha:1.0];
203 | }// Color in rgba(x,x,x,a) format
204 | else if ([colorString rangeOfString:@"rgba("].length > 0)
205 | {
206 | colorString = [colorString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
207 | char *rgbChars = (char*) [[[colorString stringByReplacingOccurrencesOfString:@"rgba(" withString:@""] stringByReplacingOccurrencesOfString:@")" withString:@""] cStringUsingEncoding:NSUTF8StringEncoding];
208 | int r = atoi( strtok(rgbChars, ",") );
209 | int g = atoi( strtok(NULL, ",") );
210 | int b = atoi( strtok(NULL, ",") );
211 | CGFloat a = atof( strtok(NULL, ",") );
212 | a = MAX( 0, MIN(a, 1.0) );
213 | NSLog(@"r:%i, g:%i, b:%i a:%.f", r, g, b, a);
214 | colorValue = [NSColor colorWithCalibratedRed:r / 255.0
215 | green:g / 255.0
216 | blue:b / 255.0
217 | alpha:a];
218 | }
219 | // Color in hex format
220 | else
221 | {
222 | unsigned colorInt = 0;
223 | NSArray *components = [colorString componentsSeparatedByString:@","];
224 |
225 | NSString *hexString = colorString;
226 | NSString *alphaString = nil;
227 |
228 | if (components.count == 2)
229 | {
230 | hexString = [components objectAtIndex:0];
231 | alphaString = [components objectAtIndex:1];
232 | }
233 |
234 | [[NSScanner scannerWithString:hexString] scanHexInt:&colorInt];
235 |
236 | if (alphaString.length > 0)
237 | {
238 | float alpha = 1.0;
239 | [[NSScanner scannerWithString:alphaString] scanFloat:&alpha];
240 |
241 | colorValue = NSColorFromRGBA(colorInt, alpha);
242 | }
243 | else
244 | {
245 | colorValue = NSColorFromRGB(colorInt);
246 | }
247 | }
248 |
249 | return colorValue;
250 | } /* parseColorString */
251 |
252 | - (void)createSuggestedColorsFile:(id)sender
253 | {
254 | NSDictionary *dictionary = @{@"colors":@{ @"Hex Format":@"ff7373"
255 | , @"HEX alpha Format":@"ff7373,0.8"
256 | , @"RGB Format":@"rgb(128,128,128)"
257 | , @"RGBA Format":@"rgba(128,128,128,0.5"}
258 | , @"useMyColors":@YES};
259 | NSError *error;
260 | NSData *dicDat = [NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:&error];
261 |
262 | if (error)
263 | {
264 | return;
265 | }
266 |
267 | NSMenuItem *editMenuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
268 |
269 | if(editMenuItem)
270 | {
271 | [editMenuItem.submenu removeItem:self.separatorItem];
272 | [editMenuItem.submenu removeItem:self.createFileMenuItem];
273 | }
274 |
275 | XCProject *proj = [[XCProject alloc] initWithFilePath:self.projectWorkspacePath];
276 | NSString *projName = [[[proj filePath] lastPathComponent] stringByDeletingPathExtension];
277 | XCGroup *topGroup = [[proj rootGroup] memberWithDisplayName:projName];
278 |
279 | if(!topGroup)
280 | {
281 | topGroup = [proj rootGroup];
282 | }
283 |
284 | XCSourceFileDefinition *sourceFileDef = [XCSourceFileDefinition sourceDefinitionWithName:SuggestedColorsPlistName data:dicDat type:PropertyList];
285 | [topGroup addSourceFile:sourceFileDef];
286 | [proj save];
287 | } /* createSuggestedColorsFile */
288 |
289 | - (void)dealloc
290 | {
291 | [[NSNotificationCenter defaultCenter] removeObserver:self];
292 | }
293 |
294 | - (void)documentDidChange:(NSNotification*)notification
295 | {
296 | id doc = notification.object;
297 |
298 | if([doc isKindOfClass:objc_getClass("IDEPlistDocument")])
299 | {
300 | if ([[[doc filePath] fileName] isEqualToString:SuggestedColorsPlistName])
301 | {
302 | [self reloadColors:nil];
303 | }
304 | }
305 | } /* documentDidChange */
306 |
307 | - (void)notificationListener:(NSNotification*)notification
308 | {
309 | // let's filter all the "normal" NSxxx events so that we only
310 | // really see the Xcode specific events.
311 | if ( ([[notification name] length] >= 2) && [[[notification name] substringWithRange:NSMakeRange(0, 2)] isEqualTo:@"NS"] )
312 | {
313 | return;
314 | }
315 | else
316 | {
317 | NSLog(@" Notification: %@", [notification name]);
318 | }
319 | } /* notificationListener */
320 |
321 | @end
322 |
--------------------------------------------------------------------------------
/SuggestedColors/SuggestedColors.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | colors
6 |
7 | My Custom Color
8 | ff7373
9 |
10 | useMyColors
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SuggestedColors/View.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/Utils/XCKeyBuilder.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import
14 | #import
15 |
16 | #define HASH_VALUE_STORAGE_SIZE 48
17 |
18 | typedef struct
19 | {
20 | char value[CC_MD5_DIGEST_LENGTH];
21 | } HashValueMD5Hash;
22 |
23 |
24 | @interface XCKeyBuilder : NSObject
25 | {
26 | unsigned char _value[HASH_VALUE_STORAGE_SIZE];
27 | }
28 |
29 | + (XCKeyBuilder*)forItemNamed:(NSString*)name;
30 |
31 | + (XCKeyBuilder*)createUnique;
32 |
33 | - (id)initHashValueMD5HashWithBytes:(const void*)bytes length:(NSUInteger)length;
34 |
35 | - (NSString*)build;
36 |
37 | @end
38 |
39 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/Utils/XCKeyBuilder.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 | #import "XCKeyBuilder.h"
13 |
14 | @implementation XCKeyBuilder
15 |
16 | /* ================================================= Class Methods ================================================== */
17 | + (XCKeyBuilder*)forItemNamed:(NSString*)name
18 | {
19 | NSData* data = [name dataUsingEncoding:NSUTF8StringEncoding];
20 | return [[XCKeyBuilder alloc] initHashValueMD5HashWithBytes:[data bytes] length:[data length]];
21 |
22 | }
23 |
24 | + (XCKeyBuilder*)createUnique
25 | {
26 | CFUUIDRef theUUID = CFUUIDCreate(NULL);
27 | CFUUIDBytes bytes = CFUUIDGetUUIDBytes(theUUID);
28 | CFRelease(theUUID);
29 |
30 | return [[XCKeyBuilder alloc] initHashValueMD5HashWithBytes:&bytes length:sizeof(bytes)];
31 | }
32 |
33 | /* ================================================== Initializers ================================================== */
34 | - (id)initHashValueMD5HashWithBytes:(const void*)bytes length:(NSUInteger)length
35 | {
36 | self = [super init];
37 | if (self != nil)
38 | {
39 | CC_MD5(bytes, (int) length, _value);
40 | }
41 | return self;
42 | }
43 |
44 | /* ================================================ Interface Methods =============================================== */
45 | - (NSString*)build
46 | {
47 | NSInteger byteLength = sizeof(HashValueMD5Hash);
48 | NSMutableString* stringValue = [NSMutableString stringWithCapacity:byteLength * 2];
49 | NSInteger i;
50 | for (i = 0; i < byteLength; i++)
51 | {
52 | [stringValue appendFormat:@"%02x", _value[i]];
53 | }
54 | return [[stringValue substringToIndex:24] uppercaseString];
55 | }
56 |
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCAbstractDefinition.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import
14 |
15 | typedef enum
16 | {
17 |
18 | /**
19 | * Creates the reference in the project and writes the contents to disk. If a file already exists at the specified
20 | * location, its contents will be updated.
21 | */
22 | XCFileOperationTypeOverwrite,
23 |
24 | /**
25 | * Creates the reference in the project. If a file already exists at the specified location, the contents will not
26 | * be updated.
27 | */
28 | XCFileOperationTypeAcceptExisting,
29 |
30 | /**
31 | * Creates the reference in the project, but does not write to disk. The filesystem is expected to be updated
32 | * through some other means.
33 | */
34 | XCFileOperationTypeReferenceOnly
35 | } XCFileOperationType;
36 |
37 | /**
38 | * Holds properties to all types of resource that can be added to an Xcode project.
39 | */
40 | @interface XCAbstractDefinition : NSObject
41 | {
42 | XCFileOperationType _fileOperationType;
43 | }
44 |
45 | @property(nonatomic) XCFileOperationType fileOperationType;
46 |
47 |
48 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCAbstractDefinition.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import "XCAbstractDefinition.h"
14 |
15 |
16 | @implementation XCAbstractDefinition
17 |
18 | @synthesize fileOperationType = _fileOperationType;
19 |
20 |
21 | /* ====================================================================================================================================== */
22 | #pragma mark - Initialization & Destruction
23 |
24 | - (id)init
25 | {
26 | self = [super init];
27 | if (self)
28 | {
29 | _fileOperationType = XCFileOperationTypeOverwrite;
30 | }
31 | return self;
32 | }
33 |
34 |
35 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCBuildConfig.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 | #import
13 |
14 | @class XCProject;
15 |
16 | @interface XCBuildConfig : NSObject
17 | {
18 | @private
19 | __weak XCProject* _project;
20 | NSString* _key;
21 |
22 | NSMutableDictionary* _buildSettings;
23 | NSMutableDictionary* _xcconfigSettings;
24 | }
25 |
26 | @property(nonatomic, readonly) NSDictionary* specifiedBuildSettings;
27 |
28 | + (NSDictionary*)buildConfigurationsFromArray:(NSArray*)array inProject:(XCProject*)project;
29 |
30 | - (instancetype)initWithProject:(XCProject*)project key:(NSString*)key;
31 |
32 | - (void)addBuildSettings:(NSDictionary*)buildSettings;
33 |
34 | - (void)addOrReplaceSetting:(id )setting forKey:(NSString*)key;
35 |
36 | - (id )valueForKey:(NSString*)key;
37 |
38 | + (NSString*)duplicatedBuildConfigurationListWithKey:(NSString*)buildConfigurationListKey inProject:(XCProject*)project
39 | withBuildConfigurationVisitor:(void (^)(NSMutableDictionary*))buildConfigurationVisitor;
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCBuildConfig.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCBuildConfig.h"
15 | #import "XCGroup.h"
16 | #import "XCKeyBuilder.h"
17 | #import "XCProject.h"
18 | #import "XCSourceFile.h"
19 |
20 | @implementation XCBuildConfig
21 |
22 | /* ====================================================================================================================================== */
23 | #pragma mark - Class Methods
24 |
25 | + (NSDictionary*)buildConfigurationsFromArray:(NSArray*)array inProject:(XCProject*)project
26 | {
27 | NSMutableDictionary* configurations = [NSMutableDictionary dictionary];
28 |
29 | for (NSString* buildConfigurationKey in array)
30 | {
31 | NSDictionary* buildConfiguration = [[project objects] objectForKey:buildConfigurationKey];
32 |
33 | if ([[buildConfiguration valueForKey:@"isa"] asMemberType] == XCBuildConfigurationType)
34 | {
35 | XCBuildConfig* configuration = [configurations objectForKey:[buildConfiguration objectForKey:@"name"]];
36 | if (!configuration)
37 | {
38 | configuration = [[XCBuildConfig alloc] initWithProject:project key:buildConfigurationKey];
39 |
40 | [configurations setObject:configuration forKey:[buildConfiguration objectForKey:@"name"]];
41 | }
42 |
43 |
44 | XCSourceFile* configurationFile = [project fileWithKey:[buildConfiguration objectForKey:@"baseConfigurationReference"]];
45 | if (configurationFile)
46 | {
47 | NSString* path = configurationFile.path;
48 |
49 | if (![[NSFileManager defaultManager] fileExistsAtPath:path])
50 | {
51 | XCGroup* group = [project groupWithSourceFile:configurationFile];
52 | path = [[group pathRelativeToParent] stringByAppendingPathComponent:path];
53 | }
54 |
55 | if (![[NSFileManager defaultManager] fileExistsAtPath:path])
56 | {
57 | path = [[[project filePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:path];
58 | }
59 |
60 | if (![[NSFileManager defaultManager] fileExistsAtPath:path])
61 | {
62 | path = [[[project filePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:configurationFile.path];
63 | }
64 |
65 | if (![[NSFileManager defaultManager] fileExistsAtPath:path])
66 | {
67 | [NSException raise:@"XCConfig not found" format:@"Unable to find XCConfig file at %@", path];
68 | }
69 |
70 | }
71 |
72 | [configuration addBuildSettings:[buildConfiguration objectForKey:@"buildSettings"]];
73 | }
74 | }
75 |
76 | return configurations;
77 | }
78 |
79 | + (NSString*)duplicatedBuildConfigurationListWithKey:(NSString*)buildConfigurationListKey inProject:(XCProject*)project
80 | withBuildConfigurationVisitor:(void (^)(NSMutableDictionary*))buildConfigurationVisitor
81 | {
82 |
83 | NSDictionary* buildConfigurationList = project.objects[buildConfigurationListKey];
84 | NSMutableDictionary* dupBuildConfigurationList = [buildConfigurationList mutableCopy];
85 |
86 | NSMutableArray* dupBuildConfigurations = [NSMutableArray array];
87 |
88 | for (NSString* buildConfigurationKey in buildConfigurationList[@"buildConfigurations"])
89 | {
90 | [dupBuildConfigurations addObject:[self duplicatedBuildConfigurationWithKey:buildConfigurationKey inProject:project
91 | withBuildConfigurationVisitor:buildConfigurationVisitor]];
92 | }
93 |
94 | dupBuildConfigurationList[@"buildConfigurations"] = dupBuildConfigurations;
95 |
96 | NSString* dupBuildConfigurationListKey = [[XCKeyBuilder createUnique] build];
97 |
98 | project.objects[dupBuildConfigurationListKey] = dupBuildConfigurationList;
99 |
100 | return dupBuildConfigurationListKey;
101 | }
102 |
103 | /* ====================================================================================================================================== */
104 | #pragma mark - Initialization & Destruction
105 |
106 | - (instancetype)initWithProject:(XCProject*)project key:(NSString*)key
107 | {
108 | self = [super init];
109 | if (self)
110 | {
111 | _project = project;
112 | _key = [key copy];
113 |
114 | _buildSettings = [[NSMutableDictionary alloc] init];
115 | _xcconfigSettings = [[NSMutableDictionary alloc] init];
116 | }
117 | return self;
118 | }
119 |
120 | - (id)init
121 | {
122 | return [self initWithProject:nil key:nil];
123 | }
124 |
125 |
126 | /* ====================================================================================================================================== */
127 | #pragma mark - Interface Methods
128 |
129 | - (NSDictionary*)specifiedBuildSettings
130 | {
131 | return [_buildSettings copy];
132 | }
133 |
134 | - (void)addBuildSettings:(NSDictionary*)buildSettings
135 | {
136 | [_xcconfigSettings removeObjectsForKeys:[buildSettings allKeys]];
137 | [_buildSettings addEntriesFromDictionary:buildSettings];
138 | }
139 |
140 | - (void)addOrReplaceSetting:(id )setting forKey:(NSString*)key
141 | {
142 | NSDictionary* settings = [NSDictionary dictionaryWithObject:setting forKey:key];
143 | [self addBuildSettings:settings];
144 |
145 |
146 | NSMutableDictionary* dict = [[[_project objects] objectForKey:_key] mutableCopy];
147 | [dict setValue:_buildSettings forKey:@"buildSettings"];
148 | [_project.objects setValue:dict forKey:_key];
149 |
150 |
151 | }
152 |
153 |
154 | - (id )valueForKey:(NSString*)key
155 | {
156 | id value = [_buildSettings objectForKey:key];
157 | if (!value)
158 | {
159 | value = [_xcconfigSettings objectForKey:key];
160 | }
161 | return value;
162 | }
163 |
164 | /* ====================================================================================================================================== */
165 | #pragma mark - Utility Methods
166 |
167 | - (NSString*)description
168 | {
169 | NSMutableString* description = [[super description] mutableCopy];
170 |
171 | [description appendFormat:@"build settings: %@, inherited: %@", _buildSettings, _xcconfigSettings];
172 |
173 | return description;
174 | }
175 |
176 |
177 | /* ====================================================================================================================================== */
178 | #pragma mark - Private Methods
179 |
180 | + (NSString*)duplicatedBuildConfigurationWithKey:(NSString*)buildConfigurationKey inProject:(XCProject*)project
181 | withBuildConfigurationVisitor:(void (^)(NSMutableDictionary*))buildConfigurationVisitor
182 | {
183 | NSDictionary* buildConfiguration = project.objects[buildConfigurationKey];
184 | NSMutableDictionary* dupBuildConfiguration = [buildConfiguration mutableCopy];
185 |
186 | buildConfigurationVisitor(dupBuildConfiguration);
187 |
188 | NSString* dupBuildConfigurationKey = [[XCKeyBuilder createUnique] build];
189 |
190 | project.objects[dupBuildConfigurationKey] = dupBuildConfiguration;
191 |
192 | return dupBuildConfigurationKey;
193 | }
194 |
195 | @end
196 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCClassDefinition.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import
14 | #import "XCAbstractDefinition.h"
15 |
16 | typedef enum
17 | {
18 | ObjectiveC,
19 | ObjectiveCPlusPlus,
20 | CPlusPlus,
21 | } ClassDefinitionLanguage;
22 |
23 | @interface XCClassDefinition : XCAbstractDefinition
24 | {
25 |
26 | NSString* _className;
27 | NSString* _header;
28 | NSString* _source;
29 |
30 | @private
31 | ClassDefinitionLanguage _language;
32 | }
33 |
34 | @property(strong, nonatomic, readonly) NSString* className;
35 | @property(nonatomic, strong) NSString* header;
36 | @property(nonatomic, strong) NSString* source;
37 |
38 | + (XCClassDefinition*)classDefinitionWithName:(NSString*)fileName;
39 |
40 | + (XCClassDefinition*)classDefinitionWithName:(NSString*)className language:(ClassDefinitionLanguage)language;
41 |
42 | /**
43 | * Initializes a new objective-c class definition.
44 | */
45 | - (id)initWithName:(NSString*)fileName;
46 |
47 | /**
48 | * Initializes a new class definition with the specified language.
49 | */
50 | - (id)initWithName:(NSString*)className language:(ClassDefinitionLanguage)language;
51 |
52 | - (BOOL)isObjectiveC;
53 |
54 | - (BOOL)isObjectiveCPlusPlus;
55 |
56 | - (BOOL)isCPlusPlus;
57 |
58 | - (NSString*)headerFileName;
59 |
60 | - (NSString*)sourceFileName;
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCClassDefinition.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 |
15 |
16 | #import "XCClassDefinition.h"
17 |
18 | @implementation XCClassDefinition
19 |
20 |
21 | @synthesize className = _className;
22 | @synthesize header = _header;
23 | @synthesize source = _source;
24 |
25 | /* ====================================================================================================================================== */
26 | #pragma mark - Class Methods
27 |
28 | + (XCClassDefinition*)classDefinitionWithName:(NSString*)fileName
29 | {
30 | return [[XCClassDefinition alloc] initWithName:fileName];
31 | }
32 |
33 | + (XCClassDefinition*)classDefinitionWithName:(NSString*)className language:(ClassDefinitionLanguage)language
34 | {
35 | return [[XCClassDefinition alloc] initWithName:className language:language];
36 | }
37 |
38 | /* ====================================================================================================================================== */
39 | #pragma mark - Initialization & Destruction
40 |
41 | - (id)initWithName:(NSString*)className
42 | {
43 | return [self initWithName:className language:ObjectiveC];
44 | }
45 |
46 | - (id)initWithName:(NSString*)className language:(ClassDefinitionLanguage)language
47 | {
48 | self = [super init];
49 | if (self)
50 | {
51 | _className = [className copy];
52 | if (!(language == ObjectiveC || language == ObjectiveCPlusPlus || language == CPlusPlus))
53 | {
54 | [NSException raise:NSInvalidArgumentException format:@"Language must be one of ObjectiveC, ObjectiveCPlusPlus"];
55 | }
56 | _language = language;
57 | }
58 | return self;
59 | }
60 |
61 |
62 | /* ====================================================================================================================================== */
63 | #pragma mark - Interface Methods
64 |
65 | - (BOOL)isObjectiveC
66 | {
67 | return _language == ObjectiveC;
68 | }
69 |
70 | - (BOOL)isObjectiveCPlusPlus
71 | {
72 | return _language == ObjectiveCPlusPlus;
73 | }
74 |
75 | - (BOOL)isCPlusPlus
76 | {
77 | return _language == CPlusPlus;
78 | }
79 |
80 | - (NSString*)headerFileName
81 | {
82 | return [_className stringByAppendingString:@".h"];
83 |
84 | }
85 |
86 | - (NSString*)sourceFileName
87 | {
88 | NSString* sourceFileName = nil;
89 | if ([self isObjectiveC])
90 | {
91 | sourceFileName = [_className stringByAppendingString:@".m"];
92 | }
93 | else if ([self isObjectiveCPlusPlus])
94 | {
95 | sourceFileName = [_className stringByAppendingString:@".mm"];
96 | }
97 | else if ([self isCPlusPlus])
98 | {
99 | sourceFileName = [_className stringByAppendingString:@".cpp"];
100 | }
101 | return sourceFileName;
102 | }
103 |
104 |
105 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCFileOperationQueue.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import
14 |
15 |
16 | @interface XCFileOperationQueue : NSObject
17 | {
18 |
19 | @private
20 | NSString* _baseDirectory;
21 | NSMutableDictionary* _filesToWrite;
22 | NSMutableDictionary* _frameworksToCopy;
23 | NSMutableArray* _filesToDelete;
24 | NSMutableArray* _directoriesToCreate;
25 | }
26 |
27 |
28 | - (id)initWithBaseDirectory:(NSString*)baseDirectory;
29 |
30 | - (BOOL)fileWithName:(NSString*)name existsInProjectDirectory:(NSString*)directory;
31 |
32 | - (void)queueTextFile:(NSString*)fileName inDirectory:(NSString*)directory withContents:(NSString*)contents;
33 |
34 | - (void)queueDataFile:(NSString*)fileName inDirectory:(NSString*)directory withContents:(NSData*)contents;
35 |
36 | - (void)queueFrameworkWithFilePath:(NSString*)filePath inDirectory:(NSString*)directory;
37 |
38 | - (void)queueDeletion:(NSString*)filePath;
39 |
40 | - (void)queueDirectory:(NSString*)withName inDirectory:(NSString*)parentDirectory;
41 |
42 | - (void)commitFileOperations;
43 |
44 | @end
45 |
46 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCFileOperationQueue.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCFileOperationQueue.h"
15 |
16 | @interface XCFileOperationQueue ()
17 |
18 | - (NSString*)destinationPathFor:(NSString*)fileName inProjectDirectory:(NSString*)directory;
19 |
20 | - (void)performFileWrites;
21 |
22 | - (void)performCopyFrameworks;
23 |
24 | - (void)performFileDeletions;
25 |
26 | - (void)performCreateDirectories;
27 |
28 | @end
29 |
30 |
31 | @implementation XCFileOperationQueue
32 |
33 | /* ====================================================================================================================================== */
34 | #pragma mark - Initialization & Destruction
35 |
36 | - (id)initWithBaseDirectory:(NSString*)baseDirectory
37 | {
38 | self = [super init];
39 | if (self)
40 | {
41 | _baseDirectory = [baseDirectory copy];
42 | _filesToWrite = [[NSMutableDictionary alloc] init];
43 | _frameworksToCopy = [[NSMutableDictionary alloc] init];
44 | _filesToDelete = [[NSMutableArray alloc] init];
45 | _directoriesToCreate = [[NSMutableArray alloc] init];
46 | }
47 | return self;
48 | }
49 |
50 | /* ====================================================================================================================================== */
51 | #pragma mark - Interface Methods
52 |
53 | - (BOOL)fileWithName:(NSString*)name existsInProjectDirectory:(NSString*)directory
54 | {
55 | NSString* filePath = [self destinationPathFor:name inProjectDirectory:directory];
56 | return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
57 | }
58 |
59 |
60 | - (void)queueTextFile:(NSString*)fileName inDirectory:(NSString*)directory withContents:(NSString*)contents
61 | {
62 | [_filesToWrite setObject:[contents dataUsingEncoding:NSUTF8StringEncoding]
63 | forKey:[self destinationPathFor:fileName inProjectDirectory:directory]];
64 | }
65 |
66 | - (void)queueDataFile:(NSString*)fileName inDirectory:(NSString*)directory withContents:(NSData*)contents
67 | {
68 | [_filesToWrite setObject:contents forKey:[self destinationPathFor:fileName inProjectDirectory:directory]];
69 | }
70 |
71 |
72 | - (void)queueFrameworkWithFilePath:(NSString*)filePath inDirectory:(NSString*)directory
73 | {
74 |
75 | NSURL* sourceUrl = [NSURL fileURLWithPath:filePath isDirectory:YES];
76 | NSString* destinationPath =
77 | [[_baseDirectory stringByAppendingPathComponent:directory] stringByAppendingPathComponent:[filePath lastPathComponent]];
78 | NSURL* destinationUrl = [NSURL fileURLWithPath:destinationPath isDirectory:YES];
79 | [_frameworksToCopy setObject:sourceUrl forKey:destinationUrl];
80 | }
81 |
82 | - (void)queueDeletion:(NSString*)filePath
83 | {
84 | NSLog(@"Queue deletion at: %@", filePath);
85 | [_filesToDelete addObject:filePath];
86 | }
87 |
88 | - (void)queueDirectory:(NSString*)withName inDirectory:(NSString*)parentDirectory
89 | {
90 | [_directoriesToCreate addObject:[self destinationPathFor:withName inProjectDirectory:parentDirectory]];
91 | }
92 |
93 | - (void)commitFileOperations
94 | {
95 | [self performFileWrites];
96 | [self performCopyFrameworks];
97 | [self performFileDeletions];
98 | [self performCreateDirectories];
99 | }
100 |
101 |
102 | /* ====================================================================================================================================== */
103 | #pragma mark - Private Methods
104 |
105 | - (NSString*)destinationPathFor:(NSString*)fileName inProjectDirectory:(NSString*)directory
106 | {
107 | return [[_baseDirectory stringByAppendingPathComponent:directory] stringByAppendingPathComponent:fileName];
108 | }
109 |
110 | - (void)performFileWrites
111 | {
112 | [_filesToWrite enumerateKeysAndObjectsUsingBlock:^(NSString* filePath, NSData* data, BOOL* stop)
113 | {
114 | NSError* error = nil;
115 | if (![data writeToFile:filePath options:NSDataWritingAtomic error:&error])
116 | {
117 | [NSException raise:NSInternalInconsistencyException format:@"Error writing file at filePath: %@, error: %@", filePath, error];
118 | }
119 | }];
120 | [_filesToWrite removeAllObjects];
121 | }
122 |
123 | - (void)performCopyFrameworks
124 | {
125 | [_frameworksToCopy enumerateKeysAndObjectsUsingBlock:^(NSURL* destinationUrl, NSURL* frameworkPath, BOOL* stop)
126 | {
127 |
128 | NSFileManager* fileManager = [NSFileManager defaultManager];
129 |
130 | if ([fileManager fileExistsAtPath:[destinationUrl path]])
131 | {
132 | [fileManager removeItemAtURL:destinationUrl error:nil];
133 | }
134 | NSError* error = nil;
135 | if (![fileManager copyItemAtURL:frameworkPath toURL:destinationUrl error:&error])
136 | {
137 | [NSException raise:NSInternalInconsistencyException format:@"Error writing file at filePath: %@",
138 | [frameworkPath absoluteString]];
139 | }
140 | }];
141 | [_frameworksToCopy removeAllObjects];
142 | }
143 |
144 | - (void)performFileDeletions
145 | {
146 | for (NSString* filePath in [_filesToDelete reverseObjectEnumerator])
147 | {
148 | NSString* fullPath = [_baseDirectory stringByAppendingPathComponent:filePath];
149 | NSError* error = nil;
150 |
151 | if (![[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error])
152 | {
153 | NSLog(@"failed to remove item at path; error == %@", error);
154 | [NSException raise:NSInternalInconsistencyException format:@"Error deleting file at filePath: %@", filePath];
155 | }
156 | else
157 | {
158 | NSLog(@"Deleted: %@", fullPath);
159 | }
160 | }
161 | [_filesToDelete removeAllObjects];
162 | }
163 |
164 | - (void)performCreateDirectories
165 | {
166 | for (NSString* filePath in _directoriesToCreate)
167 | {
168 | NSFileManager* fileManager = [NSFileManager defaultManager];
169 | if (![fileManager fileExistsAtPath:filePath])
170 | {
171 | if (![fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil])
172 | {
173 | [NSException raise:NSInvalidArgumentException format:@"Error: Create folder failed %@", filePath];
174 | }
175 | }
176 | }
177 | }
178 |
179 |
180 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCFrameworkDefinition.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import
15 | #import "XCAbstractDefinition.h"
16 |
17 |
18 | @interface XCFrameworkDefinition : XCAbstractDefinition
19 | {
20 | NSString* _filePath;
21 | BOOL _copyToDestination;
22 | }
23 |
24 | @property(nonatomic, strong, readonly) NSString* filePath;
25 | @property(nonatomic, readonly) BOOL copyToDestination;
26 |
27 | + (XCFrameworkDefinition*)frameworkDefinitionWithFilePath:(NSString*)filePath copyToDestination:(BOOL)copyToDestination;
28 |
29 | - (id)initWithFilePath:(NSString*)filePath copyToDestination:(BOOL)copyToDestination;
30 |
31 | - (NSString*)name;
32 |
33 |
34 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCFrameworkDefinition.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCFrameworkDefinition.h"
15 |
16 | @implementation XCFrameworkDefinition
17 |
18 | @synthesize filePath = _filePath;
19 | @synthesize copyToDestination = _copyToDestination;
20 |
21 | /* ====================================================================================================================================== */
22 | #pragma mark - Class Methods
23 |
24 | + (XCFrameworkDefinition*)frameworkDefinitionWithFilePath:(NSString*)filePath copyToDestination:(BOOL)copyToDestination
25 | {
26 |
27 | return [[XCFrameworkDefinition alloc] initWithFilePath:filePath copyToDestination:copyToDestination];
28 | }
29 |
30 | /* ====================================================================================================================================== */
31 | #pragma mark - Initialization & Destruction
32 |
33 | - (id)initWithFilePath:(NSString*)filePath copyToDestination:(BOOL)copyToDestination
34 | {
35 | self = [super init];
36 | if (self)
37 | {
38 | _filePath = [filePath copy];
39 | _copyToDestination = copyToDestination;
40 | }
41 | return self;
42 | }
43 |
44 | /* ====================================================================================================================================== */
45 | #pragma mark - Interface Methods
46 |
47 | - (NSString*)name
48 | {
49 | return [_filePath lastPathComponent];
50 | }
51 |
52 |
53 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCGroup.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import
14 | #import "XcodeGroupMember.h"
15 |
16 | @class XCProject;
17 | @class XCClassDefinition;
18 | @class XCSourceFile;
19 | @class XCXibDefinition;
20 | @class XCFileOperationQueue;
21 | @class XCFrameworkDefinition;
22 | @class XCSourceFileDefinition;
23 | @class XCSubProjectDefinition;
24 |
25 |
26 | /**
27 | * Represents a group container in an Xcode project. A group can contain members of type `XCSourceFile` or other
28 | * groups.
29 | */
30 | @interface XCGroup : NSObject
31 | {
32 |
33 | NSString* _pathRelativeToParent;
34 | NSString* _key;
35 | NSString* _alias;
36 |
37 |
38 | @private
39 | NSString* _pathRelativeToProjectRoot;
40 | NSMutableArray* _children;
41 | NSMutableArray* _members;
42 |
43 | XCFileOperationQueue* _fileOperationQueue; // weak
44 | XCProject* _project;
45 |
46 | }
47 |
48 |
49 | /**
50 | * The alias of the group, which can be used to give the group a name other than the last path component.
51 | *
52 | * See: [XcodeGroupMember displayName]
53 | */
54 | @property(nonatomic, strong, readonly) NSString* alias;
55 |
56 | /**
57 | * The path of the group relative to the group's parent.
58 | *
59 | * See: [XcodeGroupMember displayName]
60 | */
61 | @property(nonatomic, strong, readonly) NSString* pathRelativeToParent;
62 |
63 | /**
64 | * The group's unique key.
65 | */
66 | @property(nonatomic, strong, readonly) NSString* key;
67 |
68 | /**
69 | * An array containing the groups members as `XcodeGroupMember` types.
70 | */
71 | @property(nonatomic, strong, readonly) NSMutableArray* children;
72 |
73 |
74 | #pragma mark Initializers
75 |
76 | + (XCGroup*)groupWithProject:(XCProject*)project key:(NSString*)key alias:(NSString*)alias path:(NSString*)path children:(NSArray*)children;
77 |
78 | - (id)initWithProject:(XCProject*)project key:(NSString*)key alias:(NSString*)alias path:(NSString*)path children:(NSArray*)children;
79 |
80 | #pragma mark Parent group
81 |
82 | - (void)removeFromParentGroup;
83 |
84 | - (void)removeFromParentDeletingChildren:(BOOL)deleteChildren;
85 |
86 | - (XCGroup*)parentGroup;
87 |
88 | - (BOOL)isRootGroup;
89 |
90 | #pragma mark Adding children
91 | /**
92 | * Adds a class to the group, as specified by the ClassDefinition. If the group already contains a class by the same
93 | * name, the contents will be updated.
94 | */
95 | - (void)addClass:(XCClassDefinition*)classDefinition;
96 |
97 | /**
98 | * Adds a class to the group, making it a member of the specified [targets](XCTarget).
99 | */
100 | - (void)addClass:(XCClassDefinition*)classDefinition toTargets:(NSArray*)targets;
101 |
102 | /**
103 | * Adds a framework to the group. If the group already contains the framework, the contents will be updated if the
104 | * framework definition's copyToDestination flag is yes, otherwise it will be ignored.
105 | */
106 | - (void)addFramework:(XCFrameworkDefinition*)frameworkDefinition;
107 |
108 | /**
109 | * Adds a group with a path relative to this group.
110 | */
111 | - (XCGroup*)addGroupWithPath:(NSString*)path;
112 |
113 | /**
114 | * Adds a framework to the group, making it a member of the specified targets.
115 | */
116 | - (void)addFramework:(XCFrameworkDefinition*)framework toTargets:(NSArray*)targets;
117 |
118 | /**
119 | * Adds a source file of arbitrary type - image resource, header, etc.
120 | */
121 | - (void)addSourceFile:(XCSourceFileDefinition*)sourceFileDefinition;
122 |
123 |
124 | /**
125 | * Adds a xib file to the group. If the group already contains a class by the same name, the contents will be updated.
126 | */
127 | - (void)addXib:(XCXibDefinition*)xibDefinition;
128 |
129 | /**
130 | * Adds a xib to the group, making it a member of the specified [targets](XCTarget).
131 | */
132 | - (void)addXib:(XCXibDefinition*)xibDefinition toTargets:(NSArray*)targets;
133 |
134 | /**
135 | * Adds a sub-project to the group. If the group already contains a sub-project by the same name, the contents will be
136 | * updated.
137 | * Returns boolean success/fail; if method fails, caller should assume that project file is corrupt (or file format has
138 | * changed).
139 | */
140 | - (void)addSubProject:(XCSubProjectDefinition*)projectDefinition;
141 |
142 | /**
143 | * Adds a sub-project to the group, making it a member of the specified [targets](XCTarget).
144 | */
145 | - (void)addSubProject:(XCSubProjectDefinition*)projectDefinition toTargets:(NSArray*)targets;
146 |
147 | - (void)removeSubProject:(XCSubProjectDefinition*)projectDefinition;
148 |
149 | - (void)removeSubProject:(XCSubProjectDefinition*)projectDefinition fromTargets:(NSArray*)targets;
150 |
151 |
152 | #pragma mark Locating children
153 | /**
154 | * Instances of `XCSourceFile` and `XCGroup` returned as the type `XcodeGroupMember`.
155 | */
156 | - (NSArray*)members;
157 |
158 | /**
159 | * Instances of `XCSourceFile` from this group and any child groups.
160 | */
161 | - (NSArray*)recursiveMembers;
162 |
163 |
164 | - (NSArray*)buildFileKeys;
165 |
166 | /**
167 | * Returns the child with the specified key, or nil.
168 | */
169 | - (id )memberWithKey:(NSString*)key;
170 |
171 | /**
172 | * Returns the child with the specified name, or nil.
173 | */
174 | - (id )memberWithDisplayName:(NSString*)name;
175 |
176 |
177 | @end
178 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCGroup.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCFrameworkDefinition.h"
15 | #import "XCTarget.h"
16 | #import "XCFileOperationQueue.h"
17 | #import "XCXibDefinition.h"
18 | #import "XCSourceFile.h"
19 | #import "XCGroup.h"
20 | #import "XCProject.h"
21 | #import "XCClassDefinition.h"
22 | #import "Utils/XCKeyBuilder.h"
23 | #import "XCSourceFileDefinition.h"
24 | #import "XCSubProjectDefinition.h"
25 | #import "XCProject+SubProject.h"
26 |
27 |
28 | @implementation XCGroup
29 |
30 |
31 | /* ====================================================================================================================================== */
32 | #pragma mark - Class Methods
33 |
34 | + (XCGroup*)groupWithProject:(XCProject*)project key:(NSString*)key alias:(NSString*)alias path:(NSString*)path children:(NSArray*)children
35 | {
36 |
37 | return [[XCGroup alloc] initWithProject:project key:key alias:alias path:path children:children];
38 | }
39 |
40 | /* ====================================================================================================================================== */
41 | #pragma mark - Initialization & Destruction
42 |
43 | - (id)initWithProject:(XCProject*)project key:(NSString*)key alias:(NSString*)alias path:(NSString*)path children:(NSArray*)children
44 | {
45 | self = [super init];
46 | if (self)
47 | {
48 | _project = project;
49 | _fileOperationQueue = [_project fileOperationQueue];
50 | _key = [key copy];
51 | _alias = [alias copy];
52 | _pathRelativeToParent = [path copy];
53 |
54 | _children = [children mutableCopy];
55 | if (!_children)
56 | {
57 | _children = [[NSMutableArray alloc] init];
58 | }
59 | }
60 | return self;
61 | }
62 |
63 | /* ====================================================================================================================================== */
64 | #pragma mark - Interface Methods
65 |
66 | #pragma mark Parent group
67 |
68 | - (void)removeFromParentGroup
69 | {
70 | [self removeFromParentDeletingChildren:NO];
71 | }
72 |
73 |
74 | - (void)removeFromParentDeletingChildren:(BOOL)deleteChildren
75 | {
76 | if (deleteChildren)
77 | {
78 | [_fileOperationQueue queueDeletion:[self pathRelativeToProjectRoot]];
79 | }
80 | NSDictionary* dictionary = [[_project objects] objectForKey:_key];
81 | NSLog(@"Here's the dictionary: %@", dictionary);
82 |
83 | [[_project objects] removeObjectForKey:_key];
84 |
85 | dictionary = [[_project objects] objectForKey:_key];
86 | NSLog(@"Here's the dictionary: %@", dictionary);
87 |
88 | for (XCTarget* target in [_project targets])
89 | {
90 | [target removeMembersWithKeys:[self recursiveMembers]];
91 | }
92 | NSLog(@"Done!!!");
93 | }
94 |
95 | - (XCGroup*)parentGroup
96 | {
97 | return [_project groupForGroupMemberWithKey:_key];
98 | }
99 |
100 | - (BOOL)isRootGroup
101 | {
102 | return [self pathRelativeToParent] == nil && [self displayName] == nil;
103 | }
104 |
105 |
106 | /* ================================================================================================================== */
107 | #pragma mark Adding children
108 |
109 |
110 | - (void)addClass:(XCClassDefinition*)classDefinition
111 | {
112 |
113 | if ([classDefinition header])
114 | {
115 | [self makeGroupMemberWithName:[classDefinition headerFileName] contents:[classDefinition header] type:SourceCodeHeader
116 | fileOperationStyle:[classDefinition fileOperationType]];
117 | }
118 |
119 | if ([classDefinition isObjectiveC])
120 | {
121 | [self makeGroupMemberWithName:[classDefinition sourceFileName] contents:[classDefinition source] type:SourceCodeObjC
122 | fileOperationStyle:[classDefinition fileOperationType]];
123 | }
124 | else if ([classDefinition isObjectiveCPlusPlus])
125 | {
126 | [self makeGroupMemberWithName:[classDefinition sourceFileName] contents:[classDefinition source] type:SourceCodeObjCPlusPlus
127 | fileOperationStyle:[classDefinition fileOperationType]];
128 | }
129 |
130 | [[_project objects] setObject:[self asDictionary] forKey:_key];
131 | }
132 |
133 |
134 | - (void)addClass:(XCClassDefinition*)classDefinition toTargets:(NSArray*)targets
135 | {
136 | [self addClass:classDefinition];
137 | XCSourceFile* sourceFile = [_project fileWithName:[classDefinition sourceFileName]];
138 | [self addSourceFile:sourceFile toTargets:targets];
139 | }
140 |
141 | - (void)addFramework:(XCFrameworkDefinition*)frameworkDefinition
142 | {
143 | if (([self memberWithDisplayName:[frameworkDefinition name]]) == nil)
144 | {
145 | NSDictionary* fileReference;
146 | if ([frameworkDefinition copyToDestination])
147 | {
148 | fileReference = [self makeFileReferenceWithPath:[frameworkDefinition name] name:nil type:Framework];
149 | BOOL copyFramework = NO;
150 | if ([frameworkDefinition fileOperationType] == XCFileOperationTypeOverwrite)
151 | {
152 | copyFramework = YES;
153 | }
154 | else if ([frameworkDefinition fileOperationType] == XCFileOperationTypeAcceptExisting)
155 | {
156 | NSString* frameworkName = [[frameworkDefinition filePath] lastPathComponent];
157 | if (![_fileOperationQueue fileWithName:frameworkName existsInProjectDirectory:[self pathRelativeToProjectRoot]])
158 | {
159 | copyFramework = YES;
160 | }
161 |
162 | }
163 | if (copyFramework)
164 | {
165 | [_fileOperationQueue queueFrameworkWithFilePath:[frameworkDefinition filePath]
166 | inDirectory:[self pathRelativeToProjectRoot]];
167 | }
168 | }
169 | else
170 | {
171 | NSString* path = [frameworkDefinition filePath];
172 | NSString* name = [frameworkDefinition name];
173 | fileReference = [self makeFileReferenceWithPath:path name:name type:Framework];
174 | }
175 | NSString* frameworkKey = [[XCKeyBuilder forItemNamed:[frameworkDefinition name]] build];
176 | [[_project objects] setObject:fileReference forKey:frameworkKey];
177 | [self addMemberWithKey:frameworkKey];
178 | }
179 | [[_project objects] setObject:[self asDictionary] forKey:_key];
180 | }
181 |
182 |
183 | - (void)addFramework:(XCFrameworkDefinition*)frameworkDefinition toTargets:(NSArray*)targets
184 | {
185 | [self addFramework:frameworkDefinition];
186 | XCSourceFile* frameworkSourceRef = (XCSourceFile*) [self memberWithDisplayName:[frameworkDefinition name]];
187 | [self addSourceFile:frameworkSourceRef toTargets:targets];
188 | }
189 |
190 | - (XCGroup*)addGroupWithPath:(NSString*)path
191 | {
192 | NSString* groupKeyPath = self.pathRelativeToProjectRoot ? [self.pathRelativeToProjectRoot stringByAppendingPathComponent:path] : path;
193 |
194 | NSString* groupKey = [[XCKeyBuilder forItemNamed:groupKeyPath] build];
195 |
196 | NSArray* members = [self members];
197 | for (id groupMember in members)
198 | {
199 | if ([groupMember groupMemberType] == PBXGroupType || [groupMember groupMemberType] == PBXVariantGroupType)
200 | {
201 |
202 | if ([[[groupMember pathRelativeToProjectRoot] lastPathComponent] isEqualToString:path] ||
203 | [[groupMember displayName] isEqualToString:path] || [[groupMember key] isEqualToString:groupKey])
204 | {
205 | return nil;
206 | }
207 | }
208 | }
209 |
210 | XCGroup* group = [[XCGroup alloc] initWithProject:_project key:groupKey alias:nil path:path children:nil];
211 | NSDictionary* groupDict = [group asDictionary];
212 |
213 | [[_project objects] setObject:groupDict forKey:groupKey];
214 | [_fileOperationQueue queueDirectory:path inDirectory:[self pathRelativeToProjectRoot]];
215 | [self addMemberWithKey:groupKey];
216 |
217 | NSDictionary* dict = [self asDictionary];
218 | [[_project objects] setObject:dict forKey:_key];
219 |
220 | return group;
221 | }
222 |
223 | - (void)addSourceFile:(XCSourceFileDefinition*)sourceFileDefinition
224 | {
225 | [self makeGroupMemberWithName:[sourceFileDefinition sourceFileName] contents:[sourceFileDefinition data]
226 | type:[sourceFileDefinition type] fileOperationStyle:[sourceFileDefinition fileOperationType]];
227 | [[_project objects] setObject:[self asDictionary] forKey:_key];
228 | }
229 |
230 | - (void)addXib:(XCXibDefinition*)xibDefinition
231 | {
232 | [self makeGroupMemberWithName:[xibDefinition xibFileName] contents:[xibDefinition content] type:XibFile
233 | fileOperationStyle:[xibDefinition fileOperationType]];
234 | [[_project objects] setObject:[self asDictionary] forKey:_key];
235 | }
236 |
237 | - (void)addXib:(XCXibDefinition*)xibDefinition toTargets:(NSArray*)targets
238 | {
239 | [self addXib:xibDefinition];
240 | XCSourceFile* sourceFile = [_project fileWithName:[xibDefinition xibFileName]];
241 | [self addSourceFile:sourceFile toTargets:targets];
242 | }
243 |
244 |
245 | // adds an xcodeproj as a subproject of the current project.
246 | - (void)addSubProject:(XCSubProjectDefinition*)projectDefinition
247 | {
248 | // set up path to the xcodeproj file as Xcode sees it - path to top level of project + group path if any
249 | [projectDefinition initFullProjectPath:_project.filePath groupPath:[self pathRelativeToParent]];
250 |
251 | // create PBXFileReference for xcodeproj file and add to PBXGroup for the current group
252 | // (will retrieve existing if already there)
253 | [self makeGroupMemberWithName:[projectDefinition projectFileName] path:[projectDefinition pathRelativeToProjectRoot] type:XcodeProject
254 | fileOperationStyle:[projectDefinition fileOperationType]];
255 | [[_project objects] setObject:[self asDictionary] forKey:_key];
256 |
257 | // create PBXContainerItemProxies and PBXReferenceProxies
258 | [_project addProxies:projectDefinition];
259 |
260 | // add projectReferences key to PBXProject
261 | [self addProductsGroupToProject:projectDefinition];
262 | }
263 |
264 | // adds an xcodeproj as a subproject of the current project, and also adds all build products except for test bundle(s)
265 | // to targets.
266 | - (void)addSubProject:(XCSubProjectDefinition*)projectDefinition toTargets:(NSArray*)targets
267 | {
268 | [self addSubProject:projectDefinition];
269 |
270 | // add subproject's build products to targets (does not add the subproject's test bundle)
271 | NSArray* buildProductFiles = [_project buildProductsForTargets:[projectDefinition projectKey]];
272 | for (XCSourceFile* file in buildProductFiles)
273 | {
274 | [self addSourceFile:file toTargets:targets];
275 | }
276 | // add main target of subproject as target dependency to main target of project
277 | [_project addAsTargetDependency:projectDefinition toTargets:targets];
278 | }
279 |
280 | // removes an xcodeproj from the current project.
281 | - (void)removeSubProject:(XCSubProjectDefinition*)projectDefinition
282 | {
283 | if (projectDefinition == nil)
284 | {
285 | return;
286 | }
287 |
288 | // set up path to the xcodeproj file as Xcode sees it - path to top level of project + group path if any
289 | [projectDefinition initFullProjectPath:_project.filePath groupPath:[self pathRelativeToParent]];
290 |
291 | NSString* xcodeprojKey = [projectDefinition projectKey];
292 |
293 | // Remove from group and remove PBXFileReference
294 | [self removeGroupMemberWithKey:xcodeprojKey];
295 |
296 | // remove PBXContainerItemProxies and PBXReferenceProxies
297 | [_project removeProxies:xcodeprojKey];
298 |
299 | // get the key for the Products group
300 | NSString* productsGroupKey = [_project productsGroupKeyForKey:xcodeprojKey];
301 |
302 | // remove from the ProjectReferences array of PBXProject
303 | [_project removeFromProjectReferences:xcodeprojKey forProductsGroup:productsGroupKey];
304 |
305 | // remove PDXBuildFile entries
306 | [self removeProductsGroupFromProject:productsGroupKey];
307 |
308 | // remove Products group
309 | [[_project objects] removeObjectForKey:productsGroupKey];
310 |
311 | // remove from all targets
312 | [_project removeTargetDependencies:[projectDefinition name]];
313 | }
314 |
315 | - (void)removeSubProject:(XCSubProjectDefinition*)projectDefinition fromTargets:(NSArray*)targets
316 | {
317 | if (projectDefinition == nil)
318 | {
319 | return;
320 | }
321 |
322 | // set up path to the xcodeproj file as Xcode sees it - path to top level of project + group path if any
323 | [projectDefinition initFullProjectPath:_project.filePath groupPath:[self pathRelativeToParent]];
324 |
325 | NSString* xcodeprojKey = [projectDefinition projectKey];
326 |
327 | // Remove PBXBundleFile entries and corresponding inclusion in PBXFrameworksBuildPhase and PBXResourcesBuidPhase
328 | NSString* productsGroupKey = [_project productsGroupKeyForKey:xcodeprojKey];
329 | [self removeProductsGroupFromProject:productsGroupKey];
330 |
331 | // Remove the PBXContainerItemProxy for this xcodeproj with proxyType 1
332 | NSString* containerItemProxyKey = [_project containerItemProxyKeyForName:[projectDefinition pathRelativeToProjectRoot] proxyType:@"1"];
333 | if (containerItemProxyKey != nil)
334 | {
335 | [[_project objects] removeObjectForKey:containerItemProxyKey];
336 | }
337 |
338 | // Remove PBXTargetDependency and entry in PBXNativeTarget
339 | [_project removeTargetDependencies:[projectDefinition name]];
340 | }
341 |
342 | /* ====================================================================================================================================== */
343 | #pragma mark Members
344 |
345 | - (NSArray*)members
346 | {
347 | if (_members == nil)
348 | {
349 | _members = [[NSMutableArray alloc] init];
350 | for (NSString* childKey in _children)
351 | {
352 | XcodeMemberType type = [self typeForKey:childKey];
353 |
354 | @autoreleasepool
355 | {
356 | if (type == PBXGroupType || type == PBXVariantGroupType)
357 | {
358 | [_members addObject:[_project groupWithKey:childKey]];
359 | }
360 | else if (type == PBXFileReferenceType)
361 | {
362 | [_members addObject:[_project fileWithKey:childKey]];
363 | }
364 | }
365 | }
366 | }
367 | return _members;
368 | }
369 |
370 | - (NSArray*)recursiveMembers
371 | {
372 | NSMutableArray* recursiveMembers = [NSMutableArray array];
373 | for (NSString* childKey in _children)
374 | {
375 | XcodeMemberType type = [self typeForKey:childKey];
376 | if (type == PBXGroupType || type == PBXVariantGroupType)
377 | {
378 | XCGroup* group = [_project groupWithKey:childKey];
379 | NSArray* groupChildren = [group recursiveMembers];
380 | [recursiveMembers addObjectsFromArray:groupChildren];
381 | }
382 | else if (type == PBXFileReferenceType)
383 | {
384 | [recursiveMembers addObject:childKey];
385 | }
386 | }
387 | [recursiveMembers addObject:_key];
388 | return [recursiveMembers arrayByAddingObjectsFromArray:recursiveMembers];
389 | }
390 |
391 | - (NSArray*)buildFileKeys
392 | {
393 |
394 | NSMutableArray* arrayOfBuildFileKeys = [NSMutableArray array];
395 | for (id groupMember in [self members])
396 | {
397 |
398 | if ([groupMember groupMemberType] == PBXGroupType || [groupMember groupMemberType] == PBXVariantGroupType)
399 | {
400 | XCGroup* group = (XCGroup*) groupMember;
401 | [arrayOfBuildFileKeys addObjectsFromArray:[group buildFileKeys]];
402 | }
403 | else if ([groupMember groupMemberType] == PBXFileReferenceType)
404 | {
405 | [arrayOfBuildFileKeys addObject:[groupMember key]];
406 | }
407 | }
408 | return arrayOfBuildFileKeys;
409 | }
410 |
411 | - (id )memberWithKey:(NSString*)key
412 | {
413 | id groupMember = nil;
414 |
415 | if ([_children containsObject:key])
416 | {
417 | XcodeMemberType type = [self typeForKey:key];
418 | if (type == PBXGroupType || type == PBXVariantGroupType)
419 | {
420 | groupMember = [_project groupWithKey:key];
421 | }
422 | else if (type == PBXFileReferenceType)
423 | {
424 | groupMember = [_project fileWithKey:key];
425 | }
426 | }
427 | return groupMember;
428 | }
429 |
430 | - (id )memberWithDisplayName:(NSString*)name
431 | {
432 | for (id member in [self members])
433 | {
434 | if ([[member displayName] isEqualToString:name])
435 | {
436 | return member;
437 | }
438 | }
439 | return nil;
440 | }
441 |
442 | /* ====================================================================================================================================== */
443 | #pragma mark - Protocol Methods
444 |
445 | - (XcodeMemberType)groupMemberType
446 | {
447 | return [self typeForKey:self.key];
448 | }
449 |
450 | - (NSString*)displayName
451 | {
452 | if (_alias)
453 | {
454 | return _alias;
455 | }
456 | return [_pathRelativeToParent lastPathComponent];
457 | }
458 |
459 | - (NSString*)pathRelativeToProjectRoot
460 | {
461 | if (_pathRelativeToProjectRoot == nil)
462 | {
463 | NSMutableArray* pathComponents = [[NSMutableArray alloc] init];
464 | XCGroup* group = nil;
465 | NSString* key = [_key copy];
466 |
467 | while ((group = [_project groupForGroupMemberWithKey:key]) != nil && !([group pathRelativeToParent] == nil))
468 | {
469 | [pathComponents addObject:[group pathRelativeToParent]];
470 | id old = key;
471 | key = [[group key] copy];
472 | }
473 |
474 | NSMutableString* fullPath = [[NSMutableString alloc] init];
475 | for (NSInteger i = (NSInteger) [pathComponents count] - 1; i >= 0; i--)
476 | {
477 | [fullPath appendFormat:@"%@/", [pathComponents objectAtIndex:i]];
478 | }
479 | _pathRelativeToProjectRoot = [[fullPath stringByAppendingPathComponent:_pathRelativeToParent] copy];
480 | }
481 | return _pathRelativeToProjectRoot;
482 | }
483 |
484 | /* ====================================================================================================================================== */
485 | #pragma mark - Utility Methods
486 |
487 | - (NSString*)description
488 | {
489 | return [NSString stringWithFormat:@"Group: displayName = %@, key=%@", [self displayName], _key];
490 | }
491 |
492 | /* ====================================================================================================================================== */
493 | #pragma mark - Private Methods
494 |
495 | #pragma mark Private
496 |
497 | - (void)addMemberWithKey:(NSString*)key
498 | {
499 |
500 | for (NSString* childKey in _children)
501 | {
502 | if ([childKey isEqualToString:key])
503 | {
504 | [self flagMembersAsDirty];
505 | return;
506 | }
507 | }
508 | [_children addObject:key];
509 | [self flagMembersAsDirty];
510 | }
511 |
512 | - (void)flagMembersAsDirty
513 | {
514 | _members = nil;
515 | }
516 |
517 | /* ====================================================================================================================================== */
518 |
519 | - (void)makeGroupMemberWithName:(NSString*)name contents:(id)contents type:(XcodeSourceFileType)type
520 | fileOperationStyle:(XCFileOperationType)fileOperationStyle
521 | {
522 |
523 | NSString* filePath;
524 | XCSourceFile* currentSourceFile = (XCSourceFile*) [self memberWithDisplayName:name];
525 | if ((currentSourceFile) == nil)
526 | {
527 | NSDictionary* reference = [self makeFileReferenceWithPath:name name:nil type:type];
528 | NSString* fileKey = [[XCKeyBuilder forItemNamed:name] build];
529 | [[_project objects] setObject:reference forKey:fileKey];
530 | [self addMemberWithKey:fileKey];
531 | filePath = [self pathRelativeToProjectRoot];
532 | }
533 | else
534 | {
535 | filePath = [[currentSourceFile pathRelativeToProjectRoot] stringByDeletingLastPathComponent];
536 | }
537 |
538 | BOOL writeFile = NO;
539 | if (fileOperationStyle == XCFileOperationTypeOverwrite)
540 | {
541 | writeFile = YES;
542 | [_fileOperationQueue fileWithName:name existsInProjectDirectory:filePath];
543 | }
544 | else if (fileOperationStyle == XCFileOperationTypeAcceptExisting &&
545 | ![_fileOperationQueue fileWithName:name existsInProjectDirectory:filePath])
546 | {
547 | writeFile = YES;
548 | }
549 | if (writeFile)
550 | {
551 | if ([contents isKindOfClass:[NSString class]])
552 | {
553 | [_fileOperationQueue queueTextFile:name inDirectory:filePath withContents:contents];
554 | }
555 | else
556 | {
557 | [_fileOperationQueue queueDataFile:name inDirectory:filePath withContents:contents];
558 | }
559 | }
560 | }
561 |
562 | /* ====================================================================================================================================== */
563 |
564 | #pragma mark Xcodeproj methods
565 |
566 | // creates PBXFileReference and adds to group if not already there; returns key for file reference. Locates
567 | // member via path rather than name, because that is how subprojects are stored by Xcode
568 | - (void)makeGroupMemberWithName:(NSString*)name path:(NSString*)path type:(XcodeSourceFileType)type
569 | fileOperationStyle:(XCFileOperationType)fileOperationStyle
570 | {
571 | XCSourceFile* currentSourceFile = (XCSourceFile*) [self memberWithDisplayName:name];
572 | if ((currentSourceFile) == nil)
573 | {
574 | NSDictionary* reference = [self makeFileReferenceWithPath:path name:name type:type];
575 | NSString* fileKey = [[XCKeyBuilder forItemNamed:name] build];
576 | [[_project objects] setObject:reference forKey:fileKey];
577 | [self addMemberWithKey:fileKey];
578 | }
579 | }
580 |
581 | // makes a new group called Products and returns its key
582 | - (NSString*)makeProductsGroup:(XCSubProjectDefinition*)xcodeprojDefinition
583 | {
584 | NSMutableArray* children = [NSMutableArray array];
585 | NSString* uniquer = @"";
586 | for (NSString* productName in [xcodeprojDefinition buildProductNames])
587 | {
588 | [children addObject:[_project referenceProxyKeyForName:productName]];
589 | uniquer = [uniquer stringByAppendingString:productName];
590 | }
591 | NSString* productKey = [[XCKeyBuilder forItemNamed:[NSString stringWithFormat:@"%@-Products", uniquer]] build];
592 | XCGroup* productsGroup = [XCGroup groupWithProject:_project key:productKey alias:@"Products" path:nil children:children];
593 | [[_project objects] setObject:[productsGroup asDictionary] forKey:productKey];
594 | return productKey;
595 | }
596 |
597 | // makes a new Products group (by calling the method above), makes a new projectReferences array for it and
598 | // then adds it to the PBXProject object
599 | - (void)addProductsGroupToProject:(XCSubProjectDefinition*)xcodeprojDefinition
600 | {
601 | NSString* productKey = [self makeProductsGroup:xcodeprojDefinition];
602 |
603 | NSMutableDictionary* PBXProjectDict = [_project PBXProjectDict];
604 | NSMutableArray* projectReferences = [PBXProjectDict valueForKey:@"projectReferences"];
605 |
606 | NSMutableDictionary* newProjectReference = [NSMutableDictionary dictionary];
607 | [newProjectReference setObject:productKey forKey:@"ProductGroup"];
608 | NSString* projectFileKey = [[_project fileWithName:[xcodeprojDefinition pathRelativeToProjectRoot]] key];
609 | [newProjectReference setObject:projectFileKey forKey:@"ProjectRef"];
610 |
611 | if (projectReferences == nil)
612 | {
613 | projectReferences = [NSMutableArray array];
614 | }
615 | [projectReferences addObject:newProjectReference];
616 | [PBXProjectDict setObject:projectReferences forKey:@"projectReferences"];
617 | }
618 |
619 | // removes PBXFileReference from group and project
620 | - (void)removeGroupMemberWithKey:(NSString*)key
621 | {
622 | NSMutableArray* children = [self valueForKey:@"children"];
623 | [children removeObject:key];
624 | [[_project objects] setObject:[self asDictionary] forKey:_key];
625 | // remove PBXFileReference
626 | [[_project objects] removeObjectForKey:key];
627 | }
628 |
629 | // removes the given key from the files arrays of the given section, if found (intended to be used with
630 | // PBXFrameworksBuildPhase and PBXResourcesBuildPhase)
631 | // they are not required because we are currently not adding these entries; Xcode is doing it for us. The existing
632 | // code for adding to a target doesn't do it, and I didn't add it since Xcode will take care of it for me and I was
633 | // avoiding modifying existing code as much as possible)
634 | - (void)removeBuildPhaseFileKey:(NSString*)key forType:(XcodeMemberType)memberType
635 | {
636 | NSArray* buildPhases = [_project keysForProjectObjectsOfType:memberType withIdentifier:nil singleton:NO required:NO];
637 | for (NSString* buildPhaseKey in buildPhases)
638 | {
639 | NSDictionary* buildPhaseDict = [[_project objects] valueForKey:buildPhaseKey];
640 | NSMutableArray* fileKeys = [buildPhaseDict valueForKey:@"files"];
641 | for (NSString* fileKey in fileKeys)
642 | {
643 | if ([fileKey isEqualToString:key])
644 | {
645 | [fileKeys removeObject:fileKey];
646 | }
647 | }
648 | }
649 | }
650 |
651 | // removes entries from PBXBuildFiles, PBXFrameworksBuildPhase and PBXResourcesBuildPhase
652 | - (void)removeProductsGroupFromProject:(NSString*)key
653 | {
654 | // remove product group's build products from PDXBuildFiles
655 | NSDictionary* productsGroup = [[_project objects] objectForKey:key];
656 | for (NSString* childKey in [productsGroup valueForKey:@"children"])
657 | {
658 | NSArray* buildFileKeys = [_project keysForProjectObjectsOfType:PBXBuildFileType withIdentifier:childKey singleton:NO required:NO];
659 | // could be zero - we didn't add the test bundle as a build product
660 | if ([buildFileKeys count] == 1)
661 | {
662 | NSString* buildFileKey = [buildFileKeys objectAtIndex:0];
663 | [[_project objects] removeObjectForKey:buildFileKey];
664 | [self removeBuildPhaseFileKey:buildFileKey forType:PBXFrameworksBuildPhaseType];
665 | [self removeBuildPhaseFileKey:buildFileKey forType:PBXResourcesBuildPhaseType];
666 | }
667 | }
668 | }
669 |
670 | /* ====================================================================================================================================== */
671 |
672 | #pragma mark Dictionary Representations
673 |
674 | - (NSDictionary*)makeFileReferenceWithPath:(NSString*)path name:(NSString*)name type:(XcodeSourceFileType)type
675 | {
676 | NSMutableDictionary* reference = [NSMutableDictionary dictionary];
677 | [reference setObject:[NSString stringFromMemberType:PBXFileReferenceType] forKey:@"isa"];
678 | [reference setObject:@"4" forKey:@"fileEncoding"];
679 | [reference setObject:NSStringFromXCSourceFileType(type) forKey:@"lastKnownFileType"];
680 | if (name != nil)
681 | {
682 | [reference setObject:[name lastPathComponent] forKey:@"name"];
683 | }
684 | if (path != nil)
685 | {
686 | [reference setObject:path forKey:@"path"];
687 | }
688 | [reference setObject:@"" forKey:@"sourceTree"];
689 | return reference;
690 | }
691 |
692 |
693 | - (NSDictionary*)asDictionary
694 | {
695 | NSMutableDictionary* groupData = [NSMutableDictionary dictionary];
696 | [groupData setObject:[NSString stringFromMemberType:PBXGroupType] forKey:@"isa"];
697 | [groupData setObject:@"" forKey:@"sourceTree"];
698 |
699 | if (_alias != nil)
700 | {
701 | [groupData setObject:_alias forKey:@"name"];
702 | }
703 |
704 | if (_pathRelativeToParent)
705 | {
706 | [groupData setObject:_pathRelativeToParent forKey:@"path"];
707 | }
708 |
709 | if (_children)
710 | {
711 | [groupData setObject:_children forKey:@"children"];
712 | }
713 |
714 | return groupData;
715 | }
716 |
717 | - (XcodeMemberType)typeForKey:(NSString*)key
718 | {
719 | NSDictionary* obj = [[_project objects] valueForKey:key];
720 | return [[obj valueForKey:@"isa"] asMemberType];
721 | }
722 |
723 | - (void)addSourceFile:(XCSourceFile*)sourceFile toTargets:(NSArray*)targets
724 | {
725 | for (XCTarget* target in targets)
726 | {
727 | [target addMember:sourceFile];
728 | }
729 | }
730 |
731 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCProject+SubProject.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import
15 | #import "XCProject.h"
16 |
17 | @interface XCProject (SubProject)
18 |
19 |
20 | - (NSString*)referenceProxyKeyForName:(NSString*)name;
21 |
22 | - (NSArray*)buildProductsForTargets:(NSString*)xcodeprojKey;
23 |
24 | - (void)addAsTargetDependency:(XCSubProjectDefinition*)xcodeprojDefinition toTargets:(NSArray*)targets;
25 |
26 | - (NSArray*)keysForProjectObjectsOfType:(XcodeMemberType)memberType withIdentifier:(NSString*)identifier singleton:(BOOL)singleton
27 | required:(BOOL)required;
28 |
29 | - (NSMutableDictionary*)PBXProjectDict;
30 |
31 | - (void)removeProxies:(NSString*)xcodeprojKey;
32 |
33 | - (void)addProxies:(XCSubProjectDefinition*)xcodeproj;
34 |
35 | - (void)removeFromProjectReferences:(NSString*)key forProductsGroup:(NSString*)productsGroupKey;
36 |
37 | - (void)removeTargetDependencies:(NSString*)name;
38 |
39 | - (NSString*)containerItemProxyKeyForName:(NSString*)name proxyType:(NSString*)proxyType;
40 |
41 | - (NSString*)productsGroupKeyForKey:(NSString*)key;
42 |
43 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCProject+SubProject.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCSourceFile.h"
15 | #import "XCTarget.h"
16 | #import "Utils/XCKeyBuilder.h"
17 | #import "XCProject+SubProject.h"
18 | #import "XCSubProjectDefinition.h"
19 |
20 |
21 | @implementation XCProject (SubProject)
22 |
23 |
24 | #pragma mark sub-project related public methods
25 |
26 | // returns the key for the reference proxy with the given path (nil if not found)
27 | // does not use keysForProjectObjectsOfType:withIdentifier: because the identifier it uses for
28 | // PBXReferenceProxy is different.
29 | - (NSString*)referenceProxyKeyForName:(NSString*)name
30 | {
31 | __block NSString* result = nil;
32 | [[self objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
33 | {
34 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXReferenceProxyType)
35 | {
36 | if ([[obj valueForKey:@"path"] isEqualTo:name])
37 | {
38 | result = key;
39 | *stop = YES;
40 | }
41 | }
42 | }];
43 | return result;
44 | }
45 |
46 | // returns an array of build products, excluding bundles with extensions other than ".bundle" (which is kind
47 | // of gross, but I didn't see a better way to exclude test bundles without giving them their own XcodeSourceFileType)
48 | - (NSArray*)buildProductsForTargets:(NSString*)xcodeprojKey
49 | {
50 | NSMutableArray* results = [[NSMutableArray alloc] init];
51 | [[self objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
52 | {
53 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXReferenceProxyType)
54 | {
55 | // make sure it belongs to the xcodeproj we're adding
56 | NSString* remoteRef = [obj valueForKey:@"remoteRef"];
57 | NSDictionary* containerProxy = [[self objects] valueForKey:remoteRef];
58 | NSString* containerPortal = [containerProxy valueForKey:@"containerPortal"];
59 | if ([containerPortal isEqualToString:xcodeprojKey])
60 | {
61 | XcodeSourceFileType type = XCSourceFileTypeFromStringRepresentation([obj valueForKey:@"fileType"]);
62 | NSString* path = (NSString*) [obj valueForKey:@"path"];
63 | if (type != Bundle || [[path pathExtension] isEqualToString:@"bundle"])
64 | {
65 | [results addObject:[XCSourceFile sourceFileWithProject:self key:key type:type name:path sourceTree:nil path:nil]];
66 | }
67 | }
68 | }
69 | }];
70 | return results;
71 | }
72 |
73 | // makes PBXContainerItemProxy and PBXTargetDependency objects for the xcodeproj, and adds the dependency key
74 | // to all the specified targets
75 | - (void)addAsTargetDependency:(XCSubProjectDefinition*)xcodeprojDefinition toTargets:(NSArray*)targets
76 | {
77 | for (XCTarget* target in targets)
78 | {
79 | // make a new PBXContainerItemProxy
80 | NSString* key = [[self fileWithName:[xcodeprojDefinition pathRelativeToProjectRoot]] key];
81 | NSString* containerItemProxyKey =
82 | [self makeContainerItemProxyForName:[xcodeprojDefinition name] fileRef:key proxyType:@"1" uniqueName:[target name]];
83 | // make a PBXTargetDependency
84 | NSString* targetDependencyKey =
85 | [self makeTargetDependency:[xcodeprojDefinition name] forContainerItemProxyKey:containerItemProxyKey uniqueName:[target name]];
86 | // add entry in each targets dependencies list
87 | [target addDependency:targetDependencyKey];
88 | }
89 | }
90 |
91 | // returns an array of keys for all project objects (not just files) that match the given criteria. Since this is
92 | // a convenience method intended to save typing elsewhere, each type has its own field to match to rather than each
93 | // matching on name or path as you might expect.
94 | - (NSArray*)keysForProjectObjectsOfType:(XcodeMemberType)memberType withIdentifier:(NSString*)identifier singleton:(BOOL)singleton
95 | required:(BOOL)required
96 | {
97 | __block NSMutableArray* returnValue = [[NSMutableArray alloc] init];
98 | [[self objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
99 | {
100 | if ([[obj valueForKey:@"isa"] asMemberType] == memberType)
101 | {
102 | if (memberType == PBXContainerItemProxyType)
103 | {
104 | if ([[obj valueForKey:@"containerPortal"] isEqualToString:identifier])
105 | {
106 | [returnValue addObject:key];
107 | }
108 | }
109 | else if (memberType == PBXReferenceProxyType)
110 | {
111 | if ([[obj valueForKey:@"remoteRef"] isEqualToString:identifier])
112 | {
113 | [returnValue addObject:key];
114 | }
115 | }
116 | else if (memberType == PBXTargetDependencyType || memberType == PBXGroupType || memberType == PBXVariantGroupType)
117 | {
118 | if ([[obj valueForKey:@"name"] isEqualToString:identifier])
119 | {
120 | [returnValue addObject:key];
121 | }
122 | }
123 | else if (memberType == PBXNativeTargetType)
124 | {
125 | for (NSString* dependencyKey in [obj valueForKey:@"dependencies"])
126 | {
127 | if ([dependencyKey isEqualToString:identifier])
128 | {
129 | [returnValue addObject:key];
130 | }
131 | }
132 | }
133 | else if (memberType == PBXBuildFileType)
134 | {
135 | if ([[obj valueForKey:@"fileRef"] isEqualToString:identifier])
136 | {
137 | [returnValue addObject:key];
138 | }
139 | }
140 | else if (memberType == PBXProjectType)
141 | {
142 | [returnValue addObject:key];
143 | }
144 | else if (memberType == PBXFileReferenceType)
145 | {
146 | if ([[obj valueForKey:@"path"] isEqualToString:identifier])
147 | {
148 | [returnValue addObject:key];
149 | }
150 | }
151 | else if (memberType == PBXFrameworksBuildPhaseType || memberType == PBXResourcesBuildPhaseType)
152 | {
153 | [returnValue addObject:key];
154 | }
155 | else
156 | {
157 | [NSException raise:NSInvalidArgumentException format:@"Unrecognized member type %@",
158 | [NSString stringFromMemberType:memberType]];
159 | }
160 | }
161 | }];
162 | if (singleton && [returnValue count] > 1)
163 | {
164 | [NSException raise:NSGenericException format:@"Searched for one instance of member type %@ with value %@, but found %ld",
165 | [NSString stringFromMemberType:memberType], identifier, [returnValue count]];
166 | }
167 | if (required && [returnValue count] == 0)
168 | {
169 | [NSException raise:NSGenericException format:@"Searched for instances of member type %@ with value %@, but did not find any",
170 | [NSString stringFromMemberType:memberType], identifier];
171 | }
172 | return returnValue;
173 | }
174 |
175 | // returns the dictionary for the PBXProject. Raises an exception if more or less than 1 are found.
176 | - (NSMutableDictionary*)PBXProjectDict
177 | {
178 | NSString* PBXProjectKey;
179 | NSArray* PBXProjectKeys = [self keysForProjectObjectsOfType:PBXProjectType withIdentifier:nil singleton:YES required:YES];
180 | PBXProjectKey = [PBXProjectKeys objectAtIndex:0];
181 | NSMutableDictionary* PBXProjectDict = [[self objects] valueForKey:PBXProjectKey];
182 | return PBXProjectDict;
183 | }
184 |
185 | // returns the key of the PBXContainerItemProxy for the given name and proxy type. nil if not found.
186 | - (NSString*)containerItemProxyKeyForName:(NSString*)name proxyType:(NSString*)proxyType
187 | {
188 | NSMutableArray* results = [[NSMutableArray alloc] init];
189 | [[self objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
190 | {
191 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXContainerItemProxyType)
192 | {
193 | NSString* remoteInfo = [obj valueForKey:@"remoteInfo"];
194 | NSString* proxy = [obj valueForKey:@"proxyType"];
195 | if ([remoteInfo isEqualToString:name] && [proxy isEqualToString:proxyType])
196 | {
197 | [results addObject:key];
198 | }
199 | }
200 | }];
201 | if ([results count] > 1)
202 | {
203 | [NSException raise:NSGenericException format:@"Searched for one instance of member type %@ with value %@, but found %ld",
204 | @"PBXContainerItemProxy",
205 | [NSString stringWithFormat:@"%@ and proxyType of %@", name, proxyType],
206 | [results count]];
207 | }
208 | if ([results count] == 0)
209 | {
210 | return nil;
211 | }
212 | return [results objectAtIndex:0];
213 | }
214 |
215 | /* ====================================================================================================================================== */
216 | #pragma mark - Private Methods
217 | #pragma mark sub-project related private methods
218 |
219 | // makes a PBXContainerItemProxy object for a given PBXFileReference object. Replaces pre-existing objects.
220 | - (NSString*)makeContainerItemProxyForName:(NSString*)name fileRef:(NSString*)fileRef proxyType:(NSString*)proxyType
221 | uniqueName:(NSString*)uniqueName
222 | {
223 | NSString* keyName;
224 | if (uniqueName != nil)
225 | {
226 | keyName = [NSString stringWithFormat:@"%@-%@", name, uniqueName];
227 | }
228 | else
229 | {
230 | keyName = name;
231 | }
232 | // remove old if it exists
233 | NSString* existingProxyKey = [self containerItemProxyKeyForName:keyName proxyType:proxyType];
234 | if (existingProxyKey)
235 | {
236 | [[self objects] removeObjectForKey:existingProxyKey];
237 | }
238 | // make new one
239 | NSMutableDictionary* proxy = [NSMutableDictionary dictionary];
240 | [proxy setObject:[NSString stringFromMemberType:PBXContainerItemProxyType] forKey:@"isa"];
241 | [proxy setObject:fileRef forKey:@"containerPortal"];
242 | [proxy setObject:proxyType forKey:@"proxyType"];
243 | // give it a random key - the keys xcode puts here are not in the project file anywhere else
244 | NSString* key = [[XCKeyBuilder forItemNamed:[NSString stringWithFormat:@"%@-junk", keyName]] build];
245 | [proxy setObject:key forKey:@"remoteGlobalIDString"];
246 | [proxy setObject:name forKey:@"remoteInfo"];
247 | // add to project. use proxyType to generate key, so that multiple keys for the same name don't overwrite each other
248 | key = [[XCKeyBuilder forItemNamed:[NSString stringWithFormat:@"%@-containerProxy-%@", keyName, proxyType]] build];
249 | [[self objects] setObject:proxy forKey:key];
250 |
251 | return key;
252 | }
253 |
254 | // makes a PBXReferenceProxy object for a given PBXContainerProxy object. Replaces pre-existing objects.
255 | - (void)makeReferenceProxyForContainerItemProxy:(NSString*)containerItemProxyKey buildProductReference:(NSDictionary*)buildProductReference
256 | {
257 | NSString* path = [buildProductReference valueForKey:@"path"];
258 | // remove old if any exists
259 | NSArray* existingProxyKeys = [self keysForProjectObjectsOfType:PBXReferenceProxyType withIdentifier:path singleton:NO required:NO];
260 | if ([existingProxyKeys count] > 0)
261 | {
262 | for (NSString* existingProxyKey in existingProxyKeys)
263 | {
264 | [[self objects] removeObjectForKey:existingProxyKey];
265 | }
266 | }
267 | // make new one
268 | NSMutableDictionary* proxy = [NSMutableDictionary dictionary];
269 | [proxy setObject:[NSString stringFromMemberType:PBXReferenceProxyType] forKey:@"isa"];
270 | [proxy setObject:[buildProductReference valueForKey:@"explicitFileType"] forKey:@"fileType"];
271 | [proxy setObject:path forKey:@"path"];
272 | [proxy setObject:containerItemProxyKey forKey:@"remoteRef"];
273 | [proxy setObject:[buildProductReference valueForKey:@"sourceTree"] forKey:@"sourceTree"];
274 | // add to project
275 | NSString* key = [[XCKeyBuilder forItemNamed:[NSString stringWithFormat:@"%@-referenceProxy", path]] build];
276 | [[self objects] setObject:proxy forKey:key];
277 | }
278 |
279 | // makes a PBXTargetDependency object for a given PBXContainerItemProxy. Replaces pre-existing objects.
280 | - (NSString*)makeTargetDependency:(NSString*)name forContainerItemProxyKey:(NSString*)containerItemProxyKey uniqueName:(NSString*)uniqueName
281 | {
282 | NSString* keyName;
283 | if (uniqueName != nil)
284 | {
285 | keyName = [NSString stringWithFormat:@"%@-%@", name, uniqueName];
286 | }
287 | else
288 | {
289 | keyName = name;
290 | }
291 | // remove old if it exists
292 | NSArray* existingDependencyKeys =
293 | [self keysForProjectObjectsOfType:PBXTargetDependencyType withIdentifier:keyName singleton:NO required:NO];
294 | if ([existingDependencyKeys count] > 0)
295 | {
296 | for (NSString* existingDependencyKey in existingDependencyKeys)
297 | {
298 | [[self objects] removeObjectForKey:existingDependencyKey];
299 | }
300 | }
301 | // make new one
302 | NSMutableDictionary* targetDependency = [NSMutableDictionary dictionary];
303 | [targetDependency setObject:[NSString stringFromMemberType:PBXTargetDependencyType] forKey:@"isa"];
304 | [targetDependency setObject:name forKey:@"name"];
305 | [targetDependency setObject:containerItemProxyKey forKey:@"targetProxy"];
306 | NSString* targetDependencyKey = [[XCKeyBuilder forItemNamed:[NSString stringWithFormat:@"%@-targetProxy", keyName]] build];
307 | [[self objects] setObject:targetDependency forKey:targetDependencyKey];
308 | return targetDependencyKey;
309 | }
310 |
311 | // make a PBXContainerItemProxy and PBXReferenceProxy for each target in the subProject
312 | - (void)addProxies:(XCSubProjectDefinition*)xcodeproj
313 | {
314 | NSString* fileRef = [[self fileWithName:[xcodeproj pathRelativeToProjectRoot]] key];
315 | for (NSDictionary* target in [xcodeproj.subProject targets])
316 | {
317 | NSString* containerItemProxyKey =
318 | [self makeContainerItemProxyForName:[target valueForKey:@"name"] fileRef:fileRef proxyType:@"2" uniqueName:nil];
319 | NSString* productFileReferenceKey = [target valueForKey:@"productReference"];
320 | NSDictionary* productFileReference = [[xcodeproj.subProject objects] valueForKey:productFileReferenceKey];
321 | [self makeReferenceProxyForContainerItemProxy:containerItemProxyKey buildProductReference:productFileReference];
322 | }
323 | }
324 |
325 | // remove the PBXContainerItemProxy and PBXReferenceProxy objects for the given object key (which is the PBXFilereference
326 | // for the xcodeproj file)
327 | - (void)removeProxies:(NSString*)xcodeprojKey
328 | {
329 | NSMutableArray* keysToDelete = [NSMutableArray array];
330 | // use the xcodeproj's PBXFileReference key to get the PBXContainerItemProxy keys
331 | NSArray* containerItemProxyKeys =
332 | [self keysForProjectObjectsOfType:PBXContainerItemProxyType withIdentifier:xcodeprojKey singleton:NO required:YES];
333 | // use the PBXContainerItemProxy keys to get the PBXReferenceProxy keys
334 | for (NSString* key in containerItemProxyKeys)
335 | {
336 | [keysToDelete addObjectsFromArray:[self keysForProjectObjectsOfType:PBXReferenceProxyType withIdentifier:key singleton:NO
337 | required:NO]];
338 | [keysToDelete addObject:key];
339 | }
340 | // remove all objects located above
341 | [keysToDelete enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop)
342 | {
343 | [[self objects] removeObjectForKey:obj];
344 | }];
345 | }
346 |
347 | // returns the Products group key for the given PBXFileReference key, nil if not found.
348 | - (NSString*)productsGroupKeyForKey:(NSString*)key
349 | {
350 | NSMutableArray* projectReferences = [[self PBXProjectDict] valueForKey:@"projectReferences"];
351 | NSString* productsGroupKey = nil;
352 | for (NSDictionary* projectRef in projectReferences)
353 | {
354 | if ([[projectRef valueForKey:@"ProjectRef"] isEqualToString:key])
355 | {
356 | // it's an error if we find more than one
357 | if (productsGroupKey != nil)
358 | {
359 | [NSException raise:NSGenericException format:@"Found more than one project reference for key %@", key];
360 | }
361 | productsGroupKey = [projectRef valueForKey:@"ProductGroup"];
362 | }
363 | }
364 | return productsGroupKey;
365 | }
366 |
367 | // removes a file reference from the projectReferences array in PBXProject (removing the array itself if this action
368 | // leaves it empty).
369 | - (void)removeFromProjectReferences:(NSString*)key forProductsGroup:(NSString*)productsGroupKey
370 | {
371 | NSMutableArray* projectReferences = [[self PBXProjectDict] valueForKey:@"projectReferences"];
372 | // remove entry from PBXProject's projectReferences
373 | NSMutableArray* referencesToRemove = [NSMutableArray array];
374 | for (NSDictionary* projectRef in projectReferences)
375 | {
376 | if ([[projectRef valueForKey:@"ProjectRef"] isEqualToString:key])
377 | {
378 | [referencesToRemove addObject:projectRef];
379 | }
380 | }
381 | for (NSDictionary* projectRef in referencesToRemove)
382 | {
383 | [projectReferences removeObject:projectRef];
384 | }
385 | // if that was the last project reference, remove the array from the project
386 | if ([projectReferences count] == 0)
387 | {
388 | [[self PBXProjectDict] removeObjectForKey:@"projectReferences"];
389 | }
390 | }
391 |
392 | // removes a specific xcodeproj file from any targets (by name). It's not an error if no entries are found,
393 | // because we support adding a project file without adding it to any targets.
394 | - (void)removeTargetDependencies:(NSString*)name
395 | {
396 | // get the key for the PBXTargetDependency with name = xcodeproj file name (without extension)
397 | NSArray* targetDependencyKeys = [self keysForProjectObjectsOfType:PBXTargetDependencyType withIdentifier:name singleton:NO required:NO];
398 | // we might not find any if the project wasn't added to targets in the first place
399 | if ([targetDependencyKeys count] == 0)
400 | {
401 | return;
402 | }
403 | NSString* targetDependencyKey = [targetDependencyKeys objectAtIndex:0];
404 | // use the key for the PBXTargetDependency to get the key for any PBXNativeTargets that depend on it
405 | NSArray* nativeTargetKeys =
406 | [self keysForProjectObjectsOfType:PBXNativeTargetType withIdentifier:targetDependencyKey singleton:NO required:NO];
407 | // remove the key for the PBXTargetDependency from the PBXNativeTarget's dependencies arrays (leave in place even if empty)
408 | for (NSString* nativeTargetKey in nativeTargetKeys)
409 | {
410 | NSMutableDictionary* nativeTarget = [[self objects] objectForKey:nativeTargetKey];
411 | NSMutableArray* dependencies = [nativeTarget valueForKey:@"dependencies"];
412 | [dependencies removeObject:targetDependencyKey];
413 | [nativeTarget setObject:dependencies forKey:@"dependencies"];
414 | }
415 | // remove the PBXTargetDependency
416 | [[self objects] removeObjectForKey:targetDependencyKey];
417 | }
418 |
419 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCProject.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 | #import
13 | #import "XcodeMemberType.h"
14 | #import "XcodeSourceFileType.h"
15 |
16 | @class XCClassDefinition;
17 | @class XCGroup;
18 | @class XCFileOperationQueue;
19 | @class XCSourceFile;
20 | @class XCTarget;
21 | @class XCSubProjectDefinition;
22 | @class XCBuildConfig;
23 |
24 | NSString* const XCProjectNotFoundException;
25 |
26 | @interface XCProject : NSObject
27 | {
28 | @protected
29 | XCFileOperationQueue* _fileOperationQueue;
30 |
31 | NSString* _filePath;
32 | NSMutableDictionary* _dataStore;
33 | NSMutableArray* _targets;
34 |
35 | NSMutableDictionary* _groups;
36 | NSMutableDictionary* _configurations;
37 |
38 | NSString* _defaultConfigurationName;
39 | NSString* _rootObjectKey;
40 | }
41 |
42 | @property(nonatomic, strong, readonly) XCFileOperationQueue* fileOperationQueue;
43 |
44 | /* ============================================================ Initializers ============================================================ */
45 |
46 | + (XCProject*)projectWithFilePath:(NSString*)filePath;
47 |
48 | /**
49 | * Creates a new project editor instance with the specified Project.xcodeproj file.
50 | */
51 | - (id)initWithFilePath:(NSString*)filePath;
52 |
53 | /* ====================================================================================================================================== */
54 |
55 | #pragma mark Files
56 | /**
57 | * Returns all file resources in the project, as an array of `XCSourceFile` objects.
58 | */
59 | - (NSArray*)files;
60 |
61 | /**
62 | * Returns the project file with the specified key, or nil.
63 | */
64 | - (XCSourceFile*)fileWithKey:(NSString*)key;
65 |
66 | /**
67 | * Returns the project file with the specified name, or nil. If more than one project file matches the specified name,
68 | * which one is returned is undefined.
69 | */
70 | - (XCSourceFile*)fileWithName:(NSString*)name;
71 |
72 | /**
73 | * Returns all header files in the project, as an array of `XCSourceFile` objects.
74 | */
75 | - (NSArray*)headerFiles;
76 |
77 | /**
78 | * Returns all implementation obj-c implementation files in the project, as an array of `XCSourceFile` objects.
79 | */
80 | - (NSArray*)objectiveCFiles;
81 |
82 | /**
83 | * Returns all implementation obj-c++ implementation files in the project, as an array of `XCSourceFile` objects.
84 | */
85 | - (NSArray*)objectiveCPlusPlusFiles;
86 |
87 | /**
88 | * Returns all the xib files in the project, as an array of `XCSourceFile` objects.
89 | */
90 | - (NSArray*)xibFiles;
91 |
92 | - (NSArray*)imagePNGFiles;
93 |
94 | - (NSString*)filePath;
95 |
96 |
97 | /* ====================================================================================================================================== */
98 | #pragma mark Groups
99 | /**
100 | * Lists the groups in an xcode project, returning an array of `XCGroup` objects.
101 | */
102 | - (NSArray*)groups;
103 |
104 | /**
105 | * Returns the root (top-level) group.
106 | */
107 | - (XCGroup*)rootGroup;
108 |
109 | /**
110 | * Returns the root (top-level) groups, if there are multiple. An array of rootGroup if there is only one.
111 | */
112 | - (NSArray*)rootGroups;
113 |
114 | /**
115 | * Returns the group with the given key, or nil.
116 | */
117 | - (XCGroup*)groupWithKey:(NSString*)key;
118 |
119 | /**
120 | * Returns the group with the specified display name path - the directory relative to the root group. Eg Source/Main
121 | */
122 | - (XCGroup*)groupWithPathFromRoot:(NSString*)path;
123 |
124 | /**
125 | * Returns the parent group for the group or file with the given key;
126 | */
127 | - (XCGroup*)groupForGroupMemberWithKey:(NSString*)key;
128 |
129 | /**
130 | * Returns the parent group for the group or file with the source file
131 | */
132 | - (XCGroup*)groupWithSourceFile:(XCSourceFile*)sourceFile;
133 |
134 | /* ====================================================================================================================================== */
135 | #pragma mark Targets
136 | /**
137 | * Lists the targets in an xcode project, returning an array of `XCTarget` objects.
138 | */
139 | - (NSArray*)targets;
140 |
141 | /**
142 | * Returns the target with the specified name, or nil.
143 | */
144 | - (XCTarget*)targetWithName:(NSString*)name;
145 |
146 | #pragma mark Configurations
147 |
148 | /**
149 | * Returns the target with the specified name, or nil.
150 | */
151 | - (NSDictionary*)configurations;
152 |
153 | - (NSDictionary*)configurationWithName:(NSString*)name;
154 |
155 | - (XCBuildConfig*)defaultConfiguration;
156 |
157 | /* ====================================================================================================================================== */
158 | #pragma mark Saving
159 | /**
160 | * Saves a project after editing.
161 | */
162 | - (void)save;
163 |
164 |
165 | /* ====================================================================================================================================== */
166 | /**
167 | * Raw project data.
168 | */
169 | - (NSMutableDictionary*)objects;
170 |
171 | - (NSMutableDictionary*)dataStore;
172 |
173 | - (void)dropCache;
174 |
175 | @end
176 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCProject.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 - 2013 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import "XCProject.h"
14 | #import "XCGroup.h"
15 | #import "XCSourceFile.h"
16 | #import "XCTarget.h"
17 | #import "XCFileOperationQueue.h"
18 | #import "XCBuildConfig.h"
19 |
20 |
21 | @implementation XCProject
22 |
23 |
24 | @synthesize fileOperationQueue = _fileOperationQueue;
25 |
26 | /* ====================================================================================================================================== */
27 | #pragma mark - Class Methods
28 |
29 | + (XCProject*)projectWithFilePath:(NSString*)filePath
30 | {
31 | return [[XCProject alloc] initWithFilePath:filePath];
32 | }
33 |
34 |
35 | /* ====================================================================================================================================== */
36 | #pragma mark - Initialization & Destruction
37 |
38 | - (id)initWithFilePath:(NSString*)filePath
39 | {
40 | if ((self = [super init]))
41 | {
42 | _filePath = [filePath copy];
43 | _dataStore = [[NSMutableDictionary alloc] initWithContentsOfFile:[_filePath stringByAppendingPathComponent:@"project.pbxproj"]];
44 |
45 | if (!_dataStore)
46 | {
47 | [NSException raise:XCProjectNotFoundException format:@"Project file not found at file path %@", _filePath];
48 | }
49 |
50 | _fileOperationQueue = [[XCFileOperationQueue alloc] initWithBaseDirectory:[_filePath stringByDeletingLastPathComponent]];
51 |
52 | }
53 | return self;
54 | }
55 |
56 | /* ====================================================================================================================================== */
57 | #pragma mark - Interface Methods
58 |
59 | #pragma mark Files
60 |
61 | - (NSArray*)files
62 | {
63 | NSMutableArray* results = [NSMutableArray array];
64 | [[self objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
65 | {
66 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXFileReferenceType)
67 | {
68 | XcodeSourceFileType fileType = XCSourceFileTypeFromStringRepresentation([obj valueForKey:@"lastKnownFileType"]);
69 | NSString* path = [obj valueForKey:@"path"];
70 | NSString* sourceTree = [obj valueForKey:@"sourceTree"];
71 | [results addObject:[XCSourceFile sourceFileWithProject:self key:key type:fileType name:path
72 | sourceTree:(sourceTree ? sourceTree : @"") path:nil]];
73 | }
74 | }];
75 | return results;
76 | }
77 |
78 | - (XCSourceFile*)fileWithKey:(NSString*)key
79 | {
80 | NSDictionary* obj = [[self objects] valueForKey:key];
81 | if (obj && ([[obj valueForKey:@"isa"] asMemberType] == PBXFileReferenceType || [[obj valueForKey:@"isa"] asMemberType] ==
82 | PBXReferenceProxyType))
83 | {
84 | XcodeSourceFileType fileType = XCSourceFileTypeFromStringRepresentation([obj valueForKey:@"lastKnownFileType"]);
85 |
86 | NSString* name = [obj valueForKey:@"name"];
87 | NSString* sourceTree = [obj valueForKey:@"sourceTree"];
88 |
89 | if (name == nil)
90 | {
91 | name = [obj valueForKey:@"path"];
92 | }
93 | return [XCSourceFile sourceFileWithProject:self key:key type:fileType name:name sourceTree:(sourceTree ? sourceTree : @"")
94 | path:[obj valueForKey:@"path"]];
95 | }
96 | return nil;
97 | }
98 |
99 | - (XCSourceFile*)fileWithName:(NSString*)name
100 | {
101 | for (XCSourceFile* projectFile in [self files])
102 | {
103 | if ([[projectFile name] isEqualToString:name])
104 | {
105 | return projectFile;
106 | }
107 | }
108 | return nil;
109 | }
110 |
111 |
112 | - (NSArray*)headerFiles
113 | {
114 | return [self projectFilesOfType:SourceCodeHeader];
115 | }
116 |
117 | - (NSArray*)objectiveCFiles
118 | {
119 | return [self projectFilesOfType:SourceCodeObjC];
120 | }
121 |
122 | - (NSArray*)objectiveCPlusPlusFiles
123 | {
124 | return [self projectFilesOfType:SourceCodeObjCPlusPlus];
125 | }
126 |
127 |
128 | - (NSArray*)xibFiles
129 | {
130 | return [self projectFilesOfType:XibFile];
131 | }
132 |
133 | - (NSArray*)imagePNGFiles
134 | {
135 | return [self projectFilesOfType:ImageResourcePNG];
136 | }
137 |
138 | // need this value to construct relative path in XcodeprojDefinition
139 | - (NSString*)filePath
140 | {
141 | return _filePath;
142 | }
143 |
144 | /* ====================================================================================================================================== */
145 | #pragma mark Groups
146 |
147 | - (NSArray*)groups
148 | {
149 |
150 | NSMutableArray* results = [[NSMutableArray alloc] init];
151 | [[_dataStore objectForKey:@"objects"] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
152 | {
153 |
154 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXGroupType || [[obj valueForKeyPath:@"isa"] asMemberType] == PBXVariantGroupType)
155 | {
156 | [results addObject:[self groupWithKey:key]];
157 | }
158 | }];
159 | return results;
160 | }
161 |
162 | //TODO: Optimize this implementation.
163 | - (XCGroup*)rootGroup
164 | {
165 | for (XCGroup* group in [self groups])
166 | {
167 | if ([group isRootGroup])
168 | {
169 | return group;
170 | }
171 | }
172 | return nil;
173 | }
174 |
175 | - (NSArray*)rootGroups
176 | {
177 | XCGroup* group = [self rootGroup];
178 | if (group)
179 | {
180 | return [NSArray arrayWithObject:group];
181 | }
182 |
183 | NSMutableArray* results = [NSMutableArray array];
184 | for (XCGroup* group in [self groups])
185 | {
186 | if ([group parentGroup] == nil)
187 | {
188 | [results addObject:group];
189 | }
190 | }
191 |
192 | return [results copy];
193 | }
194 |
195 | - (XCGroup*)groupWithKey:(NSString*)key
196 | {
197 | XCGroup* group = [_groups objectForKey:key];
198 | if (group)
199 | {
200 | return group;
201 | }
202 |
203 | NSDictionary* obj = [[self objects] objectForKey:key];
204 | if (obj && ([[obj valueForKey:@"isa"] asMemberType] == PBXGroupType || [[obj valueForKey:@"isa"] asMemberType] == PBXVariantGroupType))
205 | {
206 |
207 | NSString* name = [obj valueForKey:@"name"];
208 | NSString* path = [obj valueForKey:@"path"];
209 | NSArray* children = [obj valueForKey:@"children"];
210 | XCGroup* group = [XCGroup groupWithProject:self key:key alias:name path:path children:children];
211 |
212 | [_groups setObject:group forKey:key];
213 |
214 | return group;
215 | }
216 | return nil;
217 | }
218 |
219 | - (XCGroup*)groupForGroupMemberWithKey:(NSString*)key
220 | {
221 | for (XCGroup* group in [self groups])
222 | {
223 | if ([group memberWithKey:key])
224 | {
225 | return group;
226 | }
227 | }
228 | return nil;
229 | }
230 |
231 | - (XCGroup*)groupWithSourceFile:(XCSourceFile*)sourceFile
232 | {
233 | for (XCGroup* group in [self groups])
234 | {
235 | for (id member in [group members])
236 | {
237 | if ([member isKindOfClass:[XCSourceFile class]] && [[sourceFile key] isEqualToString:[member key]])
238 | {
239 | return group;
240 | }
241 | }
242 | }
243 | return nil;
244 | }
245 |
246 | //TODO: This could fail if the path attribute on a given group is more than one directory. Start with candidates and
247 | //TODO: search backwards.
248 | - (XCGroup*)groupWithPathFromRoot:(NSString*)path
249 | {
250 | NSArray* pathItems = [path componentsSeparatedByString:@"/"];
251 | XCGroup* currentGroup = [self rootGroup];
252 | for (NSString* pathItem in pathItems)
253 | {
254 | id group = [currentGroup memberWithDisplayName:pathItem];
255 | if ([group isKindOfClass:[XCGroup class]])
256 | {
257 | currentGroup = group;
258 | }
259 | else
260 | {
261 | return nil;
262 | }
263 | }
264 | return currentGroup;
265 | }
266 |
267 |
268 | /* ====================================================================================================================================== */
269 | #pragma mark targets
270 |
271 | - (NSArray*)targets
272 | {
273 | if (_targets == nil)
274 | {
275 | _targets = [[NSMutableArray alloc] init];
276 | [[self objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
277 | {
278 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXNativeTargetType)
279 | {
280 | XCTarget* target =
281 | [XCTarget targetWithProject:self key:key name:[obj valueForKey:@"name"] productName:[obj valueForKey:@"productName"]
282 | productReference:[obj valueForKey:@"productReference"]];
283 | [_targets addObject:target];
284 | }
285 | }];
286 | }
287 | return _targets;
288 | }
289 |
290 | - (XCTarget*)targetWithName:(NSString*)name
291 | {
292 | for (XCTarget* target in [self targets])
293 | {
294 | if ([[target name] isEqualToString:name])
295 | {
296 | return target;
297 | }
298 | }
299 | return nil;
300 | }
301 |
302 | - (void)save
303 | {
304 | [_fileOperationQueue commitFileOperations];
305 | [_dataStore writeToFile:[_filePath stringByAppendingPathComponent:@"project.pbxproj"] atomically:YES];
306 |
307 | NSLog(@"Saved project");
308 | }
309 |
310 | - (NSMutableDictionary*)objects
311 | {
312 | return [_dataStore objectForKey:@"objects"];
313 | }
314 |
315 | - (NSMutableDictionary*)dataStore
316 | {
317 | return _dataStore;
318 | }
319 |
320 | - (void)dropCache
321 | {
322 | _targets = nil;
323 | _configurations = nil;
324 | _rootObjectKey = nil;
325 | }
326 |
327 |
328 | - (NSDictionary*)configurations
329 | {
330 | if (_configurations == nil)
331 | {
332 | NSString* buildConfigurationRootSectionKey =
333 | [[[self objects] objectForKey:[self rootObjectKey]] objectForKey:@"buildConfigurationList"];
334 | NSDictionary* buildConfigurationDictionary = [[self objects] objectForKey:buildConfigurationRootSectionKey];
335 | _configurations =
336 | [[XCBuildConfig buildConfigurationsFromArray:[buildConfigurationDictionary objectForKey:@"buildConfigurations"]
337 | inProject:self] mutableCopy];
338 | _defaultConfigurationName = [[buildConfigurationDictionary objectForKey:@"defaultConfigurationName"] copy];
339 | }
340 |
341 | return [_configurations copy];
342 | }
343 |
344 | - (NSDictionary*)configurationWithName:(NSString*)name
345 | {
346 | return [[self configurations] objectForKey:name];
347 | }
348 |
349 | - (XCBuildConfig*)defaultConfiguration
350 | {
351 | return [[self configurations] objectForKey:_defaultConfigurationName];
352 | }
353 |
354 | /* ====================================================================================================================================== */
355 | #pragma mark Private
356 |
357 | - (NSString*)rootObjectKey
358 | {
359 | if (_rootObjectKey == nil)
360 | {
361 | _rootObjectKey = [[_dataStore objectForKey:@"rootObject"] copy];;
362 | }
363 |
364 | return _rootObjectKey;
365 | }
366 |
367 | - (NSArray*)projectFilesOfType:(XcodeSourceFileType)projectFileType
368 | {
369 | NSMutableArray* results = [NSMutableArray array];
370 | for (XCSourceFile* file in [self files])
371 | {
372 | if ([file type] == projectFileType)
373 | {
374 | [results addObject:file];
375 | }
376 | }
377 | return results;
378 | }
379 |
380 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCSourceFile.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import
15 | #import "XcodeGroupMember.h"
16 | #import "XcodeSourceFileType.h"
17 |
18 | @class XCProject;
19 |
20 | /**
21 | * Represents a file resource in an xcode project.
22 | */
23 | @interface XCSourceFile : NSObject
24 | {
25 |
26 | @private
27 | XCProject* _project;
28 |
29 | NSNumber* _isBuildFile;
30 | NSString* _buildFileKey;
31 | NSString* _name;
32 | NSString* _sourceTree;
33 | NSString* _key;
34 | NSString* _path;
35 | XcodeSourceFileType _type;
36 | }
37 |
38 | @property(nonatomic, readonly) XcodeSourceFileType type;
39 | @property(nonatomic, strong, readonly) NSString* key;
40 | @property(nonatomic, strong) NSString* name;
41 | @property(nonatomic, strong, readonly) NSString* sourceTree;
42 | @property(nonatomic, strong) NSString* path;
43 |
44 | + (XCSourceFile*)sourceFileWithProject:(XCProject*)project key:(NSString*)key type:(XcodeSourceFileType)type name:(NSString*)name
45 | sourceTree:(NSString*)tree path:(NSString*)path;
46 |
47 | - (id)initWithProject:(XCProject*)project key:(NSString*)key type:(XcodeSourceFileType)type name:(NSString*)name sourceTree:(NSString*)tree
48 | path:(NSString*)path;
49 |
50 | /**
51 | * If yes, indicates the file is able to be included for compilation in an `XCTarget`.
52 | */
53 | - (BOOL)isBuildFile;
54 |
55 | - (BOOL)canBecomeBuildFile;
56 |
57 | - (XcodeMemberType)buildPhase;
58 |
59 | - (NSString*)buildFileKey;
60 |
61 | /**
62 | * Adds this file to the project as an `xcode_BuildFile`, ready to be included in targets.
63 | */
64 | - (void)becomeBuildFile;
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCSourceFile.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCSourceFile.h"
15 | #import "XCProject.h"
16 | #import "Utils/XCKeyBuilder.h"
17 | #import "XCGroup.h"
18 |
19 | @implementation XCSourceFile
20 |
21 | @synthesize type = _type;
22 | @synthesize key = _key;
23 | @synthesize sourceTree = _sourceTree;
24 |
25 | /* ====================================================================================================================================== */
26 | #pragma mark - Class Methods
27 |
28 | + (XCSourceFile*)sourceFileWithProject:(XCProject*)project key:(NSString*)key type:(XcodeSourceFileType)type name:(NSString*)name
29 | sourceTree:(NSString*)_tree path:(NSString*)path
30 | {
31 | return [[XCSourceFile alloc] initWithProject:project key:key type:type name:name sourceTree:_tree path:path];
32 | }
33 |
34 |
35 | /* ====================================================================================================================================== */
36 | #pragma mark - Initialization & Destruction
37 |
38 | - (id)initWithProject:(XCProject*)project key:(NSString*)key type:(XcodeSourceFileType)type name:(NSString*)name sourceTree:(NSString*)tree
39 | path:(NSString*)path
40 | {
41 |
42 | self = [super init];
43 | if (self)
44 | {
45 | _project = project;
46 | _key = [key copy];
47 | _type = type;
48 | _name = [name copy];
49 | _sourceTree = [tree copy];
50 | _path = [path copy];
51 | }
52 | return self;
53 | }
54 |
55 |
56 | /* ====================================================================================================================================== */
57 | #pragma mark - Interface Methods
58 |
59 | // Goes to the entry for this object in the project and sets a value for one of the keys, such as name, path, etc.
60 | - (void)setValue:(id)val forProjectItemPropertyWithKey:(NSString*)key
61 | {
62 | NSMutableDictionary* obj = [[[_project objects] objectForKey:_key] mutableCopy];
63 | if (nil == obj)
64 | {
65 | [NSException raise:@"Project item not found" format:@"Project item with key %@ not found.", _key];
66 | }
67 | [obj setValue:val forKey:key];
68 | [[_project objects] setValue:obj forKey:_key];
69 | }
70 |
71 |
72 | - (NSString*)name
73 | {
74 | return _name;
75 | }
76 |
77 | - (void)setName:(NSString*)name
78 | {
79 | id old = _name;
80 | _name = [name copy];
81 |
82 | [self setValue:name forProjectItemPropertyWithKey:@"name"];
83 | }
84 |
85 |
86 | - (NSString*)path
87 | {
88 | return _path;
89 | }
90 |
91 | - (void)setPath:(NSString*)path
92 | {
93 | id old = _path;
94 | _path = [path copy];
95 |
96 | [self setValue:path forProjectItemPropertyWithKey:@"path"];
97 | }
98 |
99 | - (BOOL)isBuildFile
100 | {
101 | if ([self canBecomeBuildFile] && _isBuildFile == nil)
102 | {
103 | id old = _isBuildFile;
104 | _isBuildFile = [[NSNumber numberWithBool:NO] copy];
105 | [[_project objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
106 | {
107 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXBuildFileType)
108 | {
109 | if ([[obj valueForKey:@"fileRef"] isEqualToString:_key])
110 | {
111 | _isBuildFile = nil;
112 |
113 | _isBuildFile = [[NSNumber numberWithBool:YES] copy];
114 | }
115 | }
116 | }];
117 | }
118 | return [_isBuildFile boolValue];
119 | }
120 |
121 | - (BOOL)canBecomeBuildFile
122 | {
123 | return _type == SourceCodeObjC || _type == SourceCodeObjCPlusPlus || _type == SourceCodeCPlusPlus || _type == XibFile || _type ==
124 | Framework || _type == ImageResourcePNG || _type == HTML || _type == Bundle || _type == Archive;
125 | }
126 |
127 |
128 | - (XcodeMemberType)buildPhase
129 | {
130 | if (_type == SourceCodeObjC || _type == SourceCodeObjCPlusPlus || _type == SourceCodeCPlusPlus || _type == XibFile)
131 | {
132 | return PBXSourcesBuildPhaseType;
133 | }
134 | else if (_type == Framework)
135 | {
136 | return PBXFrameworksBuildPhaseType;
137 | }
138 | else if (_type == ImageResourcePNG || _type == HTML || _type == Bundle)
139 | {
140 | return PBXResourcesBuildPhaseType;
141 | }
142 | else if (_type == Archive)
143 | {
144 | return PBXFrameworksBuildPhaseType;
145 | }
146 | return PBXNilType;
147 | }
148 |
149 | - (NSString*)buildFileKey
150 | {
151 | if (_buildFileKey == nil)
152 | {
153 | [[_project objects] enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
154 | {
155 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXBuildFileType)
156 | {
157 | if ([[obj valueForKey:@"fileRef"] isEqualToString:_key])
158 | {
159 | _buildFileKey = [key copy];
160 | }
161 | }
162 | }];
163 | }
164 | return [_buildFileKey copy];
165 |
166 | }
167 |
168 |
169 | - (void)becomeBuildFile
170 | {
171 | if (![self isBuildFile])
172 | {
173 | if ([self canBecomeBuildFile])
174 | {
175 | NSMutableDictionary* sourceBuildFile = [NSMutableDictionary dictionary];
176 | [sourceBuildFile setObject:[NSString stringFromMemberType:PBXBuildFileType] forKey:@"isa"];
177 | [sourceBuildFile setObject:_key forKey:@"fileRef"];
178 | NSString* buildFileKey = [[XCKeyBuilder forItemNamed:[_name stringByAppendingString:@".buildFile"]] build];
179 | [[_project objects] setObject:sourceBuildFile forKey:buildFileKey];
180 | }
181 | else if (_type == Framework)
182 | {
183 | [NSException raise:NSInvalidArgumentException format:@"Add framework to target not implemented yet."];
184 | }
185 | else
186 | {
187 | [NSException raise:NSInvalidArgumentException format:@"Project file of type %@ can't become a build file.",
188 | NSStringFromXCSourceFileType(_type)];
189 | }
190 |
191 | }
192 | }
193 |
194 | /* ====================================================================================================================================== */
195 | #pragma mark - Protocol Methods
196 |
197 | - (XcodeMemberType)groupMemberType
198 | {
199 | return PBXFileReferenceType;
200 | }
201 |
202 | - (NSString*)displayName
203 | {
204 | return _name;
205 | }
206 |
207 | - (NSString*)pathRelativeToProjectRoot
208 | {
209 | NSString* parentPath = [[_project groupForGroupMemberWithKey:_key] pathRelativeToProjectRoot];
210 | NSString* result = [parentPath stringByAppendingPathComponent:_name];
211 | return result;
212 | }
213 |
214 | /* ====================================================================================================================================== */
215 | #pragma mark - Utility Methods
216 |
217 | - (NSString*)description
218 | {
219 | return [NSString stringWithFormat:@"Project file: key=%@, name=%@, fullPath=%@", _key, _name, [self pathRelativeToProjectRoot]];
220 | }
221 |
222 |
223 | @end
224 |
225 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCSourceFileDefinition.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import
15 | #import "XCAbstractDefinition.h"
16 | #import "XcodeSourceFileType.h"
17 |
18 | @interface XCSourceFileDefinition : XCAbstractDefinition
19 | {
20 |
21 | NSString* _sourceFileName;
22 | XcodeSourceFileType _type;
23 | NSData* _data;
24 |
25 | }
26 |
27 | @property(nonatomic, strong, readonly) NSString* sourceFileName;
28 | @property(nonatomic, strong, readonly) NSData* data;
29 | @property(nonatomic, readonly) XcodeSourceFileType type;
30 |
31 | + (XCSourceFileDefinition*)sourceDefinitionWithName:(NSString*)name text:(NSString*)text type:(XcodeSourceFileType)type;
32 |
33 | + (XCSourceFileDefinition*)sourceDefinitionWithName:(NSString*)name data:(NSData*)data type:(XcodeSourceFileType)type;
34 |
35 | - (id)initWithName:(NSString*)name text:(NSString*)text type:(XcodeSourceFileType)type;
36 |
37 | - (id)initWithName:(NSString*)name data:(NSData*)data type:(XcodeSourceFileType)type;
38 |
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCSourceFileDefinition.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCSourceFileDefinition.h"
15 |
16 | @implementation XCSourceFileDefinition
17 |
18 | @synthesize sourceFileName = _sourceFileName;
19 | @synthesize type = _type;
20 | @synthesize data = _data;
21 |
22 | /* ====================================================================================================================================== */
23 | #pragma mark - Class Methods
24 |
25 | + (XCSourceFileDefinition*)sourceDefinitionWithName:(NSString*)name text:(NSString*)text type:(XcodeSourceFileType)type
26 | {
27 |
28 | return [[XCSourceFileDefinition alloc] initWithName:name text:text type:type];
29 | }
30 |
31 | + (XCSourceFileDefinition*)sourceDefinitionWithName:(NSString*)name data:(NSData*)data type:(XcodeSourceFileType)type
32 | {
33 |
34 | return [[XCSourceFileDefinition alloc] initWithName:name data:data type:type];
35 | }
36 |
37 |
38 | /* ====================================================================================================================================== */
39 | #pragma mark - Initialization & Destruction
40 |
41 | - (id)initWithName:(NSString*)name text:(NSString*)text type:(XcodeSourceFileType)type
42 | {
43 | self = [super init];
44 | if (self)
45 | {
46 | _sourceFileName = [name copy];
47 | _data = [[text dataUsingEncoding:NSUTF8StringEncoding] copy];
48 | _type = type;
49 | }
50 | return self;
51 | }
52 |
53 | - (id)initWithName:(NSString*)name data:(NSData*)data type:(XcodeSourceFileType)type
54 | {
55 | self = [super init];
56 | if (self)
57 | {
58 | _sourceFileName = [name copy];
59 | _data = [data copy];
60 | _type = type;
61 | }
62 | return self;
63 |
64 | }
65 |
66 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCSubProjectDefinition.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import
15 | #import "XCAbstractDefinition.h"
16 | #import "XcodeSourceFileType.h"
17 |
18 | @class XCProject;
19 |
20 |
21 | @interface XCSubProjectDefinition : XCAbstractDefinition
22 | {
23 |
24 | NSString* _name;
25 | NSString* _path;
26 | XcodeSourceFileType _type;
27 | XCProject* _subProject;
28 | XCProject* _parentProject;
29 | NSString* _key;
30 | NSString* _fullProjectPath;
31 | NSString* _relativePath;
32 | }
33 |
34 |
35 | @property(nonatomic, strong, readonly) NSString* name;
36 | @property(nonatomic, strong, readonly) NSString* path;
37 | @property(nonatomic, readonly) XcodeSourceFileType type;
38 | @property(nonatomic, strong, readonly) XCProject* subProject;
39 | @property(nonatomic, strong, readonly) XCProject* parentProject;
40 | @property(nonatomic, strong, readonly) NSString* key;
41 | @property(nonatomic, strong, readwrite) NSString* fullProjectPath;
42 |
43 | + (XCSubProjectDefinition*)withName:(NSString*)name path:(NSString*)path parentProject:(XCProject*)parentProject;
44 |
45 | - (id)initWithName:(NSString*)name path:(NSString*)path parentProject:(XCProject*)parentProject;
46 |
47 | - (NSString*)projectFileName;
48 |
49 | - (NSString*)fullPathName;
50 |
51 | - (NSArray*)buildProductNames;
52 |
53 | - (NSString*)projectKey;
54 |
55 | - (NSString*)pathRelativeToProjectRoot;
56 |
57 | - (NSString*)description;
58 |
59 | - (void)initFullProjectPath:(NSString*)fullProjectPath groupPath:(NSString*)groupPath;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCSubProjectDefinition.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XCProject.h"
15 | #import "XCProject+SubProject.h"
16 | #import "XCSubProjectDefinition.h"
17 |
18 | @interface XCSubProjectDefinition ()
19 | @property(nonatomic, strong, readwrite) NSString* relativePath;
20 | @end
21 |
22 | @implementation XCSubProjectDefinition
23 |
24 | @synthesize name = _name;
25 | @synthesize path = _path;
26 | @synthesize type = _type;
27 | @synthesize parentProject = _parentProject;
28 | @synthesize subProject = _subProject;
29 | @synthesize relativePath = _relativePath;
30 | @synthesize key = _key;
31 | @synthesize fullProjectPath = _fullProjectPath;
32 |
33 | /* ====================================================================================================================================== */
34 | #pragma mark - Class Methods
35 |
36 | + (XCSubProjectDefinition*)withName:(NSString*)name path:(NSString*)path parentProject:(XCProject*)parentProject
37 | {
38 |
39 | return [[XCSubProjectDefinition alloc] initWithName:name path:path parentProject:parentProject];
40 | }
41 |
42 | /* ====================================================================================================================================== */
43 | #pragma mark - Initialization & Destruction
44 |
45 | // Note - _path is most often going to be an absolute path. The method pathRelativeToProjectRoot below should be
46 | // used to get the form that's stored in the main project file.
47 | - (id)initWithName:(NSString*)name path:(NSString*)path parentProject:(XCProject*)parentProject
48 | {
49 | self = [super init];
50 | if (self)
51 | {
52 | _name = [name copy];
53 | _path = [path copy];
54 | _type = XcodeProject;
55 | _parentProject = parentProject;
56 | _subProject = [[XCProject alloc] initWithFilePath:[NSString stringWithFormat:@"%@/%@.xcodeproj", path, name]];
57 | }
58 | return self;
59 | }
60 |
61 | /* ====================================================================================================================================== */
62 | #pragma mark - Interface Methods
63 |
64 | - (NSString*)projectFileName
65 | {
66 | return [_name stringByAppendingString:@".xcodeproj"];
67 | }
68 |
69 | - (NSString*)fullPathName
70 | {
71 | return [NSString stringWithFormat:@"%@/%@", _path, [_name stringByAppendingString:@".xcodeproj"]];
72 | }
73 |
74 | // returns an array of names of the build products of this project
75 | - (NSArray*)buildProductNames
76 | {
77 | NSMutableArray* results = [NSMutableArray array];
78 | NSDictionary* objects = [_subProject objects];
79 | [objects enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSDictionary* obj, BOOL* stop)
80 | {
81 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXProjectType)
82 | {
83 | NSString* productRefGroupKey = [obj valueForKey:@"productRefGroup"];
84 | NSDictionary* products = [objects valueForKey:productRefGroupKey];
85 | NSArray* children = [products valueForKey:@"children"];
86 | for (NSString* childKey in children)
87 | {
88 | NSDictionary* child = [objects valueForKey:childKey];
89 | [results addObject:[child valueForKey:@"path"]];
90 | }
91 | }
92 | }];
93 | return results;
94 | }
95 |
96 | // returns the key of the PBXFileReference of the xcodeproj file
97 | - (NSString*)projectKey
98 | {
99 | if (_key == nil)
100 | {
101 | NSArray* xcodeprojKeys =
102 | [_parentProject keysForProjectObjectsOfType:PBXFileReferenceType withIdentifier:[self pathRelativeToProjectRoot] singleton:YES
103 | required:YES];
104 | _key = [[xcodeprojKeys objectAtIndex:0] copy];
105 | }
106 | return [_key copy];
107 | }
108 |
109 | - (void)initFullProjectPath:(NSString*)fullProjectPath groupPath:(NSString*)groupPath
110 | {
111 | if (groupPath != nil)
112 | {
113 | NSMutableArray* fullPathComponents = [[fullProjectPath pathComponents] mutableCopy];
114 | [fullPathComponents removeLastObject];
115 | fullProjectPath = [[NSString pathWithComponents:fullPathComponents] stringByAppendingFormat:@"/%@", groupPath];
116 | }
117 | _fullProjectPath = [fullProjectPath copy];
118 |
119 | }
120 |
121 | // compares the given path to the filePath of the project, and returns a relative version. _fullProjectPath, which has
122 | // to hve been previously set, is the full path to the project *plus* the path to the xcodeproj's group, if any.
123 | - (NSString*)pathRelativeToProjectRoot
124 | {
125 | if (_relativePath == nil)
126 | {
127 | if (_fullProjectPath == nil)
128 | {
129 | [NSException raise:NSInvalidArgumentException format:@"fullProjectPath has not been set"];
130 | }
131 | NSMutableArray* projectPathComponents = [[_fullProjectPath pathComponents] mutableCopy];
132 | NSArray* objectPathComponents = [[self fullPathName] pathComponents];
133 | NSString* convertedPath = @"";
134 |
135 | // skip over path components from root that are equal
136 | NSInteger limit =
137 | ([projectPathComponents count] < [objectPathComponents count]) ? [projectPathComponents count] : [objectPathComponents count];
138 | NSInteger index1 = 0;
139 | for (; index1 < limit; index1++)
140 | {
141 | if ([[projectPathComponents objectAtIndex:index1] isEqualToString:[objectPathComponents objectAtIndex:index1]])
142 | {
143 | continue;
144 | }
145 | else
146 | {
147 | break;
148 | }
149 | }
150 | // insert "../" for each remaining path component in project's xcodeproj path
151 | for (NSInteger index2 = 0; index2 < ([projectPathComponents count] - index1); index2++)
152 | {
153 | convertedPath = [convertedPath stringByAppendingString:@"../"];
154 | }
155 | // tack on the unique part of the object's path
156 | for (NSInteger index3 = index1; index3 < [objectPathComponents count] - 1; index3++)
157 | {
158 | convertedPath = [convertedPath stringByAppendingFormat:@"%@/", [objectPathComponents objectAtIndex:index3]];
159 | }
160 | _relativePath = [[convertedPath stringByAppendingString:[objectPathComponents lastObject]] copy];
161 | }
162 | return [_relativePath copy];
163 | }
164 |
165 |
166 | /* ====================================================================================================================================== */
167 | #pragma mark - Utility Methods
168 |
169 | - (NSString*)description
170 | {
171 | return [NSString stringWithFormat:@"XcodeprojDefinition: sourceFileName = %@, path=%@, type=%d", _name, _path, _type];
172 | }
173 |
174 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCTarget.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import
14 |
15 | @class XCProject;
16 | @class XCSourceFile;
17 | @class XCBuildConfig;
18 |
19 | /**
20 | * Represents a target in an xcode project.
21 | */
22 | @interface XCTarget : NSObject
23 | {
24 |
25 | XCProject* _project;
26 | NSString* _key;
27 | NSString* _name;
28 | NSString* _productName;
29 | NSString* _productReference;
30 | NSString* _defaultConfigurationName;
31 |
32 | @private
33 | NSMutableArray* _members;
34 | NSMutableArray* _resources;
35 | NSMutableDictionary* _configurations;
36 | }
37 |
38 | @property(nonatomic, strong, readonly) NSString* key;
39 | @property(nonatomic, strong) NSString* name;
40 | @property(nonatomic, strong) NSString* productName;
41 | @property(nonatomic, strong, readonly) NSString* productReference;
42 |
43 | + (XCTarget*)targetWithProject:(XCProject*)project key:(NSString*)key name:(NSString*)name productName:(NSString*)productName
44 | productReference:(NSString*)productReference;
45 |
46 | - (id)initWithProject:(XCProject*)project key:(NSString*)key name:(NSString*)name productName:(NSString*)productName
47 | productReference:(NSString*)productReference;
48 |
49 | - (NSArray*)resources;
50 |
51 | - (NSArray*)members;
52 |
53 | - (NSDictionary*)configurations;
54 |
55 | - (XCBuildConfig*)configurationWithName:(NSString*)name;
56 |
57 | - (XCBuildConfig*)defaultConfiguration;
58 |
59 | - (void)addMember:(XCSourceFile*)member;
60 |
61 | - (void)removeMemberWithKey:(NSString*)key;
62 |
63 | - (void)removeMembersWithKeys:(NSArray*)keys;
64 |
65 | - (void)addDependency:(NSString*)key;
66 |
67 | - (instancetype)duplicateWithTargetName:(NSString*)targetName productName:(NSString*)productName;
68 |
69 | @end
70 |
71 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCTarget.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 | #import "XCGroup.h"
13 | #import "XCKeyBuilder.h"
14 | #import "XCTarget.h"
15 | #import "XCSourceFile.h"
16 | #import "XCProject.h"
17 | #import "XCBuildConfig.h"
18 |
19 | @implementation XCTarget
20 |
21 | /* ====================================================================================================================================== */
22 | #pragma mark - Class Methods
23 |
24 | + (XCTarget*)targetWithProject:(XCProject*)project key:(NSString*)key name:(NSString*)name productName:(NSString*)productName
25 | productReference:(NSString*)productReference
26 | {
27 | return [[XCTarget alloc] initWithProject:project key:key name:name productName:productName productReference:productReference];
28 | }
29 |
30 |
31 | /* ====================================================================================================================================== */
32 | #pragma mark - Initialization & Destruction
33 |
34 | - (id)initWithProject:(XCProject*)project key:(NSString*)key name:(NSString*)name productName:(NSString*)productName
35 | productReference:(NSString*)productReference
36 | {
37 | self = [super init];
38 | if (self)
39 | {
40 | _project = project;
41 | _key = [key copy];
42 | _name = [name copy];
43 | _productName = [productName copy];
44 | _productReference = [productReference copy];
45 | }
46 | return self;
47 | }
48 |
49 | /* ====================================================================================================================================== */
50 | #pragma mark - Interface Methods
51 |
52 | - (NSArray*)resources
53 | {
54 | if (_resources == nil)
55 | {
56 | _resources = [[NSMutableArray alloc] init];
57 | for (NSString* buildPhaseKey in [[[_project objects] objectForKey:_key] objectForKey:@"buildPhases"])
58 | {
59 | NSDictionary* buildPhase = [[_project objects] objectForKey:buildPhaseKey];
60 | if ([[buildPhase valueForKey:@"isa"] asMemberType] == PBXResourcesBuildPhaseType)
61 | {
62 | for (NSString* buildFileKey in [buildPhase objectForKey:@"files"])
63 | {
64 | XCSourceFile* targetMember = [self buildFileWithKey:buildFileKey];
65 | if (targetMember)
66 | {
67 | [_resources addObject:[self buildFileWithKey:buildFileKey]];
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
74 | return _resources;
75 | }
76 |
77 | - (NSDictionary*)configurations
78 | {
79 | if (_configurations == nil)
80 | {
81 | NSString* buildConfigurationRootSectionKey = [[[_project objects] objectForKey:_key] objectForKey:@"buildConfigurationList"];
82 | NSDictionary* buildConfigurationDictionary = [[_project objects] objectForKey:buildConfigurationRootSectionKey];
83 | _configurations =
84 | [[XCBuildConfig buildConfigurationsFromArray:[buildConfigurationDictionary objectForKey:@"buildConfigurations"]
85 | inProject:_project] mutableCopy];
86 | _defaultConfigurationName = [[buildConfigurationDictionary objectForKey:@"defaultConfigurationName"] copy];
87 | }
88 |
89 | return _configurations;
90 | }
91 |
92 | - (XCBuildConfig*)defaultConfiguration
93 | {
94 | return [[self configurations] objectForKey:_defaultConfigurationName];
95 | }
96 |
97 | - (XCBuildConfig*)configurationWithName:(NSString*)name
98 | {
99 | return [[self configurations] objectForKey:name];
100 | }
101 |
102 | - (NSArray*)members
103 | {
104 | if (_members == nil)
105 | {
106 | _members = [[NSMutableArray alloc] init];
107 | for (NSString* buildPhaseKey in [[[_project objects] objectForKey:_key] objectForKey:@"buildPhases"])
108 | {
109 | NSDictionary* buildPhase = [[_project objects] objectForKey:buildPhaseKey];
110 | if ([[buildPhase valueForKey:@"isa"] asMemberType] == PBXSourcesBuildPhaseType ||
111 | [[buildPhase valueForKey:@"isa"] asMemberType] == PBXFrameworksBuildPhaseType)
112 | {
113 | for (NSString* buildFileKey in [buildPhase objectForKey:@"files"])
114 | {
115 | XCSourceFile* targetMember = [self buildFileWithKey:buildFileKey];
116 | if (targetMember)
117 | {
118 | [_members addObject:[_project fileWithKey:targetMember.key]];
119 | }
120 | }
121 | }
122 | }
123 | }
124 | return _members;
125 | }
126 |
127 | - (void)addMember:(XCSourceFile*)member
128 | {
129 | [member becomeBuildFile];
130 | NSDictionary* target = [[_project objects] objectForKey:_key];
131 |
132 | for (NSString* buildPhaseKey in [target objectForKey:@"buildPhases"])
133 | {
134 | NSMutableDictionary* buildPhase = [[_project objects] objectForKey:buildPhaseKey];
135 | if ([[buildPhase valueForKey:@"isa"] asMemberType] == [member buildPhase])
136 | {
137 |
138 | NSMutableArray* files = [buildPhase objectForKey:@"files"];
139 | if (![files containsObject:[member buildFileKey]])
140 | {
141 | [files addObject:[member buildFileKey]];
142 | }
143 |
144 | [buildPhase setObject:files forKey:@"files"];
145 | }
146 | }
147 | [self flagMembersAsDirty];
148 | }
149 |
150 | - (NSDictionary*)buildRefWithFileRefKey
151 | {
152 | NSMutableDictionary* buildRefWithFileRefDict = [NSMutableDictionary dictionary];
153 | NSDictionary* allObjects = [_project objects];
154 | NSArray* keys = [allObjects allKeys];
155 |
156 | for (NSString* key in keys)
157 | {
158 | NSDictionary* dictionaryInfo = [allObjects objectForKey:key];
159 |
160 | NSString* type = [dictionaryInfo objectForKey:@"isa"];
161 | if (type)
162 | {
163 | if ([type isEqualToString:@"PBXBuildFile"])
164 | {
165 | NSString* fileRef = [dictionaryInfo objectForKey:@"fileRef"];
166 |
167 | if (fileRef)
168 | {
169 | [buildRefWithFileRefDict setObject:key forKey:fileRef];
170 | }
171 | }
172 | }
173 | }
174 | return buildRefWithFileRefDict;
175 | }
176 |
177 | - (void)removeMemberWithKey:(NSString*)key
178 | {
179 |
180 | NSDictionary* buildRefWithFileRef = [self buildRefWithFileRefKey];
181 | NSDictionary* target = [[_project objects] objectForKey:_key];
182 | NSString* buildRef = [buildRefWithFileRef objectForKey:key];
183 |
184 | if (!buildRef)
185 | {
186 | return;
187 | }
188 |
189 | for (NSString* buildPhaseKey in [target objectForKey:@"buildPhases"])
190 | {
191 | NSMutableDictionary* buildPhase = [[_project objects] objectForKey:buildPhaseKey];
192 | NSMutableArray* files = [buildPhase objectForKey:@"files"];
193 |
194 | [files removeObjectIdenticalTo:buildRef];
195 | [buildPhase setObject:files forKey:@"files"];
196 | }
197 | [self flagMembersAsDirty];
198 | }
199 |
200 | - (void)removeMembersWithKeys:(NSArray*)keys
201 | {
202 | for (NSString* key in keys)
203 | {
204 | [self removeMemberWithKey:key];
205 | }
206 | }
207 |
208 | - (void)addDependency:(NSString*)key
209 | {
210 | NSDictionary* targetObj = [[_project objects] objectForKey:_key];
211 | NSMutableArray* dependencies = [targetObj valueForKey:@"dependencies"];
212 | // add only if not already there
213 | BOOL found = NO;
214 | for (NSString* dependency in dependencies)
215 | {
216 | if ([dependency isEqualToString:key])
217 | {
218 | found = YES;
219 | break;
220 | }
221 | }
222 | if (!found)
223 | {
224 | [dependencies addObject:key];
225 | }
226 | }
227 |
228 | - (instancetype)duplicateWithTargetName:(NSString*)targetName productName:(NSString*)productName
229 | {
230 |
231 | NSDictionary* targetObj = _project.objects[_key];
232 | NSMutableDictionary* dupTargetObj = [targetObj mutableCopy];
233 |
234 | dupTargetObj[@"name"] = targetName;
235 | dupTargetObj[@"productName"] = productName;
236 |
237 | NSString* buildConfigurationListKey = dupTargetObj[@"buildConfigurationList"];
238 |
239 | void(^visitor)(NSMutableDictionary*) = ^(NSMutableDictionary* buildConfiguration)
240 | {
241 | buildConfiguration[@"buildSettings"][@"PRODUCT_NAME"] = productName;
242 | };
243 |
244 | dupTargetObj[@"buildConfigurationList"] =
245 | [XCBuildConfig duplicatedBuildConfigurationListWithKey:buildConfigurationListKey inProject:_project
246 | withBuildConfigurationVisitor:visitor];
247 |
248 | [self duplicateProductReferenceForTargetObject:dupTargetObj withProductName:productName];
249 |
250 | [self duplicateBuildPhasesForTargetObject:dupTargetObj];
251 |
252 | [self addReferenceToProductsGroupForTargetObject:dupTargetObj];
253 |
254 | NSString* dupTargetObjKey = [self addTargetToRootObjectTargets:dupTargetObj];
255 |
256 | [_project dropCache];
257 |
258 | return [[XCTarget alloc] initWithProject:_project key:dupTargetObjKey name:targetName productName:productName
259 | productReference:dupTargetObj[@"productReference"]];
260 | }
261 |
262 | /* ====================================================================================================================================== */
263 | #pragma mark - Overridden Methods
264 |
265 | - (void)setName:(NSString*)name
266 | {
267 | _name = name;
268 | NSDictionary* dictionary = [_project.objects objectForKey:_key];
269 | [dictionary setValue:_name forKey:@"name"];
270 | }
271 |
272 | - (void)setProductName:(NSString*)productName
273 | {
274 | _productName = productName;
275 | NSDictionary* dictionary = [_project.objects objectForKey:_key];
276 | [dictionary setValue:_productName forKey:@"productName"];
277 | }
278 |
279 |
280 |
281 | /* ====================================================================================================================================== */
282 | #pragma mark - Utility Methods
283 |
284 | - (NSString*)description
285 | {
286 | return [NSString stringWithFormat:@"Target: name=%@, files=%@", _name, _members];
287 | }
288 |
289 | /* ====================================================================================================================================== */
290 | #pragma mark - Private Methods
291 |
292 | - (XCSourceFile*)buildFileWithKey:(NSString*)theKey
293 | {
294 | NSDictionary* obj = [[_project objects] valueForKey:theKey];
295 | if (obj)
296 | {
297 | if ([[obj valueForKey:@"isa"] asMemberType] == PBXBuildFileType)
298 | {
299 | return [_project fileWithKey:[obj valueForKey:@"fileRef"]];
300 | }
301 | }
302 | return nil;
303 | }
304 |
305 | - (void)flagMembersAsDirty
306 | {
307 | _members = nil;
308 | }
309 |
310 | - (void)duplicateProductReferenceForTargetObject:(NSMutableDictionary*)dupTargetObj withProductName:(NSString*)productName
311 | {
312 |
313 | NSString* productReferenceKey = dupTargetObj[@"productReference"];
314 | NSMutableDictionary* dupProductReference = [_project.objects[productReferenceKey] mutableCopy];
315 |
316 | NSString* path = dupProductReference[@"path"];
317 | NSString* dupPath = [path stringByDeletingLastPathComponent];
318 | dupPath = [dupPath stringByAppendingPathComponent:productName];
319 | dupPath = [dupPath stringByAppendingPathExtension:@"app"];
320 | dupProductReference[@"path"] = dupPath;
321 |
322 | NSString* dupProductReferenceKey = [[XCKeyBuilder createUnique] build];
323 |
324 | _project.objects[dupProductReferenceKey] = dupProductReference;
325 | dupTargetObj[@"productReference"] = dupProductReferenceKey;
326 | }
327 |
328 | - (void)duplicateBuildPhasesForTargetObject:(NSMutableDictionary*)dupTargetObj
329 | {
330 |
331 | NSMutableArray* buildPhases = [NSMutableArray array];
332 |
333 | for (NSString* buildPhaseKey in dupTargetObj[@"buildPhases"])
334 | {
335 |
336 | NSMutableDictionary* dupBuildPhase = [_project.objects[buildPhaseKey] mutableCopy];
337 | NSMutableArray* dupFiles = [NSMutableArray array];
338 |
339 | for (NSString* fileKey in dupBuildPhase[@"files"])
340 | {
341 |
342 | NSMutableDictionary* dupFile = [_project.objects[fileKey] mutableCopy];
343 | NSString* dupFileKey = [[XCKeyBuilder createUnique] build];
344 |
345 | _project.objects[dupFileKey] = dupFile;
346 | [dupFiles addObject:dupFileKey];
347 | }
348 |
349 | dupBuildPhase[@"files"] = dupFiles;
350 |
351 | NSString* dupBuildPhaseKey = [[XCKeyBuilder createUnique] build];
352 | _project.objects[dupBuildPhaseKey] = dupBuildPhase;
353 | [buildPhases addObject:dupBuildPhaseKey];
354 | }
355 |
356 | dupTargetObj[@"buildPhases"] = buildPhases;
357 | }
358 |
359 | - (void)addReferenceToProductsGroupForTargetObject:(NSMutableDictionary*)dupTargetObj
360 | {
361 |
362 | XCGroup* mainGroup = nil;
363 | NSPredicate* productsPredicate = [NSPredicate predicateWithFormat:@"displayName == 'Products'"];
364 | NSArray* filteredGroups = [_project.groups filteredArrayUsingPredicate:productsPredicate];
365 |
366 | if (filteredGroups.count > 0)
367 | {
368 | mainGroup = filteredGroups[0];
369 | NSMutableArray* children = [_project.objects[mainGroup.key][@"children"] mutableCopy];
370 | [children addObject:dupTargetObj[@"productReference"]];
371 | _project.objects[mainGroup.key][@"children"] = children;
372 | }
373 | }
374 |
375 | - (NSString*)addTargetToRootObjectTargets:(NSMutableDictionary*)dupTargetObj
376 | {
377 | NSString* dupTargetObjKey = [[XCKeyBuilder createUnique] build];
378 |
379 | _project.objects[dupTargetObjKey] = dupTargetObj;
380 |
381 | NSString* rootObjKey = _project.dataStore[@"rootObject"];
382 | NSMutableDictionary* rootObj = [_project.objects[rootObjKey] mutableCopy];
383 | NSMutableArray* rootObjTargets = [rootObj[@"targets"] mutableCopy];
384 | [rootObjTargets addObject:dupTargetObjKey];
385 |
386 | rootObj[@"targets"] = rootObjTargets;
387 | _project.objects[rootObjKey] = rootObj;
388 |
389 | return dupTargetObjKey;
390 | }
391 |
392 | @end
393 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCXibDefinition.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import
15 | #import "XCAbstractDefinition.h"
16 |
17 |
18 | @interface XCXibDefinition : XCAbstractDefinition
19 | {
20 | NSString* _name;
21 | NSString* _content;
22 | }
23 | @property(nonatomic, strong, readonly) NSString* name;
24 | @property(nonatomic, strong) NSString* content;
25 |
26 | + (XCXibDefinition*)xibDefinitionWithName:(NSString*)name;
27 |
28 | + (XCXibDefinition*)xibDefinitionWithName:(NSString*)name content:(NSString*)content;
29 |
30 | - (id)initWithName:(NSString*)name;
31 |
32 | - (id)initWithName:(NSString*)name content:(NSString*)content;
33 |
34 | - (NSString*)xibFileName;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XCXibDefinition.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import "XCXibDefinition.h"
14 |
15 | @implementation XCXibDefinition
16 |
17 | @synthesize name = _name;
18 | @synthesize content = _content;
19 |
20 | /* ====================================================================================================================================== */
21 | #pragma mark - Class Methods
22 |
23 | + (XCXibDefinition*)xibDefinitionWithName:(NSString*)name
24 | {
25 | return [[XCXibDefinition alloc] initWithName:name];
26 | }
27 |
28 | + (XCXibDefinition*)xibDefinitionWithName:(NSString*)name content:(NSString*)content
29 | {
30 | return [[XCXibDefinition alloc] initWithName:name content:content];
31 | }
32 |
33 |
34 | /* ====================================================================================================================================== */
35 | #pragma mark - Initialization & Destruction
36 |
37 | - (id)initWithName:(NSString*)name
38 | {
39 | return [self initWithName:name content:nil];
40 | }
41 |
42 |
43 | - (id)initWithName:(NSString*)name content:(NSString*)content
44 | {
45 | self = [super init];
46 | if (self)
47 | {
48 | _name = [name copy];
49 | _content = [content copy];
50 | }
51 | return self;
52 | }
53 |
54 |
55 | /* ====================================================================================================================================== */
56 | #pragma mark - Interface Methods
57 |
58 | - (NSString*)xibFileName
59 | {
60 | return [_name stringByAppendingString:@".xib"];
61 | }
62 |
63 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XcodeEditor.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #import "XCAbstractDefinition.h"
14 | #import "XCGroup.h"
15 | #import "XCClassDefinition.h"
16 | #import "XCFileOperationQueue.h"
17 | #import "XCFrameworkDefinition.h"
18 | #import "XCProject.h"
19 | #import "XCSourceFile.h"
20 | #import "XCSourceFileDefinition.h"
21 | #import "XCSubProjectDefinition.h"
22 | #import "XCTarget.h"
23 | #import "XCXibDefinition.h"
24 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XcodeGroupMember.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XcodeMemberType.h"
15 |
16 | @protocol XcodeGroupMember
17 |
18 | - (NSString*)key;
19 |
20 | - (NSString*)displayName;
21 |
22 | - (NSString*)pathRelativeToProjectRoot;
23 |
24 | /**
25 | * Group members can either be other groups (PBXGroup) or source files (PBXFileReference).
26 | */
27 | - (XcodeMemberType)groupMemberType;
28 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XcodeMemberType.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 | #import
13 |
14 | typedef enum
15 | {
16 | PBXNilType,
17 | PBXBuildFileType,
18 | PBXContainerItemProxyType,
19 | PBXCopyFilesBuildPhaseType,
20 | PBXFileReferenceType,
21 | PBXFrameworksBuildPhaseType,
22 | PBXGroupType,
23 | PBXNativeTargetType,
24 | PBXProjectType,
25 | PBXReferenceProxyType,
26 | PBXResourcesBuildPhaseType,
27 | PBXSourcesBuildPhaseType,
28 | PBXTargetDependencyType,
29 | PBXVariantGroupType,
30 | XCBuildConfigurationType,
31 | XCConfigurationListType
32 | } XcodeMemberType;
33 |
34 | @interface NSString (XcodeMemberTypeExtensions)
35 |
36 | + (NSString*)stringFromMemberType:(XcodeMemberType)nodeType;
37 |
38 | - (XcodeMemberType)asMemberType;
39 |
40 | @end
41 |
42 |
43 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XcodeMemberType.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 |
15 | #import "XcodeMemberType.h"
16 |
17 |
18 | @implementation NSDictionary (XcodeMemberType)
19 |
20 |
21 | + (NSDictionary*)dictionaryWithProjectNodeTypesAsStrings
22 | {
23 | // This is the most vital operation on adding 500+ files
24 | // So, we caching this dictionary
25 | static NSDictionary* _projectNodeTypesAsStrings;
26 | static dispatch_once_t onceToken;
27 | dispatch_once(&onceToken, ^
28 | {
29 | _projectNodeTypesAsStrings =
30 | [[NSDictionary alloc] initWithObjectsAndKeys:@(PBXNilType), @"PBXNilType",
31 | @(PBXBuildFileType), @"PBXBuildFile",
32 | @(PBXContainerItemProxyType), @"PBXContainerItemProxy",
33 | @(PBXCopyFilesBuildPhaseType), @"PBXCopyFilesBuildPhase",
34 | @(PBXFileReferenceType), @"PBXFileReference",
35 | @(PBXFrameworksBuildPhaseType), @"PBXFrameworksBuildPhase",
36 | @(PBXGroupType), @"PBXGroup",
37 | @(PBXNativeTargetType), @"PBXNativeTarget",
38 | @(PBXProjectType), @"PBXProject",
39 | @(PBXReferenceProxyType), @"PBXReferenceProxy",
40 | @(PBXResourcesBuildPhaseType), @"PBXResourcesBuildPhase",
41 | @(PBXSourcesBuildPhaseType), @"PBXSourcesBuildPhase",
42 | @(PBXTargetDependencyType), @"PBXTargetDependency",
43 | @(PBXVariantGroupType), @"PBXVariantGroup",
44 | @(XCBuildConfigurationType), @"XCBuildConfiguration",
45 | @(XCConfigurationListType), @"XCConfigurationList", nil];
46 | });
47 | return _projectNodeTypesAsStrings;
48 | }
49 |
50 | @end
51 |
52 | @implementation NSString (XcodeMemberTypeExtensions)
53 |
54 | + (NSString*)stringFromMemberType:(XcodeMemberType)nodeType
55 | {
56 | NSDictionary* nodeTypesToString = [NSDictionary dictionaryWithProjectNodeTypesAsStrings];
57 | return [[nodeTypesToString allKeysForObject:@(nodeType)] objectAtIndex:0];
58 | }
59 |
60 |
61 | - (XcodeMemberType)asMemberType
62 | {
63 | NSDictionary* nodeTypesToString = [NSDictionary dictionaryWithProjectNodeTypesAsStrings];
64 | return (XcodeMemberType) [[nodeTypesToString objectForKey:self] intValue];
65 | }
66 |
67 |
68 | @end
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XcodeSourceFileType.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 | #import
13 |
14 | typedef enum
15 | {
16 | FileTypeNil, // Unknown filetype
17 | Framework, // .framework
18 | PropertyList, // .plist
19 | SourceCodeHeader, // .h
20 | SourceCodeObjC, // .m
21 | SourceCodeObjCPlusPlus, // .mm
22 | SourceCodeCPlusPlus, // .cpp
23 | XibFile, // .xib
24 | ImageResourcePNG, // .png
25 | Bundle, // .bundle .octet
26 | Archive, // .a files
27 | HTML, // HTML file
28 | TEXT, // Some text file
29 | XcodeProject // .xcodeproj
30 | } XcodeSourceFileType;
31 |
32 | NSString* NSStringFromXCSourceFileType(XcodeSourceFileType type);
33 |
34 | XcodeSourceFileType XCSourceFileTypeFromStringRepresentation(NSString* string);
35 |
36 | XcodeSourceFileType XCSourceFileTypeFromFileName(NSString* fileName);
37 |
38 |
--------------------------------------------------------------------------------
/SuggestedColors/XCodeEditor/XcodeSourceFileType.m:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // JASPER BLUES
4 | // Copyright 2012 Jasper Blues
5 | // All Rights Reserved.
6 | //
7 | // NOTICE: Jasper Blues permits you to use, modify, and distribute this file
8 | // in accordance with the terms of the license agreement accompanying it.
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 |
14 | #import "XcodeSourceFileType.h"
15 |
16 | NSDictionary* NSDictionaryWithXCFileReferenceTypes()
17 | {
18 | static NSDictionary* dictionary;
19 | static dispatch_once_t onceToken;
20 | dispatch_once(&onceToken, ^
21 | {
22 | dictionary = @{
23 | @"sourcecode.c.h" : @(SourceCodeHeader),
24 | @"sourcecode.c.objc" : @(SourceCodeObjC),
25 | @"wrapper.framework" : @(Framework),
26 | @"text.plist.strings" : @(PropertyList),
27 | @"sourcecode.cpp.objcpp" : @(SourceCodeObjCPlusPlus),
28 | @"sourcecode.cpp.cpp" : @(SourceCodeCPlusPlus),
29 | @"file.xib" : @(XibFile),
30 | @"image.png" : @(ImageResourcePNG),
31 | @"wrapper.cfbundle" : @(Bundle),
32 | @"archive.ar" : @(Archive),
33 | @"text.html" : @(HTML),
34 | @"text" : @(TEXT),
35 | @"wrapper.pb-project" : @(XcodeProject)
36 | };
37 | });
38 |
39 | return dictionary;
40 | }
41 |
42 | NSString* NSStringFromXCSourceFileType(XcodeSourceFileType type)
43 | {
44 | return [[NSDictionaryWithXCFileReferenceTypes() allKeysForObject:@(type)] objectAtIndex:0];
45 | }
46 |
47 | XcodeSourceFileType XCSourceFileTypeFromStringRepresentation(NSString* string)
48 | {
49 | NSDictionary* typeStrings = NSDictionaryWithXCFileReferenceTypes();
50 |
51 | if ([typeStrings objectForKey:string])
52 | {
53 | return (XcodeSourceFileType) [[typeStrings objectForKey:string] intValue];
54 | }
55 | else
56 | {
57 | return FileTypeNil;
58 | }
59 | }
60 |
61 |
62 | XcodeSourceFileType XCSourceFileTypeFromFileName(NSString* fileName)
63 | {
64 | if ([fileName hasSuffix:@".h"] || [fileName hasSuffix:@".hh"] || [fileName hasSuffix:@".hpp"] || [fileName hasSuffix:@".hxx"])
65 | {
66 | return SourceCodeHeader;
67 | }
68 | if ([fileName hasSuffix:@".c"] || [fileName hasSuffix:@".m"])
69 | {
70 | return SourceCodeObjC;
71 | }
72 | if ([fileName hasSuffix:@".mm"])
73 | {
74 | return SourceCodeObjCPlusPlus;
75 | }
76 | if ([fileName hasSuffix:@".cpp"])
77 | {
78 | return SourceCodeCPlusPlus;
79 | }
80 | return FileTypeNil;
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/SuggestedColorsTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.dangdang.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SuggestedColorsTests/SuggestedColorsTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // SuggestedColorsTests.m
3 | // SuggestedColorsTests
4 | //
5 | // Created by wangchaojs02 on 15/6/3.
6 | // Copyright (c) 2015年 Monsters Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface SuggestedColorsTests : XCTestCase
13 |
14 | @end
15 |
16 | @implementation SuggestedColorsTests
17 |
18 | - (void)setUp {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown {
24 | // Put teardown code here. This method is called after the invocation of each test method in the class.
25 | [super tearDown];
26 | }
27 |
28 | - (void)testExample {
29 | // This is an example of a functional test case.
30 | XCTAssert(YES, @"Pass");
31 | }
32 |
33 | - (void)testPerformanceExample {
34 | // This is an example of a performance test case.
35 | [self measureBlock:^{
36 | // Put the code you want to measure the time of here.
37 | }];
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------