Compare commits

..
72 Commits
Author SHA1 Message Date
Scott KyleandRoss Boucher 4c81c9e21e Fixed typo "Janurary" 2010-01-07 12:26:51 -08:00
Francisco Ryan Tolmasky I f4912eb23b Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2010-01-06 22:51:31 -08:00
Francisco Ryan Tolmasky I 7f85b8b33f Tiny bit more support for toolbars in nib2cib.
Reviewed by me.
2010-01-06 21:08:01 -08:00
Tom Robinson 85c68f78da Update for compatibility with latest narwhal. Switch back to 280north/narwhal 2010-01-06 20:00:37 -08:00
Francisco Ryan Tolmasky I af03085d5f Fix for incorrect menu logic.
Reviewed by me.
2010-01-05 19:20:47 -08:00
Francisco Ryan Tolmasky I b7d747ee17 Fixed a bug in CPTreeNode's KVO implementation.
Reviewed by me.
2010-01-05 15:49:16 -08:00
Francisco Ryan Tolmasky I b6f100888a Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2010-01-05 11:15:45 -08:00
Francisco Ryan Tolmasky I 3cfd392e3e Added new automatic undo API to CPUndoManager.
Added archiving support for CPTreeNode.

Reviewd by me.
2010-01-05 11:14:56 -08:00
Ross Boucher 7ed98a8655 Fix a typo pointed out by Bruno on the mailing list. 2010-01-05 09:50:02 -05:00
Ross Boucher d78eb4a4e5 Fix an undefined notification variable 2010-01-04 19:11:10 -05:00
Randall LueckeandRoss Boucher a3d168b646 left unnessisary line... whoops 2010-01-04 10:24:45 -05:00
Randall LueckeandRoss Boucher 5018df511b fix for window overlapping the menu bar if the user dragged it up there. 2010-01-04 10:24:38 -05:00
Ross Boucher 09345a9d53 Use a notificaiton rather than a direct call for windowDidResize:
Closes #393.
2010-01-04 10:21:16 -05:00
Francisco Ryan Tolmasky I 8b17cd3cde Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-31 01:24:51 -08:00
Francisco Ryan Tolmasky I 403fcd8fff Preparing for options fix in Narhwal.
Reviewed by me.
2009-12-30 23:52:55 -08:00
tlrobinson 409be4020b Temporarily use tlrobinson/narwhal/master in bootstrap. 2009-12-29 13:35:48 -08:00
Nicholas Small 24801a220c Merge branch 'jake' of github.com:280north/cappuccino into jake 2009-12-26 19:12:31 -05:00
Nicholas Small 19b9f4e1c1 Enabling an accordion item will cause it to expand. 2009-12-26 19:11:33 -05:00
Francisco Ryan Tolmasky I 48d584df58 Fixed typo in setSubviews:.
Reviewed by me.
2009-12-26 01:20:16 -08:00
Francisco Ryan Tolmasky I dd999a29fd Added applyChange:toKeyPath: and inverseChangedDictionary to support "automatic" undo with KVO.
Reviewed by me.
2009-12-24 19:15:38 -08:00
Francisco Ryan Tolmasky I 75fdfb5a0b Improved observable arrays to support indexOfObject:, indexOfObjectIdenticalTo:, and removeObjectIdenticalTo:.
Reviewed by me.
2009-12-24 18:45:20 -08:00
Francisco Ryan Tolmasky I 6b4db4e9ae Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-23 19:32:43 -08:00
Francisco Ryan Tolmasky I 2571b24f22 Removed TextMate and Xcode files since the ones being used now have their own repos. Linked to them in the README.
Reviewed by me.
2009-12-23 19:31:51 -08:00
Nicholas Small 855a9eea44 Merge branch 'jake' of github.com:280north/cappuccino into jake 2009-12-23 16:51:46 -05:00
Nicholas Small 189e299592 Added CPAccordionView -setEnabled:forItemAtIndex: 2009-12-23 16:50:56 -05:00
Ross Boucher 6cbaa35849 Add CPOperation to Foundation 2009-12-23 11:30:10 -05:00
Ross Boucher cb1cfa4d94 Better support for recursing in CPDictionaryWithJSObject: 2009-12-20 20:32:17 -05:00
Ross Boucher 5bbf893a37 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-20 20:11:59 -05:00
Ross Boucher 3ddbfb5dea Encode the header clip view in the CPCoder methods.
Closes 363.
2009-12-20 20:11:22 -05:00
Francisco Ryan Tolmasky I 5352d062d5 Fix for boundsOrigin and boundsSize being affected by bounds. Also changed UID to return a string instead of a Number.
Reviewed by me.
2009-12-20 17:02:06 -08:00
Randall LueckeandFrancisco Ryan Tolmasky I e15cbfca33 fix bug in CPPlatformWindow where the visible frame for the platform window would offset itself for the menu bar height, even though no menu bar would be displayed because it's not the primaryPlatformWindow 2009-12-20 15:44:39 -08:00
Francisco Ryan Tolmasky I 51b58f911e Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-20 13:01:11 -08:00
Francisco Ryan Tolmasky I 7acfbb9eed Added [CPView setSubviews:] which allows you to add multiple subviews, remove multiple subviews, and reorder multple subviews.
Reviewed by me.
2009-12-20 13:00:25 -08:00
Ross Boucher 4bf9853a25 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-20 13:13:15 -05:00
Ross Boucher 58c6db0a8f Fix the logic behind CPURLConnection's _isLocalFileConnection 2009-12-20 13:12:29 -05:00
tlrobinson aed52a7829 Improved bootstrap.sh further. Prompt to delete existing installations, etc. 2009-12-19 23:16:37 -08:00
Ross Boucher a1e24a3f95 Fix a bug where keyPaths which had a component evaluating to self would send notifications containing the wrong keypath in the observation.
Includes test case.
2009-12-19 17:47:02 -05:00
Ross Boucher 11cff29916 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-19 15:32:52 -05:00
Ross Boucher f184b9bcc4 Add a few KVO tests around arrays 2009-12-19 15:32:23 -05:00
tlrobinson bab0024e0c Cleanup some build scripts 2009-12-19 04:31:11 -08:00
aburkhalterandtlrobinson deed92cff7 Toll-free bridge Error to CPException. Add rhinoException in objj_exception for better error reporting. 2009-12-19 03:49:22 -08:00
Francisco Ryan Tolmasky I a9bc949679 Actual fix for disabled items in CPMenu. Previous fix still selected disabled items and showed submenus for disabled items.
Reviewed by me.
2009-12-18 22:31:12 -08:00
Randall LueckeandRoss Boucher 1411410f4e fixed bug in CPMenu where action would be sent when the user clicked on a disabled menu item. 2009-12-18 18:43:03 -05:00
Ross Boucher 648fbe1b10 Add sendsActionOnEndEditing to the CPCoding methods for CPControl 2009-12-18 15:54:44 -05:00
Ross Boucher 7042f89620 Fix a return type error. Closes #358. 2009-12-17 00:57:09 -05:00
Ross Boucher e235fffb5e Correct HTML escaping and unescaping in Objective-J/plist. Closes 361. 2009-12-17 00:54:00 -05:00
Ross Boucher 6aadd13450 Update CPColorPanel to handle drag and drop correctly, which broke with native drag and drop. Closes 364. 2009-12-17 00:25:49 -05:00
Ross Boucher 349de098af Merge branch 'jake' of git@github.com:280north/cappuccino into jake
Conflicts:
	AppKit/CPMenuItem/CPMenuItem.j
2009-12-16 19:00:48 -05:00
Ross Boucher 5527e585f6 Make Windows handle key equivalents in menus correctly. Make the menu display the string properly on Windows too. 2009-12-16 18:58:21 -05:00
Francisco Ryan Tolmasky I a6e9814dfc Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-16 15:03:27 -08:00
Francisco Ryan Tolmasky I f01a7d3933 Fix for menu items incorrectly leaving out shift symbol if the key equivalent is uppercase.
Reviewed by me.
2009-12-16 15:02:35 -08:00
Nicholas Small d2cd3b899f Fix CPTabViewItem -tabView. 2009-12-16 00:22:35 -05:00
Francisco Ryan Tolmasky I ac2c0d5d84 Update CPUndoManager to post checkpoint notifications and only create run loop performs if undos actually take place.
Reviewed by me.
2009-12-15 16:37:47 -08:00
Ross Boucher f0d0b512ca Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-13 18:30:16 -08:00
Ross Boucher c859ffd0f7 Support for copy/paste/cut and selectedRange/setSelectedRange in CPTextField.
Improvements to the Pasteboard integration code from yesterday.
2009-12-13 18:29:25 -08:00
Tom Robinson 4eb57f3cc5 Merge branch 'jake' of github.com:280north/cappuccino into jake 2009-12-13 15:02:38 -08:00
Tom Robinson 6218bfaf9e Rewrite/cleanup of press. Incomplete, but press --flatten "works" for some value of "work". 2009-12-13 15:01:19 -08:00
Ross Boucher 4d5cdcaeae Fix for the pasteboard changes breaking everything. 2009-12-12 18:36:48 -08:00
Ross Boucher 6ad62a6f2f Add support for native pasteboards to webtop 2009-12-12 14:15:45 -08:00
Ross Boucher 37d4b151d7 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-11 16:55:36 -08:00
Ross Boucher 37c1d804f6 Fix for text shadows sometimes being the wrong color.
Closes #359.
2009-12-11 16:54:38 -08:00
Francisco Ryan Tolmasky I d200df3e9c Typo in last commit.
Reviewed by me.
2009-12-11 12:03:25 -08:00
Francisco Ryan Tolmasky I eb43e416ae Added CPProxy class to support better undo proxying in CPUndoManager.
Closes #370.
Closes #371.

Reviewed by me.
2009-12-11 11:38:26 -08:00
Francisco Ryan Tolmasky I e6244f71bd Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-11 11:16:37 -08:00
Francisco Ryan Tolmasky I 403277ed06 Further refined KVO tests.
Reviewed by me.
2009-12-11 11:16:17 -08:00
Ross Boucher dbe8a59c3c Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-11 10:58:40 -08:00
Ross Boucher a98de54db4 A few additions for pretty printing things and getting better error messages 2009-12-11 10:58:07 -08:00
Francisco Ryan Tolmasky I 7edb7266f2 Added test for old dependent values in KVO.
Reviewed by me.
2009-12-11 10:54:17 -08:00
Nicholas Small d14e077511 Make CPTableView selection notifications behave the same as in Cocoa. 2009-12-10 03:07:22 -05:00
Francisco Ryan Tolmasky I 211c14e316 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-07 18:59:57 -08:00
Francisco Ryan Tolmasky I 4fbc140551 Better descriptions for CPArray.
Reviewed by me.
2009-12-07 18:54:01 -08:00
Ross Boucher ee8e65c80d Fix for alt+character key events not propagating correctly.
Closes #354.
2009-12-05 16:58:26 -08:00
95 changed files with 3109 additions and 4208 deletions
+21 -1
View File
@@ -197,6 +197,20 @@
return indexSet;
}
- (void)setEnabled:(BOOL)isEnabled forItemAtIndex:(CPInteger)anIndex
{
var itemView = _itemViews[anIndex];
if (!itemView)
return;
if (!isEnabled)
[self collapseItemAtIndex:anIndex];
else
[self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled];
}
- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
{
if (_dirtyItemIndex === CPNotFound)
@@ -301,6 +315,12 @@
[_headerView setStringValue:aLabel];
}
- (void)setEnabled:(BOOL)isEnabled
{
if ([_headerView respondsToSelector:@selector(setEnabled:)])
[_headerView setEnabled:isEnabled];
}
- (void)setContentView:(CPView)aView
{
if (_contentView === aView)
@@ -312,7 +332,7 @@
_contentView = aView;
[_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL];
[_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL];
[self addSubview:_contentView];
+1 -1
View File
@@ -701,7 +701,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
{
var target = [self targetForAction:anAction to:aTarget from:aSender];
if (!target)
return NO;
+1 -1
View File
@@ -321,7 +321,7 @@
*/
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
return [_selectionIndexes copy];
}
/* @ignore */
+10 -9
View File
@@ -140,7 +140,7 @@ CPColorPickerViewHeight = 370;
Sets the color of the panel, and updates the picker. Also posts a \c CPColorPanelDidChangeNotification.
*/
- (void)setColor:(CPColor)aColor
{
{
_color = aColor;
[_previewView setBackgroundColor: _color];
@@ -518,9 +518,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)mouseUp:(CPEvent)anEvent
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds];
if(point.x > [self bounds].size.width - 1 || point.x < 1)
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
return NO;
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
@@ -563,7 +564,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
[aPasteboard setData:_dragColor forType:aType];
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
}
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
@@ -575,7 +576,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO;
[self setColor:[pasteboard dataForType:CPColorDragType] atIndex: FLOOR(location.x / 13)];
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
}
@end
@@ -612,8 +613,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO;
var color = [pasteboard dataForType:CPColorDragType];
[_colorPanel setColor: color updatePicker: YES];
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES];
}
- (BOOL)isOpaque
@@ -625,7 +626,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
var bounds = CPRectMake(0, 0, 15, 15);
@@ -650,7 +651,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
[aPasteboard setData:[self backgroundColor] forType:aType];
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
}
@end
+7 -1
View File
@@ -572,7 +572,9 @@ var CPControlValueKey = "CPControlValueKey",
CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey";
CPControlSendActionOnKey = "CPControlSendActionOnKey",
CPControlSendsActionOnEndEditingKey = "CPControlSendsActionOnEndEditingKey";
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
@@ -595,6 +597,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
}
return self;
@@ -608,6 +611,9 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
{
[super encodeWithCoder:aCoder];
if (_sendsActionOnEndEditing)
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
if (_value !== nil)
[aCoder encodeObject:_value forKey:CPControlValueKey];
+1 -1
View File
@@ -310,7 +310,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
}
else
_draggingOffset = _CGSizeMakerZero();
_draggingOffset = _CGSizeMakeZero();
if ([CPPlatform isBrowser])
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
+14 -2
View File
@@ -648,7 +648,10 @@ var _CPMenuBarVisible = NO,
while ([highlightedItem submenu] && [highlightedItem action] === @selector(submenuAction:))
highlightedItem = [[highlightedItem submenu] highlightedItem];
if (highlightedItem)
// FIXME: It is theoretically not necessarily to check isEnabled here since
// highlightedItem is always enabled. Do there exist edge cases: disabling on closing a menu,
// etc.? Requires further investigation and tests.
if (highlightedItem && [highlightedItem isEnabled])
[CPApp sendAction:[highlightedItem action] to:[highlightedItem target] from:highlightedItem];
}
@@ -920,7 +923,16 @@ var _CPMenuBarVisible = NO,
for(; index < count; ++index)
{
var item = _items[index],
modifierMask = [item keyEquivalentModifierMask] | ([item keyEquivalent] === [[item keyEquivalent] uppercaseString] ? CPShiftKeyMask : 0);
modifierMask = [item keyEquivalentModifierMask];
if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString])
modifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask))
{
modifierMask |= CPControlKeyMask;
modifierMask &= ~CPCommandKeyMask;
}
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
[characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
+15 -5
View File
@@ -113,11 +113,21 @@ var SharedMenuManager = nil;
// Find which menu window the mouse is currently on top of
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation],
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
activeMenu = activeMenuContainer ? [activeMenuContainer menu] : nil,
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil,
mouseOverMenuView = activeMenuContainer ? [activeItem view] : nil;
activeMenu = [activeMenuContainer menu],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
// Find out the item the mouse is currently on top of
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
// If the item isn't enabled its as if we clicked on nothing.
if (![activeItem isEnabled])
{
activeItemIndex = CPNotFound;
activeItem = nil;
}
var mouseOverMenuView = [activeItem view];
if (type === CPPeriodic)
{
+25 -7
View File
@@ -590,16 +590,34 @@ CPControlKeyMask
if (![_keyEquivalent length])
return @"";
var string = _keyEquivalent.toUpperCase();
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "⌘" + string;
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "⌘" + string;
if (_keyEquivalentModifierMask & CPShiftKeyMask)
string = "⇧" + string;
if (needsShift)
string = "⇧" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
}
else
{
if (needsShift)
string = "Shift-" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "Alt-" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
string = "Ctrl-" + string;
}
return string;
}
+82 -10
View File
@@ -43,11 +43,14 @@ CPURLPboardType = @"CPURLPboardType";
CPImagesPboardType = @"CPImagesPboardType";
CPVideosPboardType = @"CPVideosPboardType";
UTF8PboardType = @"public.utf8-plain-text";
// Deprecated
CPImagePboardType = @"CPImagePboardType";
var CPPasteboards = nil;
var CPPasteboards = nil,
supportsNativePasteboard = NO;
/*!
@ingroup appkit
@@ -63,6 +66,8 @@ var CPPasteboards = nil;
unsigned _changeCount;
CPString _stateUID;
WebScriptObject _nativePasteboard;
}
/*
@@ -76,6 +81,9 @@ var CPPasteboards = nil;
[self setVersion:1.0];
CPPasteboards = [CPDictionary dictionary];
if (typeof window.cpPasteboardWithName !== "undefined")
supportsNativePasteboard = YES;
}
/*!
@@ -94,7 +102,7 @@ var CPPasteboards = nil;
+ (id)pasteboardWithName:(CPString)aName
{
var pasteboard = [CPPasteboards objectForKey:aName];
if (pasteboard)
return pasteboard;
@@ -118,6 +126,12 @@ var CPPasteboards = nil;
_provided = [CPDictionary dictionary];
_changeCount = 0;
if (supportsNativePasteboard)
{
_nativePasteboard = window.cpPasteboardWithName(aName);
[self _synchronizePasteboard];
}
}
return self;
@@ -146,7 +160,16 @@ var CPPasteboards = nil;
[_owners setObject:anOwner forKey:type];
}
if (_nativePasteboard)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.addTypes_(nativeTypes);
}
return ++_changeCount;
}
@@ -157,6 +180,12 @@ var CPPasteboards = nil;
@return the pasteboard's change count
*/
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
{
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
}
/*! @ignore */
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
{
[_types setArray:types];
@@ -167,7 +196,16 @@ var CPPasteboards = nil;
while (count--)
[_owners setObject:anOwner forKey:_types[count]];
if (_nativePasteboard && shouldUpdate)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.declareTypes_(nativeTypes);
_changeCount = _nativePasteboard.changeCount();
}
return ++_changeCount;
}
@@ -180,7 +218,10 @@ var CPPasteboards = nil;
- (BOOL)setData:(CPData)aData forType:(CPString)aType
{
[_provided setObject:aData forKey:aType];
if (aType === CPStringPboardType)
[self setData:aData forType:UTF8PboardType];
return YES;
}
@@ -203,7 +244,7 @@ var CPPasteboards = nil;
*/
- (void)setString:(CPString)aString forType:(CPString)aType
{
return [self setPropertyList:aString forType:aType];
[self setPropertyList:aString forType:aType];
}
// Determining Types
@@ -223,6 +264,7 @@ var CPPasteboards = nil;
*/
- (CPArray)types
{
[self _synchronizePasteboard];
return _types;
}
@@ -251,16 +293,46 @@ var CPPasteboards = nil;
if (owner)
{
[owner pasteboard:self provideDataForType:aType];
++_changeCount;
[owner pasteboard:self provideDataForType:aType];
return [_provided objectForKey:aType];
}
if (aType === CPStringPboardType)
return [self dataForType:UTF8PboardType];
return nil;
}
- (void)_synchronizePasteboard
{
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
{
var nativeTypes = [_nativePasteboard.types() copy];
if ([nativeTypes containsObject:UTF8PboardType])
nativeTypes.push(CPStringPboardType);
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
_changeCount = _nativePasteboard.changeCount();
}
}
/*! @ignore
method provided for integration with native pasteboard
*/
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if (aType === CPStringPboardType)
{
var string = _nativePasteboard.stringForType_(UTF8PboardType);
[self setString:string forType:CPStringPboardType];
[self setString:string forType:UTF8PboardType];
}
else
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
}
/*!
Returns the property list for the specified data type
@param aType the requested data type
+13 -10
View File
@@ -716,15 +716,16 @@
@end
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
@implementation CPScrollView (CPCoding)
@@ -740,6 +741,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -760,7 +762,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
+5 -1
View File
@@ -247,6 +247,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
@@ -263,9 +265,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var index = [self indexOfTabViewItem:aTabViewItem];
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
}
+10
View File
@@ -58,6 +58,8 @@ CPPressedTab = 2;
CPView _view;
CPView _auxiliaryView;
CPTabView _tabView;
}
- (id)init
@@ -168,6 +170,14 @@ CPPressedTab = 2;
return _tabView;
}
/*!
@ignore
*/
- (void)_setTabView:(CPTabView)aView
{
_tabView = aView;
}
@end
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
+8 -7
View File
@@ -577,7 +577,9 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
[_selectedRowIndexes addIndexes:rows];
else
_selectedRowIndexes = [rows copy];
[self _noteSelectionDidChange];
[self setNeedsLayout];
}
@@ -586,7 +588,7 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
return _selectedColumnIndexes;
}
- (void)selectedRowIndexes
- (CPIndexSet)selectedRowIndexes
{
return _selectedRowIndexes;
}
@@ -1637,8 +1639,7 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
if (![_previouslySelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes])
[self _noteSelectionDidChange];
}
- (void)_updateSelectionWithMouseAtRow:(CPInteger)aRow
@@ -1709,10 +1710,10 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
if (!_previouslySelectedRowIndexes)
_previouslySelectedRowIndexes = [_selectedRowIndexes copy];
[self selectRowIndexes:newSelection byExtendingSelection:NO];
[self _noteSelectionIsChanging];
[self selectRowIndexes:newSelection byExtendingSelection:NO];
}
- (void)_noteSelectionIsChanging
+118
View File
@@ -789,11 +789,129 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#endif
}
- (void)copy:(id)sender
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 1)
return;
var pasteboard = [CPPasteboard generalPasteboard],
stringValue = [self stringValue],
stringForPasting = [stringValue substringWithRange:selectedRange];
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:stringForPasting forType:CPStringPboardType];
}
- (void)cut:(id)sender
{
[self copy:sender];
[self deleteBackwards:sender];
}
- (void)paste:(id)sender
{
var pasteboard = [CPPasteboard generalPasteboard];
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
[self deleteBackwards:sender];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
pasteString = [pasteboard stringForType:CPStringPboardType],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
}
- (CPRange)selectedRange
{
if ([[self window] firstResponder] !== self)
return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances
try
{
var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
selectionRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(selectionRange))
{
range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length);
}
}
catch (e)
{
// fall through to the return
}
return CGMakeRange(0, 0);
}
- (void)setSelectedRange:(CPRange)aRange
{
if (![[self window] firstResponder] === self)
return;
var inputElement = [self _inputElement];
try
{
if ([inputElement.selectionStart isKindOfClass:CPNumber])
{
inputElement.selectionStart = aRange.location;
inputElement.selectionEnd = CPMaxRange(aRange);
}
else
{
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(existingRange))
{
range.collapse(true);
range.move('character', aRange.location);
range.moveEnd('character', aRange.length);
range.select();
}
}
}
catch (e)
{
}
}
- (void)selectAll:(id)sender
{
[self selectText:sender];
}
- (void)deleteBackwards:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
}
#pragma mark Setting the Delegate
- (void)setDelegate:(id)aDelegate
+77
View File
@@ -495,6 +495,83 @@ CPToolbarItemVisibilityPriorityUser
@end
var CPToolbarItemIdentifierKey = @"CPToolbarItemIdentifierKey",
CPToolbarItemLabelKey = @"CPToolbarItemLabelKey",
CPToolbarItemPaletteLabelKey = @"CPToolbarItemPaletteLabelKey",
CPToolbarItemToolTipKey = @"CPToolbarItemToolTipKey",
CPToolbarItemTagKey = @"CPToolbarItemTagKey",
CPToolbarItemTargetKey = @"CPToolbarItemTargetKey",
CPToolbarItemActionKey = @"CPToolbarItemActionKey",
CPToolbarItemEnabledKey = @"CPToolbarItemEnabledKey",
CPToolbarItemImageKey = @"CPToolbarItemImageKey",
CPToolbarItemAlternateImageKey = @"CPToolbarItemAlternateImageKey",
CPToolbarItemViewKey = @"CPToolbarItemViewKey",
CPToolbarItemMinSizeKey = @"CPToolbarItemMinSizeKey",
CPToolbarItemMaxSizeKey = @"CPToolbarItemMaxSizeKey",
CPToolbarItemVisibilityPriorityKey = @"CPToolbarItemVisibilityPriorityKey";
@implementation CPToolbarItem (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_itemIdentifier = [aCoder decodeObjectForKey:CPToolbarItemIdentifierKey];
[self setLabel:[aCoder decodeObjectForKey:CPToolbarItemLabelKey]];
[self setPaletteLabel:[aCoder decodeObjectForKey:CPToolbarItemPaletteLabelKey]];
[self setToolTip:[aCoder decodeObjectForKey:CPToolbarItemToolTipKey]];
[self setTag:[aCoder decodeObjectForKey:CPToolbarItemTagKey]];
[self setTarget:[aCoder decodeObjectForKey:CPToolbarItemTargetKey]];
[self setAction:[aCoder decodeObjectForKey:CPToolbarItemActionKey]];
[self setEnabled:[aCoder decodeBoolForKey:CPToolbarItemEnabledKey]];
[self setImage:[aCoder decodeBoolForKey:CPToolbarItemImageKey]];
[self setAlternateImage:[aCoder decodeBoolForKey:CPToolbarItemAlternateImageKey]];
[self setView:[aCoder decodeObjectForKey:CPToolbarItemViewKey]];
[self setMinSize:[aCoder decodeSizeForKey:CPToolbarItemMinSizeKey]];
[self setMaxSize:[aCoder decodeSizeForKey:CPToolbarItemMaxSizeKey]];
[self setVisibilityPriority:[aCoder decodeIntForKey:CPToolbarItemVisibilityPriorityKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_itemIdentifier forKey:CPToolbarItemItemIdentifierKey];
[aCoder encodeObject:[self label] forKey:CPToolbarItemLabelKey];
[aCoder encodeObject:[self paletteLabel] forKey:CPToolbarItemPaletteLabelKey];
[aCoder encodeObject:[self toolTip] forKey:CPToolbarItemToolTipKey];
[aCoder encodeObject:[self tag] forKey:CPToolbarItemTagKey];
[aCoder encodeObject:[self target] forKey:CPToolbarItemTargetKey];
[aCoder encodeObject:[self action] forKey:CPToolbarItemActionKey];
[aCoder encodeObject:[self isEnabled] forKey:CPToolbarItemEnabledKey];
[aCoder encodeObject:[self image] forKey:CPToolbarItemImageKey];
[aCoder encodeObject:[self alternateImage] forKey:CPToolbarItemAlternateImageKey];
[aCoder encodeObject:[self view] forKey:CPToolbarItemViewKey];
[aCoder encodeSize:[self minSize] forKey:CPToolbarItemMinSizeKey];
[aCoder encodeSize:[self maxSize] forKey:CPToolbarItemMaxSizeKey];
[aCoder encodeObject:[self visibilityPriority] forKey:CPToolbarItemVisibilityPriorityKey];
}
@end
@implementation CPToolbarItem (CPCopying)
- (id)copy
+45 -8
View File
@@ -7,7 +7,7 @@
id _representedObject @accessors(readonly, property=representedObject);
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
CPMutableArray _childNodes @accessors(readonly, property=childNodes);
CPMutableArray _childNodes;
}
+ (id)treeNodeWithRepresentedObject:(id)anObject
@@ -33,16 +33,23 @@
return [_childNodes count] <= 0;
}
- (CPArray)childNodes
{
return [_childNodes copy];
}
- (CPMutableArray)mutableChildNodes
{
return [self mutableArrayValueForKey:@"childNodes"];
}
- (void)insertObject:(id)anObject inChildNodesAtIndex:(CPInteger)anIndex
- (void)insertObject:(id)aTreeNode inChildNodesAtIndex:(CPInteger)anIndex
{
anObject._parentNode = self;
[[aTreeNode._parentNode mutableChildNodes] removeObjectIdenticalTo:aTreeNode];
[_childNodes addObject:anObject];
aTreeNode._parentNode = self;
[_childNodes insertObject:aTreeNode atIndex:anIndex];
}
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
@@ -52,13 +59,14 @@
[_childNodes removeObjectAtIndex:anIndex];
}
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)anObject
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)aTreeNode
{
var oldObject = [_childNodes objectAtIndex:anIndex];
var oldTreeNode = [_childNodes objectAtIndex:anIndex];
oldObject._parentNode = nil;
oldTreeNode._parentNode = nil;
aTreeNode._parentNode = self;
[_childNodes replaceObjectAtIndex:anIndex withObject:anObject];
[_childNodes replaceObjectAtIndex:anIndex withObject:aTreeNode];
}
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
@@ -80,3 +88,32 @@
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
CPTreeNodeParentNodeKey = @"CPTreeNodeParentNodeKey",
CPTreeNodeChildNodesKey = @"CPTreeNodeChildNodesKey";
@implementation CPTreeNode (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_representedObject = [aCoder decodeObjectForKey:CPTreeNodeRepresentedObjectKey];
_parentNode = [aCoder decodeObjectForKey:CPTreeNodeParentNodeKey];
_childNodes = [aCoder decodeObjectForKey:CPTreeNodeChildNodesKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_representedObject forKey:CPTreeNodeRepresentedObjectKey];
[aCoder encodeConditionalObject:_parentNode forKey:CPTreeNodeParentNodeKey];
[aCoder encodeObject:_childNodes forKey:CPTreeNodeChildNodesKey];
}
@end
+86 -5
View File
@@ -238,6 +238,11 @@ var CPViewFlags = { },
return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
}
+ (CPSet)keyPathsForValuesAffectingBounds
{
return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
}
- (id)init
{
return [self initWithFrame:CGRectMakeZero()];
@@ -308,7 +313,7 @@ var CPViewFlags = { },
*/
- (CPArray)subviews
{
return _subviews;
return [_subviews copy];
}
/*!
@@ -441,7 +446,7 @@ var CPViewFlags = { },
[_superview willRemoveSubview:self];
[[_superview subviews] removeObject:self];
[_superview._subviews removeObject:self];
#if PLATFORM(DOM)
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
@@ -468,6 +473,73 @@ var CPViewFlags = { },
[self _insertSubview:aView atIndex:index];
}
- (void)setSubviews:(CPArray)newSubviews
{
if (!newSubviews)
[CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
// Trivial Case 0: Same array somehow
if ([_subviews isEqual:newSubviews])
return;
// Trivial Case 1: No current subviews, simply add all new subviews.
if ([_subviews count] === 0)
{
var index = 0,
count = [newSubviews count];
for (; index < count; ++index)
[self addSubview:newSubviews[index]];
return;
}
// Trivial Case 2: No new subviews, simply remove all current subviews.
if ([newSubviews count] === 0)
{
var count = [_subviews count];
while (count--)
[_subviews[count] removeFromSuperview];
return;
}
// Find out the views that were removed.
var removedSubviews = [CPMutableSet setWithArray:_subviews];
[removedSubviews removeObjectsInArray:newSubviews];
[removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
// Find out which views need to be added.
var addedSubviews = [CPMutableSet setWithArray:newSubviews];
[addedSubviews removeObjectsInArray:_subviews];
var addedSubview = nil,
addedSubviewEnumerator = [addedSubviews objectEnumerator];
while (addedSubview = [addedSubviewEnumerator nextObject])
[self addSubview:addedSubview];
// If the order is fine, no need to reorder.
if ([_subviews isEqual:newSubviews])
return;
_subviews = [newSubviews copy];
var index = 0,
count = [_subviews count];
for (; index < count; ++index)
{
var subview = _subviews[index];
CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
}
}
/* @ignore */
- (void)_setWindow:(CPWindow)aWindow
{
@@ -816,6 +888,16 @@ var CPViewFlags = { },
return _CGRectMakeCopy(_bounds);
}
- (CGPoint)boundsOrigin
{
return _CGPointMakeCopy(_bounds.origin);
}
- (CGSize)boundsSize
{
return _CGSizeMakeCopy(_bounds.size);
}
/*!
Sets the location of the receiver inside its frame. The method
posts a CPViewBoundsDidChangeNotification to the
@@ -1863,12 +1945,11 @@ setBoundsOrigin:
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
var subviews = [self subviews],
count = [subviews count];
var count = [_subviews count];
// Is reverse iteration correct here? It matches the other (correct) code like hit testing.
while (count--)
if ([subviews[count] performKeyEquivalent:anEvent])
if ([_subviews[count] performKeyEquivalent:anEvent])
return YES;
return NO;
+27 -5
View File
@@ -175,6 +175,7 @@ CPWindowBelow = 2;
CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
CPWindowDidResizeNotification = @"CPWindowDidResizeNotification";
CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification";
CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification";
@@ -680,8 +681,8 @@ CPTexturedBackgroundWindowMask
if (_hasShadow)
[_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + size.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + size.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)];
if (!_isAnimating && [_delegate respondsToSelector:@selector(windowDidResize:)])
[_delegate windowDidResize:self];
if (!_isAnimating)
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self];
}
if ([self _sharesChromeWithPlatformWindow])
@@ -1086,6 +1087,13 @@ CPTexturedBackgroundWindowMask
selector:@selector(windowDidMove:)
name:CPWindowDidMoveNotification
object:self];
if ([_delegate respondsToSelector:@selector(windowDidResize:)])
[defaultCenter
addObserver:_delegate
selector:@selector(windowDidResize:)
name:CPWindowDidResizeNotification
object:self];
}
/*!
@@ -1999,7 +2007,8 @@ CPTexturedBackgroundWindowMask
- (void)_setUpMasksForView:(CPView)aView
{
var views = [CPArray arrayWithArray:[aView subviews]];
var views = [aView subviews];
[views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++)
@@ -2014,7 +2023,8 @@ CPTexturedBackgroundWindowMask
- (void)_restoreMasksForView:(CPView)aView
{
var views = [CPArray arrayWithArray:[aView subviews]];
var views = [aView subviews];
[views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++)
@@ -2369,9 +2379,21 @@ var keyViewComparator = function(a, b, context)
*/
- (CPUndoManager)undoManager
{
// If we've ever created an undo manager, return it.
if (_undoManager)
return _undoManager;
// If not, check to see if the document has one.
var documentUndoManager = [[_windowController document] undoManager];
if (documentUndoManager)
return documentUndoManager;
// If not, check to see if the delegate has one.
if (_delegateRespondsToWindowWillReturnUndoManagerSelector)
return [_delegate windowWillReturnUndoManager:self];
// If not, create one.
if (!_undoManager)
_undoManager = [[CPUndoManager alloc] init];
+7 -1
View File
@@ -37,6 +37,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
CPView _toolbarView;
// BOOL _isAnimatingToolbar;
CGRect _resizeFrame;
CGPoint _mouseDraggedPoint;
@@ -160,10 +161,15 @@ var _CPWindowViewResizeIndicatorImage = nil;
if (!visibleFrame)
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
var minPointY = 0;
if([CPMenu menuBarVisible])
minPointY = [[CPApp mainMenu] menuBarHeight];
var restrictedPoint = CGPointMake(0, 0);
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.0);
restrictedPoint.y = MIN(MAX(aPoint.y, 0.0), CGRectGetMaxY(visibleFrame) - 8.0);
restrictedPoint.y = MIN(MAX(aPoint.y, minPointY), CGRectGetMaxY(visibleFrame) - 8.0);
return restrictedPoint;
}
+7 -3
View File
@@ -37,7 +37,13 @@
- (void)setCustomClassName:(CPString)aClassName
{
if (_className === aClassName)
return;
_className = aClassName;
[self setNeedsDisplay:YES];
[self setNeedsLayout];
}
@end
@@ -97,9 +103,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
[view setBounds:[self bounds]];
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
// we need to copy subviews since each time we add a subview to a different view its removed from the original subviews array
var subviews = [[self subviews] copy],
var subviews = [self subviews],
index = 0,
count = subviews.length;
+1 -1
View File
@@ -104,7 +104,7 @@ var PrimaryPlatformWindow = NULL;
frame.origin = CGPointMakeZero();
if ([CPMenu menuBarVisible])
if ([CPMenu menuBarVisible] && [CPPlatformWindow primaryPlatformWindow] === self)
{
var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
+4 -3
View File
@@ -583,7 +583,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (_keyCode === CPKeyCodes.CAPS_LOCK)
_capsLockActive = YES;
if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask | CPAlternateKeyMask))
if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))
{
//we are simply going to skip all keypress events that use cmd/ctrl key
//this lets us be consistent in all browsers and send on the keydown
@@ -630,7 +630,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
case "keypress":
// we unconditionally break on keypress events with modifiers,
// because we forced the event to be sent on the keydown
if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask | CPAlternateKeyMask)))
if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)))
break;
var keyCode = _keyCode,
@@ -896,7 +896,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
// We should pay attention to mouse down and mouse up in conjunction with this.
//window.liveResize = YES;
[CPApp._activeMenu cancelTracking];
if ([CPPlatform isBrowser])
[CPApp._activeMenu cancelTracking];
var oldSize = [self contentRect].size;
+1
View File
@@ -376,6 +376,7 @@ var HORIZONTAL_MARGIN = 3.0,
shadowStyle.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString];
shadowStyle.position = "absolute";
shadowStyle.whiteSpace = textStyle.whiteSpace;
shadowStyle.color = [_textShadowColor cssString];
shadowStyle.zIndex = 150;
shadowStyle.textOverflow = textStyle.textOverflow;
+48
View File
@@ -181,6 +181,45 @@
return [[self _representedObject] count];
}
- (int)indexOfObject:(CPObject)anObject inRange:(CPRange)aRange
{
var index = aRange.location,
count = aRange.length,
shouldIsEqual = !!anObject.isa;
for (; index < count; ++index)
{
var object = [self objectAtIndex:index];
if (anObject === object || shouldIsEqual && !!object.isa && [anObject isEqual:object])
return index;
}
return CPNotFound;
}
- (int)indexOfObject:(CPObject)anObject
{
return [self indexOfObject:anObject range:CPMakeRange(0, [self count])];
}
- (int)indexOfObjectIdenticalTo:(CPObject)anObject inRange:(CPRange)aRange
{
var index = aRange.location,
count = aRange.length;
for (; index < count; ++index)
if (anObject === [self objectAtIndex:index])
return index;
return CPNotFound;
}
- (int)indexOfObjectIdenticalTo:(CPObject)anObject
{
return [self indexOfObjectIdenticalTo:anObject inRange:CPMakeRange(0, [self count])];
}
- (id)objectAtIndex:(unsigned)anIndex
{
if(_objectAtIndex)
@@ -200,6 +239,15 @@
[self _setRepresentedObject:target];
}
- (void)addObjectsFromArray:(CPArray)anArray
{
var index = 0,
count = [anArray count];
for (; index < count; ++index)
[self addObject:[anArray objectAtIndex:index]];
}
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
{
if (_insert)
+17 -16
View File
@@ -365,7 +365,7 @@
count = length;
for(; index < count; ++index)
if(self[index] == anObject)
if(self[index] === anObject)
return index;
}
@@ -534,14 +534,11 @@
*/
- (CPArray)objectsAtIndexes:(CPIndexSet)indexes
{
var index = [indexes firstIndex],
var index = CPNotFound,
objects = [];
while(index != CPNotFound)
{
[objects addObject:self[index]];
index = [indexes indexGreaterThanIndex:index];
}
while((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound)
[objects addObject:[self objectAtIndex:index]];
return objects;
}
@@ -816,15 +813,18 @@
for(; index < count; ++index)
{
var object = self[index];
if (index === 0)
description += '\n';
if (object && object.isa)
description += [object description];
else
description += object;
var object = self[index],
objectDescription = object && object.isa ? [object description] : object + "";
description += "\t" + objectDescription.split('\n').join("\n\t");
if (index !== count - 1)
description += ", ";
description += '\n';
}
return description + ')';
@@ -1112,7 +1112,7 @@
*/
- (void)removeObjectIdenticalTo:(id)anObject
{
[self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, length)];
[self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, [self count])];
}
/*!
@@ -1124,12 +1124,13 @@
*/
- (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
{
var index;
var index,
count = [self count];
while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) != CPNotFound)
while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) !== CPNotFound)
{
[self removeObjectAtIndex:index];
aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
aRange = CPIntersectionRange(CPMakeRange(index, (--count) - index), aRange);
}
}
+17 -1
View File
@@ -33,6 +33,10 @@
@implementation CPBundle : CPObject
{
//properties set up in file.js
//this.path = NULL;
//this.info = NULL;
//this._URIMap = { };
}
+ (id)alloc
@@ -185,13 +189,25 @@
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
alert("Couldnot find bundle:" + anError)
if ([_delegate respondsToSelector:@selector(bundle:didFailWithError:)])
[_delegate bundle:self didFailWithError:anError];
CPLog.error("Could not find bundle: " + self);
}
- (void)connectionDidFinishLoading:(CPURLConnection)aConnection
{
}
- (CPString)description
{
return [super description] + "(" + path + ")";
}
@end
objj_bundle.prototype.isa = CPBundle;
objj_bundle.prototype.toString = function()
{
return [this description];
}
+28 -3
View File
@@ -148,11 +148,32 @@
for (var key in object)
{
if (!object.hasOwnProperty(key))
continue;
var value = object[key];
if (recursively && value.constructor === Object)
value = [CPDictionary dictionaryWithJSObject:value recursively:YES];
if (recursively)
{
if (value.constructor === Object)
value = [CPDictionary dictionaryWithJSObject:value recursively:YES];
else if ([value isKindOfClass:CPArray])
{
var newValue = [];
for (var i = 0, count = value.length; i < count; i++)
{
var thisValue = value[i];
if (thisValue.constructor === Object)
newValue.push([CPDictionary dictionaryWithJSObject:thisValue recursively:YES]);
else
newValue.push(thisValue);
}
value = newValue;
}
}
[dictionary setObject:value forKey:key];
}
@@ -609,3 +630,7 @@
@end
objj_dictionary.prototype.isa = CPDictionary;
objj_dictionary.prototype.toString = function()
{
return [this description];
}
+10 -7
View File
@@ -92,7 +92,7 @@ if (input == nil)
if (self)
{
name = aName;
reason = aReason;
message = aReason;
userInfo = aUserInfo;
}
@@ -112,7 +112,7 @@ if (input == nil)
*/
- (CPString)reason
{
return reason;
return message;
}
/*!
@@ -128,7 +128,7 @@ if (input == nil)
*/
- (CPString)description
{
return reason;
return message;
}
/*!
@@ -145,7 +145,7 @@ if (input == nil)
- (id)copy
{
return [[self class] exceptionWithName:name reason:reason userInfo:userInfo];
return [[self class] exceptionWithName:name reason:message userInfo:userInfo];
}
@end
@@ -168,7 +168,7 @@ var CPExceptionNameKey = "CPExceptionNameKey",
if (self)
{
name = [aCoder decodeObjectForKey:CPExceptionNameKey];
reason = [aCoder decodeObjectForKey:CPExceptionReasonKey];
message = [aCoder decodeObjectForKey:CPExceptionReasonKey];
userInfo = [aCoder decodeObjectForKey:CPExceptionUserInfoKey];
}
@@ -182,13 +182,16 @@ var CPExceptionNameKey = "CPExceptionNameKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:name forKey:CPExceptionNameKey];
[aCoder encodeObject:reason forKey:CPExceptionReasonKey];
[aCoder encodeObject:message forKey:CPExceptionReasonKey];
[aCoder encodeObject:userInfo forKey:CPExceptionUserInfoKey];
}
@end
objj_exception.prototype.isa = CPException;
// toll-free bridge Error to CPException
// [CPException alloc] uses an objj_exception, which is a subclass of Error
Error.prototype.isa = CPException;
[CPException initialize];
function _CPRaiseInvalidAbstractInvocation(anObject, aSelector)
+85
View File
@@ -0,0 +1,85 @@
/*
* CPFunctionOperation.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPOperation.j"
/*!
@class CPFunctionOperation
@brief Represents an operation using a JavaScript function that can be run in an CPOperationQueue
*/
@implementation CPFunctionOperation : CPOperation
{
CPArray _functions;
}
- (void)main
{
if (_functions && [_functions count] > 0)
{
var i = 0;
for (i = 0; i < [_functions count]; i++)
{
var func = [_functions objectAtIndex:i];
func();
}
}
}
- (id)init
{
if (self = [super init])
{
_functions = [];
}
return self;
}
/*!
Adds the specified JS function to the receivers list of functions to perform.
*/
- (void)addExecutionFunction:(JSObject)jsFunction
{
[_functions addObject:jsFunction];
}
/*!
Returns an array containing the functions associated with the receiver.
*/
- (CPArray)executionFunctions
{
return _functions;
}
/*!
Creates and returns an NSFunctionOperation object and adds the specified function to it.
*/
+ (id)functionOperationWithFunction:(JSObject)jsFunction
{
functionOp = [[CPFunctionOperation alloc] init];
[functionOp addExecutionFunction:jsFunction];
return functionOp;
}
@end
+107
View File
@@ -0,0 +1,107 @@
/*
* CPInvocationOperation.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPInvocation.j>
@import "CPOperation.j"
/*!
@class CPInvocationOperation
@brief Represents an operation using an invocation that can be run in an CPOperationQueue
*/
@implementation CPInvocationOperation : CPOperation
{
CPInvocation _invocation;
}
- (void)main
{
if (_invocation)
{
[_invocation invoke];
}
}
- (id)init
{
if (self = [super init])
{
_invocation = nil;
}
return self;
}
/*!
Returns a CPInvocationOperation object initialized with the specified invocation object.
@param inv the invocation
*/
- (id)initWithInvocation:(CPInvocation)inv
{
if (self = [self init])
{
_invocation = inv;
}
return self;
}
/*!
Returns an NSInvocationOperation object initialized with the specified target and selector.
@param target the target
@param sel the selector that should be called on the target
@param arg the arguments
*/
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg
{
var inv = [[CPInvocation alloc] initWithMethodSignature:nil];
[inv setTarget:target];
[inv setSelector:sel];
[inv setArgument:arg atIndex:2];
return [self initWithInvocation:inv];
}
/*!
Returns the receivers invocation object.
*/
- (CPInvocation)invocation
{
return _invocation;
}
/*!
Returns the result of the invocation or method.
*/
- (id)result
{
if ([self isFinished] && _invocation)
{
return [_invocation returnValue];
}
return nil;
}
@end
+95 -11
View File
@@ -77,6 +77,81 @@
return [CPSet set];
}
- (void)applyChange:(CPDictionary)aChange toKeyPath:(CPString)aKeyPath
{
var changeKind = [aChange objectForKey:CPKeyValueChangeKindKey];
if (changeKind === CPKeyValueChangeSetting)
{
var value = [aChange objectForKey:CPKeyValueChangeNewKey];
[self setValue:value === [CPNull null] ? nil : value forKeyPath:aKeyPath];
}
else if (changeKind === CPKeyValueChangeInsertion)
[[self mutableArrayValueForKeyPath:aKeyPath]
insertObjects:[aChange objectForKey:CPKeyValueChangeNewKey]
atIndexes:[aChange objectForKey:CPKeyValueChangeIndexesKey]];
else if (changeKind === CPKeyValueChangeRemoval)
[[self mutableArrayValueForKeyPath:aKeyPath]
removeObjectsAtIndexes:[aChange objectForKey:CPKeyValueChangeIndexesKey]];
else if (changeKind === CPKeyValueChangeReplacement)
[[self mutableArrayValueForKeyPath:aKeyPath]
replaceObjectAtIndexes:[aChange objectForKey:CPKeyValueChangeIndexesKey]
withObjects:[aChange objectForKey:CPKeyValueChangeNewKey]];
}
@end
@implementation CPDictionary (KeyValueObserving)
- (CPDictionary)inverseChangeDictionary
{
var inverseChangeDictionary = [self mutableCopy],
changeKind = [self objectForKey:CPKeyValueChangeKindKey];
if (changeKind === CPKeyValueChangeSetting || changeKind === CPKeyValueChangeReplacement)
{
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeOldKey]
forKey:CPKeyValueChangeNewKey];
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeNewKey]
forKey:CPKeyValueChangeOldKey];
}
else if (changeKind === CPKeyValueChangeInsertion)
{
[inverseChangeDictionary
setObject:CPKeyValueChangeRemoval
forKey:CPKeyValueChangeKindKey];
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeNewKey]
forKey:CPKeyValueChangeOldKey];
[inverseChangeDictionary removeObjectForKey:CPKeyValueChangeNewKey];
}
else if (changeKind === CPKeyValueChangeRemoval)
{
[inverseChangeDictionary
setObject:CPKeyValueChangeInsertion
forKey:CPKeyValueChangeKindKey];
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeOldKey]
forKey:CPKeyValueChangeNewKey];
[inverseChangeDictionary removeObjectForKey:CPKeyValueChangeOldKey];
}
return inverseChangeDictionary;
}
@end
// KVO Options
@@ -311,11 +386,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
var type = [changes objectForKey:CPKeyValueChangeKindKey];
// for to-many relationships, oldvalue is only sensible for replace and remove
if (type == CPKeyValueChangeReplacement || type == CPKeyValueChangeRemoval)
if (type === CPKeyValueChangeReplacement || type === CPKeyValueChangeRemoval)
{
//FIXME: do we need to go through and replace "" with CPNull?
var oldValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
[changes setValue:oldValues forKey:CPKeyValueChangeOldKey];
var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
[changes setValue:newValues forKey:CPKeyValueChangeOldKey];
}
}
else
@@ -373,19 +448,28 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
else if (!isBefore)
[observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context];
}
var dependentKeysMap = _nativeClass[DependentKeysKey];
if (!dependentKeysMap)
return;
var keysComposedOfKey = [dependentKeysMap[aKey] allObjects];
if (!keysComposedOfKey)
var dependentKeyPaths = [dependentKeysMap[aKey] allObjects];
if (!dependentKeyPaths)
return;
for (var i=0, count=keysComposedOfKey.length; i<count; i++)
[self _sendNotificationsForKey:keysComposedOfKey[i] changeOptions:changeOptions isBefore:isBefore];
var index = 0,
count = [dependentKeyPaths count];
for (; index < count; ++index)
{
var keyPath = dependentKeyPaths[index];
[self _sendNotificationsForKey:keyPath
changeOptions:isBefore ? [changeOptions copy] : _changesForKey[keyPath]
isBefore:isBefore];
}
}
@end
@@ -501,7 +585,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
{
if (anObject == _object)
if (aKeyPath === _firstPart)
{
[_observer observeValueForKeyPath:_firstPart ofObject:_object change:changes context:_context];
@@ -514,7 +598,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
if (_value)
[_value addObserver:self forKeyPath:_secondPart options:kvoNewAndOld context:nil];
}
else /* if (anObject == _value || !_value) */
else
{
//a is the same, but a.b has changed -- nothing to do but forward this message along
[_observer observeValueForKeyPath:_firstPart+"."+aKeyPath ofObject:_object change:changes context:_context];
+5 -3
View File
@@ -227,6 +227,7 @@ CPLog(@"Got some class: %@", inst);
*/
- (BOOL)respondsToSelector:(SEL)aSelector
{
// isa is isa.isa in class case.
return !!class_getInstanceMethod(isa, aSelector);
}
@@ -269,7 +270,7 @@ CPLog(@"Got some class: %@", inst);
*/
- (CPString)description
{
return "<" + isa.name + " 0x" + [CPString stringWithHash:[self UID]] + ">";
return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
}
// Sending Messages
@@ -322,6 +323,7 @@ CPLog(@"Got some class: %@", inst);
Used for forwarding of messages to other objects.
@ignore
*/
// FIXME: This should be moved to the runtime?
- (void)forward:(SEL)aSelector :(marg_list)args
{
var signature = [self methodSignatureForSelector:aSelector];
@@ -468,12 +470,12 @@ CPLog(@"Got some class: %@", inst);
return [self UID];
}
- (unsigned)UID
- (CPString)UID
{
if (typeof self.__address === "undefined")
self.__address = _objj_generateObjectHash();
return __address;
return __address + "";
}
/*!
+293
View File
@@ -0,0 +1,293 @@
/*
* CPOperation.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
/*!
Operations receive very low priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityVeryLow = -8;
/*!
Operations receive low priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityLow = -4;
/*!
Operations receive normal priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityNormal = 0;
/*!
Operations receive high priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityHigh = 4;
/*!
Operations receive very high priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityVeryHigh = 8;
/*!
@class CPOperation
@brief Represents an operation that can be run in an CPOperationQueue
It should be subclassed an the subclass should implement its own main method to do the actual work.
*/
@implementation CPOperation : CPObject
{
CPArray operations;
BOOL _cancelled;
BOOL _executing;
BOOL _finished;
BOOL _ready;
int _queuePriority;
JSObject _completionFunction;
CPArray _dependencies;
}
- (void)main
{
// should be overridden in child class
}
- (id)init
{
if (self = [super init])
{
_cancelled = NO;
_executing = NO;
_finished = NO;
_ready = YES;
_dependencies = [[CPArray alloc] init];
_queuePriority = CPOperationQueuePriorityNormal;
}
return self;
}
/*!
Starts the operation (runs the main method), sets all the status flags and runs the completion function if it's set
*/
- (void)start
{
if (!_cancelled)
{
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
[self main];
if (_completionFunction)
{
_completionFunction();
}
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
[self didChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
}
}
/*!
Indicates if this operation has been cancelled
@return if this operation has been cancelled
*/
- (BOOL)isCancelled
{
return _cancelled;
}
/*!
Indicates if this operation is currently executing
@return if this operation is currently executing
*/
- (BOOL)isExecuting
{
return _executing;
}
/*!
Indicates if this operation has finished running
@return if this operation has finished running
*/
- (BOOL)isFinished
{
return _finished;
}
/*!
Just added for Cocoa compatibility
@return always false
*/
- (BOOL)isConcurrent
{
return NO;
}
/*!
Indicates if this operation is ready to be executed. Takes the "isFinished" state of dependent operations into account
@return if this operation is ready to run
*/
- (BOOL)isReady
{
return _ready;
}
/*!
The JS function that should be run after the main method
@return JS function
*/
(JSObject)completionFunction
{
return _completionFunction;
}
/*!
Sets the JS function that should be run after the main method
*/
- (void)setCompletionFunction:(JSObject)aJavaScriptFunction
{
_completionFunction = aJavaScriptFunction;
}
/*!
Makes the receiver dependent on the completion of the specified operation.
@param anOperation the operation that the receiver should depend on
*/
- (void)addDependency:(CPOperation)anOperation
{
[self willChangeValueForKey:@"dependencies"];
[anOperation addObserver:self
forKeyPath:@"isFinished"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[_dependencies addObject:anOperation];
[self didChangeValueForKey:@"dependencies"];
[self _updateIsReadyState];
}
/*!
Removes the receivers dependence on the specified operation.
@param anOperation the operation that the receiver should no longer depend on
*/
- (void)removeDependency:(CPOperation)anOperation
{
[self willChangeValueForKey:@"dependencies"];
[_dependencies removeObject:anOperation];
[anOperation removeObserver:self
forKeyPath:@"isFinished"];
[self didChangeValueForKey:@"dependencies"];
[self _updateIsReadyState];
}
/*!
The operations that the receiver depends on
@return array of operations
*/
- (CPArray)dependencies
{
return _dependencies;
}
/*!
Just added for Cocoa compatibility, doesn't do anything
*/
- (void)waitUntilFinished
{
}
/*!
Advises the operation object that it should stop executing its task.
*/
- (void)cancel
{
[self willChangeValueForKey:@"isCancelled"];
_cancelled = YES;
[self didChangeValueForKey:@"isCancelled"];
}
/*!
Sets the priority of the operation when used in an operation queue.
@param priority the priority
*/
- (void)setQueuePriority:(int)priority
{
_queuePriority = priority;
}
/*!
The priority of the operation when used in an operation queue.
@return the priority
*/
- (int)queuePriority
{
return _queuePriority;
}
// We need to observe the "isFinished" key of our dependent operations so we can update our own "isReady" state
- (void)observeValueForKeyPath:(CPString)keyPath
ofObject:(id)object
change:(CPDictionary)change
context:(void)context
{
if (keyPath == @"isFinished")
{
[self _updateIsReadyState];
}
}
- (void)_updateIsReadyState
{
var newReady = YES;
if (_dependencies && [_dependencies count] > 0)
{
var i = 0;
for (i = 0; i < [_dependencies count]; i++)
{
if (![[_dependencies objectAtIndex:i] isFinished])
{
newReady = NO;
}
}
}
if (newReady != _ready)
{
[self willChangeValueForKey:@"isReady"];
_ready = newReady;
[self didChangeValueForKey:@"isReady"];
}
}
@end
+293
View File
@@ -0,0 +1,293 @@
/*
* CPOperationQueue.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPOperation.j"
@import "CPInvocationOperation.j"
@import "CPFunctionOperation.j"
// the global queue (mainQueue)
var cpOperationMainQueue = nil;
/*!
@class CPOperationQueue
@brief Represents an operation queue that can run CPOperations
*/
@implementation CPOperationQueue : CPObject
{
CPArray _operations;
BOOL _suspended;
CPString _name @accessors(property=name);
CPTimer _timer;
}
- (id)init
{
if (self = [super init])
{
_operations = [[CPArray alloc] init];
_suspended = NO;
_currentlyModifyingOps = NO;
_timer = [CPTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(_runNextOpsInQueue)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)_runNextOpsInQueue
{
if (!_suspended && [self operationCount] > 0)
{
var i = 0;
for (i = 0; i < [_operations count]; i++)
{
var op = [_operations objectAtIndex:i];
if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting])
{
[op start];
}
}
}
}
- (void)_enableTimer:(BOOL)enable
{
if (!enable)
{
if (_timer)
{
[_timer invalidate];
_timer = nil;
}
}
else
{
if (!_timer)
{
_timer = [CPTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(_runNextOpsInQueue)
userInfo:nil
repeats:YES];
}
}
}
/*!
Adds the specified operation object to the receiver.
@param anOperation the operation that should be scheduled for execution
*/
- (void)addOperation:(CPOperation)anOperation
{
[self willChangeValueForKey:@"operations"];
[self willChangeValueForKey:@"operationCount"];
[_operations addObject:anOperation];
[self _sortOpsByPriority:_operations];
[self didChangeValueForKey:@"operations"];
[self didChangeValueForKey:@"operationCount"];
}
/*!
Adds the specified array of operations to the queue.
@param ops The array of CPOperation objects that you want to add to the receiver.
@param wait If YES, the method only returns once all of the specified operations finish executing. If NO, the operations are added to the queue and control returns immediately to the caller.
*/
- (void)addOperations:(CPArray)ops waitUntilFinished:(BOOL)wait
{
if (ops)
{
if (wait)
{
[self _sortOpsByPriority:ops];
[self _runOpsSynchronously:ops];
}
[_operations addObjectsFromArray:ops];
[self _sortOpsByPriority:_operations];
}
}
/*!
Wraps the given js function in a CPOperation and adds it to the queue
@param aFunction the JS function to add
*/
- (void)addOperationWithFunction:(JSObject)aFunction
{
[self addOperation:[CPFunctionOperation functionOperationWithFunction:aFunction]];
}
- (CPArray)operations
{
return _operations;
}
- (int)operationCount
{
if (_operations)
{
return [_operations count];
}
return 0;
}
/*!
Cancels all queued and executing operations.
*/
- (void)cancelAllOperations
{
if (_operations)
{
var i = 0;
for (i = 0; i < [_operations count]; i++)
{
[[_operations objectAtIndex:i] cancel];
}
}
}
/*!
Blocks until all of the receivers queued and executing operations finish executing.
*/
- (void)waitUntilAllOperationsAreFinished
{
// lets first stop the timer so it won't interfere
[self _enableTimer:NO];
[self _runOpsSynchronously:_operations];
if (!_suspended)
{
[self _enableTimer:YES];
}
}
/*!
Returns the maximum number of concurrent operations that the receiver can execute.
Always returns 1 because JS doesn't have threads
*/
- (int)maxConcurrentOperationCount
{
return 1;
}
/*!
Modifies the execution of pending operations
@param suspend if YES, queue execution is suspended. If NO, it is resumed
*/
- (void)setSuspended:(BOOL)suspend
{
_suspended = suspend;
[self _enableTimer:!suspend];
}
/*!
Returns a Boolean value indicating whether the receiver is scheduling queued operations for execution.
*/
- (BOOL)isSuspended
{
return _suspended;
}
- (void)_sortOpsByPriority:(CPArray)someOps
{
if (someOps)
{
[someOps sortUsingFunction:function(lhs, rhs)
{
if ([lhs queuePriority] < [rhs queuePriority])
{
return 1;
}
else
{
if ([lhs queuePriority] > [rhs queuePriority])
{
return -1;
}
else
{
return 0;
}
}
}
context:nil];
}
}
- (void)_runOpsSynchronously:(CPArray)ops
{
if (ops)
{
var keepGoing = YES;
while (keepGoing)
{
var i = 0;
keepGoing = NO;
// start the ones that are ready
for (i = 0; i < [ops count]; i++)
{
var op = [ops objectAtIndex:i];
if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting])
{
[op start];
}
}
// make sure they are all done
for (i = 0; i < [ops count]; i++)
{
var op = [ops objectAtIndex:i];
if (![op isFinished] && ![op isCancelled])
{
keepGoing = YES;
}
}
}
}
}
/*!
Convenience method for one system wide singelton queue. Returns the same queue as currentQueue.
*/
+ (CPOperationQueue)mainQueue
{
if (!cpOperationMainQueue)
{
cpOperationMainQueue = [[CPOperationQueue alloc] init];
[cpOperationMainQueue setName:@"main"];
}
return cpOperationMainQueue;
}
/*!
Convenience method for one system wide singelton queue. Returns the same queue as mainQueue.
*/
+ (CPOperationQueue)currentQueue
{
return [CPOperationQueue mainQueue];
}
@end
+161
View File
@@ -0,0 +1,161 @@
/*
* CPProxy.j
* Foundation
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPException.j"
@import "CPInvocation.j"
@import "CPString.j"
@implementation CPProxy
{
}
+ (void)load
{
}
+ (void)initialize
{
}
+ (Class)class
{
return self;
}
+ (id)alloc
{
return class_createInstance(self);
}
+ (BOOL)respondsToSelector:(SEL)selector
{
return !!class_getInstanceMethod(isa, aSelector);
}
- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
{
[CPException raise:CPInvalidArgumentException
reason:@"-methodSignatureForSelector: called on abstract CPProxy class."];
}
- (void)forwardInvocation:(CPInvocation)anInvocation
{
[CPException raise:CPInvalidArgumentException
reason:@"-methodSignatureForSelector: called on abstract CPProxy class."];
}
// FIXME: This should be moved to the runtime?
- (void)forward:(SEL)aSelector :(marg_list)args
{
[CPObject methodForSelector:_cmd](self, _cmd, aSelector, args);
}
- (unsigned)hash
{
return [self UID];
}
- (unsigned)UID
{
if (typeof self.__address === "undefined")
self.__address = _objj_generateObjectHash();
return __address;
}
- (BOOL)isEqual:(id)anObject
{
return self === object;
}
- (id)self
{
return self;
}
- (Class)class
{
return isa;
}
- (Class)superclass
{
return class_getSuperclass(isa);
}
- (id)performSelector:(SEL)aSelector
{
return objj_msgSend(self, aSelector);
}
- (id)performSelector:(SEL)aSelector withObject:(id)anObject
{
return objj_msgSend(self, aSelector, anObject);
}
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
{
return objj_msgSend(self, aSelector, anObject, anotherObject);
}
- (BOOL)isProxy
{
return YES;
}
- (BOOL)isKindOfClass:(Class)aClass
{
var signature = [self methodSignatureForSelector:_cmd],
invocation = [CPInvocation invocationWithMethodSignature:signature];
[self forwardInvocation:invocation];
return [invocation returnValue];
}
-(BOOL)isMemberOfClass:(Class)aClass
{
var signature = [self methodSignatureForSelector:_cmd],
invocation = [CPInvocation invocationWithMethodSignature:signature];
[self forwardInvocation:invocation];
return [invocation returnValue];
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
var signature = [self methodSignatureForSelector:_cmd],
invocation = [CPInvocation invocationWithMethodSignature:signature];
[self forwardInvocation:invocation];
return [invocation returnValue];
}
- (CPString)description
{
return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
}
@end
+1 -1
View File
@@ -159,7 +159,7 @@ var CPURLConnectionDelegate = nil;
// Browsers use "file:", Titanium uses "app:"
_isLocalFileConnection = scheme === "file" ||
((scheme !== "http" || scheme !== "https:") &&
((scheme === "http" || scheme === "https:") &&
window.location &&
(window.location.protocol === "file:" || window.location.protocol === "app:"));
+159 -78
View File
@@ -22,6 +22,7 @@
@import "CPObject.j"
@import "CPInvocation.j"
@import "CPProxy.j"
var CPUndoManagerNormal = 0,
@@ -170,15 +171,17 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
{
CPMutableArray _redoStack;
CPMutableArray _undoStack;
BOOL _groupsByEvent;
int _disableCount;
int _levelsOfUndo;
id _currentGrouping;
int _state;
CPString _actionName;
id _preparedTarget;
id _undoManagerProxy;
CPArray _runLoopModes;
BOOL _registeredWithRunLoop;
}
@@ -200,12 +203,29 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
[self setRunLoopModes:[CPDefaultRunLoopMode]];
[self setGroupsByEvent:YES];
_performRegistered = NO;
_undoManagerProxy = [_CPUndoManagerProxy alloc];
_undoManagerProxy._undoManager = self;
}
return self;
}
- (void)_addUndoInvocation:(CPInvocation)anInvocation
{
if (!_currentGrouping)
// Remember that we create these lazily...
if ([self groupsByEvent])
[self _beginUndoGroupingForEvent];
else
[CPException raise:CPInternalInconsistencyException reason:"No undo group is currently open"];
[_currentGrouping addInvocation:anInvocation];
if (_state === CPUndoManagerNormal)
[_redoStack removeAllObjects];
}
// Registering Undo Operations
/*!
Registers an undo operation. You invoke this method with the target of the undo action providing the selector which can perform the undo with the provided object. The object is often a dictionary of the identifying the attribute and their values before the change. The invocation will be added to the current grouping. If the registrations have been disabled through \c -disableUndoRegistration, this method does nothing.
@@ -216,9 +236,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)registerUndoWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anObject
{
if (!_currentGrouping)
[CPException raise:CPInternalInconsistencyException reason:"No undo group is currently open"];
// Don't do anything if we're disabled.
if (_disableCount > 0)
return;
@@ -230,10 +248,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
[invocation setSelector:aSelector];
[invocation setArgument:anObject atIndex:2];
[_currentGrouping addInvocation:invocation];
if (_state == CPUndoManagerNormal)
[_redoStack removeAllObjects];
[self _addUndoInvocation:invocation];
}
/*!
Prepares the specified target for the undo action.
@@ -244,14 +259,14 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
{
_preparedTarget = aTarget;
return self;
return _undoManagerProxy;
}
/*
FIXME This method doesn't seem to do anything right
@ignore
*/
-(CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
- (CPMethodSignature)_methodSignatureOfPreparedTargetForSelector:(SEL)aSelector
{
if ([_preparedTarget respondsToSelector:aSelector])
return 1;
@@ -264,23 +279,20 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
target on the invocation, and adds it to the current grouping.
@param anInvocation the message to record
*/
- (void)forwardInvocation:(CPInvocation)anInvocation
- (void)_forwardInvocationToPreparedTarget:(CPInvocation)anInvocation
{
// Don't do anything if we're disabled.
if (_disableCount > 0)
return;
/* if (_preparedTarget == nil)
[NSException raise:NSInternalInconsistencyException
format:@"forwardInvocation called without first preparing a target"];
if (_currentGroup == nil)
/*
if (_currentGroup == nil)
[NSException raise:NSInternalInconsistencyException
format:@"forwardInvocation called without first opening an undo group"];
*/
[anInvocation setTarget:_preparedTarget];
[_currentGrouping addInvocation:anInvocation];
if (_state == CPUndoManagerNormal)
[_redoStack removeAllObjects];
[self _addUndoInvocation:anInvocation];
_preparedTarget = nil;
}
@@ -291,7 +303,11 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (BOOL)canRedo
{
return _redoStack.length > 0;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPUndoManagerCheckpointNotification
object:self];
return [_redoStack count] > 0;
}
/*!
@@ -311,9 +327,9 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)undo
{
if ([self groupingLevel] == 1)
if ([self groupingLevel] === 1)
[self endUndoGrouping];
[self undoNestedGroup];
}
@@ -322,28 +338,31 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)undoNestedGroup
{
if (_undoStack.length == 0)
if ([_undoStack count] <= 0)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
/* [[NSNotificationCenter defaultCenter] postNotificationName:NSUndoManagerCheckpointNotification
object:self];
*/
[defaultCenter postNotificationName:CPUndoManagerWillUndoChangeNotification object:self];
[defaultCenter postNotificationName:CPUndoManagerCheckpointNotification
object:self];
[defaultCenter postNotificationName:CPUndoManagerWillUndoChangeNotification
object:self];
var undoGrouping = _undoStack.pop();
_state = CPUndoManagerUndoing;
[self beginUndoGrouping];
[self _beginUndoGrouping];
[undoGrouping invoke];
[self endUndoGrouping];
[_CPUndoGrouping _poolUndoGrouping:undoGrouping];
_state = CPUndoManagerNormal;
[defaultCenter postNotificationName:CPUndoManagerDidUndoChangeNotification object:self];
[defaultCenter postNotificationName:CPUndoManagerDidUndoChangeNotification
object:self];
}
/*!
@@ -352,19 +371,21 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
- (void)redo
{
// Don't do anything if we have no redos.
if (_redoStack.length == 0)
if ([_redoStack count] <= 0)
return;
/* if (_state == NSUndoManagerUndoing)
[NSException raise:NSInternalInconsistencyException
format:@"redo called while undoing"];
[[NSNotificationCenter defaultCenter] postNotificationName:NSUndoManagerCheckpointNotification
object:self];
*/
var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter postNotificationName:CPUndoManagerWillRedoChangeNotification object:self];
[defaultCenter postNotificationName:CPUndoManagerCheckpointNotification
object:self];
[defaultCenter postNotificationName:CPUndoManagerWillRedoChangeNotification
object:self];
var oldUndoGrouping = _currentGrouping,
undoGrouping = _redoStack.pop();
@@ -372,7 +393,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
_currentGrouping = nil;
_state = CPUndoManagerRedoing;
[self beginUndoGrouping];
[self _beginUndoGrouping];
[undoGrouping invoke];
[self endUndoGrouping];
@@ -389,6 +410,29 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
Starts a new grouping of undo tasks, and makes it the current grouping.
*/
- (void)beginUndoGrouping
{
// It doesn't matter that the user is creating a group themselves, we are
// pretending to have opened the group at the beginning of the run loop,
// so create an implicit one here.
if (!_currentGrouping && [self groupsByEvent])
[self _beginUndoGroupingForEvent];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPUndoManagerCheckpointNotification
object:self];
[self _beginUndoGrouping];
}
/* @ignore */
- (void)_beginUndoGroupingForEvent
{
[self _beginUndoGrouping];
[self _registerWithRunLoop];
}
/* @ignore */
- (void)_beginUndoGrouping
{
_currentGrouping = [_CPUndoGrouping undoGroupingWithParent:_currentGrouping];
}
@@ -402,17 +446,22 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
if (!_currentGrouping)
[CPException raise:CPInternalInconsistencyException reason:"endUndoGrouping. No undo group is currently open."];
var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter postNotificationName:CPUndoManagerCheckpointNotification
object:self];
var parent = [_currentGrouping parent];
if (!parent && [_currentGrouping invocations].length > 0)
{
[[CPNotificationCenter defaultCenter]
[defaultCenter
postNotificationName:CPUndoManagerWillCloseUndoGroupNotification
object:self];
// Put this group on the redo stack if we are currently undoing, otherwise
// Put this group on the redo stack if we are currently undoing, otherwise
// put it on the undo stack. That way, "undos" become "redos".
var stack = _state == CPUndoManagerUndoing ? _redoStack : _undoStack;
var stack = _state === CPUndoManagerUndoing ? _redoStack : _undoStack;
stack.push(_currentGrouping);
@@ -460,21 +509,14 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)setGroupsByEvent:(BOOL)aFlag
{
if (_groupsByEvent == aFlag)
aFlag = !!aFlag;
if (_groupsByEvent === aFlag)
return;
_groupsByEvent = aFlag;
if (_groupsByEvent)
{
[self _registerWithRunLoop];
// There is a chance that the event loop selector won't fire before our first register,
// so kick it off here.
if (!_currentGrouping)
[self beginUndoGrouping];
}
else
if (![self groupsByEvent])
[self _unregisterWithRunLoop];
}
@@ -515,7 +557,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (BOOL)isUndoing
{
return _state == CPUndoManagerUndoing;
return _state === CPUndoManagerUndoing;
}
/*!
@@ -523,7 +565,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (BOOL)isRedoing
{
return _state == CPUndoManagerRedoing;
return _state === CPUndoManagerRedoing;
}
// Clearing Undo Operations
@@ -623,27 +665,19 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)setRunLoopModes:(CPArray)modes
{
_runLoopModes = modes;
[self _unregisterWithRunLoop];
if (_groupsByEvent)
_runLoopModes = [modes copy];
if (_registeredWithRunLoop)
{
[self _unregisterWithRunLoop];
[self _registerWithRunLoop];
}
}
/* @ignore */
- (void)beginUndoGroupingForEvent
- (void)_runLoopEndUndoGrouping
{
if (!_groupsByEvent)
return;
if (_currentGrouping != nil)
[self endUndoGrouping];
[self beginUndoGrouping];
[[CPRunLoop currentRunLoop] performSelector:@selector(beginUndoGroupingForEvent)
target:self argument:nil order:CPUndoCloseGroupingRunLoopOrdering modes:_runLoopModes];
[self endUndoGrouping];
_registeredWithRunLoop = NO;
}
/* @ignore */
@@ -653,8 +687,12 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
return;
_registeredWithRunLoop = YES;
[[CPRunLoop currentRunLoop] performSelector:@selector(beginUndoGroupingForEvent)
target:self argument:nil order:CPUndoCloseGroupingRunLoopOrdering modes:_runLoopModes];
[[CPRunLoop currentRunLoop]
performSelector:@selector(_runLoopEndUndoGrouping)
target:self
argument:nil
order:CPUndoCloseGroupingRunLoopOrdering
modes:_runLoopModes];
}
/* @ignore */
@@ -664,7 +702,33 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
return;
_registeredWithRunLoop = NO;
[[CPRunLoop currentRunLoop] cancelPerformSelector:@selector(beginUndoGroupingForEvent) target:self argument:nil];
[[CPRunLoop currentRunLoop]
cancelPerformSelector:@selector(_runLoopEndUndoGrouping)
target:self
argument:nil];
}
- (void)observeChangesForKeyPath:(CPString)aKeyPath ofObject:(id)anObject
{
[anObject addObserver:self
forKeyPath:aKeyPath
options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew
context:NULL];
}
- (void)stopObservingChangesForKeyPath:(CPString)aKeyPath ofObject:(id)anObject
{
[anObject removeObserver:self forKeyPath:aKeyPath];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath
ofObject:(id)anObject
change:(CPDictionary)aChange
context:(id)aContext
{
[[self prepareWithInvocationTarget:anObject]
applyChange:[aChange inverseChangeDictionary]
toKeyPath:aKeyPath];
}
@end
@@ -718,3 +782,20 @@ var CPUndoManagerRedoStackKey = @"CPUndoManagerRedoStackKey",
}
@end
@implementation _CPUndoManagerProxy : CPProxy
{
CPUndoManager _undoManager;
}
- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
{
return [_undoManager _methodSignatureOfPreparedTargetForSelector:aSelector];
}
- (void)forwardInvocation:(CPInvocation)anInvocation
{
[_undoManager _forwardInvocationToPreparedTarget:anInvocation];
}
@end
+2
View File
@@ -42,6 +42,8 @@
@import "CPNumber.j"
@import "CPObject.j"
@import "CPObjJRuntime.j"
@import "CPOperation.j"
@import "CPOperationQueue.j"
@import "CPPropertyListSerialization.j"
@import "CPRange.j"
@import "CPRunLoop.j"
+8 -8
View File
@@ -48,7 +48,7 @@ task ("install", ["CommonJS"], function()
{
// FIXME: require("narwhal/tusk/install").install({}, $COMMONJS);
// Doesn't work due to some weird this.print business.
OS.system("sudo tusk install --force " + $BUILD_CJS_OBJECTIVE_J + " " + $BUILD_CJS_CAPPUCCINO);
OS.system(["sudo", "tusk", "install", "--force", $BUILD_CJS_OBJECTIVE_J, $BUILD_CJS_CAPPUCCINO]);
});
// Documentation
@@ -61,7 +61,7 @@ task ("documentation", function()
{
if (executableExists("doxygen"))
{
if (OS.system("doxygen " + FILE.join("Tools", "Documentation", "Cappuccino.doxygen")))
if (OS.system(["doxygen", FILE.join("Tools", "Documentation", "Cappuccino.doxygen")]))
OS.exit(1); //rake abort if ($? != 0)
rm_rf($DOCUMENTATION_BUILD);
@@ -95,7 +95,7 @@ filedir ($STARTER_DOWNLOAD_APPLICATION, ["CommonJS"], function()
rm_rf($STARTER_DOWNLOAD_APPLICATION);
FILE.mkdirs($STARTER_DOWNLOAD);
if (OS.system("capp gen " + $STARTER_DOWNLOAD_APPLICATION + " -t Application --noconfig"))
if (OS.system(["capp", "gen", $STARTER_DOWNLOAD_APPLICATION, "-t", "Application", "--noconfig"]))
// FIXME: uncomment this: we get conversion errors
//OS.exit(1); // rake abort if ($? != 0)
{}
@@ -161,13 +161,14 @@ task ("deploy", ["downloads"], function()
// Testing
task ("test", ["build"], function()
task("test", ["build", "test-only"]);
task("test-only", function()
{
var tests = new FileList('Tests/**/*Test.j');
var cmd = ["ojtest"].concat(tests.items());
var cmdString = cmd.map(OS.enquote).join(" ");
var code = OS.system(cmdString);
var code = OS.system(cmd);
if (code !== 0)
OS.exit(code);
});
@@ -198,8 +199,7 @@ function pushPackage(path, remote)
["git", "push", "origin", "master"]
];
var cmdString = cmds.map(function(cmd)
{
var cmdString = cmds.map(function(cmd) {
return cmd.map(OS.enquote).join(" ");
}).join(" && ");
+5 -3
View File
@@ -62,12 +62,14 @@ if (system.env["OBJJ_INCLUDE_PATHS"])
// TODO: somehow make window object the top scope?
with (window)
{
var objectivejSource = FILE.read(objectivejPath, { charset:"UTF-8" });
// read and eval Objective-J.js with the module's scope
if (system.engine === "rhino")
Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, FILE.read(objectivejPath, { charset:"UTF-8" }), "Objective-J.js", 0, null);
Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, objectivejSource, objectivejPath, 0, null);
else
eval(FILE.read(objectivejPath, { charset:"UTF-8" }));
eval(objectivejSource);
// export desired variables. must eval variable name to obtain a reference.
[
"objj_preprocess",
@@ -27,7 +27,7 @@ var compressor = null;
function sharedCompressor()
{
if (!compressor)
compressor = OS.popen("java -server -Dfile.encoding=UTF-8 -classpath " + RHINO_PATH + ":" + SHRINKSAFE_PATH + " org.dojotoolkit.shrinksafe.Main");
compressor = OS.popen("java -server -Dfile.encoding=UTF-8 -classpath " + RHINO_PATH + ":" + SHRINKSAFE_PATH + " org.dojotoolkit.shrinksafe.Main", { charset:"UTF-8" });
return compressor;
}
@@ -65,7 +65,7 @@ function compileWithResolvedFlags(aFilePath, objjcFlags, gccFlags)
else
{
// GCC preprocess the file.
var gcc = OS.popen("gcc -E -x c -P " + (gccFlags ? gccFlags.join(" ") : "") + " " + OS.enquote(aFilePath)),
var gcc = OS.popen("gcc -E -x c -P " + (gccFlags ? gccFlags.join(" ") : "") + " " + OS.enquote(aFilePath), { charset:"UTF-8" }),
chunk = "";
while (chunk = gcc.stdout.read())
+51 -18
View File
@@ -28,20 +28,32 @@ require("../common.jake");
$BUILD_OBJECTIVE_J = FILE.join($BUILD_CONFIGURATION_DIR, "Objective-J");
Files = new FileList("Runtime/constants.js", "Runtime/utilities.js", "Runtime/json2.js", "Runtime/runtime.js", "Runtime/dictionary.js", "Runtime/plist.js", "Runtime/file.js", "Runtime/exception.js", "Runtime/preprocess.js", "Runtime/evaluate.js", "Runtime/bootstrap.js");
var OBJECTIVE_J_FILES = new FileList(
"Runtime/constants.js",
"Runtime/utilities.js",
"Runtime/json2.js",
"Runtime/runtime.js",
"Runtime/dictionary.js",
"Runtime/plist.js",
"Runtime/file.js",
"Runtime/exception.js",
"Runtime/preprocess.js",
"Runtime/evaluate.js",
"Runtime/bootstrap.js"
);
if ($CONFIGURATION === "Debug")
Files.include("Runtime/debug.js");
OBJECTIVE_J_FILES.include("Runtime/debug.js");
$BUILD_BROWSER_FILE = FILE.join($BUILD_OBJECTIVE_J, "Objective-J.js");
$BUILD_CJS_FILE = FILE.join($BUILD_OBJECTIVE_J, "CommonJS.environment", "Objective-J.js");
filedir ($BUILD_BROWSER_FILE, Files, function(aTask)
filedir($BUILD_BROWSER_FILE, OBJECTIVE_J_FILES, function(aTask)
{
build_product(aTask.name(), environmentFlags("ObjJ") + " -DPLATFORM_USERAGENT");
});
filedir ($BUILD_CJS_FILE, Files, function(aTask)
filedir($BUILD_CJS_FILE, OBJECTIVE_J_FILES, function(aTask)
{
flags = environmentFlags("CommonJS", "ObjJ");
flags += ' -DRHINO'
@@ -52,7 +64,7 @@ filedir ($BUILD_CJS_FILE, Files, function(aTask)
$LICENSE = FILE.join("CommonJS", "lib", "objective-j", "jake", "LICENSES", "LGPL-v2.1");
$BUILD_LICENSE = FILE.join($BUILD_OBJECTIVE_J, "LICENSE");
filedir ($BUILD_LICENSE, [$LICENSE], function()
filedir($BUILD_LICENSE, [$LICENSE], function()
{
FILE.copy($LICENSE, $BUILD_LICENSE);
});
@@ -83,7 +95,7 @@ new FileList("CommonJS/**/*").forEach(function(aFilename)
$BUILD_CJS_OBJECTIVE_J_FRAMEWORK = FILE.join($BUILD_CJS_OBJECTIVE_J, "Frameworks", "Objective-J");
filedir ($BUILD_CJS_OBJECTIVE_J_FRAMEWORK, function()
filedir($BUILD_CJS_OBJECTIVE_J_FRAMEWORK, function()
{
cp_r($BUILD_OBJECTIVE_J, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK);
});
@@ -92,24 +104,45 @@ CLOBBER.include($BUILD_OBJECTIVE_J);
function environmentFlags()
{
return "-DENVIRONMENTS=\"[" + Array.prototype.map.apply(arguments, [function(anEnvironment)
{
return "-DENVIRONMENTS=\"[" + Array.prototype.map.apply(arguments, [function(anEnvironment) {
return "\\\"" + anEnvironment + "\\\"";
}]).join(", ") + "]\"";
}
function build_product(path, flags)
{
OS.system("cat Runtime/header.txt > " + OS.enquote(path));
OS.system("cat " +
Files.filter(function(aName)
{
return !!aName.match(/\.js$/);
}).map(function(aName)
{
return OS.enquote(aName);
}).join(' ') + " | gcc " + flags + " -E -x c -P - >> " + OS.enquote(path));
var sources = OBJECTIVE_J_FILES.filter(function(aName) { return !!aName.match(/\.js$/); });
var productOut = FILE.open(path, "w", { charset : "UTF-8" });
FILE.open("Runtime/header.txt", "r", { charset : "UTF-8" })
.copy(productOut)
.close();
var preprocessor = OS.popen("gcc " + flags + " -E -x c -P -");
sources.forEach(function(source) {
FILE.open(source, "r", { charset : "UTF-8" })
.copy(preprocessor.stdin)
.close();
});
preprocessor.stdin.close();
preprocessor.stdout.copy(productOut);
productOut.close();
var code = preprocessor.wait();
// this is equivalent to the above, but less cross platform:
//OS.system(["cp", "Runtime/header.txt", path]);
//var code = OS.system("cat " + sources.map(OS.enquote).join(' ') + " | gcc " + flags + " -E -x c -P - >> " + OS.enquote(path));
if (code !== 0) {
FILE.remove(path);
OS.exit(1);
}
// rake abort if ($? != 0)
}
task ("build", [$BUILD_BROWSER_FILE, $BUILD_CJS_FILE, $BUILD_LICENSE, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK]);
task("build", [$BUILD_BROWSER_FILE, $BUILD_CJS_FILE, $BUILD_LICENSE, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK]);
+8 -5
View File
@@ -25,15 +25,18 @@ var OBJJ_EXCEPTION_OUTPUT_STREAM = NULL;
function objj_exception(aName, aReason, aUserInfo)
{
this.name = aName;
this.reason = aReason;
this.message = aReason;
this.userInfo = aUserInfo;
this.__address = _objj_generateObjectHash();
// add rhinoException to get better stack traces
if (typeof Packages !== "undefined" && Packages && Packages.org)
this.rhinoException = Packages.org.mozilla.javascript.JavaScriptException(this, null, 0);
}
objj_exception.prototype.toString = function()
{
return this.reason;
}
// make objj_exception a subclass of Error
// later we toll-free bridge Error to CPException
objj_exception.prototype = new Error();
function objj_exception_throw(anException)
{
+2 -2
View File
@@ -607,10 +607,10 @@ function objj_decompile(aString, bundle)
var stream = new objj_markedStream(aString);
if (stream.magicNumber() != STATIC_MAGIC_NUMBER)
objj_exception_throw(new objj_exception(OBJJUnrecognizedFormatException, "*** Could not recognize executable code format."));
objj_exception_throw(new objj_exception(OBJJUnrecognizedFormatException, "*** Could not recognize executable code format in bundle: "+bundle));
if (stream.version() != 1.0)
objj_exception_throw(new objj_exception(OBJJUnrecognizedFormatException, "*** Could not recognize executable code format."));
objj_exception_throw(new objj_exception(OBJJUnrecognizedFormatException, "*** Could not recognize executable code format in bundle: "+bundle));
var file = NULL,
files = [],
+2 -2
View File
@@ -419,12 +419,12 @@ var _CPDictionaryAppendXMLData = function(XMLData, aDictionary)
var _encodeHTMLComponent = function(aString)
{
return aString.replace('<', "&lt;").replace('>', "&gt;").replace('\"', "&quot;").replace('\'', "&apos;").replace('&', "&amp;");
return aString.replace(/&/g,'&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
var _decodeHTMLComponent = function(aString)
{
return aString.replace("&lt;", '<').replace("&gt;", '>').replace("&quot;", '\"').replace("&apos;", '\'').replace("&amp;", '&');
return aString.replace(/&quot;/g, '"').replace(/&apos;/g, '\'').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
}
var _CPPropertyListAppendXMLData = function(XMLData, aPlist)
+5
View File
@@ -48,6 +48,11 @@ install it and all of its dependencies:
$ sudo ./bootstrap.sh
Editors
------------
The Cappuccino TextMate Bundle: http://github.com/malkomalko/Cappuccino.tmbundle
The Cappuccino Xcode Plugin: http://github.com/rbartolome/xcode-cappuccino
Getting Help
------------
If you need help with Cappuccino, you can get help from the following sources:
+5 -4
View File
@@ -1,12 +1,13 @@
#!/usr/bin/env ruby
print('
puts <<-eos
Building with rake is no longer supported, use "jake" instead.
The commands are all the same (e.g. rake install -> jake install).
If you do not have jake, you can run sudo ./bootstrap.sh to install it and its dependencies.
If you do not have jake, you can run sudo ./bootstrap.sh to install jake and it's dependencies.
PLEASE remove your Build folder ($CAPP_BUILD if it's set) when switching from rake to jake.
eos
PLEASE remove your Build folder when switching from rake to jake.
');
exit(1);
@@ -0,0 +1,33 @@
@import <Foundation/CPFunctionOperation.j>
@implementation SomeObject : CPObject
{
CPString result @accessors;
}
- (CPString)setAString:(CPString)someString
{
result = someString;
return @"Done";
}
@end
@implementation CPFunctionOperationTest : OJTestCase
- (void)testRunInvocation
{
so = [[SomeObject alloc] init];
var someVar = nil;
funcOp = [CPFunctionOperation functionOperationWithFunction:function() {[so setAString:@"Hello World"]}];
[funcOp addExecutionFunction:function() {someVar = 'Soylent Green';}];
[funcOp start];
[self assert:@"Hello World" equals:[so result]];
[self assert:@"Soylent Green" equals:someVar];
}
@end
+2 -2
View File
@@ -283,7 +283,7 @@ function descriptionWithoutEntity(aString)
[self assert:[_set lastIndex] equals:19];
[self assert:[[CPIndexSet indexSet] lastIndex] equals:CPNotFound];
}
/*
- (void)testAddSpeed
{
var startTime = [CPDate date];
@@ -296,7 +296,7 @@ function descriptionWithoutEntity(aString)
print([startTime timeIntervalSinceNow]);
//[self assertTrue: ABS([startTime timeIntervalSinceNow]) < 2];
}
*/
- (void)testIndexGreaterThanIndex
{
[self assert:[_set indexGreaterThanIndex:5] equals:10];
@@ -0,0 +1,30 @@
@import <Foundation/CPInvocationOperation.j>
@implementation SomeObject : CPObject
{
CPString result @accessors;
}
- (CPString)setAString:(CPString)someString
{
result = someString;
return @"Done";
}
@end
@implementation CPInvocationOperationTest : OJTestCase
- (void)testRunInvocation
{
var so = [[SomeObject alloc] init],
io = [[CPInvocationOperation alloc] initWithTarget:so selector:@selector(setAString:) object:@"Hello World"];
[io start];
[self assert:@"Hello World" equals:[so result]];
[self assert:@"Done" equals:[io result]];
}
@end
+152 -24
View File
@@ -160,10 +160,11 @@
bob.name = "paul";
[bob addObserver:self forKeyPath:@"bobName" options:0 context:"testDependentKeyObservation"];
[bob addObserver:self forKeyPath:@"twiceRemoved" options:0 context:"testDependentKeyObservation2"];
[bob setValue:@"bob" forKey:@"name"];
[self assertTrue: _sawDependentObservation message: "asked for bobName but did not recieve corresponding notification"];
[self assertTrue:_sawDependentObservation message:"asked for bobName but did not recieve corresponding notification"];
[self assertTrue: [bob valueForKey:@"bobName"] === @"BOB! set_bob" message: "should have been BOB! set_bob, was "+[bob valueForKey:@"bobName"]];
}
@@ -171,7 +172,7 @@
{
cs101 = [ClassTester new];
bob = [PersonTester new];
[cs101 setTeacher:bob];
[cs101 addObserver:self forKeyPath:@"teacher.name" options:0 context:"testMultipartKey"];
@@ -182,12 +183,26 @@
[self assertTrue: _sawObservation message:"Never recieved an observation"];
}
- (void)testMultiPartKeysWhereValuesEvaluateToSelf
{
focus = [CarTester new];
bob = [PersonTester new];
[bob setValue:focus forKey:"car"];
[bob addObserver:self forKeyPath:@"self.car.thisCar.model" options:0 context:"testMultiPartKeysWhereValuesEvaluateToSelf"];
[focus setValue:"ford focus" forKey:"model"];
[self assertTrue: _sawObservation message:"Never recieved an observation"];
}
- (void)testThreePartKey
{
focus = [CarTester new];
cs101 = [ClassTester new];
bob = [PersonTester new];
[cs101 setTeacher:bob];
[bob setValue:focus forKey:"car"];
@@ -202,7 +217,7 @@
focus = [CarTester new];
cs101 = [ClassTester new];
bob = [PersonTester new];
[cs101 setTeacher:bob];
[focus setValue:"2000" forKey:"year"];
@@ -217,7 +232,7 @@
{
cs101 = [ClassTester new];
bob = [PersonTester new];
[cs101 setTeacher:bob];
[cs101 addObserver:self forKeyPath:@"teacher.name" options:0 context:"testRemoveMultipartKey"];
@@ -234,7 +249,7 @@
focus = [CarTester new];
cs101 = [ClassTester new];
bob = [PersonTester new];
[cs101 setTeacher:bob];
[bob setValue:focus forKey:"car"];
@@ -301,27 +316,53 @@
- (void)testInsertIntoToManyProperty
{
var tester = [ToManyTester new];
[tester setValue:[1, 2, 3, 4] forKey:@"managedObjects"];
[tester addObserver:self forKeyPath:@"managedObjects" options:0 context:"testInsertIntoToManyProperty"];
[tester insertObject:5 inManagedObjectsAtIndex:4];
[self assertTrue: _sawObservation message:"Never recieved an observation"];
}
- (void)testRemoveFromToManyProperty
{
var tester = [ToManyTester new];
[tester setValue:[1, 2, 3, 4] forKey:@"managedObjects"];
[tester addObserver:self forKeyPath:@"managedObjects" options:0 context:"testRemoveFromToManyProperty"];
[tester removeObjectFromManagedObjectsAtIndex:0];
[self assertTrue: _sawObservation message:"Never recieved an observation"];
}
- (void)testInsertIntoToManyPropertyIndirectly
{
var tester = [IndirectToManyTester new];
tester.tester = [ToManyTester new];
[tester.tester setValue:[1, 2, 3, 4] forKey:@"managedObjects"];
[tester addObserver:self forKeyPath:@"tester.managedObjects" options:0 context:"testInsertIntoToManyPropertyIndirectly"];
[tester.tester insertObject:5 inManagedObjectsAtIndex:4];
[self assertTrue: _sawObservation message:"Never recieved an observation"];
}
- (void)testInsertIntoArrayPropertyIndirectly
{
var tester = [IndirectToManyTester new];
tester.tester = [ToManyTester new];
[tester.tester setValue:[1, 2, 3, 4] forKey:@"subviews"];
[tester addObserver:self forKeyPath:@"tester.subviews" options:0 context:"testInsertIntoArrayPropertyIndirectly"];
[tester.tester insertSubview:5 atIndex:4];
[self assertTrue: _sawObservation message:"Never recieved an observation"];
}
@@ -340,7 +381,7 @@
- (void)testPerformance
{
bob = [PersonTester new];
[bob setValue:"initial bob" forKey:"name"];
var startTime = new Date();
@@ -492,29 +533,78 @@
break;
case "testDependentKeyObservation":
[self assertTrue: aKeyPath == "bobName" message: @"expected key value change for bobName, got: "+aKeyPath];
[self assertTrue:aKeyPath === "bobName"
message:@"expected key value change for bobName, got: " + aKeyPath];
[self assertTrue:oldValue === "BOB! paul"
message:@"expected old value of " + aKeyPath + " to be \"BOB! paul\", got: " + oldValue];
_sawDependentObservation = YES;
break;
case "testDependentKeyObservation2":
[self assertTrue:aKeyPath === "twiceRemoved"
message:@"expected key value change for twiceRemoved, got: " + aKeyPath];
[self assertTrue:oldValue === "BOB! paul twice"
message:@"expected old value to be \"BOB! paul twice\", got: " + oldValue];
_sawDependentObservation = YES;
break;
case "testInsertIntoToManyProperty":
var type = [changes objectForKey:CPKeyValueChangeKindKey];
[self assertTrue: type == CPKeyValueChangeInsertion message: "Should have been an insertion, was: "+type];
var values = [changes objectForKey:CPKeyValueChangeNewKey];
[self assertTrue: [values isEqual:[5]] message: "array should have contained 5, was: "+values+" type: "+[values.isa description]+" length: "+values.length];
break;
case "testInsertIntoToManyPropertyIndirectly":
var type = [changes objectForKey:CPKeyValueChangeKindKey];
[self assertTrue: type == CPKeyValueChangeInsertion message: "Should have been an insertion, was: "+type];
var values = [changes objectForKey:CPKeyValueChangeNewKey];
[self assertTrue: [values isEqual:[5]] message: "array should have contained 5, was: "+values+" type: "+[values.isa description]+" length: "+values.length];
[self assert:aKeyPath equals:"tester.managedObjects"];
[self assert:[anObject valueForKeyPath:@"tester.managedObjects"] equals:[1, 2, 3, 4, 5]];
break;
case "testInsertIntoArrayPropertyIndirectly":
var type = [changes objectForKey:CPKeyValueChangeKindKey];
[self assertTrue: type == CPKeyValueChangeInsertion message: "Should have been an insertion, was: "+type];
var values = [changes objectForKey:CPKeyValueChangeNewKey];
[self assertTrue: [values isEqual:[5]] message: "array should have contained 5, was: "+values+" type: "+[values.isa description]+" length: "+values.length];
[self assert:aKeyPath equals:"tester.subviews"];
[self assert:[anObject valueForKeyPath:aKeyPath] equals:[1, 2, 3, 4, 5]];
break;
case "testRemoveFromToManyProperty":
var type = [changes objectForKey:CPKeyValueChangeKindKey];
[self assertTrue: type == CPKeyValueChangeRemoval message: "Should have been a removal, was: "+type];
var values = [changes objectForKey:CPKeyValueChangeOldKey];
[self assertTrue: [values isEqual:[1]] message: "array should have contained 1, was: "+values+" type: "+[values.isa description]+" length: "+values.length];
[[anObject valueForKey:@"managedObjects"] isEqual:[2, 3, 4]];
[self assert:[anObject valueForKey:@"managedObjects"] equals:[2, 3, 4]];
[self assert:aKeyPath equals:"managedObjects"];
break;
case "testMultiPartKeysWhereValuesEvaluateToSelf":
[self assert:aKeyPath equals:"self.car.thisCar.model"];
[self assert:newValue equals:"ford focus"];
[self assert:anObject equals:bob];
break;
default:
[self assertFalse:YES message:"unhandled observation, must be an error"];
return;
@@ -541,6 +631,11 @@
CarTester car;
}
+ (CPSet)keyPathsForValuesAffectingTwiceRemoved
{
return [CPSet setWithObject:"bobName"];
}
+ (CPSet)keyPathsForValuesAffectingBobName
{
return [CPSet setWithObject:"name"];
@@ -553,7 +648,12 @@
- (CPString)bobName
{
return "BOB! "+name;
return "BOB! " + name;
}
- (CPString)twiceRemoved
{
return [self bobName] + " twice";
}
@end
@@ -582,11 +682,39 @@
model = aModel;
}
- (void)thisCar
{
return self;
}
@end
@implementation IndirectToManyTester : CPObject
{
ToManyTester tester @accessors;
}
@end
@implementation ToManyTester : CPObject
{
CPArray managedObjects;
CPArray subviews;
}
- (void)insertSubview:(CPView)aSubview atIndex:(int)anIndex
{
var mutatedIndexes = [CPIndexSet indexSetWithIndex:anIndex];
[self willChange:CPKeyValueChangeInsertion
valuesAtIndexes:mutatedIndexes
forKey:@"subviews"];
[subviews insertObject:aSubview atIndex:anIndex];
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:mutatedIndexes
forKey:@"subviews"];
}
- (unsigned int)countOfManagedObjects
+172
View File
@@ -0,0 +1,172 @@
@import <Foundation/CPOperationQueue.j>
globalResults = [];
@implementation TestOperation : CPOperation
{
CPString name @accessors;
CPString value @accessors;
}
- (void)main
{
[self setName:@"test"];
globalResults.push([self value]);
}
@end
@implementation TestObserver : CPObject
{
CPArray changedKeyPaths @accessors;
}
- (id)init
{
if (self = [super init])
{
changedKeyPaths = [[CPArray alloc] init];
}
return self;
}
// KVO change notification
- (void)observeValueForKeyPath:(CPString)keyPath
ofObject:(id)object
change:(CPDictionary)change
context:(void)context
{
[changedKeyPaths addObject:keyPath];
}
@end
@implementation CPOperationQueueTest : OJTestCase
- (void)testAddOperation
{
var oq = [[CPOperationQueue alloc] init],
to = [[TestOperation alloc] init];
[self assert:0 equals:[oq operationCount]];
[oq addOperation:to];
[self assert:1 equals:[oq operationCount]];
}
- (void)testAddOperationsWithWaitUntilFinished
{
var oq = [[CPOperationQueue alloc] init],
to1 = [[TestOperation alloc] init],
to2 = [[TestOperation alloc] init],
to3 = [[TestOperation alloc] init];
[to3 addDependency:to1];
[to3 addDependency:to2];
[self assert:0 equals:[oq operationCount]];
[oq addOperations:[to1, to2, to3] waitUntilFinished:YES];
//make sure they all ran and are finished...
[self assertTrue:[to1 isFinished]];
[self assertTrue:[to2 isFinished]];
[self assertTrue:[to3 isFinished]];
[self assert:@"test" equals:[to1 name]];
[self assert:@"test" equals:[to2 name]];
[self assert:@"test" equals:[to3 name]];
[self assert:3 equals:[oq operationCount]];
}
- (void)testRunOperationsInCorrectOrder
{
var oq = [[CPOperationQueue alloc] init],
to1 = [[TestOperation alloc] init];
[to1 setQueuePriority:CPOperationQueuePriorityVeryLow];
[to1 setValue:@"very low"];
var to2 = [[TestOperation alloc] init];
[to2 setQueuePriority:CPOperationQueuePriorityVeryHigh];
[to2 setValue:@"very high"];
var to3 = [[TestOperation alloc] init];
[to3 setValue:@"normal"]
var to4 = [[TestOperation alloc] init];
[to4 setQueuePriority:CPOperationQueuePriorityLow];
[to4 setValue:@"low"];
var to5 = [[TestOperation alloc] init];
[to5 setQueuePriority:CPOperationQueuePriorityHigh];
[to5 setValue:@"high"];
var to6 = [[TestOperation alloc] init];
[to6 setValue:@"also normal"];
globalResults = [];
[oq addOperations:[to3, to4, to5, to6] waitUntilFinished:NO];
[oq waitUntilAllOperationsAreFinished];
[self assertTrue:[to3 isFinished]];
[self assertTrue:[to4 isFinished]];
[self assertTrue:[to5 isFinished]];
[self assertTrue:[to6 isFinished]];
[self assert:@"high" equals:globalResults[0]];
[self assert:@"normal" equals:globalResults[1]];
[self assert:@"also normal" equals:globalResults[2]];
[self assert:@"low" equals:globalResults[3]];
globalResults = [];
[oq addOperation:to1];
[oq addOperation:to2];
[oq waitUntilAllOperationsAreFinished];
[self assert:@"very high" equals:globalResults[0]];
[self assert:@"very low" equals:globalResults[1]];
}
- (void)testAddOperationWithFunction
{
var oq = [[CPOperationQueue alloc] init];
globalResults = [];
[oq addOperationWithFunction:function() {globalResults.push("Soylent");}];
[oq waitUntilAllOperationsAreFinished];
[self assert:@"Soylent" equals:globalResults[0]];
}
- (void)testKVO
{
var oq = [[CPOperationQueue alloc] init],
obs = [[TestObserver alloc] init];
[oq addObserver:obs
forKeyPath:@"operations"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[oq addObserver:obs
forKeyPath:@"operationCount"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[oq addObserver:obs
forKeyPath:@"suspended"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[oq addObserver:obs
forKeyPath:@"name"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[oq addOperationWithFunction:function() {globalResults.push("Soylent");}];
[self assert:@"operations" equals:[[obs changedKeyPaths] objectAtIndex:0]];
[self assert:@"operationCount" equals:[[obs changedKeyPaths] objectAtIndex:1]];
[oq setSuspended:YES];
[self assert:@"suspended" equals:[[obs changedKeyPaths] objectAtIndex:2]];
[oq setSuspended:NO];
[self assert:@"suspended" equals:[[obs changedKeyPaths] objectAtIndex:3]];
[oq setName:@"Soylent"];
[self assert:@"name" equals:[[obs changedKeyPaths] objectAtIndex:4]];
}
@end
+185
View File
@@ -0,0 +1,185 @@
@import <Foundation/CPOperation.j>
@implementation TestOperation : CPOperation
{
CPString name @accessors;
CPString value @accessors;
}
- (void)main
{
[self setName:@"test"];
}
@end
@implementation TestObserver : CPObject
{
CPArray changedKeyPaths @accessors;
}
- (id)init
{
if (self = [super init])
{
changedKeyPaths = [[CPArray alloc] init];
}
return self;
}
// KVO change notification
- (void)observeValueForKeyPath:(CPString)keyPath
ofObject:(id)object
change:(CPDictionary)change
context:(void)context
{
[changedKeyPaths addObject:keyPath];
}
@end
@implementation CPOperationTest : OJTestCase
- (void)testAddDependency
{
var co = [[CPOperation alloc] init],
co_dep = [[CPOperation alloc] init];
[co addDependency:co_dep];
[self assert:1 equals:[[co dependencies] count]];
}
- (void)testRemoveDependency
{
var co = [[CPOperation alloc] init],
co_dep1 = [[CPOperation alloc] init],
co_dep2 = [[CPOperation alloc] init];
[co addDependency:co_dep1];
[co addDependency:co_dep2];
[self assert:2 equals:[[co dependencies] count]];
[co removeDependency:co_dep2];
[self assert:1 equals:[[co dependencies] count]];
[co removeDependency:co_dep2];
[self assert:1 equals:[[co dependencies] count]];
[co removeDependency:co_dep1];
[self assert:0 equals:[[co dependencies] count]];
}
- (void)testCorrectValuesOnInit
{
var co = [[CPOperation alloc] init];
[self assertTrue:[co isReady]];
[self assertFalse:[co isCancelled]];
[self assertFalse:[co isConcurrent]];
[self assertFalse:[co isFinished]];
[self assertFalse:[co isExecuting]];
[self assert:CPOperationQueuePriorityNormal equals:[co queuePriority]];
}
- (void)testIsReadyWithDependencies
{
var co = [[CPOperation alloc] init],
co_dep1 = [[CPOperation alloc] init],
co_dep2 = [[CPOperation alloc] init];
[self assertTrue:[co isReady]];
[co addDependency:co_dep1];
[co addDependency:co_dep2];
[self assertFalse:[co isReady]];
[co_dep1 start];
[self assertFalse:[co isReady]];
[co_dep2 start];
[self assertTrue:[co isReady]];
}
- (void)testCompletionFunction
{
var to = [[TestOperation alloc] init];
[to setCompletionFunction:function() {[to setValue:@"something"];}];
[to start];
[self assert:@"something" equals:[to value]];
}
// KVO Tests
- (void)testKVO
{
var to = [[TestOperation alloc] init],
to2 = [[TestOperation alloc] init],
obs = [[TestObserver alloc] init];
[to addObserver:obs
forKeyPath:@"isCancelled"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addObserver:obs
forKeyPath:@"isExecuting"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addObserver:obs
forKeyPath:@"isFinished"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addObserver:obs
forKeyPath:@"isReady"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addObserver:obs
forKeyPath:@"dependencies"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addObserver:obs
forKeyPath:@"queuePriority"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addObserver:obs
forKeyPath:@"completionFunction"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[to addDependency:to2];
[self assert:@"dependencies" equals:[[obs changedKeyPaths] objectAtIndex:0]];
[self assert:@"isReady" equals:[[obs changedKeyPaths] objectAtIndex:1]];
[to2 start];
[self assert:@"isReady" equals:[[obs changedKeyPaths] objectAtIndex:2]];
[to removeDependency:to2];
[self assert:@"dependencies" equals:[[obs changedKeyPaths] objectAtIndex:3]];
[to setQueuePriority:CPOperationQueuePriorityHigh];
[self assert:@"queuePriority" equals:[[obs changedKeyPaths] objectAtIndex:4]];
[to setCompletionFunction:function() {}];
[self assert:@"completionFunction" equals:[[obs changedKeyPaths] objectAtIndex:5]];
// this should set executing = yes, executing = no, finished = yes.
[to start];
[self assert:@"isExecuting" equals:[[obs changedKeyPaths] objectAtIndex:6]];
[self assert:@"isExecuting" equals:[[obs changedKeyPaths] objectAtIndex:7]];
[self assert:@"isFinished" equals:[[obs changedKeyPaths] objectAtIndex:8]];
[to cancel];
[self assert:@"isCancelled" equals:[[obs changedKeyPaths] objectAtIndex:9]];
}
@end
@@ -1 +0,0 @@
.svn
@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>#!/usr/bin/env ruby
proto_re = /
^\s* # Start of the line and optional space
[+-]\s* # a plus or minus for method specifier
\([^)]+\) # the return type in brackets
((?:\n|[^{])*)
(?m:.*?)
\{
/x
previous_lines = STDIN.readlines[1..ENV['TM_LINE_NUMBER'].to_i - 1]
invocation_line = previous_lines[-1]
proto = previous_lines.join.scan(proto_re)[-1]
exit if proto.nil? or proto.empty?
last_proto_sel_with_types = proto[0].strip.sub(/^\s+/, '').sub(%r{\s*//.*$}, '').gsub(/\n\s*/, ' ')
params = []
params = last_proto_sel_with_types.scan(/(.+?):\((.+?)\)(\w+)/)
def format_specifier_for_type(type)
%w[int bool BOOL long].each { |t| return('%d') if type.include? t }
return '%c' if type == 'char'
return '%C' if type == 'unichar'
return '%s' if type == 'char*'
'%@'
end
def transformer_for(type, name)
return "CPStringFromRect(#{name})" if type == 'CPRect'
return "CPStringFromPoint(#{name})" if type == 'CPPoint'
return "CPStringFromSize(#{name})" if type == 'CPSize'
return "CPStringFromSelector(#{name})" if type == 'SEL'
name
end
print 'CPLog("[%@ '
if params.empty?
print last_proto_sel_with_types
else
print params.map { |param, type, name| param + ':' + format_specifier_for_type(type) }.join
end
print ']", [self class]'
print ', ' + params.map { |param, type, name| transformer_for(type, name) }.join(', ') unless params.empty?
print ");"
</string>
<key>input</key>
<string>document</string>
<key>name</key>
<string>CPLog() for Current Method</string>
<key>output</key>
<string>insertAsSnippet</string>
<key>scope</key>
<string>source.js.objj meta.scope.implementation</string>
<key>tabTrigger</key>
<string>logm</string>
<key>uuid</key>
<string>F220FEE6-6522-4281-8091-CF8C66AED44F</string>
</dict>
</plist>
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>
. "$TM_SUPPORT_PATH/lib/webpreview.sh"
html_header "Objective-J Bundle Help" "Objective-J"
"$TM_SUPPORT_PATH/lib/markdown_to_help.rb" "$TM_BUNDLE_SUPPORT/help/help.markdown"
html_footer</string>
<key>input</key>
<string>none</string>
<key>keyEquivalent</key>
<string></string>
<key>name</key>
<string>Help</string>
<key>output</key>
<string>showAsHTML</string>
<key>scope</key>
<string>source.js.objj</string>
<key>uuid</key>
<string>AF27A8B3-C87F-410A-915B-D83271FDDC00</string>
</dict>
</plist>
@@ -1,320 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>bundleUUID</key>
<string>4679484F-6227-11D9-BFB1-000D93589AF6</string>
<key>command</key>
<string>#!/usr/bin/env ruby
require "#{ENV['TM_SUPPORT_PATH']}/lib/escape"
require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes"
class Lexer
include Enumerable
def initialize
@label = nil
@pattern = nil
@handler = nil
@input = nil
reset
yield self if block_given?
end
def input(&amp;reader)
if @input.is_a? self.class
@input.input(&amp;reader)
else
class &lt;&lt; reader
alias_method :next, :call
end
@input = reader
end
end
def add_token(label, pattern, &amp;handler)
unless @label.nil?
@input = clone
end
@label = label
@pattern = /(#{pattern})/
@handler = handler || lambda { |label, match| [label, match] }
reset
end
def next(peek = false)
while @tokens.empty? and not @finished
new_input = @input.next
if new_input.nil? or new_input.is_a? String
@buffer += new_input unless new_input.nil?
new_tokens = @buffer.split(@pattern)
while new_tokens.size &gt; 2 or (new_input.nil? and not new_tokens.empty?)
@tokens &lt;&lt; new_tokens.shift
@tokens &lt;&lt; @handler[@label, new_tokens.shift] unless new_tokens.empty?
end
@buffer = new_tokens.join
@finished = true if new_input.nil?
else
separator, new_token = @buffer.split(@pattern)
new_token = @handler[@label, new_token] unless new_token.nil?
@tokens.push( *[ separator,
new_token,
new_input ].select { |t| not t.nil? and t != "" } )
reset(:buffer)
end
end
peek ? @tokens.first : @tokens.shift
end
def peek
self.next(true)
end
def each
while token = self.next
yield token
end
end
private
def reset(*attrs)
@buffer = String.new if attrs.empty? or attrs.include? :buffer
@tokens = Array.new if attrs.empty? or attrs.include? :tokens
@finished = false if attrs.empty? or attrs.include? :finished
end
end
class ObjcParser
attr_reader :list
def initialize(args)
@list = args
end
def get_position
return nil,nil if @list.empty?
has_message = true
a = @list.pop
endings = [:close,:post_op,:at_string,:at_selector,:identifier]
openings = [:open,:return,:control]
if a.tt == :identifier &amp;&amp; !@list.empty? &amp;&amp; endings.include?(@list[-1].tt)
insert_point = find_object_start
else
@list &lt;&lt; a
has_message = false unless methodList
insert_point = find_object_start
end
return insert_point, has_message
end
def methodList
old = Array.new(@list)
a = selector_loop(@list)
if !a.nil? &amp;&amp; a.tt == :selector
if file_contains_selector? a.text
return true
else
internal = Array.new(@list)
b = a.text
until internal.empty?
tmp = selector_loop(internal)
return true if tmp.nil?
b = tmp.text + b
if file_contains_selector? b
@list = internal
return true
end
end
end
else
end
@list = old
return false
end
def file_contains_selector?(methodName)
fileNames = ["#{ENV['TM_BUNDLE_SUPPORT']}/cocoa.txt.gz"]
userMethods = "#{ENV['TM_PROJECT_DIRECTORY']}/.methods.TM_Completions.txt.gz"
fileNames += [userMethods] if File.exists? userMethods
candidates = []
fileNames.each do |fileName|
zGrepped = %x{zgrep ^#{e_sh methodName }[[:space:]] #{e_sh fileName }}
candidates += zGrepped.split("\n")
end
return !candidates.empty?
end
def selector_loop(l)
until l.empty?
obj = l.pop
case obj.tt
when :selector
return obj
when :close
return nil if match_bracket(obj.text,l).nil?
when :open
return nil
end
end
return nil
end
def match_bracket(type,l)
partner = {"]"=&gt;"[",")"=&gt;"(","}"=&gt;"{"}[type]
up = 1
until l.empty?
obj = l.pop
case obj.text
when type
up +=1
when partner
up -=1
end
return obj.beg if up == 0
end
end
def find_object_start
openings = [:operator,:selector,:open,:return,:control]
until @list.empty? || openings.include?(@list[-1].tt)
obj = @list.pop
case obj.tt
when :close
tmp = match_bracket(obj.text, @list)
b = tmp unless tmp.nil?
when :star
b, ate = eat_star(b,obj.beg)
return b unless ate
when :nil
b = nil
else
b = obj.beg
end
end
return b
end
def eat_star(prev, curr)
openings = [:operator,:selector,:open,:return,:control,:star]
if @list.empty? || openings.include?(@list[-1].tt)
return curr, true
else
return prev, false
end
end
end
if __FILE__ == $PROGRAM_NAME
require "stringio"
line = ENV['TM_CURRENT_LINE']
caret_placement =ENV['TM_LINE_INDEX'].to_i - 1
up = 0
pat = /"(?:\\.|[^"\\])*"|\[|\]/
line.scan(pat).each do |item|
case item
when "["
up+=1
when "]"
up -=1
end
end
if caret_placement ==-1
print "]$0" + e_sn(line[caret_placement+1..-1])
TextMate.exit_insert_snippet
end
if up != 0
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
TextMate.exit_insert_snippet
end
to_parse = StringIO.new(line[0..caret_placement])
lexer = Lexer.new do |l|
l.add_token(:return, /\breturn\b/)
l.add_token(:nil, /\bnil\b/)
l.add_token(:control, /\b(?:if|while|for|do)(?:\s*)\(/)# /\bif|while|for|do(?:\s*)\(/)
l.add_token(:at_string, /"(?:\\.|[^"\\])*"/)
l.add_token(:selector, /\b[A-Za-z_0-9]+:/)
l.add_token(:identifier, /\b[A-Za-z_0-9]+\b/)
l.add_token(:bind, /(?:-&gt;)|\./)
l.add_token(:post_op, /\+\+|\-\-/)
l.add_token(:at, /@/)
l.add_token(:star, /\*/)
l.add_token(:close, /\)|\]|\}/)
l.add_token(:open, /\(|\[|\{/)
l.add_token(:operator, /[&amp;-+\/=%!:\,\?;&lt;&gt;\|\~\^]/)
l.add_token(:terminator, /;\n*|\n+/)
l.add_token(:whitespace, /\s+/)
l.add_token(:unknown, /./)
l.input { to_parse.gets }
#l.input {STDIN.read}
end
offset = 0
tokenList = []
A = Struct.new(:tt, :text, :beg)
lexer.each do |token|
tokenList &lt;&lt; A.new(*(token&lt;&lt;offset)) unless [:whitespace,:terminator].include? token[0]
offset +=token[1].length
end
if tokenList.empty?
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
TextMate.exit_insert_snippet
end
par = ObjcParser.new(tokenList)
b, has_message = par.get_position
if !line[caret_placement+1].nil? &amp;&amp; line[caret_placement+1].chr == "]"
if b.nil? || par.list.empty? || par.list[-1].text == "["
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+2..-1])
TextMate.exit_insert_snippet
end
end
if b.nil?
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
elsif !has_message &amp;&amp; (b &lt; caret_placement )
print e_sn(line[0..b-1]) unless b == 0
ins = (/\s/ =~ line[caret_placement].chr ? "$0]" : " $0]")
print "[" +e_sn(line[b..caret_placement]) + ins +e_sn(line[caret_placement+1..-1])
elsif b &lt; caret_placement
print e_sn(line[0..b-1]) unless b == 0
print "[" +e_sn(line[b..caret_placement]) +"]$0"+e_sn(line[caret_placement+1..-1])
else
print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
end
end
</string>
<key>fallbackInput</key>
<string>line</string>
<key>input</key>
<string>selection</string>
<key>keyEquivalent</key>
<string>]</string>
<key>name</key>
<string>Insert Matching Start Bracket</string>
<key>output</key>
<string>insertAsSnippet</string>
<key>scope</key>
<string>source.js.objj</string>
<key>uuid</key>
<string>CD025B3E-36B9-4E16-A81E-8DB6E8466CD1</string>
</dict>
</plist>
@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>#!/usr/bin/env ruby
def e (str); str.gsub(/[$`\\]/, '\\\\\0'); end
line = STDIN.read
col = ENV['TM_LINE_INDEX'].to_i
left, right = line[0...col], line[col..-1]
if left =~ /(.*?)(\[)?(\w+)\s+$/ then
lead, bracket, cl = $1, $2, $3
right = line[col+1..-1] unless bracket.nil?
print "#{e lead}${1/.+/[/}[[#{e cl} alloc] init$0]"
print right.empty? ? ";" : "#{e right}"
else
# this is only if we were not able to interpret the line
print "#{e left}$0#{e right}"
end
</string>
<key>fallbackInput</key>
<string>line</string>
<key>input</key>
<string>selection</string>
<key>name</key>
<string>Insert [[… alloc] init]</string>
<key>output</key>
<string>insertAsSnippet</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>alloc</string>
<key>uuid</key>
<string>DF55A80D-E733-4CE2-A318-D56789B18406</string>
</dict>
</plist>
@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>#!/usr/bin/env ruby -wKU
#
# Open Document in Running Browser(s)
# v3 - November 22, 2007
#
# Now supports multiple running versions of a single browser along
# with a range of new/old browsers. Bring back support for Firefox.
#
# Options: Set TM_PROJECT_SITEURL in your TM Project Window Info Button
# in the following form: "http://example.com/"
require "#{ENV['TM_SUPPORT_PATH']}/lib/escape.rb"
if ENV['TM_PROJECT_SITEURL']
url = "#{ENV['TM_PROJECT_SITEURL']}" + ENV['TM_FILEPATH'].sub(/^#{Regexp.escape(ENV['TM_PROJECT_DIRECTORY'])}\//, '')
else
url = "file://#{ENV['TM_PROJECT_DIRECTORY']}/index.html"
end
proclist = `ps -x -o command`
active = []
os = `defaults read /System/Library/CoreServices/SystemVersion ProductVersion`
browsers = %w[ Safari OmniWeb Camino Shiira firefox-bin Xyle\ scope Opera Internet\ Explorer flock-bin iCab Sunrise seamonkey-bin navigator-bin ].join('|')
# Build paths to each active browser
#
# Notes:
# - 'WebKit' look ahead is to rule it out so we can use the working
# rule below.
# - 'LaunchCFMApp' portion is so iCab works.
active = proclist.scan(%r{^(?:/.*LaunchCFMApp )?(/.*\.app)(?=/Contents/MacOS/(?:#{browsers})\b(?!\s-WebKit))})
# Special check for WebKit as it appears as Safari
# Note: Only supports one running instance of WebKit, picked at random.
if proclist =~ %r{/Contents/MacOS/Safari.*-WebKit(DeveloperExtras|ScriptDebuggerEnabled)}
active &lt;&lt; "WebKit"
end
# TODO: Change when Leopard Only
# On Leopard use the -g option to open in background.
if os =~ /^10\.(5|6)/
active.each {|p| `open -g -a #{e_sh(p)} #{e_sh(url)}` }
else
active.each {|p| `open -a #{e_sh(p)} #{e_sh(url)}` }
end</string>
<key>input</key>
<string>none</string>
<key>keyEquivalent</key>
<string>@R</string>
<key>name</key>
<string>Run in Browsers</string>
<key>output</key>
<string>discard</string>
<key>scope</key>
<string>source.js.objj</string>
<key>uuid</key>
<string>36FD3695-1051-401E-8536-89FB9CEEEAB4</string>
</dict>
</plist>
@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>### Refresh All Active Browsers - OmniWeb, Safari, Firefox &amp; IE
### v1.0. 2005-03-29
###
# Check if Internet Explorer is running, if so refresh
ps -xc|grep -sq "Internet Explorer" &amp;&amp; osascript -e 'tell app "Internet Explorer"' -e 'activate' -e 'OpenURL "JavaScript:window.location.reload();" toWindow -1' -e 'end tell'
# Check if OmniWeb is running, if so refresh
ps -xc|grep -sq OmniWeb &amp;&amp; osascript -e 'tell app "OmniWeb"' -e 'activate' -e 'reload first browser' -e 'end tell'
# Check if Firefox is running, if so refresh
ps -xc|grep -sqi firefox &amp;&amp; osascript &lt;&lt;'APPLESCRIPT'
tell app "Firefox" to activate
tell app "System Events"
if UI elements enabled then
keystroke "r" using command down
-- Fails if System Preferences &gt; Universal access &gt; "Enable access for assistive devices" is not on
else
tell app "Firefox" to Get URL "JavaScript:window.location.reload();" inside window 1
-- Fails if Firefox is set to open URLs from external apps in new tabs.
end if
end tell
APPLESCRIPT
# Check if Safari is running, if so refresh
ps -xc|grep -sq Safari &amp;&amp; osascript -e 'tell app "Safari"' -e 'activate' -e 'do JavaScript "window.location.reload();" in first document' -e 'end tell'
# Check if Camino is running, if so refresh
ps -xc|grep -sq Camino &amp;&amp; osascript -e 'tell app "Camino"' -e 'activate' -e 'tell app "System Events" to keystroke "r" using {command down}' -e 'end tell'
</string>
<key>input</key>
<string>none</string>
<key>name</key>
<string>Refresh Running Browser(s)</string>
<key>output</key>
<string>discard</string>
<key>scope</key>
<string>source.js.objj</string>
<key>uuid</key>
<string>033BC36A-97DA-4F48-9ACB-B58C80D1A689</string>
</dict>
</plist>
@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>saveActiveFile</string>
<key>command</key>
<string>
[[ ! -z $TM_OBJJ_MASTER_FILE ]] &amp;&amp; INDEXFILE="$TM_OBJJ_MASTER_FILE"
[[ ! -z $TM_PROJECT_DIRECTORY ]] &amp;&amp; INDEXFILE="$TM_PROJECT_DIRECTORY/index.html"
[[ ! -z $TM_DIRECTORY ]] &amp;&amp; INDEXFILE="$TM_DIRECTORY/index.html"
if [ -z "$INDEXFILE" ]; then
D=`dirname "$TM_FILEPATH"`
while [ -z `find "$D" -name index.html` ]; do
D=`dirname "$D"`
done
INDEXFILE="${D}/index.html"
fi
[[ -z $INDEXFILE ]] &amp;&amp; echo "No start file found. Please set the shell variable 'OBJJ_MASTER_FILE'" &amp;&amp; exit 206
cat &lt;&lt;-HTML
&lt;script type="text/javascript" charset="utf-8"&gt;
try {
if (TextMate.system("", function (task) { })) {
var __TM_confirm_Status;
alert = function(s){TextMate.system("\"$DIALOG\" -e -p '{messageTitle=\"JavaScript\";informativeText=\""+s.toString().replace(/\x27/g,"").replace(/\"/g,'\\\"')+"\";}'",null);};
confirm = function(s){TextMate.system("\"$DIALOG\" -e -p '{messageTitle=\"JavaScript\";informativeText=\""+s.toString().replace(/\x27/g,"").replace(/\"/g,'\\\"')+"\";buttonTitles=(\"OK\",\"Cancel\");}'",null).onreadoutput=function(s){__TM_confirm_Status = s != 1;};return(__TM_confirm_Status)};
}
} catch(e) {}
&lt;/script&gt;
&lt;base href="file://${INDEXFILE// /%20}"&gt;
HTML
cat "$INDEXFILE"
[[ ! -z $(grep 'objj_exception_setOutputStream' "$INDEXFILE") ]] &amp;&amp; exit 205
cat &lt;&lt;-JS
&lt;script type="text/javascript" charset="utf-8"&gt;
objj_exception_setOutputStream(function(aString) { console.log(aString);alert(aString) });
&lt;/script&gt;
JS
exit 205
</string>
<key>input</key>
<string>none</string>
<key>keyEquivalent</key>
<string>@r</string>
<key>name</key>
<string>Run</string>
<key>output</key>
<string>showAsTooltip</string>
<key>scope</key>
<string>source.js.objj</string>
<key>uuid</key>
<string>0C55A19B-3B2D-418F-B7FD-7E64B736F379</string>
</dict>
</plist>
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>cat &lt;&lt;-HTM
&lt;body onload='javascript:window.location.href="http://cappuccino.org/learn/documentation/"'&gt;
&lt;/body&gt;
HTM
exit 205
</string>
<key>input</key>
<string>none</string>
<key>keyEquivalent</key>
<string>^H</string>
<key>name</key>
<string>Show Documentation</string>
<key>output</key>
<string>showAsTooltip</string>
<key>scope</key>
<string>source.js.objj</string>
<key>uuid</key>
<string>344244D8-67A3-4F23-8270-397BD1696AC4</string>
</dict>
</plist>
@@ -1,214 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>nop</string>
<key>command</key>
<string>[[ -z $OBJJ_HOME ]] &amp;&amp; echo "OBJJ_HOME wasn't set!" &amp;&amp; exit 206
[[ ! -d "$OBJJ_HOME/Documentation" ]] &amp;&amp; echo "Please copy the folder Documentation to $OBJJ_HOME" &amp;&amp; exit 206
function showUpClassPage {
cat &lt;&lt;-HTM
&lt;body onload='javascript:window.location.href="tm-file://$OBJJ_HOME/Documentation/class$1"'&gt;
&lt;/body&gt;
HTM
exit 205
}
function showUpPage {
cat &lt;&lt;-HTM
&lt;body onload='javascript:window.location.href="tm-file://$1"'&gt;
&lt;/body&gt;
HTM
exit 205
}
DOCHEAD=$(perl -e '
#$line_nr = defined($ENV{"TM_INPUT_START_LINE"}) ? $ENV{"TM_INPUT_START_LINE"} : 1;
$line_nr = 1;
$cur_line_nr = $ENV{"TM_LINE_NUMBER"};
$header = "";
while($cur_line_nr--&gt;$line_nr) {$header.=&lt;&gt;;}
$tail = &lt;&gt;;
$header .= substr($tail,0,$ENV{"TM_LINE_INDEX"});
print $header;
')
# caret is inside of a class name
if [ `echo $TM_SCOPE | grep -c 'support.class.cappuccino'` -gt 0 ]; then
n=$(echo $TM_CURRENT_WORD | perl -pe 's/(.)(.)(.*)/_$1_$2_$3/;s/(?&lt;!_)([A-Z])(?!_)/_$1/g;s/_{2,}/_/g')
showUpClassPage "$n.html"
fi
# caret is inside of a foundation class name
if [ `echo $TM_SCOPE | grep -c 'support.variable.cappuccino.foundation'` -gt 0 ]; then
[[ "$TM_CURRENT_WORD" == "CPApp" ]] &amp;&amp; showUpClassPage "_C_P_Application.html"
fi
# caret is inside of a objj function
if [ `echo $TM_SCOPE | grep -c 'support.function.cappuccino'` -gt 0 ]; then
FILE=$(ruby -e '
require File.join(ENV["TM_SUPPORT_PATH"], "lib/ui.rb")
require File.join(ENV["TM_SUPPORT_PATH"], "lib/exit_codes.rb")
cur_word = ""
cur_word &lt;&lt; ENV["TM_CURRENT_WORD"]
cur_word.sub!("CG", "C[GP]") if cur_word[0..1] == "CG" or cur_word[0..1] == "CP"
lg = %x{egrep -rl "C[GP]RectMake" '$OBJJ_HOME/Documentation'}
urls = lg.split(/\n/).sort
if urls.length == 1
print urls.first
else
display = urls.map{|x| x.split("/").last.sub!(".html","")}
index=TextMate::UI.menu(display)
if index != nil
print urls[index]
else
TextMate.exit_discard()
end
end
')
FUNC=$(echo -en $TM_CURRENT_WORD | perl -pe 's/^(C[PG])(.*)/C[PG]$2/')
ANKER=`cat "$FILE" | egrep -o "\"#$FUNC.*?\"" | sed -e 's/^"//;s/".*//' | head -n 1`
[[ ! -z "$ANKER" ]] &amp;&amp; showUpPage "$FILE$ANKER"
[[ ! -z $FILE ]] &amp;&amp; showUpPage "$FILE" &amp;&amp; exit 206
fi
# caret is inside of a constant
if [ `echo $TM_SCOPE | grep -c 'support.constant.cappuccino'` -gt 0 ]; then
FILE=$(ruby -e '
require File.join(ENV["TM_SUPPORT_PATH"], "lib/ui.rb")
require File.join(ENV["TM_SUPPORT_PATH"], "lib/exit_codes.rb")
lg = %x{egrep -rl #{ENV["TM_CURRENT_WORD"]} '$OBJJ_HOME/Documentation'}
urls = lg.split(/\n/).sort
if urls.length == 1
print urls.first
else
display = urls.map{|x| x.split("/").last.sub!(".html","")}
index=TextMate::UI.menu(display)
if index != nil
print urls[index]
else
TextMate.exit_discard()
end
end
')
[[ ! -z $FILE ]] &amp;&amp; showUpPage "$FILE" &amp;&amp; exit 206
fi
# caret is inside of [method]
if [ `echo $TM_SCOPE | grep -c 'meta.bracketed.js.objj'` -gt 0 ]; then
# find []
DECL=$(echo -en "$DOCHEAD" | perl -e '
undef $/;
$header = &lt;&gt;;
$header=~s/\n/ /g;
@arr=split(//,$header);$c=0;
for($i=$#arr;$i&gt;-1;$i--){$c-- if($arr[$i] eq "]");$c++ if($arr[$i] eq "[");last if $c&gt;0;}
if($i==-1) {
print "";
} else {
print substr($header,$i+1);
}
')
# find the class for a method
CLASS=$(echo -en "$DECL" | perl -e '
undef $/;
$header = &lt;&gt;;
substr($header,0) =~ m/^\s*(\w+).*/;
$f = $1;
if (defined($f)) {
if($f=~m/CPApp/) {
print "CPApplication";
} else {
print $f;
}
} else {
substr($header,1) =~ m/^\s*(\w+).*/;
$f = $1;
if(defined($f)) {
if($f=~m/CPApp/) {
print "CPApplication";
} else {
print $f;
}
}
}
')
if [ ! -e "$OBJJ_HOME/Documentation/classes/$CLASS.html" ]; then
CLASS=$(echo -en "$DOCHEAD" | ruby -e '
require File.join(ENV["TM_SUPPORT_PATH"], "lib/ui.rb")
require File.join(ENV["TM_SUPPORT_PATH"], "lib/exit_codes.rb")
known_classes = []
classes = []
lg = %x{cd '$OBJJ_HOME/Documentation/classes'; egrep -rl #{ENV["TM_CURRENT_WORD"]} .}
known_classes = lg.split(/\n/).map{|x| x.sub("\.html","").sub("./","") }.sort
if known_classes.empty?
lg = %x{ls '$OBJJ_HOME/Documentation/classes'}
known_classes = lg.split(/\n/).map{|x| x.sub("\.html","").sub("./","") }.sort
end
STDIN.read().scan(/\b[_]{0,2}[NC][APS]\w+(?=[^\.])\b/) {|c| classes &lt;&lt; c if ! classes.include?(c) &amp;&amp; known_classes.include?(c)}
classes.sort!
if classes != known_classes
classes &lt;&lt; "--"
classes += known_classes
end
if classes.length == 1
if classes.first != "--"
print classes.first
else
TextMate.exit_discard()
end
else
index=TextMate::UI.menu(classes)
if index != nil
print classes[index]
else
TextMate.exit_discard()
end
end
')
fi
[[ -z $CLASS ]] &amp;&amp; exit 200
[[ ! -e "$OBJJ_HOME/Documentation/classes/$CLASS.html" ]] &amp;&amp; echo "Nothing for '$CLASS'!" &amp;&amp; exit 206
# tries to find only the first method for 'method1: method2: etc'
FIRSTMETHOD=$(echo -en "$DECL" | perl -e '
undef $/;$d = &lt;&gt;;
$d=~m/\s*(\w+):/m;
print $1;
')
METHOD=${FIRSTMETHOD:-$TM_CURRENT_WORD}
# find the correct anker within CLASS.html
ANKER=`cat "$OBJJ_HOME/Documentation/classes/$CLASS.html" | egrep -o "\"#$METHOD.*?\"" | sed -e 's/^"//;s/".*//' | head -n 1`
[[ ! -z "$ANKER" ]] &amp;&amp; showUpClassPage "$CLASS.html$ANKER"
# check for inherited methods
ANKER=`cat "$OBJJ_HOME/Documentation/classes/$CLASS.html" | egrep -o "[^#\"]+?html#$METHOD" | head -n 1`
# echo $CLASS; echo $METHOD; echo $ANKER; exit 206
CLASS=$(echo -en "$ANKER" | perl -pe 's/(.*?)\.html.*/$1/;')
# find the correct anker within the new CLASS.html
ANKER=`cat "$OBJJ_HOME/Documentation/classes/$CLASS.html" | egrep -o "\"#$METHOD.*?\"" | sed -e 's/^"//;s/".*//' | head -n 1`
[[ ! -z "$ANKER" ]] &amp;&amp; showUpClassPage "$CLASS.html$ANKER"
# [[ ! -z "$ANKER" ]] &amp;&amp; showUpClassPage "$ANKER"
fi
exit 205</string>
<key>input</key>
<string>selection</string>
<key>keyEquivalent</key>
<string>^h</string>
<key>name</key>
<string>Documentation for Word</string>
<key>output</key>
<string>replaceSelectedText</string>
<key>scope</key>
<string>support.class.cappuccino, support.variable.cappuccino.foundation, meta.bracketed.js.objj, support.function.cappuccino</string>
<key>uuid</key>
<string>2D05A28A-2ED7-4A9A-9A5C-8625466BC77C</string>
</dict>
</plist>
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>Symbol List: Method</string>
<key>scope</key>
<string>meta.function.js.objj</string>
<key>settings</key>
<dict>
<key>showInSymbolList</key>
<integer>1</integer>
<key>symbolTransformation</key>
<string>
s/^([-+])\s*\(.*?\)\s*/$1 /; # strip result type
s/:\s*\(.*?\)\s*\w+\s*/:/g; # strip argument variables
s/\s*;?$//g; # strip terminating ws + semi-colon
</string>
</dict>
<key>uuid</key>
<string>E65A721C-192D-4BCC-AD35-5ED5CB0DA5BE</string>
</dict>
</plist>
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@selector(${1:method}:)</string>
<key>name</key>
<string>@selector(…)</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>sel</string>
<key>uuid</key>
<string>13D9F280-A78F-4A4C-BE99-0DE13235738D</string>
</dict>
</plist>
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>- (${1:id})${2:thing}
{
return $2;
}
- (void)set${2/./\u$0/}:($1)aValue
{
$2 = aValue;
}</string>
<key>name</key>
<string>Accessors</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>acc</string>
<key>uuid</key>
<string>AA41BEF8-5F81-4A5A-85DE-2E81A112778B</string>
</dict>
</plist>
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@implementation ${1:CLASS} (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
${2:IVAR} = [aCoder decodeObjectForKey:${3:KEY}];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:${2:IVAR} forKey:${3:KEY}];
}
@end
</string>
<key>name</key>
<string>Archiving</string>
<key>uuid</key>
<string>A840A98A-0C5B-49CB-8235-2CCD1BF7AFC1</string>
</dict>
</plist>
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>CPLog("$1"${1/[^%]*(%)?.*/(?1:, :\);)/}$2${1/[^%]*(%)?.*/(?1:\);)/}</string>
<key>name</key>
<string>CPLog(…)</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>log</string>
<key>uuid</key>
<string>C268A928-5C8E-4284-9BAB-4FDFB07B983A</string>
</dict>
</plist>
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@interface ${1:NSObject} (${2:Category})
@end
@implementation ${1:NSObject} (${2:Category})
$0
@end</string>
<key>name</key>
<string>Category</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>cat</string>
<key>uuid</key>
<string>8C001067-8A50-4BAB-9A88-BA957A84E8CF</string>
</dict>
</plist>
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@implementation ${1:class} : ${2:CPObject}
{
}
- (id)init
{
if(self = [super init])
{$0
}
return self;
}
@end
</string>
<key>name</key>
<string>Class</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>objj</string>
<key>uuid</key>
<string>96C39647-4346-4750-9F96-58070F24EDE6</string>
</dict>
</plist>
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>if([${1:[self delegate]} respondsToSelector:@selector(${2:selfDidSomething:})])
[$1 ${3:${2/((^\s*([A-Za-z0-9_]*:)\s*)|(:\s*$)|(:\s*))/(?2:$2self :\:&lt;&gt;)(?4::)(?5: :)/g}}];
</string>
<key>name</key>
<string>Delegate Responds to Selector</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>delegate</string>
<key>uuid</key>
<string>3B5B858C-645E-499C-813B-BBEEED943E9B</string>
</dict>
</plist>
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>- (id)delegate
{
return $1;
}
- (void)setDelegate:(id)aDelegate
{
${1:delegate} = aDelegate;
}</string>
<key>name</key>
<string>Delegate</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>delacc</string>
<key>uuid</key>
<string>0B3D4C4C-7D75-49E6-9CEC-E4BF4069223A</string>
</dict>
</plist>
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>${1:name} = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[$1 setStringValue:${2:@"${3:string}"}];
${4:[$1 setEditable:${5:YES}];
}${6:[$1 setFont:[CPFont systemFontOfSize:${7:12.0}]];
}${8:[$1 sizeToFit];
}${0:}</string>
<key>name</key>
<string>New CPTextField</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>textf</string>
<key>uuid</key>
<string>C7340B17-F9EC-403F-9781-E2487023ED01</string>
</dict>
</plist>
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>${TM_COMMENT_START} ${4:Send $2 to $1, if $1 supports it}${TM_COMMENT_END}
if ([${1:self} respondsToSelector:@selector(${2:someSelector:})])
{
[$1 ${3:${2/((:\s*$)|(:\s*))/:&lt;&gt;(?3: )/g}}];
}</string>
<key>name</key>
<string>Responds to Selector</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>responds</string>
<key>uuid</key>
<string>D79EC699-9839-406E-AF60-DE51F78153CB</string>
</dict>
</plist>
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>- (${1:id})${2:thing}
{
return _$2;
}
- (void)set${2/./\u$0/}:($1)aValue
{
_$2 = aValue;
}</string>
<key>name</key>
<string>_Accessors</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>_acc</string>
<key>uuid</key>
<string>85B0746B-AE1C-47B3-8B9A-2B9A95F4C71E</string>
</dict>
</plist>
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@import &lt;${1:`"$DIALOG" -u -p "{menuItems=({title=Foundation;},{title=AppKit;});}" | perl -e 'undef $/;$a=&lt;&gt;;$a=~m/&lt;key&gt;title(.|\n)+?&lt;string&gt;(.*?)&lt;/;print $2;'`}/${2:CP}$3.j&gt;
</string>
<key>name</key>
<string>import &lt;…&gt;</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>Imp</string>
<key>uuid</key>
<string>BE0553C0-B73B-4160-814C-840FC2B84C32</string>
</dict>
</plist>
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@import "${1:`"$TM_BUNDLE_SUPPORT/bin/import_FileMenu.sh" ".j"`}"
</string>
<key>name</key>
<string>import "…" (with File Menu)</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>impp</string>
<key>uuid</key>
<string>9BABD784-3DBE-4DA3-8A70-4E32FC7FDBB8</string>
</dict>
</plist>
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>content</key>
<string>@import "${1:}"
</string>
<key>name</key>
<string>import "…"</string>
<key>scope</key>
<string>source.js.objj</string>
<key>tabTrigger</key>
<string>imp</string>
<key>uuid</key>
<string>686B995F-3183-418B-A15F-CA517DFEFE2E</string>
</dict>
</plist>
@@ -1,36 +0,0 @@
EXTENSION="$1"
CURRENTDIR=`dirname $TM_FILEPATH`
if [ -z $TM_PROJECT_DIRECTORY ]; then
L=$((${#CURRENTDIR}+1))
MENUITEMS=$(find -s "$CURRENTDIR" -name "*$EXTENSION" | perl -pe "s/^.{$L}(.*?)$/{title=\"\$1\";}/" | paste -sd ',' -)
[[ -z $MENUITEMS ]] && exit 200
"$DIALOG" -u -p "{menuItems=($MENUITEMS);}" | perl -e 'undef $/;$a=<>;$a=~m/<key>title(.|\n)+?<string>(.*?)</;print $2;'
else
FILES=$(find -s "$TM_PROJECT_DIRECTORY" -name "*$EXTENSION")
FILES=$(echo "$FILES" | perl -pe "s!$CURRENTDIR/!!")
if [ "$CURRENTDIR" != "$TM_PROJECT_DIRECTORY" ]; then
CURRENTDIR=$(dirname $CURRENTDIR)
REPLACE=""
while [ "$CURRENTDIR" != "$TM_PROJECT_DIRECTORY" ]; do
REPLACE="$REPLACE../"
FILES=$(echo "$FILES" | perl -pe "s!$CURRENTDIR/!$REPLACE!")
CURRENTDIR=$(dirname $CURRENTDIR)
done
REPLACE="$REPLACE../"
FILES=$(echo "$FILES" | perl -pe "s!$CURRENTDIR/!$REPLACE!")
fi
MENUITEMS=$(echo "$FILES" | perl -pe "s/^(.*?)$/{title=\"\$1\";}/" | paste -sd ',' -)
[[ -z $MENUITEMS ]] && exit 200
"$DIALOG" -u -p "{menuItems=($MENUITEMS);}" | perl -e 'undef $/;$a=<>;$a=~m/<key>title(.|\n)+?<string>(.*?)</;print $2;'
fi
@@ -1,41 +0,0 @@
<center><font color=red>Any feedback about bugs or improvements is highly welcomed!</font></center>
# Introduction
Cappuccino <a href="http://cappuccino.org">cappuccino.org</a> is an open source framework that makes it easy to build desktop-caliber applications that run in a web browser.
# Commands
## Run
<button>&#x2318;R&nbsp;</button>
Run the current cappuccino web application in TextMate's HTML output window.
If you are inside of an Objective-J file (file extension .j) this command will look for a file `index.html` starting at the current folder and upwards within the file hierarchy or if you are working with a project it will look for it at the project's root path.
If the start HTML site differs you can set the shell variable `TM_OBJJ_MASTER_FILE` within a project.
## Run in Browser
<button>&#x21E7;&#x2318;R&nbsp;</button>
Run the current cappuccino web application in the default web browser.
If you are inside of an Objective-J file (file extension .j) this command will look for a file `index.html` starting at the current folder and upwards within the file hierarchy or if you are working with a project it will look for it at the project's root path.
If the start HTML site differs you can set the shell variable `TM_OBJJ_MASTER_FILE` within a project.
# Shell Variables #
## TM&#95;OBJJ&#95;MASTER&#95;FILE ##
This variable contains the path to the application's start HTML site.
# Main Bundle Maintainer
***Date: Sep 7 2009***
<pre>
- Tom Robinson&nbsp;<a href="mailto:tom@280north.com">tom@280north.com</a>
- Hans-Jörg Bibiko&nbsp;&nbsp;<a href="mailto:bibiko@eva.mpg.de">bibiko@eva.mpg.de</a>
</pre>
File diff suppressed because one or more lines are too long
@@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>contactEmailRot13</key>
<string>gbz@280abegu.pbz</string>
<key>contactName</key>
<string>Tom Robinson</string>
<key>deleted</key>
<array>
<string>4689ADD7-C88A-4235-B69A-84C720034296</string>
</array>
<key>description</key>
<string>&lt;a href="http://cappuccino.org/"&gt;Cappuccino&lt;/a&gt; is an open source framework that makes it easy to build desktop-caliber applications that run in a web browser.</string>
<key>mainMenu</key>
<dict>
<key>excludedItems</key>
<array>
<string>CD025B3E-36B9-4E16-A81E-8DB6E8466CD1</string>
<string>2D05A28A-2ED7-4A9A-9A5C-8625466BC77C</string>
</array>
<key>items</key>
<array>
<string>0C55A19B-3B2D-418F-B7FD-7E64B736F379</string>
<string>36FD3695-1051-401E-8536-89FB9CEEEAB4</string>
<string>033BC36A-97DA-4F48-9ACB-B58C80D1A689</string>
<string>------------------------------------</string>
<string>------------------------------------</string>
<string>AF27A8B3-C87F-410A-915B-D83271FDDC00</string>
<string>344244D8-67A3-4F23-8270-397BD1696AC4</string>
<string>------------------------------------</string>
<string>9BC0151E-82E8-4F2C-8AC1-7D4E6EC8FC80</string>
<string>3ABE883F-3236-4876-91E0-E899F5DE9B29</string>
<string>B226514A-4024-49EA-B4BD-4307C72F7EE3</string>
<string>A4BB7CC7-B06B-4034-B125-A646A22C0813</string>
<string>94B213AC-4DB1-400F-B78A-8FBCF3F93E44</string>
<string>28C6F02F-13D0-4B5B-AB6A-6F23E2CFBD5B</string>
<string>------------------------------------</string>
</array>
<key>submenus</key>
<dict>
<key>28C6F02F-13D0-4B5B-AB6A-6F23E2CFBD5B</key>
<dict>
<key>items</key>
<array>
<string>C7340B17-F9EC-403F-9781-E2487023ED01</string>
</array>
<key>name</key>
<string>UI</string>
</dict>
<key>3ABE883F-3236-4876-91E0-E899F5DE9B29</key>
<dict>
<key>items</key>
<array>
<string>AA41BEF8-5F81-4A5A-85DE-2E81A112778B</string>
<string>85B0746B-AE1C-47B3-8B9A-2B9A95F4C71E</string>
<string>0B3D4C4C-7D75-49E6-9CEC-E4BF4069223A</string>
</array>
<key>name</key>
<string>Accessor Methods For</string>
</dict>
<key>94B213AC-4DB1-400F-B78A-8FBCF3F93E44</key>
<dict>
<key>items</key>
<array>
<string>13D9F280-A78F-4A4C-BE99-0DE13235738D</string>
<string>DF55A80D-E733-4CE2-A318-D56789B18406</string>
</array>
<key>name</key>
<string>Misc</string>
</dict>
<key>9BC0151E-82E8-4F2C-8AC1-7D4E6EC8FC80</key>
<dict>
<key>items</key>
<array>
<string>BE0553C0-B73B-4160-814C-840FC2B84C32</string>
<string>686B995F-3183-418B-A15F-CA517DFEFE2E</string>
<string>9BABD784-3DBE-4DA3-8A70-4E32FC7FDBB8</string>
<string>------------------------------------</string>
<string>96C39647-4346-4750-9F96-58070F24EDE6</string>
<string>8C001067-8A50-4BAB-9A88-BA957A84E8CF</string>
<string>A840A98A-0C5B-49CB-8235-2CCD1BF7AFC1</string>
</array>
<key>name</key>
<string>Language Boilerplate</string>
</dict>
<key>A4BB7CC7-B06B-4034-B125-A646A22C0813</key>
<dict>
<key>items</key>
<array>
<string>D79EC699-9839-406E-AF60-DE51F78153CB</string>
<string>3B5B858C-645E-499C-813B-BBEEED943E9B</string>
</array>
<key>name</key>
<string>Idioms</string>
</dict>
<key>B226514A-4024-49EA-B4BD-4307C72F7EE3</key>
<dict>
<key>items</key>
<array>
<string>C268A928-5C8E-4284-9BAB-4FDFB07B983A</string>
<string>F220FEE6-6522-4281-8091-CF8C66AED44F</string>
</array>
<key>name</key>
<string>Common Method Calls</string>
</dict>
</dict>
</dict>
<key>name</key>
<string>JavaScript Objective-J</string>
<key>ordering</key>
<array>
<string>0C55A19B-3B2D-418F-B7FD-7E64B736F379</string>
<string>36FD3695-1051-401E-8536-89FB9CEEEAB4</string>
<string>033BC36A-97DA-4F48-9ACB-B58C80D1A689</string>
<string>AF27A8B3-C87F-410A-915B-D83271FDDC00</string>
<string>344244D8-67A3-4F23-8270-397BD1696AC4</string>
<string>2D05A28A-2ED7-4A9A-9A5C-8625466BC77C</string>
<string>BE0553C0-B73B-4160-814C-840FC2B84C32</string>
<string>686B995F-3183-418B-A15F-CA517DFEFE2E</string>
<string>9BABD784-3DBE-4DA3-8A70-4E32FC7FDBB8</string>
<string>96C39647-4346-4750-9F96-58070F24EDE6</string>
<string>8C001067-8A50-4BAB-9A88-BA957A84E8CF</string>
<string>AA41BEF8-5F81-4A5A-85DE-2E81A112778B</string>
<string>85B0746B-AE1C-47B3-8B9A-2B9A95F4C71E</string>
<string>0B3D4C4C-7D75-49E6-9CEC-E4BF4069223A</string>
<string>A840A98A-0C5B-49CB-8235-2CCD1BF7AFC1</string>
<string>C268A928-5C8E-4284-9BAB-4FDFB07B983A</string>
<string>F220FEE6-6522-4281-8091-CF8C66AED44F</string>
<string>D79EC699-9839-406E-AF60-DE51F78153CB</string>
<string>3B5B858C-645E-499C-813B-BBEEED943E9B</string>
<string>C7340B17-F9EC-403F-9781-E2487023ED01</string>
<string>13D9F280-A78F-4A4C-BE99-0DE13235738D</string>
<string>CD025B3E-36B9-4E16-A81E-8DB6E8466CD1</string>
<string>DF55A80D-E733-4CE2-A318-D56789B18406</string>
<string>58D4B98A-2110-423E-9C80-CC9E202816E7</string>
<string>E65A721C-192D-4BCC-AD35-5ED5CB0DA5BE</string>
</array>
<key>uuid</key>
<string>1FB3D538-84E1-4002-AA46-5705529A27E1</string>
</dict>
</plist>
-752
View File
@@ -1,752 +0,0 @@
// Objective-J language
(
/****************************************************************************/
// MARK: Strings and Characters
/****************************************************************************/
{
Identifier = "xcode.lang.string.objj";
Syntax = {
Start = "@\"";
EscapeChar = "\\";
End = "\"";
Type = "xcode.syntax.string";
};
},
/****************************************************************************/
// MARK: Objective-J keywords
/****************************************************************************/
{
Identifier = "xcode.lang.objj.identifier";
Syntax = {
StartChars = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
Chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
Words = (
// keywords from JavaScript
"break",
"case",
"catch",
"continue",
"default",
"delete",
"do",
"else",
"false",
"finally",
"for",
"function",
"if",
"in",
"instanceof",
"new",
"null",
"return",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
"class",
"window",
"document",
// Select keywords from Objective-C
"@end",
"@implementation",
"@import",
"@private",
"@property",
"@protected",
"@protocol",
"@public",
"@selector",
"@accessors",
"@action",
"@outlet",
"in",
"inout",
"oneway",
"out",
"BOOL",
"IBAction",
"IBOutlet",
"IMP",
"NO",
"Nil",
"SEL",
"YES",
"id",
"nil",
"self",
"super",
);
Type = "xcode.syntax.keyword";
AltType = "xcode.syntax.identifier"; // non-keywords are identifiers
};
},
/****************************************************************************/
// MARK: Objective-J Top-Level
/****************************************************************************/
{
Identifier = "xcode.lang.objj";
Description = "Objective-J Coloring";
BasedOn = "xcode.lang.javascript";
IncludeInMenu = YES;
Name = "Objective-J";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.toplevel";
IncludeRules = (
"xcode.lang.objj.block",
"xcode.lang.objj.bracketexpr",
"xcode.lang.objj.parenexpr",
"xcode.lang.objj.interface",
"xcode.lang.objj.implementation",
"xcode.lang.objj.protocol.declaration",
"xcode.lang.objj.protocol",
"xcode.lang.objj.function.declaration",
"xcode.lang.objj.function.definition",
"xcode.lang.objj.initializer",
);
Type = "xcode.syntax.plain";
};
},
/****************************************************************************/
// MARK: Lexers
/****************************************************************************/
// The following rule returns tokens to the other rules
{
Identifier = "xcode.lang.objj.lexer";
Syntax = {
IncludeRules = (
"xcode.lang.comment.headerdoc",
"xcode.lang.comment",
"xcode.lang.comment.singleline",
"xcode.lang.c.preprocessor",
"xcode.lang.string.objj",
"xcode.lang.string",
"xcode.lang.character",
"xcode.lang.completionplaceholder",
"xcode.lang.objj.identifier",
"xcode.lang.number",
);
};
},
{
Identifier = "xcode.lang.objj.lexer.toplevel";
Syntax = {
IncludeRules = (
"xcode.lang.comment.headerdoc",
"xcode.lang.comment",
"xcode.lang.comment.singleline",
"xcode.lang.c.preprocessor",
"xcode.lang.string.objj",
"xcode.lang.string",
"xcode.lang.character",
"xcode.lang.completionplaceholder",
"xcode.lang.objj.interface.declarator",
"xcode.lang.objj.implementation.declarator",
"xcode.lang.objj.protocol.declarator",
"xcode.lang.objj.property.declarator",
"xcode.lang.objj.identifier",
"xcode.lang.number",
);
};
},
{
Identifier = "xcode.lang.objj.lexer.attribute";
Syntax = {
IncludeRules = (
"xcode.lang.comment.headerdoc",
"xcode.lang.comment",
"xcode.lang.comment.singleline",
"xcode.lang.c.preprocessor",
"xcode.lang.string.objj",
"xcode.lang.string",
"xcode.lang.character",
"xcode.lang.completionplaceholder",
"xcode.lang.objj.identifier",
"xcode.lang.number",
);
};
},
{
Identifier = "xcode.lang.objj.parenexpr.attribute";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.attribute";
Start = "(";
End = ")";
Recursive = YES;
};
},
{
Identifier = "xcode.lang.objj.implementation.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"@implementation",
"xcode.lang.objj.classnameclause",
);
Type = "xcode.syntax.name.tree";
};
},
{
Identifier = "xcode.lang.objj.interface.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"@interface",
"xcode.lang.objj.classnameclause",
":?",
"xcode.lang.objj.classname?",
"xcode.lang.objj.protocolclause?",
);
Type = "xcode.syntax.name.tree";
};
},
{
Identifier = "xcode.lang.objj.protocol.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"@protocol",
"xcode.lang.objj.protocolname",
);
Type = "xcode.syntax.name.tree";
};
},
{
Identifier = "xcode.lang.objj.classnameclause";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.classname",
"xcode.lang.objj.categoryclause?",
);
Type = "xcode.syntax.name.tree";
};
},
{
Identifier = "xcode.lang.objj.classname";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.identifier",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.protocolname";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.identifier",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.protocol.openangle";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"<",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.protocol.closeangle";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
">",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.protocolclause";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.protocol.openangle",
"xcode.lang.objj.protocolname",
"xcode.lang.objj.protocol.protocollist*",
"xcode.lang.objj.protocol.closeangle",
);
};
},
{
Identifier = "xcode.lang.objj.categoryname";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.identifier",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.category.openparen";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"(",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.category.closeparen";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
")",
);
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.categoryclause";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.category.openparen",
"xcode.lang.objj.categoryname",
"xcode.lang.objj.category.closeparen"
);
};
},
/****************************************************************************/
// MARK: Interfaces/Implementations
/****************************************************************************/
{
Identifier = "xcode.lang.objj.protocol.declaration";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.toplevel";
Rules = (
"xcode.lang.objj.protocol.declarator",
"xcode.lang.objj.protocol.protocolclause*",
";",
);
Type = "xcode.syntax.declaration.objj.protocol";
};
},
{
Identifier = "xcode.lang.objj.protocol.protocollist";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
",",
"xcode.lang.objj.protocolname",
);
};
},
{
Identifier = "xcode.lang.objj.protocol";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.toplevel";
Start = "xcode.lang.objj.protocol.declarator";
End = "@end";
Foldable = YES;
IncludeRules = (
"xcode.lang.objj.function.declaration",
"xcode.lang.objj.method.declaration",
"xcode.lang.objj.classmethod.declaration",
"xcode.lang.objj.property.declaration",
"xcode.lang.objj.block",
"xcode.lang.objj.bracketexpr",
"xcode.lang.objj.parenexpr",
);
Type = "xcode.syntax.declaration.objj.protocol";
};
},
{
Identifier = "xcode.lang.objj.interface";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.toplevel";
Start = "xcode.lang.objj.interface.declarator";
End = "@end";
Foldable = YES;
IncludeRules = (
"xcode.lang.objj.function.declaration",
"xcode.lang.objj.method.declaration",
"xcode.lang.objj.classmethod.declaration",
"xcode.lang.objj.property.declaration",
"xcode.lang.objj.block",
"xcode.lang.objj.bracketexpr",
"xcode.lang.objj.parenexpr",
);
Type = "xcode.syntax.declaration.objj.interface";
};
},
{
Identifier = "xcode.lang.objj.implementation";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.toplevel";
Start = "xcode.lang.objj.implementation.declarator";
End = "@end";
Foldable = YES;
IncludeRules = (
"xcode.lang.objj.function.declaration",
"xcode.lang.objj.function.definition",
"xcode.lang.objj.method.definition",
"xcode.lang.objj.classmethod.definition",
"xcode.lang.objj.block",
"xcode.lang.objj.bracketexpr",
"xcode.lang.objj.parenexpr",
"xcode.lang.objj.initializer",
);
Type = "xcode.syntax.definition.objj.implementation";
};
},
/****************************************************************************/
// MARK: Methods
/****************************************************************************/
{
Identifier = "xcode.lang.objj.method.minus";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = ( "-", );
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.method.plus";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = ( "+", );
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.method.colon";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = ( ":", );
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.partialname";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = ( "xcode.lang.objj.identifier", );
Type = "xcode.syntax.name.partial";
};
},
{
Identifier = "xcode.lang.objj.method.declaration";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.method.declarator",
"xcode.lang.objj.identifier?",
";",
);
Type = "xcode.syntax.declaration.method";
};
},
{
Identifier = "xcode.lang.objj.method.definition";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.method.declarator",
";?",
"xcode.lang.objj.block",
);
Type = "xcode.syntax.definition.method";
};
},
{
Identifier = "xcode.lang.objj.method.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.method.minus",
"xcode.lang.objj.parenexpr?",
"xcode.lang.objj.partialname",
"xcode.lang.objj.method.declarator.args?",
);
Type = "xcode.syntax.method.declarator";
};
},
{
Identifier = "xcode.lang.objj.classmethod.declaration";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.classmethod.declarator",
"xcode.lang.objj.identifier?",
";",
);
Type = "xcode.syntax.declaration.method";
};
},
{
Identifier = "xcode.lang.objj.classmethod.definition";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.classmethod.declarator",
";?",
"xcode.lang.objj.block",
);
Type = "xcode.syntax.definition.method";
};
},
{
Identifier = "xcode.lang.objj.classmethod.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.method.plus",
"xcode.lang.objj.parenexpr?",
"xcode.lang.objj.partialname",
"xcode.lang.objj.method.declarator.args?",
);
Type = "xcode.syntax.method.declarator";
};
},
{
Identifier = "xcode.lang.objj.method.declarator.args";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.method.colon",
"xcode.lang.objj.parenexpr?",
"xcode.lang.objj.identifier",
"xcode.lang.objj.method.declarator.moreargs*",
"xcode.lang.objj.method.declarator.varargs?",
);
};
},
{
Identifier = "xcode.lang.objj.method.declarator.moreargs";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.partialname?",
"xcode.lang.objj.method.colon",
"xcode.lang.objj.parenexpr?",
"xcode.lang.objj.identifier"
);
};
},
{
Identifier = "xcode.lang.objj.method.declarator.varargs";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
",",
"...",
);
};
},
/****************************************************************************/
// MARK: Functions
/****************************************************************************/
{
Identifier = "xcode.lang.objj.function.definition";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.function.declarator",
"xcode.lang.objj.block",
);
Type = "xcode.syntax.definition.c.function";
};
},
{
Identifier = "xcode.lang.objj.function.declaration";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.function.declarator",
"xcode.lang.objj.identifier?",
";"
);
Type = "xcode.syntax.declaration.c.function";
};
},
{
Identifier = "xcode.lang.objj.function.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.function.name",
"xcode.lang.objj.parenexpr",
);
};
},
{
Identifier = "xcode.lang.objj.function.name";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"xcode.lang.objj.identifier",
);
Type = "xcode.syntax.name.partial";
};
},
/****************************************************************************/
// MARK: Properties
/****************************************************************************/
{
Identifier = "xcode.lang.objj.property.declaration";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Start = "xcode.lang.objj.property.declarator";
End = ";";
Type = "xcode.syntax.declaration.property";
};
},
{
Identifier = "xcode.lang.objj.property.declarator";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Rules = (
"@property",
"xcode.lang.objj.property.options?",
);
};
},
{
Identifier = "xcode.lang.objj.property.options";
Syntax = {
Tokenizer = "xcode.lang.objj.property.options.lexer";
Start = "(";
End = ")";
Recursive = YES;
};
},
{
Identifier = "xcode.lang.objj.property.options.lexer";
Syntax = {
IncludeRules = (
"xcode.lang.comment.headerdoc",
"xcode.lang.comment",
"xcode.lang.comment.singleline",
"xcode.lang.c.preprocessor",
"xcode.lang.string.objj",
"xcode.lang.string",
"xcode.lang.character",
"xcode.lang.completionplaceholder",
"xcode.lang.objj.property.options.identifier",
"xcode.lang.objj.identifier",
"xcode.lang.number",
);
};
},
{
Identifier = "xcode.lang.objj.property.options.identifier";
Syntax = {
Words = (
"setter",
"getter",
"readonly",
"readwrite",
"assign",
"retain",
"copy",
"nonatomic",
);
Type = "xcode.syntax.keyword";
};
},
/****************************************************************************/
// MARK: Blocks
/****************************************************************************/
{
Identifier = "xcode.lang.objj.block";
BasedOn = "xcode.lang.javascript.block"; // for text macros
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Start = "{";
End = "}";
Foldable = YES;
Recursive = YES;
IncludeRules = (
"xcode.lang.objj.bracketexpr",
"xcode.lang.objj.parenexpr",
);
};
},
{
Identifier = "xcode.lang.objj.parenexpr";
BasedOn = "xcode.lang.javascript.parenexpr";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Start = "(";
End = ")";
Recursive = YES;
IncludeRules = (
"xcode.lang.objj.bracketexpr",
"xcode.lang.objj.block",
);
};
},
{
Identifier = "xcode.lang.objj.bracketexpr";
BasedOn = "xcode.lang.javascript.bracketexpr";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer";
Start = "[";
End = "]";
Recursive = YES;
IncludeRules = (
"xcode.lang.objj.parenexpr",
"xcode.lang.objj.block",
);
};
},
{
Identifier = "xcode.lang.objj.initializer";
Syntax = {
Tokenizer = "xcode.lang.objj.lexer.toplevel";
Start = "=";
End = ";";
Recursive = NO;
IncludeRules = (
"xcode.lang.objj.parenexpr",
"xcode.lang.objj.bracketexpr",
);
};
},
)
-15
View File
@@ -1,15 +0,0 @@
/*
* ObjectiveJ.xcspec: Xcode file type for Objective-J
*
*/
(
{
Type = FileType;
Identifier = sourcecode.objj;
BasedOn = sourcecode;
Name = "Objective-J file";
Extensions = ( j );
Language = "xcode.lang.objj";
}
)
-541
View File
@@ -1,541 +0,0 @@
/**
Objective J text macro specifications derived from
Objective C text macro specifications and C text macro specifications which are
Copyright © 2004-2007 Apple Inc. All rights reserved.
*/
(
//
// Objective-J language macros
//
{
Identifier = objj;
Name = "Objective J";
IsMenu = YES;
// Can be set (for all languages) with the XCCodeSenseFormattingOptions user default
// DefaultSettings = {
// PreExpressionsSpacing = " ";
// InExpressionsSpacing = "";
// BlockSeparator = " ";
// PostBlockSeparator = "\n";
// };
IncludeContexts = ( "xcode.lang.objj");
ExcludeContexts = ( "xcode.lang.string", "xcode.lang.character", "xcode.lang.comment", "xcode.lang.c.preprocessor" );
},
{
Identifier = objj.try;
BasedOn = objj;
IsMenuItem = YES;
Name = "Try / Catch Block";
TextString = "@try$(BlockSeparator){\n\t<#!statements!#>\n}$(PostBlockSeparator)@catch$(PreExpressionsSpacing)($(InExpressionsSpacing)CPException * e$(InExpressionsSpacing))$(BlockSeparator){\n\t<#handler#>\n}$(PostBlockSeparator)@finally$(BlockSeparator){\n\t<#statements#>\n}";
CompletionPrefix = "@try";
IncludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.catch;
BasedOn = objj;
IsMenuItem = YES;
Name = "Catch Block";
TextString = "@catch$(PreExpressionsSpacing)($(InExpressionsSpacing)<#exception#>$(InExpressionsSpacing))$(BlockSeparator){\n\t<#!handler!#>\n}";
CompletionPrefix = "@catch";
IncludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.finally;
BasedOn = objj;
IsMenuItem = YES;
Name = "Finally Block";
TextString = "@finally$(BlockSeparator){\n\t<#!handler!#>\n}";
CompletionPrefix = "@finally";
IncludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.log;
BasedOn = objj;
IsMenuItem = YES;
Name = "CPLog() Call";
TextString = "CPLog$(PreFunctionArgsSpacing)($(InFunctionArgsSpacing)@\"<#message#>\"$(InFunctionArgsSpacing));";
CompletionPrefix = log;
IncludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.bracket;
BasedOn = objj;
IsMenuItem = YES;
Name = "Bracket Expression";
TextString = "[<#!expression!#> ]";
CompletionPrefix = "[";
},
{
Identifier = objj.allocinit;
BasedOn = objj;
IsMenuItem = YES;
Name = "Alloc / Init Call";
TextString = "[[<#!class!#> alloc] init]";
CompletionPrefix = a;
},
{
Identifier = objj.array;
BasedOn = objj;
IsMenuItem = YES;
Name = "Array Declaration";
TextString = "CPArray * array;";
CompletionPrefix = aa;
},
{
Identifier = objj.mutablearray;
BasedOn = objj;
IsMenuItem = YES;
Name = "Mutable Array Declaration";
TextString = "CPMutableArray * array;";
CompletionPrefix = ma;
},
{
Identifier = objj.arrayiteration;
BasedOn = objj;
IsMenuItem = YES;
Name = "Array For Loop";
TextString = "CPUInteger i, count = [<#array#> count];\nfor$(PreExpressionsSpacing)($(InExpressionsSpacing)i = 0; i < count; i++$(InExpressionsSpacing))$(BlockSeparator){\n\tCPObject * obj = [<#array#> objectAtIndex:i];\n\t<#!statements!#>\n}";
CompletionPrefix = fora;
IncludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.arrayiteration.foreach;
BasedOn = objj;
IsMenuItem = YES;
Name = "Array Foreach Loop";
TextString = "for$(PreExpressionsSpacing)($(InExpressionsSpacing)<#object#> in <#array#>$(InExpressionsSpacing))$(BlockSeparator){\n\t<#!statements!#>\n}";
CompletionPrefix = fore;
IncludeContexts = ( "xcode.lang.objj.block" );
},
// MARK: Block Statements
{
Identifier = objj.block;
BasedOn = objj;
TextString = "$(Statement)$(BlockSeparator){\n\t<#!statements!#>\n}";
Statement = "$(Command)$(PreExpressionsSpacing)($(InExpressionsSpacing)$(Expressions)$(InExpressionsSpacing))";
IncludeContexts = ( "xcode.lang.objj.block", "xcode.lang.java.block" ); // these all work in Java too
ExcludeContexts = ( "xcode.lang.string", "xcode.lang.character", "xcode.lang.comment", "xcode.lang.c.preprocessor", "xcode.lang.objj.parenexpr", "xcode.lang.objj.bracketexpr" );
},
{
Identifier = objj.block.if;
BasedOn = objj.block;
Name = "If Block";
IsMenuItem = YES;
Command = "if";
Expressions = "<#condition#>";
CompletionPrefix = if;
CycleList = (
objj.block.if,
objj.block.ifelse,
);
},
{
Identifier = objj.block.ifelse;
BasedOn = objj.block;
Name = "If / Else Block";
IsMenuItem = NO;
Command = "if";
Expressions = "<#condition#>";
TextString = "$(Statement)$(BlockSeparator){\n\t<#!statements!#>\n}$(PostBlockSeparator)else$(BlockSeparator){\n\t<#statements#>\n}";
CompletionPrefix = ifelse;
},
{
Identifier = objj.block.elseif;
BasedOn = objj.block;
Name = "Else If Block";
IsMenuItem = NO;
Command = "else if";
Expressions = "<#condition#>";
CompletionPrefix = elseif;
},
{
Identifier = objj.block.for;
BasedOn = objj.block;
Name = "For Loop";
IsMenuItem = YES;
Command = "for";
Expressions = "<#initial#>; <#condition#>; <#increment#>";
CompletionPrefix = for;
CycleList = (
objj.block.for,
objj.block.for.i,
);
},
{
Identifier = objj.block.for.i;
BasedOn = objj.block;
Name = "For i Loop";
IsMenuItem = NO;
Command = "for";
Expressions = "int i = 0; i < <#limit#>; i++";
CompletionPrefix = fori;
},
{
Identifier = objj.block.while;
BasedOn = objj.block;
Name = "While Loop";
IsMenuItem = YES;
Command = "while";
Expressions = "<#condition#>";
CompletionPrefix = while;
},
{
Identifier = objj.block.dowhile;
BasedOn = objj.block;
Name = "Do While Loop";
IsMenuItem = YES;
Command = "while";
TextString = "do$(BlockSeparator){\n\t<#!statements!#>\n}$(PreExpressionsSpacing)$(Statement)";
Expressions = "<#condition#>";
CompletionPrefix = do;
},
{
Identifier = objj.block.switch;
BasedOn = objj.block;
Name = "Switch Block";
IsMenuItem = YES;
Command = "switch";
TextString = "$(Statement)$(BlockSeparator){\n$(CaseStatementSpacing)case <#constant#>:\n$(CaseStatementSpacing)\t<#!statements!#>\n$(CaseStatementSpacing)\tbreak;\n$(CaseStatementSpacing)default:\n$(CaseStatementSpacing)\tbreak;\n}";
Expressions = "<#expression#>";
CompletionPrefix = switch;
},
{
Identifier = objj.caseblock;
BasedOn = objj;
IsMenuItem = YES;
Name = "Case Block";
TextString = "case <#constant#>:\n\t<#!statements!#>\n\tbreak;\n";
CompletionPrefix = case;
IncludeContexts = ( "xcode.lang.objj.block", "xcode.lang.java.block" ); // this works in Java too
ExcludeContexts = ( "xcode.lang.string", "xcode.lang.character", "xcode.lang.comment", "xcode.lang.c.preprocessor", "xcode.lang.objj.parenexpr", "xcode.lang.objj.bracketexpr" );
},
{
Identifier = objj.elseblock;
BasedOn = objj;
IsMenuItem = YES;
Name = "Else Block";
TextString = "else$(BlockSeparator){\n\t<#!statements!#>\n}\n";
CompletionPrefix = else;
IncludeContexts = ( "xcode.lang.objj.block", "xcode.lang.java.block" ); // this works in Java too
ExcludeContexts = ( "xcode.lang.string", "xcode.lang.character", "xcode.lang.comment", "xcode.lang.c.preprocessor", "xcode.lang.objj.parenexpr", "xcode.lang.objj.bracketexpr" );
CycleList = (
objj.elseblock,
objj.block.elseif,
);
},
{
Identifier = objj.paren;
BasedOn = objj;
IsMenuItem = YES;
Name = "Parenthesize Selection";
TextString = "($(InExpressionsSpacing)<#!expression!#>$(InExpressionsSpacing))";
IncludeContexts = ( "xcode.lang.objj");
},
{
Identifier = objj.quote;
BasedOn = objj;
IsMenuItem = YES;
Name = "Quote Selection";
TextString = "\"<#!text!#>\"";
IncludeContexts = ( "xcode.lang.objj");
},
{
Identifier = objj.pragmamark;
BasedOn = objj;
IsMenuItem = YES;
Name = "#Pragma Mark";
TextString = "#pragma mark <#!label!#>";
CompletionPrefix = pm;
},
{
Identifier = objj.pp.pragmamark;
BasedOn = objj;
IsMenuItem = NO;
Name = "Pragma Mark";
TextString = "pragma mark <#!label!#>";
CompletionPrefix = pragma;
IncludeContexts = ( "xcode.lang.c.preprocessor" );
},
{
Identifier = objj.import;
BasedOn = objj;
IsMenuItem = YES;
Name = "#Import Statement";
TextString = "#import \"<#!file!#>\"";
CompletionPrefix = pim;
CycleList = (
objj.import,
objj.import.sys,
objj.import.fw
);
ExcludeContexts = ( "xcode.lang.objj.block", "xcode.lang.string", "xcode.lang.character", "xcode.lang.comment", "xcode.lang.c.preprocessor" );
},
{
Identifier = objj.import.sys;
BasedOn = objj.import;
IsMenuItem = NO;
Name = "#Import Statement (System)";
TextString = "#import <<#!file!#>>";
CompletionPrefix = pims;
},
{
Identifier = objj.import.fw;
BasedOn = objj.import;
IsMenuItem = NO;
Name = "#Import Statement (Framework)";
TextString = "#import <<#framework#>/<#!file!#>>";
CompletionPrefix = pimf;
},
{
Identifier = objj.pif;
BasedOn = objj;
IsMenuItem = YES;
Name = "#If Block";
IfText = "if";
TextString = "#$(IfText) $(Expression)\n<#!statements!#>\n#endif";
Expression = "<#expression#>";
CompletionPrefix = pif;
CycleList = (
objj.pif,
objj.pifzero,
objj.pifdef,
objj.pifelse,
objj.pifdefelse
);
},
{
Identifier = objj.pifdef;
BasedOn = objj.pif;
IsMenuItem = NO;
Name = "#Ifdef Block";
IfText = "ifdef";
CompletionPrefix = pifd;
},
{
Identifier = objj.pifelse;
BasedOn = objj.pif;
IsMenuItem = NO;
Name = "#If / Else Block";
TextString = "#$(IfText) $(Expression)\n<#!statements!#>\n#else\n<#statements#>\n#endif";
CompletionPrefix = pife;
},
{
Identifier = objj.pifdefelse;
BasedOn = objj.pifelse;
IsMenuItem = NO;
IfText = "ifdef";
Name = "#Ifdef / Else Block";
CompletionPrefix = pifde;
},
{
Identifier = objj.pifzero;
BasedOn = objj.pif;
IsMenuItem = NO;
Name = "#If 0 Block";
Expression = "0";
CompletionPrefix = pifz;
},
{
Identifier = objj.copyright;
BasedOn = objj;
IsMenuItem = YES;
Name = "Copyright Comment";
TextString = "//\n// Copyright (c) $(YEAR), $(ORGANIZATIONNAME)\n// All rights reserved.\n//\n";
CompletionPrefix = copyright;
IncludeContexts = ( "xcode.lang.objj");
},
{
Identifier = objj.comment;
BasedOn = objj;
IsMenuItem = YES;
Name = "Comment Selection";
TextString = "/* <#!comment!#> */";
CompletionPrefix = comment;
IncludeContexts = ( "xcode.lang.objj");
},
{
Identifier = objj.separatorcomment;
BasedOn = objj;
IsMenuItem = YES;
Name = "Separator Comment";
TextString = "/****************************************************************************/\n";
CompletionPrefix = cseparator;
IncludeContexts = ( "xcode.lang.objj");
},
// MARK: methods templates
{
Identifier = objj.init;
BasedOn = objj;
IsMenuItem = YES;
Name = "init Definition";
TextString = "-$(PreMethodTypeSpacing)(id)$(PreMethodDeclSpacing)init$(FunctionBlockSeparator){\n\tself = [super init];\n\tif$(PreExpressionsSpacing)($(InExpressionsSpacing)self != nil$(InExpressionsSpacing))$(BlockSeparator){\n\t\t<#!initializations!#>\n\t}\n\treturn self;\n}\n";
CompletionPrefix = init;
IncludeContexts = ( "xcode.lang.objj.implementation" );
ExcludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.dealloc;
BasedOn = objj;
IsMenuItem = YES;
Name = "dealloc Definition";
TextString = "-$(PreMethodTypeSpacing)(void)$(PreMethodDeclSpacing)dealloc$(FunctionBlockSeparator){\n\t<#!deallocations!#>\n\t[super dealloc];\n}\n";
CompletionPrefix = dealloc;
IncludeContexts = ( "xcode.lang.objj.implementation" );
ExcludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.observe;
BasedOn = objj;
IsMenuItem = YES;
Name = "observeValueForKeyPath: Definition";
TextString =
"-$(PreMethodTypeSpacing)(void)$(PreMethodDeclSpacing)observeValueForKeyPath$(PreColonSpacing):$(PostColonSpacing)(CPString *)$(MessageArgSpacing)keyPath ofObject$(PreColonSpacing):$(PostColonSpacing)(id)$(MessageArgSpacing)object change$(PreColonSpacing):$(PostColonSpacing)(CPDictionary *)$(MessageArgSpacing)change context$(PreColonSpacing):$(PostColonSpacing)(void *)$(MessageArgSpacing)context$(FunctionBlockSeparator){
if$(PreExpressionsSpacing)($(InExpressionsSpacing)context == <#context#>$(InExpressionsSpacing))$(BlockSeparator){
<#work#>
}$(PostBlockSeparator)\telse$(BlockSeparator){
[$(InMessageSpacing)super observeValueForKeyPath$(PreColonSpacing):$(PostColonSpacing)keyPath ofObject$(PreColonSpacing):$(PostColonSpacing)object change$(PreColonSpacing):$(PostColonSpacing)change context$(PreColonSpacing):$(PostColonSpacing)context$(InMessageSpacing)];
}
}
";
CompletionPrefix = observeValueForKeyPath;
IncludeContexts = ( "xcode.lang.objj.implementation" );
ExcludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.observe.decl;
BasedOn = objj;
IsMenuItem = YES;
Name = "observeValueForKeyPath: Declaration";
TextString = "-$(PreMethodTypeSpacing)(void)$(PreMethodDeclSpacing)observeValueForKeyPath$(PreColonSpacing):$(PostColonSpacing)(CPString *)$(MessageArgSpacing)keyPath ofObject$(PreColonSpacing):$(PostColonSpacing)(id)$(MessageArgSpacing)object change$(PreColonSpacing):$(PostColonSpacing)(CPDictionary *)$(MessageArgSpacing)change context$(PreColonSpacing):$(PostColonSpacing)(void *)$(MessageArgSpacing)context;\n";
CompletionPrefix = observeValueForKeyPath;
IncludeContexts = ( "xcode.lang.objj.interface" );
ExcludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.bind;
BasedOn = objj;
IsMenuItem = YES;
Name = "bind: Definition";
TextString =
"-$(PreMethodTypeSpacing)(void)$(PreMethodDeclSpacing)bind$(PreColonSpacing):$(PostColonSpacing)(CPString *)$(MessageArgSpacing)binding toObject$(PreColonSpacing):$(PostColonSpacing)(id)$(MessageArgSpacing)observable withKeyPath$(PreColonSpacing):$(PostColonSpacing)(CPString *)$(MessageArgSpacing)keyPath options$(PreColonSpacing):$(PostColonSpacing)(CPDictionary *)$(MessageArgSpacing)options$(FunctionBlockSeparator){
if$(PreExpressionsSpacing)($(InExpressionsSpacing)[$(InMessageSpacing)binding isEqualToString$(PreColonSpacing):$(PostColonSpacing)<#bindingName#>$(InMessageSpacing)]$(InExpressionsSpacing))$(BlockSeparator){
[$(InMessageSpacing)observable addObserver$(PreColonSpacing):$(PostColonSpacing)self forKeyPath$(PreColonSpacing):$(PostColonSpacing)keyPath options$(PreColonSpacing):$(PostColonSpacing)0 context$(PreColonSpacing):$(PostColonSpacing)<#context#>$(InMessageSpacing)];
<#store binding info#>
}$(PostBlockSeparator)\telse$(BlockSeparator){
[$(InMessageSpacing)super bind$(PreColonSpacing):$(PostColonSpacing)binding toObject$(PreColonSpacing):$(PostColonSpacing)observable withKeyPath$(PreColonSpacing):$(PostColonSpacing)keyPath options$(PreColonSpacing):$(PostColonSpacing)options$(InMessageSpacing)];
}
}
";
CompletionPrefix = bind;
IncludeContexts = ( "xcode.lang.objj.implementation" );
ExcludeContexts = ( "xcode.lang.objj.block" );
},
{
Identifier = objj.observe.bind;
BasedOn = objj;
IsMenuItem = YES;
Name = "bind: Declaration";
TextString = "-$(PreMethodTypeSpacing)(void)$(PreMethodDeclSpacing)bind$(PreColonSpacing):$(PostColonSpacing)(CPString *)$(MessageArgSpacing)binding toObject$(PreColonSpacing):$(PostColonSpacing)(id)$(MessageArgSpacing)observable withKeyPath$(PreColonSpacing):$(PostColonSpacing)(CPString *)$(MessageArgSpacing)keyPath options$(PreColonSpacing):$(PostColonSpacing)(CPDictionary *)$(MessageArgSpacing)options;\n";
CompletionPrefix = bind;
IncludeContexts = ( "xcode.lang.objj.interface" );
ExcludeContexts = ( "xcode.lang.objj.block" );
},
// MARK: classes and protocols
{
Identifier = objj.interface;
BasedOn = objj;
IsMenuItem = YES;
Name = "@interface Definition";
TextString = "@interface <#class#> : <#superclass#>$(FunctionBlockSeparator){\n\t<#ivars#>\n}\n\n<#methods#>\n\n@end\n";
CompletionPrefix = "@interface";
ExcludeContexts = ( "xcode.lang.objj.implementation", "xcode.lang.objj.interface", "xcode.lang.objj.protocol" );
},
{
Identifier = objj.implementation;
BasedOn = objj;
IsMenuItem = YES;
Name = "@implementation Definition";
TextString = "@implementation <#class#>\n\n<#methods#>\n\n@end\n";
CompletionPrefix = "@implementation";
ExcludeContexts = ( "xcode.lang.objj.implementation", "xcode.lang.objj.interface", "xcode.lang.objj.protocol" );
},
{
Identifier = objj.protocol;
BasedOn = objj;
IsMenuItem = YES;
Name = "@protocol Definition";
TextString = "@protocol <#protocol#>\n\n<#methods#>\n\n@end\n";
CompletionPrefix = "@protocol";
ExcludeContexts = ( "xcode.lang.objj.implementation", "xcode.lang.objj.interface", "xcode.lang.objj.protocol" );
},
// MARK: Common Class shorthands
{
Identifier = objj.cps;
BasedOn = objj;
IsMenuItem = NO;
Name = "CPString";
TextString = "CPString";
CompletionPrefix = cps;
},
{
Identifier = objj.cpa;
BasedOn = objj;
IsMenuItem = NO;
Name = "CPArray";
TextString = "CPArray";
CompletionPrefix = cpa;
},
{
Identifier = objj.cpma;
BasedOn = objj;
IsMenuItem = NO;
Name = "CPMutableArray";
TextString = "CPMutableArray";
CompletionPrefix = cpma;
},
{
Identifier = objj.cpd;
BasedOn = objj;
IsMenuItem = NO;
Name = "CPDictionary";
TextString = "CPDictionary";
CompletionPrefix = cpd;
},
)
-47
View File
@@ -1,47 +0,0 @@
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf430
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww15700\viewh12860\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\fs24 \cf0 The following files provide support for Objective-J syntax coloring and text completion in Xcode version 3 and above\
\
\fs26
\b ObjectiveJ.xcspec
\b0 \
\b ObjectiveJ.xclangspec
\b0 \
\b ObjectiveJ.xctxtmacro
\b0 \
\fs24 \
The above files were derived from the Apple Objective-C and JavaScript files located at\
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
\i\fs26 \cf0 /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources
\i0\fs24 \
\i
\fs26 /Developer/Applications/Xcode.app/Contents/PlugIns/TextMacros.xctxtmacro/Contents/Resources\
\pard\tx580\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
\i0 \cf0 (
\fs20 some files are Copyright \'a9 2004-2007 Apple Inc. and copyright text has been preserved
\fs26 )
\i\fs24 \
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\i0 \cf0 \
To install the files, double click on \
\
\b\fs26 install.command
\b0\fs24 \
\
This will create a "
\i\fs26 ~/Library/Application Support/Developer/Shared/Xcode/Specifications
\i0\fs24 " directory if it does not already exist and copy the ObjectiveJ.* files to that directory. You will need to restart Xcode for the changes to take effect.}
-5
View File
@@ -1,5 +0,0 @@
#~/bin/bash
echo Creating destination directory..
mkdir -pv ~/Library/Application\ Support/Developer/Shared/Xcode/Specifications
echo Copying files...
cp -v ${0%/*}/ObjectiveJ.* ~/Library/Application\ Support/Developer/Shared/Xcode/Specifications
+1 -1
View File
@@ -34,7 +34,7 @@ var DefaultDictionary = nil,
[DefaultDictionary setObject:@"com.yourcompany" forKey:@"organization.identifier"];
var date = new Date(),
months = ["Janurary", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
[DefaultDictionary setObject:date.getFullYear() forKey:@"project.year"];
[DefaultDictionary setObject:months[date.getMonth()] + ' ' + date.getDate() + ", " + date.getFullYear() forKey:@"project.date"];
+1
View File
@@ -55,6 +55,7 @@
@import "NSTabViewItem.j"
@import "NSTextField.j"
@import "NSToolbar.j"
@import "NSToolbarItem.j"
@import "NSView.j"
@import "NSViewController.j"
@import "NSWindowTemplate.j"
+84
View File
@@ -0,0 +1,84 @@
/*
* NSToolbarItem.j
* nib2cib
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPToolbarItem.j>
@implementation CPToolbarItem (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_itemIdentifier = [aCoder decodeObjectForKey:@"NSToolbarItemIdentifier"];
[self setLabel:[aCoder decodeObjectForKey:@"NSToolbarItemLabel"]];
[self setPaletteLabel:[aCoder decodeObjectForKey:@"NSToolbarItemPaletteLabel"]];
[self setToolTip:[aCoder decodeObjectForKey:@"NSToolbarItemToolTip"]];
[self setTag:[aCoder decodeObjectForKey:@"NSToolbarItemTag"]];
[self setTarget:[aCoder decodeObjectForKey:@"NSToolbarItemTarget"]];
[self setAction:CPSelectorFromString([aCoder decodeObjectForKey:@"NSToolbarItemAction"])];
[self setEnabled:[aCoder decodeBoolForKey:@"NSToolbarItemEnabled"]];
[self setImage:[aCoder decodeBoolForKey:@"NSToolbarItemImage"]];
[self setView:[aCoder decodeObjectForKey:@"NSToolbarItemView"]];
_minSize = [aCoder decodeSizeForKey:@"NSToolbarItemMinSize"];
_maxSize = [aCoder decodeSizeForKey:@"NSToolbarItemMaxSize"];
[self setVisibilityPriority:[aCoder decodeIntForKey:@"NSToolbarItemVisibilityPriority"]];
}
return self;
}
@end
@implementation NSToolbarItem : CPToolbarItem
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
return [self NS_initWithCoder:aCoder];
}
- (Class)classForKeyedArchiver
{
return [CPToolbarItem class];
}
@end
@implementation NSToolbarSpaceItem : NSToolbarItem
@end
@implementation NSToolbarFlexibleSpaceItem : NSToolbarItem
@end
@implementation NSToolbarSeparatorItem : NSToolbarItem
@end
+229 -332
View File
@@ -1,139 +1,182 @@
var OS = require("os");
if (system.engine !== "rhino") {
system.args.splice(1,2); // remove library path and main.j
var cmd = "NARWHAL_ENGINE_HOME='' NARWHAL_ENGINE='rhino' " + system.args.map(OS.enquote).join(" ");
OS.exit(OS.system(cmd));
}
@import <Foundation/Foundation.j>
@import "objj-analysis-tools.j"
var defaultMain = "main.j",
defaultFrameworks = "Frameworks";
var ARGS = require("args");
var FILE = require("file");
var OS = require("os");
var DOM = require("browser/dom");
var usageMessage =
"Usage: press root_directory output_directory [options]\n\
--main path The relative path (from root_directory) to the main file (default: 'main.j')\n\
--frameworks path The relative path (from root_directory) to the frameworks directory (default: 'Frameworks')\n\
--platforms Platform names, colon separated (default: 'browser:objj')\n\
--png Run pngcrush on all PNGs (pngcrush must be installed!)\n\
--flatten Flatten all code into a single Application.js file and attempt add script tag to index.html (useful for Adobe AIR and CDN deployment)\n\
--nostrip Don't strip any files\n\
--v Verbose";
var serializer = new DOM.XMLSerializer();
function main()
var parser = new ARGS.Parser();
parser.usage("INPUT_PROJECT OUTPUT_PROJECT");
parser.help("Optimizes Cappuccino applications for deployment to the web.");
parser.option("-m", "--main", "main")
.def("main.j")
.set()
.help("The relative path (from INPUT_PROJECT) to the main file (default: 'main.j')");
parser.option("-F", "--framework", "frameworks")
.def(["Frameworks"])
.push()
.help("Add a frameworks directory, relative to INPUT_PROJECT (default: ['Frameworks'])");
parser.option("-E", "--environment", "environments")
.def(['W3C', 'IE7', 'IE8'])
.push()
.help("Add a platform name (default: ['W3C', 'IE7', 'IE8'])");
parser.option("-f", "--flatten", "flatten")
.def(false)
.set(true)
.help("Flatten all code into a single Application.js file and attempt add script tag to index.html (useful for Adobe AIR and CDN deployment)");
parser.option("-n", "--nostrip", "strip")
.def(true)
.set(false)
.help("Do not strip any files");
parser.option("-p", "--pngcrush", "png")
.def(false)
.set(true)
.help("Run pngcrush on all PNGs (pngcrush must be installed!)");
parser.option("-v", "--verbose", "verbose")
.def(false)
.set(true)
.help("Verbose logging");
parser.helpful();
function main(args)
{
var rootDirectory = null,
outputDirectory = null,
mainFilename = null,
frameworksDirectory = null,
platforms = ['browser', 'objj'],
optimizePNG = false,
flatten = false,
noStrip = false,
verbose = false;
var options = parser.parse(args);
var usageError = false;
while (system.args.length && !usageError)
{
var arg = system.args.shift();
switch(arg)
{
case "--main":
if (system.args.length)
mainFilename = system.args.shift();
else
usageError = true;
break;
case "--frameworks":
if (system.args.length)
frameworksDirectory = system.args.shift().replace(/\/$/, "");
else
usageError = true;
break;
case "--platforms":
if (system.args.length)
platforms = system.args.shift().split(":");
else
usageError = true;
break;
case "--png":
optimizePNG = true;
break;
case "--flatten":
flatten = true;
break;
case "--nostrip":
noStrip = true;
break;
case "--v":
verbose = true;
break;
default:
if (rootDirectory == null)
rootDirectory = arg.replace(/\/$/, "");
else if (outputDirectory == null)
outputDirectory = arg.replace(/\/$/, "");
else
usageError = true;
}
}
if (verbose)
CPLogRegister(CPLogPrint);
else
CPLogRegisterRange(CPLogPrint, "fatal", "info");
if (usageError || rootDirectory == null || outputDirectory == null || !platforms.length)
{
print(usageMessage);
if (options.args.length < 2) {
parser.printUsage(options);
return;
}
rootDirectory = absolutePath(rootDirectory);
//if (options.verbose)
CPLogRegister(CPLogPrint);
//else
// CPLogRegisterRange(CPLogPrint, "fatal", "info");
var rootPath = FILE.path(options.args[0]).absolute();
var outputPath = FILE.path(options.args[1]).absolute();
press(rootPath, outputPath, options);
}
function press(rootPath, outputPath, options) {
CPLog.info("===========================================");
CPLog.info("Application root: " + rootPath);
CPLog.info("Output directory: " + outputPath);
// determine main and frameworks paths
var mainPath = rootDirectory + "/" + (mainFilename || defaultMain),
frameworksPath = rootDirectory + "/" + (frameworksDirectory || defaultFrameworks);
var outputFiles = {};
// analyze and gather files for each environment:
options.environments.forEach(function(environment) {
pressEnvironment(rootPath, outputFiles, environment, options);
});
// phase 4: copy everything and write out the new files
CPLog.error("PHASE 4: copy to output ("+rootPath+" to "+outputPath+")");
FILE.copyTree(rootPath, outputPath);
for (var path in outputFiles) {
CPLog.trace("Writing: " + path);
CPLog.info("Application root: " + rootDirectory);
CPLog.info("Output directory: " + outputDirectory);
var file = outputPath.join(relativeToRootPath(path));
var parent = file.dirname();
if (!parent.exists()) {
CPLog.warn(parent + " doesn't exist, creating directories.");
parent.mkdirs();
}
if (typeof outputFiles[path] !== "string")
outputFiles[path] = outputFiles[path].join("");
CPLog.info((file.exists() ? "Overwriting: " : "Writing: ") + file);
FILE.write(file, outputFiles[path], { charset : "UTF-8" });
}
// outputPath.glob("**/Frameworks/Debug").forEach(function(debugFramework) {
// outputPath.join(debugFramework).rmtree();
// });
// outputPath.join("index-debug.html").remove();
if (options.png) {
pngcrushDirectory(outputPath);
}
}
function pressEnvironment(rootPath, outputFiles, environment, options) {
function relativeToRootPath(path) {
return pathRelativeTo(path, rootPath);
}
var mainPath = String(rootPath.join(options.main));
var frameworks = options.frameworks.map(function(framework) { return rootPath.join(framework); });
CPLog.info("===========================================");
CPLog.info("Main file: " + mainPath)
CPLog.info("Frameworks: " + frameworksPath);
CPLog.info("Frameworks: " + frameworks);
CPLog.info("Environment: " + environment);
// get a Rhino context
var cx = Packages.org.mozilla.javascript.Context.getCurrentContext(),
scope = makeObjjScope(cx);
var ctx = Packages.org.mozilla.javascript.Context.getCurrentContext();
var scope = makeObjjScope(ctx); // "scope" is the same as require("objective-j").window;
// set OBJJ_INCLUDE_PATHS to include the frameworks path
scope.OBJJ_INCLUDE_PATHS = [frameworksPath];
scope.OBJJ_PLATFORMS = platforms;
scope.OBJJ_INCLUDE_PATHS = frameworks;
scope.OBJJ_ENVIRONMENTS = [environment, "ObjJ"];
// flattening bookkeeping. keep track of the bundles and evaled code (in the correct order!)
var bundleArchives = [],
evaledFragments = [];
var bundleArchiveResponses = [];
var evaledFragments = [];
// here we hook into didReceiveBundleResponse to record the responses for --flattening
scope.objj_search.prototype.didReceiveBundleResponseOriginal = scope.objj_search.prototype.didReceiveBundleResponse;
scope.objj_search.prototype.didReceiveBundleResponse = function(aResponse) {
//CPLog.trace("RESPONSE: " + aResponse);
var __fakeResponse = {
var fakeResponse = {
success : aResponse.success,
filePath : pathRelativeTo(aResponse.filePath, rootDirectory)
filePath : relativeToRootPath(aResponse.filePath)
};
if (aResponse.success)
{
var xmlOutput = new Packages.java.io.ByteArrayOutputStream();
outputTransformer(xmlOutput, aResponse.xml, "UTF-8");
//__fakeResponse.xml = String(xmlOutput.toString());
__fakeResponse.text = CPPropertyListCreate280NorthData(CPPropertyListCreateFromXMLData({ string:String(xmlOutput.toString())})).string;
//CPLog.trace("SERIALIZED: " + __fakeResponse.xml.substring(0,100));
var xmlString = serializer.serializeToString(aResponse.xml);
fakeResponse.text = CPPropertyListCreate280NorthData(CPPropertyListCreateFromXMLData({ string: xmlString })).string;
}
bundleArchives.push(__fakeResponse);
bundleArchiveResponses.push(fakeResponse);
this.didReceiveBundleResponseOriginal.apply(this, arguments);
}
var context = {
ctx : ctx,
scope : scope,
relativeToRootPath : relativeToRootPath
};
// phase 1: get global defines
CPLog.error("PHASE 1: Loading application...");
var globals = findGlobalDefines(cx, scope, mainPath, evaledFragments);
var globals = findGlobalDefines(context, mainPath, evaledFragments);
// coalesce the results
var dependencies = coalesceGlobalDefines(globals);
@@ -141,14 +184,14 @@ function main()
// Log
CPLog.trace("Global defines:");
for (var i in dependencies)
CPLog.trace(" " + i + " => " + dependencies[i]);
CPLog.trace(" " + i + " => " + relativeToRootPath(dependencies[i]));
// phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included
CPLog.error("PHASE 2: Walk dependency tree...");
var requiredFiles = {};
if (noStrip)
if (options.nostrip)
{
// all files are required. no need for analysis
requiredFiles = scope.objj_files;
@@ -163,20 +206,13 @@ function main()
CPLog.warn("Analyzing dependencies...");
var context = {
scope : scope,
dependencies : dependencies,
processedFiles : {},
ignoreFrameworkImports : true,
importCallback : function(importing, imported) {
requiredFiles[imported] = true;
},
referenceCallback : function(referencing, referenced) {
requiredFiles[referenced] = true;
}
}
context.dependencies = dependencies;
context.ignoreFrameworkImports = true; // ignores "XXX/XXX.j" imports
context.importCallback = function(importing, imported) { requiredFiles[imported] = true; };
context.referenceCallback = function(referencing, referenced) { requiredFiles[referenced] = true; }
requiredFiles[mainPath] = true;
traverseDependencies(context, scope.objj_files[mainPath]);
var count = 0,
@@ -185,12 +221,12 @@ function main()
{
if (requiredFiles[path])
{
CPLog.debug("Included: " + path);
CPLog.debug("Included: " + relativeToRootPath(path));
count++;
}
else
{
CPLog.info("Excluded: " + path);
CPLog.info("Excluded: " + relativeToRootPath(path));
}
total++;
}
@@ -207,17 +243,14 @@ function main()
//}
}
var outputFiles = {};
if (flatten)
if (options.flatten)
{
// phase 3a: build single Application.js file (and modified index.html)
CPLog.error("PHASE 3a: Flattening...");
var applicationJS = [],
indexHTML = readFile(rootDirectory + "/index.html");
// shim for faking bundle stuff. kind of a giant hack.
// Shim for faking bundle responses.
// We're just defining it here so we can serialize the function. It's not used within press.
// **************************************************
var fakeDidReceiveBundleResponse = function(aResponse)
{
var bundle = new objj_bundle();
@@ -236,45 +269,52 @@ function main()
objj_bundles[aResponse.filePath] = bundle;
}
// **************************************************
var applicationScript = [];
// add fake bundle response bookkeeping
applicationJS.push("var __fakeDidReceiveBundleResponse = " + String(fakeDidReceiveBundleResponse));
applicationJS.push("var __fakeBundleArchives = " + JSON.stringify(bundleArchives) + ";");
applicationJS.push("for (var i = 0; i < __fakeBundleArchives.length; i++) __fakeDidReceiveBundleResponse(__fakeBundleArchives[i]);")
applicationScript.push("(function() {")
applicationScript.push(" var didReceiveBundleResponse = " + String(fakeDidReceiveBundleResponse));
applicationScript.push(" var bundleArchiveResponses = " + JSON.stringify(bundleArchiveResponses) + ";");
applicationScript.push(" for (var i = 0; i < bundleArchiveResponses.length; i++)");
applicationScript.push(" didReceiveBundleResponse(bundleArchiveResponses[i]);");
applicationScript.push("})();");
// add each fragment, wrapped in a function, along with OBJJ_CURRENT_BUNDLE bookkeeping
for (var i = 0; i < evaledFragments.length; i++)
{
if (requiredFiles[evaledFragments[i].file.path])
evaledFragments.forEach(function(fragment) {
if (requiredFiles[fragment.file.path])
{
applicationJS.push("(function() {");
applicationJS.push("var OBJJ_CURRENT_BUNDLE = objj_bundles['"+pathRelativeTo(evaledFragments[i].bundle.path, rootDirectory)+"'];");
applicationJS.push(evaledFragments[i].info);
applicationJS.push("})();");
applicationScript.push("(function(OBJJ_CURRENT_BUNDLE) {");
applicationScript.push(fragment.info);
applicationScript.push("})(objj_bundles['"+relativeToRootPath(fragment.bundle.path)+"']);");
}
else
{
CPLog.info("Stripping " + evaledFragments[i].file.path);
CPLog.info("Stripping " + relativeToRootPath(fragment.file.path));
}
}
});
// call main once the page has loaded
applicationJS.push(
"if (window.addEventListener) \
window.addEventListener('load', function(){main()}, false); \
else if (window.attachEvent) \
window.attachEvent('onload', function(){main()});"
);
// call main once the page has loaded. FIXME: assumes synchronous script loading?
applicationScript.push("if (window.addEventListener)");
applicationScript.push(" window.addEventListener('load', main, false);")
applicationScript.push("else if (window.attachEvent)")
applicationScript.push(" window.attachEvent('onload', main);");
var indexHTML = FILE.read(FILE.join(rootPath, "index.html"), { charset : "UTF-8" });
// comment out any OBJJ_MAIN_FILE defintions or objj_import() calls
indexHTML = indexHTML.replace(/(\bOBJJ_MAIN_FILE\s*=|\bobjj_import\s*\()/g, '//$&');
var applicationScriptName = "Application-"+environment+".js";
var indexHTMLName = "index-"+environment+".html";
// add a script tag for Application.js at the very end of the <head> block
indexHTML = indexHTML.replace(/([ \t]*)(<\/head>)/, '$1 <script src = "Application.js" type = "text/javascript"></script>\n$1$2');
indexHTML = indexHTML.replace(/([ \t]*)(<\/head>)/, '$1 <script src = "'+applicationScriptName+'" type = "text/javascript"></script>\n$1$2');
// output Application.js and index.html
outputFiles[rootDirectory + "/Application.js"] = applicationJS.join("\n");
outputFiles[rootDirectory + "/index.html"] = indexHTML;
outputFiles[rootPath.join(applicationScriptName)] = applicationScript.join("\n");
outputFiles[rootPath.join(indexHTMLName)] = indexHTML;
}
else
{
@@ -282,43 +322,40 @@ function main()
CPLog.error("PHASE 3b: Rebuild .sj");
var bundles = {};
for (var path in requiredFiles)
{
var file = scope.objj_files[path],
filename = basename(path),
directory = dirname(path);
filename = FILE.basename(path),
directory = FILE.dirname(path);
if (file.path != path)
CPLog.warn("Sanity check failed (file path): " + file.path + " vs. " + path);
if (file.bundle)
{
var bundleDirectory = dirname(file.bundle.path);
var bundleDirectory = FILE.path(file.bundle.path).dirname();
if (!bundles[file.bundle.path])
bundles[file.bundle.path] = file.bundle;
if (bundleDirectory != directory)
CPLog.warn("Sanity check failed (directory path): " + directory + " vs. " + bundleDirectory);
// if it's in a .sj
var dict = file.bundle.info,
replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"];
bundlePlatforms = [dict objectForKey:"CPBundlePlatforms"],
replacedFilePlatforms = [dict objectForKey:"CPBundleReplacedFiles"];
// compute the platform used for this bundle
var platform = "";
if (bundlePlatforms)
platform = [bundlePlatforms firstObjectCommonWithArray:scope.OBJJ_PLATFORMS];
var replacedFiles = [replacedFilePlatforms objectForKey:platform];
if (replacedFiles && [replacedFiles containsObject:filename])
{
// compute the platform used for this bundle
var platform = "",
bundlePlatforms = [dict objectForKey:"CPBundlePlatforms"];
if (bundlePlatforms)
{
platform = [bundlePlatforms firstObjectCommonWithArray:scope.OBJJ_PLATFORMS];
if (platform)
platform = platform + ".platform/";
}
var staticPath = bundleDirectory + "/" + platform + [dict objectForKey:"CPBundleExecutable"];
var staticPath = bundleDirectory.join(platform + ".platform", [dict objectForKey:"CPBundleExecutable"]);
if (!outputFiles[staticPath])
{
outputFiles[staticPath] = [];
@@ -366,7 +403,7 @@ function main()
}
}
else
CPLog.info("Ignoring import fragment " + file.fragments[i].info + " in " + path);
CPLog.info("Ignoring import fragment " + file.fragments[i].info + " in " + relativeToRootPath(path));
}
else
CPLog.error("Unknown fragment type");
@@ -379,7 +416,7 @@ function main()
}
}
else
CPLog.warn("No bundle for " + path)
CPLog.warn("No bundle for " + relativeToRootPath(path))
}
// phase 3.5: fix bundle plists
@@ -387,11 +424,11 @@ function main()
for (var path in bundles)
{
var directory = dirname(path),
var directory = FILE.dirname(path),
dict = bundles[path].info,
replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"];
CPLog.info("Modifying .sj: " + path);
CPLog.info("Modifying .sj: " + relativeToRootPath(path));
if (replacedFiles)
{
@@ -415,171 +452,31 @@ function main()
outputFiles[path] = CPPropertyListCreateXMLData(dict).string;
}
}
}
function pngcrushDirectory(directory) {
var directoryPath = FILE.path(directory);
var pngs = directoryPath.glob("**/*.png");
// phase 4: copy everything and write out the new files
CPLog.error("PHASE 4: copy to output");
var rootDirectoryFile = new Packages.java.io.File(rootDirectory),
outputDirectoryFile = new Packages.java.io.File(outputDirectory);
// FIXME: intelligently copy only what we need (Resources directories?)
copyDirectory(rootDirectoryFile, outputDirectoryFile, optimizePNG);
for (var path in outputFiles)
{
var file = new java.io.File(outputDirectoryFile, pathRelativeTo(path, rootDirectory));
system.stderr.print("Running pngcrush on " + pngs.length + " pngs:");
pngs.forEach(function(dst) {
var dstPath = directoryPath.join(dst);
var tmpPath = FILE.path(dstPath+".tmp");
var parent = file.getParentFile();
if (!parent.exists())
{
CPLog.warn(parent + " doesn't exist, creating directories.");
parent.mkdirs();
var p = OS.popen(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ dstPath, tmpPath]);
if (p.wait()) {
CPLog.warn("pngcrush failed. Ensure it's installed and on your PATH.");
}
CPLog.info("Writing out " + file);
var writer = new java.io.BufferedWriter(new java.io.FileWriter(file));
if (typeof outputFiles[path] == "string")
writer.write(outputFiles[path]);
else
writer.write(outputFiles[path].join(""));
writer.close();
}
}
// Helper Utilities
// TODO: moved elsewhere?
function copyDirectory(src, dst, optimizePNG)
{
CPLog.trace("Copying directory " + src);
dst.mkdirs();
var files = src.listFiles();
for (var i = 0; i < files.length; i++)
{
if (files[i].isFile())
copyFile(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG);
else if (files[i].isDirectory())
copyDirectory(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG);
}
}
function copyFile(src, dst, optimizePNG)
{
if (optimizePNG && (/.png$/).test(src.getName()))
{
CPLog.warn("Optimizing .png " + src);
exec(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ src.getAbsolutePath(), dst.getAbsolutePath()]);
}
else
{
CPLog.trace("Copying file " + src);
var input = (new Packages.java.io.FileInputStream(src)).getChannel(),
output = (new Packages.java.io.FileOutputStream(dst)).getChannel();
input.transferTo(0, input.size(), output);
input.close();
output.close();
}
}
function dirname(path)
{
return path.substring(0, path.lastIndexOf("/"));
}
function basename(path)
{
return path.substring(path.lastIndexOf("/") + 1);
}
function absolutePath(path)
{
return String((new Packages.java.io.File(path)).getCanonicalPath());
else {
FILE.move(tmpPath, dstPath);
system.stderr.write(".").flush();
}
});
system.stderr.print("");
}
function pathRelativeTo(target, relativeTo)
{
var components = [],
targetParts = target.split("/"),
relativeParts = relativeTo ? relativeTo.split("/") : [];
var i = 0;
while (i < targetParts.length)
{
if (targetParts[i] != relativeParts[i])
break;
i++;
}
for (var j = i; j < relativeParts.length; j++)
components.push("..");
for (var j = i; j < targetParts.length; j++)
components.push(targetParts[j]);
var result = components.join("/");
return result;
}
function exec()
{
var printOutput = false;
var runtime = Packages.java.lang.Runtime.getRuntime()
var p = runtime.exec.apply(runtime, arguments);
var stdout = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getInputStream())),
stdoutString = "",
stderr = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getErrorStream())),
stderrString = "";
var done = false;
while (!done)
{
done = true;
if (s = stdout.readLine())
{
stdoutString += s;
if (printOutput)
CPLog.info("exec: " + s);
done = false;
}
if (s = stderr.readLine())
{
stderrString += s;
//if (printOutput)
CPLog.warn("exec: " + s);
done = false;
}
}
var code = p.waitFor();
return { code : code, stdout : stdoutString, stderr : stderrString };
}
function outputTransformer(os, document, encoding, standalone)
{
var domSource = new Packages.javax.xml.transform.dom.DOMSource(document);
var streamResult = new Packages.javax.xml.transform.stream.StreamResult(os);
var tf = Packages.javax.xml.transform.TransformerFactory.newInstance();
var serializer = tf.newTransformer();
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.VERSION, "1.0");
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "yes");
if (encoding)
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.ENCODING, encoding);
if (standalone)
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.STANDALONE, (standalone ? "yes" : "no"));
String(serializer.transform(domSource, streamResult));
// TODO: fix FILE.relative to always treat the source as a directory
return FILE.relative(FILE.join(relativeTo, ""), target);
}
+91 -100
View File
@@ -1,21 +1,23 @@
var objjPath = OBJJ_HOME+'/lib/Frameworks/Objective-J/rhino.platform/Objective-J.js',
bridgePath = OBJJ_HOME+'/lib/press/bridge.js',
envPath = "/Users/tlrobinson/280North/git/cappuccino/Tools/press/env.js";
var FILE = require("file");
/*
param context includes
scope: a global variable containing objj_files hash
processedFiles: hash containing file paths which have already been analyzed
ctx: js context
dependencies: hash mapping from paths to an array of global variables defined by that file
[importCallback]: callback function that is called for each imported file (takes importing file path, and imported file path parameters)
[referencedCallback]: callback function that is called for each referenced file (takes referencing file path, referenced file path parameters, and list of tokens)
[importedFiles]: hash that will contain a mapping of file names to a hash of imported files
[referencedFiles]: hash that will contain a mapping of file names to a hash of referenced files (which contains a hash of tokens referenced)
[processedFiles]: hash containing file paths which have already been analyzed
param file is an objj_file object containing path, fragments, content, bundle, etc
*/
function traverseDependencies(context, file)
{
if (!context.processedFiles)
context.processedFiles = {};
if (context.processedFiles[file.path])
return;
context.processedFiles[file.path] = true;
@@ -23,7 +25,7 @@ function traverseDependencies(context, file)
var ignoreImports = false;
if (context.ignoreAllImports)
{
CPLog.warn("Ignoring all import fragments. ("+file.path+")");
CPLog.warn("Ignoring all import fragments. ("+context.relativeToRootPath(file.path)+")");
ignoreImports = true;
}
else if (context.ignoreFrameworkImports)
@@ -31,7 +33,7 @@ function traverseDependencies(context, file)
var matches = file.path.match(new RegExp("([^\\/]+)\\/([^\\/]+)\\.j$")); // Matches "ZZZ/ZZZ.j" (e.x. AppKit/AppKit.j and Foundation/Foundation.j)
if (matches && matches[1] === matches[2])
{
CPLog.warn("Framework import file! Ignoring all import fragments. ("+file.path+")");
CPLog.warn("Framework import file! Ignoring all import fragments. ("+context.relativeToRootPath(file.path)+")");
ignoreImports = true;
}
}
@@ -40,9 +42,9 @@ function traverseDependencies(context, file)
if (!file.fragments)
{
if (file.included)
CPLog.warn(file.path + " is included but missing fragments");
CPLog.warn(context.relativeToRootPath(file.path) + " is included but missing fragments");
else
CPLog.warn("Preprocessing " + file.path);
CPLog.warn("Preprocessing " + context.relativeToRootPath(file.path));
file.fragments = objj_preprocess(file.contents, file.bundle, file);
}
@@ -53,17 +55,18 @@ function traverseDependencies(context, file)
if (!context.bundleImages[file.bundle.path])
{
var resourcesFile = new java.io.File(dirname(file.bundle.path) + "/Resources");
if (resourcesFile.exists())
var resourcesPath = FILE.path(file.bundle.path).dirname().join("/Resources");
if (resourcesPath.exists())
{
context.bundleImages[file.bundle.path] = {};
var pngFiles = find(resourcesFile, (new RegExp("\\.png$")));
for (var i = 0; i < pngFiles.length; i++)
{
var path = pathRelativeTo(pngFiles[i].getCanonicalPath(), resourcesFile.getCanonicalPath());
context.bundleImages[file.bundle.path][path] = 1;
}
resourcesPath.glob("**/*.png").forEach(function(png) {
var pngPath = resourcesPath.join(png);
var relativePath = pathRelativeTo(pngPath.absolute(), resourcesPath.absolute());
// this is used as a bit mask, not a boolean
context.bundleImages[file.bundle.path][relativePath] = 1;
});
}
}
var images = context.bundleImages[file.bundle.path];
@@ -71,7 +74,7 @@ function traverseDependencies(context, file)
var referencedFiles = {},
importedFiles = {};
CPLog.debug("Processing " + file.path + " fragments ("+file.fragments.length+")");
CPLog.debug("Processing " + file.fragments.length + " fragments in " + context.relativeToRootPath(file.path));
for (var i = 0; i < file.fragments.length; i++)
{
var fragment = file.fragments[i];
@@ -119,10 +122,10 @@ function traverseDependencies(context, file)
if (importedFile != file.path)
importedFiles[importedFile] = true;
else
CPLog.error("Ignoring self import (why are you importing yourself!?): " + file.path);
CPLog.error("Ignoring self import (why are you importing yourself?!): " + context.relativeToRootPath(file.path));
}
else
CPLog.error("Couldn't find file for import " + fragment.info + "("+fragment.type+")");
CPLog.error("Couldn't find file for import " + fragment.info + " ("+fragment.type+")");
}
}
}
@@ -197,11 +200,9 @@ function findImportInObjjFiles(scope, fragment)
}
// given a fresh scope and the path to a root source file, determine which files define each global variable
function findGlobalDefines(context, scope, rootPath, evaledFragments)
function findGlobalDefines(context, mainPath, evaledFragments)
{
addMockBrowserEnvironment(scope);
var ignore = cloneProperties(scope, true);
var ignore = cloneProperties(context.scope, true);
ignore['bundle'] = true;
var dependencies = {};
@@ -217,18 +218,18 @@ function findGlobalDefines(context, scope, rootPath, evaledFragments)
//}
// OVERRIDE fragment_evaluate_file
var fragment_evaluate_file_original = scope.fragment_evaluate_file;
scope.fragment_evaluate_file = function(aFragment) {
var fragment_evaluate_file_original = context.scope.fragment_evaluate_file;
context.scope.fragment_evaluate_file = function(aFragment) {
return fragment_evaluate_file_original(aFragment);
}
// OVERRIDE fragment_evaluate_code
var fragment_evaluate_code_original = scope.fragment_evaluate_code;
scope.fragment_evaluate_code = function(aFragment) {
var fragment_evaluate_code_original = context.scope.fragment_evaluate_code;
context.scope.fragment_evaluate_code = function(aFragment) {
CPLog.debug("Evaling "+aFragment.file.path + " / " + aFragment.bundle.path);
CPLog.debug("Evaluating " + context.relativeToRootPath(aFragment.file.path) + " (" + context.relativeToRootPath(aFragment.bundle.path) + ")");
var before = cloneProperties(scope);
var before = cloneProperties(context.scope);
if (evaledFragments)
{
@@ -238,20 +239,23 @@ function findGlobalDefines(context, scope, rootPath, evaledFragments)
var result = fragment_evaluate_code_original(aFragment);
var definedGlobals = {};
diff(before, scope, ignore, definedGlobals, definedGlobals, null);
diff(before, context.scope, ignore, definedGlobals, definedGlobals, null);
dependencies[aFragment.file.path] = definedGlobals;
return result;
}
runWithScope(context, scope, function(importName) {
runWithScope(context, function(importName) {
objj_import(importName, true, NULL);
}, [rootPath]);
}, [mainPath]);
return dependencies;
}
// takes a hash mapping from file names to hashes of global names defined in each file
// globals = { fileName { globalName : true }}
// returns a hash mapping from global names to arrays of file names in which those globals are defined
// dependencies = { globalName : [fileName] }
function coalesceGlobalDefines(globals)
{
var dependencies = {};
@@ -269,69 +273,70 @@ function coalesceGlobalDefines(globals)
return dependencies;
}
// create a new scope loaded with Objective-J
function makeObjjScope(context, debug)
// create a new scope loaded with Narwhal and Objective-J
function makeObjjScope(ctx, debug)
{
// init standard js scope objects
var scope = context.initStandardObjects();
if (debug)
{
scope.objj_alert = print;
scope.debug = true;
}
// init standard JS scope objects
var scope = ctx.initStandardObjects();
// give the scope "print"
scope.print = function(value) { Packages.java.lang.System.out.println(String(value)); };
// set these properties required for Narwhal bootstrapping
scope.NARWHAL_HOME = system.prefix;
scope.NARWHAL_ENGINE_HOME = FILE.join(system.prefix, "engines", "rhino");
// load and eval fake browser environment
//var envSource = readFile(envPath);
//if (envSource)
// context.evaluateString(scope, envSource, "env.js", 1, null);
//else
// CPLog.warn("Missing env.js");
// load and eval the bridge
var bridgeSource = readFile(bridgePath);
if (bridgeSource)
context.evaluateString(scope, bridgeSource, "bridge.js", 1, null);
else
CPLog.warn("Missing bridge.js");
// load and eval obj-j
var objjSource = readFile(objjPath);
if (objjSource)
context.evaluateString(scope, objjSource, "Objective-J.js", 1, null);
else
CPLog.warn("Missing Objective-J.js");
// load the bootstrap.js for narwhal-rhino
var bootstrapPath = FILE.join(scope.NARWHAL_ENGINE_HOME, "bootstrap.js");
ctx.evaluateReader(scope,
new Packages.java.io.FileReader(bootstrapPath),
"bootstrap.js",
1,
null
);
return scope;
}
// run a function within the given scope (func can be a function object if the source of the function is returned by toString() as it is by default)
function runWithScope(context, scope, func, arguments)
{
scope.__runWithScopeArgs = arguments || [];
var code = "("+func+").apply(this, this.__runWithScopeArgs); serviceTimeouts();";
return context.evaluateString(scope, code, "<cmd>", 1, null);
// get the Objective-J module from this scope, return the window object.
var OBJJ = scope.require("objective-j");
addMockBrowserEnvironment(OBJJ.window);
return OBJJ.window;
}
// add a mock browser environment to the provided scope
function addMockBrowserEnvironment(scope)
{
// TODO: complete this. or use env.js?
scope.Element = function() {
this.style = {}
}
scope.document = {
createElement : function() {
return new scope.Element();
if (!scope.window)
scope.window = scope;
if (!scope.location)
scope.location = {};
if (!scope.location.href)
scope.location.href = "";
if (!scope.Element)
scope.Element = function() {
this.style = {}
}
}
if (!scope.document)
scope.document = {
createElement : function() {
return new scope.Element();
}
}
}
// run a function within the given scope (func can be a function object if the source of the function is returned by toString() as it is by default)
function runWithScope(context, func, args)
{
var functionInScope = context.ctx.compileFunction(context.scope, String(func), "<runWithScope>", 1, null);
var result = functionInScope.apply(context.scope, args);
context.scope.require('browser/timeout').serviceTimeouts();
return result;
}
// does a shallow copy of an object. if onlyList is true, it sets each property to "true" instead of the actual value
@@ -363,17 +368,3 @@ function allKeys(object)
result.push(i)
return result.sort();
}
function find(src, regex)
{
var results = [];
var files = src.listFiles();
for (var i = 0; i < files.length; i++)
{
if (files[i].isFile() && regex.test(files[i].getAbsolutePath()))
results.push(files[i]);
else if (files[i].isDirectory())
results = Array.prototype.concat.apply(results, find(files[i], regex));
}
return results;
}
+123 -81
View File
@@ -16,128 +16,170 @@ function prompt () {
}
function which () {
echo "$PATH" | tr ":" "\n" | while read line; do [ -f "$line/$1" ] && return 0; done
echo "$PATH" | tr ":" "\n" | while read line; do [ -x "$line/$1" ] && echo "$line/$1" && return 0; done
}
function path_instructions () {
echo "Add \"$INSTALL_DIRECTORY/bin\" to your PATH environment variable in your shell configuration file (e.x. .profile, .bashrc, .bash_profile)."
echo "For example:"
echo " export PATH=$INSTALL_DIRECTORY/bin:\$PATH"
function ask_remove_dir () {
dir="$1"
if [ -d "$dir" ]; then
echo "================================================================================"
echo "Found an existing Narwhal/Cappuccino installation, $dir. Remove it automatically now?"
if prompt; then
rm -rf "$dir"
fi
fi
}
function ask_append_shell_config () {
config_string="$1"
shell_config_file=""
# use order outlined by http://hayne.net/MacDev/Notes/unixFAQ.html#shellStartup
if [ -f "$HOME/.bash_profile" ]; then
shell_config_file="$HOME/.bash_profile"
elif [ -f "$HOME/.bash_login" ]; then
shell_config_file="$HOME/.bash_login"
elif [ -f "$HOME/.profile" ]; then
shell_config_file="$HOME/.profile"
elif [ -f "$HOME/.bashrc" ]; then
shell_config_file="$HOME/.bashrc"
fi
echo " \"$config_string\" will be appended to \"$shell_config_file\"."
if prompt; then
if [ "$shell_config_file" ]; then
echo >> "$shell_config_file"
echo "$config_string" >> "$shell_config_file"
echo "Added to \"$shell_config_file\". Restart your shell or run \"source $shell_config_file\"."
return 0
else
echo "Couldn't find a shell configuration file."
fi
fi
return 1
}
if [ "--clone" = "$1" ]; then
GITCLONE=1
tusk_install_command="clone"
git_clone=1
else
tusk_install_command="install"
fi
INSTALL_DIRECTORY="/usr/local/narwhal"
TEMPZIP="/tmp/narwhal.zip"
github_project="280north-narwhal"
github_path=$(echo "$github_project" | tr '-' '/')
install_directory="/usr/local/narwhal"
tmp_zip="/tmp/narwhal.zip"
ORIGINAL_PATH="$PATH"
PATH_SAVED="$PATH"
if ! which "narwhal"; then
ask_remove_dir "/usr/local/share/objj"
ask_remove_dir "/usr/local/share/narwhal"
ask_remove_dir "/usr/local/narwhal"
if ! which "narwhal" > /dev/null; then
echo "================================================================================"
echo "Narwhal JavaScript platform is required. Install it automatically?"
echo "Narwhal JavaScript platform is required. Install it automatically now?"
if prompt; then
echo "================================================================================"
echo "To use the default location, \"$INSTALL_DIRECTORY\", just hit enter/return, or enter another path:"
read INSTALL_DIRECTORY_INPUT
if [ "$INSTALL_DIRECTORY_INPUT" ]; then
INSTALL_DIRECTORY="$INSTALL_DIRECTORY_INPUT"
echo "To use the default location, \"$install_directory\", just hit enter/return, or enter another path:"
read input
if [ "$input" ]; then
install_directory="$input"
fi
if [ "$GITCLONE" ]; then
echo "Cloning Narwhal..."
git clone git://github.com/280north/narwhal.git "$INSTALL_DIRECTORY"
if [ "$git_clone" ]; then
git_repo="git://github.com/$github_path.git"
echo "Cloning Narwhal from \"$git_repo\"..."
git clone "$git_repo" "$install_directory"
else
echo "Downloading Narwhal..."
curl -L -o "$TEMPZIP" "http://github.com/280north/narwhal/zipball/master"
zip_ball="http://github.com/$github_path/zipball/master"
echo "Downloading Narwhal from \"$zip_ball\"..."
curl -L -o "$tmp_zip" "$zip_ball"
echo "Installing Narwhal..."
unzip "$TEMPZIP" -d "$INSTALL_DIRECTORY"
rm "$TEMPZIP"
unzip "$tmp_zip" -d "$install_directory"
rm "$tmp_zip"
mv $INSTALL_DIRECTORY/280north-narwhal-*/* $INSTALL_DIRECTORY/.
rm -rf $INSTALL_DIRECTORY/280north-narwhal-*
mv $install_directory/$github_project-*/* $install_directory/.
rm -rf $install_directory/$github_project-*
fi
if ! which "narwhal"; then
export PATH="$INSTALL_DIRECTORY/bin:$PATH"
if ! which "narwhal" > /dev/null; then
export PATH="$install_directory/bin:$PATH"
fi
else
echo "Narwhal required, aborting installation. To install Narwhal manually follow the instructions at http://narwhaljs.org/"
exit 1
fi
fi
if ! which "narwhal"; then
echo "Error: problem installing Narwhal"
if ! which "narwhal" > /dev/null; then
echo "Problem installing Narwhal. To install Narwhal manually follow the instructions at http://narwhaljs.org/"
exit 1
fi
echo "Installing necessary dependencies..."
install_directory=$(dirname $(dirname $(which narwhal)))
if [ "$GITCLONE" ]; then
tusk update
tusk clone browserjs jake
else
tusk install browserjs jake
echo "================================================================================"
echo "Using Narwhal installation at \"$install_directory\". Is this correct?"
if ! prompt; then
exit 1
fi
echo "Installing necessary packages..."
if ! tusk update; then
echo "Error: unable to update tusk catalog. Check that you have sufficient permissions."
exit 1
fi
tusk $tusk_install_command browserjs jake
if [ `uname` = "Darwin" ]; then
echo "================================================================================"
echo "Would you like to install the JavaScriptCore engine for Narwhal?"
echo "This is optional but will make building and running Objective-J much faster."
if prompt; then
if [ "$GITCLONE" ]; then
tusk clone narwhal-jsc
else
tusk install narwhal-jsc
fi
pushd "$INSTALL_DIRECTORY/packages/narwhal-jsc"
make webkit
popd
tusk $tusk_install_command narwhal-jsc
# echo "================================================================================"
# echo "Rhino is the default Narwhal engine, should we change the default to JavaScriptCore for you?"
# echo "This can by overridden by setting the NARWHAL_ENGINE environment variable to \"jsc\" or \"rhino\"."
# echo "(Note: you must use Rhino for certain tools such as \"tusk\")"
# if prompt; then
# tusk engine jsc
# fi
if ! (cd "$install_directory/packages/narwhal-jsc" && make webkit); then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "WARNING: building narwhal-jsc failed. Hit enter to continue."
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
read
elif ! [ "$NARWHAL_ENGINE" = "jsc" ]; then
echo "================================================================================"
echo "Rhino is the default Narwhal engine, should we change the default to JavaScriptCore for you?"
echo "This can by overridden by setting the NARWHAL_ENGINE environment variable to \"jsc\" or \"rhino\"."
ask_append_shell_config "export NARWHAL_ENGINE=jsc"
fi
fi
fi
export PATH="$ORIGINAL_PATH"
if ! which "narwhal"; then
SHELL_CONFIG=""
# use order outlined by http://hayne.net/MacDev/Notes/unixFAQ.html#shellStartup
if [ -f "$HOME/.bash_profile" ]; then
SHELL_CONFIG="$HOME/.bash_profile"
elif [ -f "$HOME/.bash_login" ]; then
SHELL_CONFIG="$HOME/.bash_login"
elif [ -f "$HOME/.profile" ]; then
SHELL_CONFIG="$HOME/.profile"
elif [ -f "$HOME/.bashrc" ]; then
SHELL_CONFIG="$HOME/.bashrc"
fi
EXPORT_PATH_STRING="export PATH=\"$INSTALL_DIRECTORY/bin:\$PATH\""
export PATH="$PATH_SAVED"
if ! which "narwhal" > /dev/null; then
echo "================================================================================"
echo "You must add Narwhal's \"bin\" directory to your PATH environment variable. Do this automatically now?"
echo "\"$EXPORT_PATH_STRING\" will be appended to \"$SHELL_CONFIG\"."
if prompt; then
if [ "$SHELL_CONFIG" ]; then
echo >> "$SHELL_CONFIG"
echo "$EXPORT_PATH_STRING" >> "$SHELL_CONFIG"
echo "Added to \"$SHELL_CONFIG\". Restart your shell or run \"source $SHELL_CONFIG\"."
else
echo "Couldn't find a shell configuration file."
path_instructions
fi
else
path_instructions
export_path_string="export PATH=\"$install_directory/bin:\$PATH\""
if ! ask_append_shell_config "$export_path_string"; then
echo "Add \"$install_directory/bin\" to your PATH environment variable in your shell configuration file (e.x. .profile, .bashrc, .bash_profile)."
echo "For example:"
echo " $export_path_string"
fi
fi
if [ "$CAPP_BUILD" ]; then
if [ -d "$CAPP_BUILD" ]; then
echo "================================================================================"
echo "An existing \$CAPP_BUILD directory at \"$CAPP_BUILD\" exists. The previous build may be incompatible. Remove it automatically now?"
if prompt; then
rm -rf "$CAPP_BUILD"
fi
fi
else
echo "================================================================================"
echo "Before building Cappuccino we recommend you set the \$CAPP_BUILD environment variable to a path where you wish to build Cappuccino."
echo "If you have previously set \$CAPP_BUILD and built Cappuccino you may want to delete the directory before rebuilding."
fi
echo "================================================================================"
echo "Bootstrapping of Narwhal and other required tools is complete. You can now build Cappuccino."
+11 -4
View File
@@ -7,10 +7,14 @@ function ensurePackageUpToDate(packageName, requiredVersion)
print("You are missing package \"" + packageName + "\", version " + requiredVersion + " or later. Please install using \"tusk install "+packageName+"\" and re-run jake");
require("os").exit(1);
}
var version = packageInfo.version;
if (version && require("util").compare(version.split("."), requiredVersion.split(".")) !== -1)
// newer versions of packages provide already split versions
var version = typeof packageInfo.version === "string" ? packageInfo.version.split(".") : packageInfo;
if (typeof requiredVersion === "string")
requiredVersion = requiredVersion.split(".");
if (version && require("util").compare(version, requiredVersion) !== -1)
return;
print("Your copy of " + packageName + " is out of date (version " + version + "). Update? yes or no:");
@@ -28,7 +32,7 @@ function ensurePackageUpToDate(packageName, requiredVersion)
// UPDATE THESE TO PICK UP CORRESPONDING CHANGES IN DEPENDENCIES
ensurePackageUpToDate("jake", "0.1.1");
ensurePackageUpToDate("browserjs", "0.1");
ensurePackageUpToDate("browserjs", "0.1.1");
var Jake = require("jake");
@@ -113,6 +117,9 @@ function partial_require(path, exports)
// FIXME: is there a better way to do this???
OS.system = function(aCommand)
{
if (Array.isArray(aCommand))
aCommand = aCommand.map(OS.enquote).join(" ");
return system("PATH=" + OS.enquote(bin) + ":$PATH " + aCommand);
}