TaskCard Plans for 1.1

Since the release of 1.0 just a couple weeks ago I have got lots of good feedback from the users. Here’s what’s planned for the next version and already under development:

  • Preference to not handle application switching like Dashboard.
  • Cut, Copy and pasting tasks. Text from other applications can now be pasted easily into cards also.
  • Preference to hide the desktop with an image for a cleaner look.
  • Global opacity and gradient settings for all cards.
  • Auto-update.
  • Real help file in the application Help menu like other OS X apps.
  • Transition effects when opening/closing cards.
  • Some multiple monitor support is added but it’s not yet complete.

Some ideas planned for later releases:

  • Printing.
  • Undo/redo when deleting and adding tasks.
  • File/URL task-attachments that can be opened in the Finder or in Safari.
  • iCal synching. I’m not sure how this can be done because there is no calendar concept in TaskCard but I suppose there could be done with some effort. I would like to see a calendar in TaskCard or at least groups for today, this week, this month etc…
  • Saving/opening cards to disk so they can be moved across computers.
  • Minimizing cards like windows in the Finder.
  • “Stacks” of cards to help you organize cards into related categories, like sub-tasks for cards.
  • Themes. I thought that it would be fun for users to create custom themes for card designs if they had a portable format they could “fill out” easily.
  • Notifications of tasks ending soon.
  • Filing cabinet for cards you don’t want to delete but may want to look at later.
  • Better color picker that has less options and easier to use.

About iPhone support. Some users mentioned this and yes, TaskCard was designed from the start to become an iPhone app. If you notice the entire interface is totally graphically and thus a very easy port to iPhone without very much changing in the interface. This is however a whole different application we’ll have to wait a while for this one. 😉

PascalGladiator 0.7.1 Released

This releases is mainly about optimizations and highly recommended. Scrolling/selecting speeds will see a noticeable difference on larger files and a bug causing the program to get slower and slower as it ran was been fixed. I don’t know why but the POSIX regex library (from GNU) was getting “stuffed” when releasing memory probably in some caching scheme, but I don’t know if I caused this or it’s a bug. The result was files taking from 2 seconds to parse to 10 depending on how long the program was running. Instead of fighting with it I replaced all regular expressions to the PCRE library which I believe is wider supported and performance better than POSIX.

As a small bonus there is now support for Objective-C dialect which was recently introduced in FPC. Objcclass/objcprotocol/objccategory (doesn’t exist yet in FPC though) are support as well as “class” methods which are used instead of constructors. Get the latest build of FPC and enjoy!

Objective-P

Seemingly out of now where FPC now supports an impressively complete Objective-C dialect (Objective-P may we call it?) making PasCocoaKit obsolete. However, the PHP parser script used for PasCocoaKit has been used for the new headers with little modification so it wasn’t all a waste. It hasn’t even been 1 year since I developed PasCocoaKit and users were talking about a native FPC dialect so I consider this to have happened very fast and I’m quite surprised.

In coming versions of PascalGladiator I will support the new dialect in the syntax parser and start to package example programs with distribution, a feature only made possible as of 0.7 with it’s improved projects.

As far as I’m aware the key missing features are properties (from Objective-C 2.0) and Categories. At some points excessive type casting must be used to override Pascal’s strong typing conventions but this will be fixed in the future I would hope. Otherwise my tests show that the latest version is practically ready for full time development.

Very special thanks for Jonas and Dmitry for their work on the compiler and promptly fixing bugs in the first 2 weeks of release. Everyone is urged to download the latest version of FPC and test these new features so they can be made stronger.

PascalGladiator 0.7 Released

This is the long awaited released which replaces the text editor WASTE with NSTextView using PasCocoaKit and HICocoaView API. Not only is the text editor greatly improved (especially in the performance area) but it features many other enhancements you will enjoy. All of my old code has been ported to Object-Pascal and custom HIView’s and the DataBrowser were also updated producing better results in general.

In the 8 months since releasing 0.4 there was a considerable amount of time spent developing PasCocoaKit then replace the WASTE text editor which used all throughout the program making it extremely difficult to part ways with. The end result is quite excellent though thanks to the intelligent design of NSTextView compared to WASTE. I’m very happy to say after years of very poor WASTE performance I’m rid of that thing and can start making a truly powerful editor core. Sadly however I removed code folding as it was too complicated to replace for this release but it will be ported to the new NSTextView system eventually.

As of this version PascalGladiator is becoming quite a useful tool indeed but my big regret still is that the debugger is not working 100%. Included in 0.7 are some enhancements such as a HUD display which displays symbols in the editor but other features are broken. I would have hoped more than 1 year after the initial release this feature would be working but it never got enough attention in face of these massive efforts, first code folding (big mistake, and now it’s even missing!) and now the text editor. It’s again on top of the priority list after fixing memory leaks and general stability.

This is the biggest update since the initial release, so here is the list of changes.

  • PascalGladiator is now 10.5 and higher only. I’m very sorry about this but the new HICocoaView API which was absolutely required only exists in 10.5.
  • FINALLY! NSTextView for the text editor core. WASTE is banished to the pit once and for all.
  • Code folding is not yet implemented into NSTextView (yet) so it’s pulled
  • All DataBrowsers and custom HIViews are re-written in Object Pascal and moved out of static libraries.
  • Projects now archive their data into property lists and are much safer, plus you can edit them by hand in the project bundle.
  • New logo and application icon.
  • Single file editor for editing files without projects.
  • Directory browser for navigation folders without projects (drag folders on the application icon).
  • Search PasCocoaKit reference in library.
  • Class browser is removed (for now) and replaced with light-weight class list in the project browser.
  • Resource group now automatically finds NIB’s in your project.
  • Disk browser mode in project (the real directory structure as it exists on the hard disk).
  • Edit RTF files and use the Cocoa font panel.
  • Sweet PascalGladiator logo in the empty tab view pane.
  • Find/replace can now search any text field (i.e. console/reference).
  • If you build an application you can browse memory leaks (using “leaks”) by showing the memory leaks window in the debug menu. If you enable “MallocLeaks” in the preferences you get a stack trace for each leak.
  • The debugging has a HUD mode which sits above the tabs like in Xcode. You can still however using the main debugger window.
  • While debugging, symbols that have values are hilited in source and when clicked show their value in a contextual help tag.
  • Syntax is compiled in the background when files are saved and re-styled in any open documents.
  • Cocoa exceptions can be debugged for PasCocoa projects.
  • The editor has an XML mode for editing .plists.
  • Builds can be stopped now using the button in the console.
  • You can turn off anti-aliasing in the preferences window.
  • Recent items are now ordered properly and organized by group: document, folder and project.
  • Smart folders in the projects.
  • New batch find which lets you search by folder also.
  • Cocoa spelling is enabled and will only search comments or strings, not actual code.
  • By turning on CFLog in the debugger preferences warnings issued from CFLog will stop execution.
  • Backups! Set backup preferences then restore by selecting the version in the Editor menu or editor’s action menu in the lower toolbar. Special thank you to Richard Ward for suggesting this and giving a simple implementation idea.
  • Symbol browsers remember their selection/scroll position in between changing documents.
  • Compile files item in the project menu that lets you select interfaces which contain symbols you would like to appear in the project.
  • 10.4/10.5 have different debugger options (-g or -gw2 -Xg) when compiling.
  • Syntax themes are working again after being broken in 0.4.
  • Font and background color are enabled in syntax style preferences, don’t have too much fun!
  • The symbol menu now contains section headers for better readability.
  • Typing helpers are re-worked and now are editable using /PascalGladiator.app/Contents/Resources/Code Sense/typing helpers.plist and regular expressions
  • User notes. lines starting with @@ written to STDOUT (using writeln for example) will appear in the error console.
  • Open quickly window in the project menu which lets you open any file in the project by file name.
  • When browsing folders you can search their contents by file in the Edit > Find > Find in … menu.
  • Project backups! PascalGladiator now uses the “rsync” utility to backup and restore projects.
  • Debug in Terminal option in the Project menu. This will execute the gdb command PascalGladiator debugger uses into Terminal.app for manually debugging. This is a meant to be a “crutch” short-term solution while the graphical debugger is under development and not always working properly.
  • Target paths can be selected using navigation services and auto-resolve to their relative position.
  • You can kill the target application while running with the “kill” button in the console window.
  • New projects templates are more complete and improved.
  • Text editor improvements:
    • Macros can be assigned command-keys
    • Macros in edit menu
    • New code completion (native NSTextView feature)
    • Context sensitive spelling checking (only strings/comments are searched)
    • Regular expressions in find/replace.
    • All new Cocoa style find/replace.
    • Spelling suggestions in the contextual menu.
    • Macros can accept document text as input, offset of the cursor and text length
    • New “select” sub menu in edit menu.
    • Shifting text is improved.
    • Unlimited split views.
    • Bookmarks in the gutter.
    • Shows invisible characters.

PasCocoaKit Guide

Memory management

Like with Cocoa objects are constantly being created and disposed of, in PasCocoa wrappers are being generated, often behind the scenes from inside the headers. To deal with this flood of extra memory that normally would not exist in Cocoa, additional memory management needs to be introduced in order to spare the user from manually manage it. The first step to using PasCocoa safely is understanding how memory works.
Also important reading is how Cocoa manages memory, as the two are directly linked.

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

Deferred releases
Wrappers that are created internally within the headers from constructor methods are added to an auto release table for deferred release (using NSRunLoop). This means you can guarantee the wrapper will exist in the current scope but will be released upon the next event loop cycle. If you wish to transfer ownership you must call retain on the object, which will remove it from the table and retain the Objective-C object. When you are finished using the object you must call release, which will free both the wrapper and internal Objective-C object.

The rules for which constructors return objects that are owned by the user are ambiguous and rely on you being familiar with the rules of memory management in Cocoa. Here is a good guide:

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

These type of constructors do not allocate and will be auto released. When the object is disposed of by calling release it will only dispose of the wrapper, not the Objective-C object (unless retain was called prior, see section b).

constructor NSColor.redColor;
constructor NSNotificationCenter.defaultCenter;
constructor NSApplication.sharedApplication;

These type of constructors do allocate and they will not be auto released. When the object is disposed of by calling release it will release both the wrapper and the Objective-C object.

constructor NSTextView.initWithFrame(frameRect: NSRect);
constructor NSDocument.initWithType_error(typeName: CFStringRef; var outError: NSErrorRef);

If you are allocating wrappers in performance sensitive code, or loops within the current scope you should retain the object to prevent generating large (and pointless) auto release tables. For example:

{ This is wrong, the auto release table now has 1000 entries to dispose of }
for i := 1 to 1000 do
  CFShow(NSColor.redColor.description);

{ This is correct,  the object is retained (thus removed from the table) and released once }
color := NSColor.redColor.retain;
for i := 1 to 1000 do
  CFShow(color.description);
color.release;

Retain/Release
Balancing retain and release calls is the same as in Cocoa except one difference: wrappers begin with their retain count at zero (unless they are allocated by Cocoa, they begin at 1. see section a above). When they are released the retain count is decremented 1, if the count reaches -1 the wrapper is released but not the Objective-C object. If the count reaches 0 both objects are released. For example:

color := NSColor.redColor   // retain count = 0
color.release;              // retain count = -1, release the wrapper

color := NSColor.redColor   // retain count = 0
color.retain;               // retain count = 1, you own the object
color.release;              // retain count = 0, release both

textField := TTextField.initWithFrame(textFieldRect); // retain count = 1 because initWithFrame allocates an object
textField.release;          // retain count = 0, release both

Wrapper Tables
All NSObjects maintain a wrapper table which releases all of it’s entries when the object is destroyed. You can append items to the table by delegating to an “owner” (see section d) or directly to an object. Read section d for more information.

{ Add value to the wrapper table of "self" }
value := NSValue.CreateWithHandle(someObject).manageObject(self);

{ Use AppendWrapperTable for a 2-line approach }
color := NSColor.blueColor;
myWindow.AppendWrapperTable(color);  // color belongs to myWindow
myWindow.release;                    // wrapper table is released, including color

{ Retrieve wrappers using a generic untyped object (id) }
color := myWindow.GetWrapper(someColor);  // someColor is a Cocoa object without a Pascal wrapper

{ Remove the object for efficiency }
color.RemoveFromTable;

Delegating Management
To make managing wrappers more convenient you can “delegate” the object to another which you are certain will be disposed of. This process adds the wrapper to the owning objects wrapper table (see section c). For example:

color.redColor.manageObject(myWindow);

When the object myWindow is disposed it will release the wrapper table which contains color.

Caching Objects
It is common that a Cocoa object may maintain any number of internal/static objects that you can retrieve and manipulate using accessor methods. When the accessor methods are called they will return deferred wrappers, which can be inefficient if you access the object often. To solve this you can “cache” objects which essentially removes the object from the auto release table and delegates (see section d) ownership to another object (which are certain will be released). Note, the object is not retained, the original retain count still stands. For example:

textView.textStorage.cacheObject(textView);
This code will return an NSTextStorage wrapper from textStorage and cache the object to textView which a NSTextView. When textView is disposed it will release it’s wrapper table, including the NSTextStorage object. Please note, only cache objects you are certain are static, i.e. they will not be released before the object who owns them is.

If you wish to un-cache the object, for example if you want to change the Cocoa reference, use RemoveFromTable.

textView.textContainer.cacheObject(owner);  // the object is cached to "owner"
textView.textContainer.RemoveFromTable;     // remove it from the cache
textView.setTextContainer(newStorage);      // we can change the Cocoa reference now safely

Or, you can simply retain the wrapper to your own instance variable and release it at any time:

myTextContainer := textView.textContainer;   // retain count = 0
size := myTextContainer.containerSize;       // use our wrapper
myTextContainer.release;                     // retain count = -1, release the wrapper, but not the Cocoa object.

Instantiating Objects from InterfaceBuilder

If you use InterfaceBuilder you will need to intervene when objects are instantiated and provide your wrapper method. To do this you must override one of a few methods depending on the type of object.

  • InstantiateWithInit (init). Custom classes, generally sub classed from NSObject.
  • InstantiateWithView (initWithFrame:). Classes descendent of NSView
  • InstantiateWithWindow (initWithContentRect:styleMask:backing:defer:). Classes descendent of NSWindow
  • InstantiateWithCoder (initWithCoder:). Any other object in InterfaceBuilder which was not included above.

To learn about why this is important read this article: http://developer.apple.com/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW19. These methods implement initialization methods that are called when the NIB is loaded and allow you to assign the wrapper to the instance allocated from Cocoa.

This is ugly boiler plate code needed for every class appearing in InterfaceBuilder until FPC has better runtime support. The example below instantiates a custom NSView and allocates our wrapper TCustomView. Basically we call Instantiate with our newly allocated wrapper (TCustomView) and the results from inherited, which invokes the Objective-C super class. From here you can override AddMethods to add methods to the class. The object will be released automatically from Cocoa, do not call release on these objects unless you made a prior call to retain. For example:

class function TCustomView.InstantiateWithView (_self: objc.id; cmd: SEL; frameRect: CGRect): Pointer; cdecl; static;
begin
  result := NSObject.Instantiate(TCustomView.CreateFromNIB, inherited InstantiateWithView(_self, cmd, frameRect));
end;

 
Finally you must register the class before the NIB is loaded, probably in the main program block. The method RegisterFromNIB will override the proper initialization methods in the class using a constant:

  • kRegisterCustomObject. Custom classes, generally sub classed from NSObject.
  • kRegisterStandardObject. Classes descendent of NSView
  • kRegisterViewObject. Classes descendent of NSWindow
  • kRegisterWindowObject. Any other object in InterfaceBuilder which was not included above.

So, if you want to register a class named TCustomView as a view object do the following:

TCustomView.RegisterFromNIB(kRegisterViewObject);

dealloc
The NSObject method dealloc has been overridden automatically behind the scenes and it will be invoked by Cocoa. If you override the destroyer method Destroy you can dispose of instance variables when the class is released by Cocoa.

awakeFromNib
This is normally a method defined in Cocoa (awakeFromNib:) but we implement a special version that is called when a new object has been fully initialized and all it’s outlets and actions connected. Override this method to initialize private instances variables.

IBActions

PasCocoa supports IBActions but they require manually registering methods to the Objective-C runtime. This step can be removed when FPC has better runtime support. Here is an example:
type
  TMyDelegate = class (NSObject)
    procedure doSomething (sender: id);
    procedure AddMethods; override;
  end;

procedure TMyDelegate.AddMethods;
begin
  AddIBAction('doSomething:', Pointer(doSomething));
end;

In AddMethods you call AddIBAction with the name of the selector (always suffixed with : ) and a pointer to the method. It’s good convention to name the method and the selector the same (including case) but this is not strictly enforced. Please note that when adding methods to the class they must follow that same format, a procedure with one parameter of type id.  You can create a wrapper from the sender if needed. For example if the sender was a button (NSButton)

button := NSButton.CreateWithHandle(sender);

This manual will not go into the details of how to create and assign targets for these actions in InterfaceBuilder.

IBOutlets

Once again, IBOutlets are supported but require ugly and annoying boiler plate code until FPC supports better runtime access. The example below overrides ConnectIBOutlet and by checking the name parameter allocates a new wrapper and sets it to an instance variable with the same name (textView). The last parameter theObject is the Objective-C object allocated by the NIB. Also note we call manageObject on self which means the wrapper will be disposed with TMyDelegate.
function TMyDelegate.ConnectIBOutlet (name, theType: String; theObject: objc.id): Pointer;
begin
  if name = 'textView' then
    textView := NSTextView.CreateWithHandle(theObject).manageObject(self);
end;

Additionally you need to register these outlets with the Objective-C runtime so the NIB knows how to send messages to them for initialization. To do this call AddIBOutlet with the name of the outlet as defined in InterfaceBuilder. For example:
 
AddIBOutlet('textView');

This manual will not go into the details of how to create outlets and connect them with user interface elements in InterfaceBuilder.

Using Delegate Methods and Controllers

PasCocoa offers a big convenience by adding all delegate methods in both AppKit and Foundation framework in NSObject and auto-wrapping parameters that contains NSObject’s. All you must do is simply override the method you require and add it to the runtime. For example to respond to applicationDidFinishLaunching events from an application delegate controller:

type
  TAppController = class (NSObject)
    procedure applicationDidFinishLaunching(notification: NSNotification); override;
    procedure AddMethods; override;
  end;

procedure TAppController.applicationDidFinishLaunching(notification: NSNotification);
begin
  CFShow(notification.name);
end;

procedure TAppController.AddMethods;
begin
  add_applicationDidFinishLaunching;
end;

To add the method use the name of the method prefixed with “add_”, which makes: add_applicationDidFinishLaunching in our example. Then override the method using plain Pascal. Please note that the parameter notification is an allocated wrapper to NSNotification which will be disposed as soon as the method ends. Do not attempt to retain these wrappers.

Subclassing Cocoa Classes & Overriding Methods

If you want to override methods defined in existing Cocoa classes you must utilize the wrapper methods built into each Cocoa class. Each method in a class has a corresponding wrapper method: implemented, super and override. To call any particular method you simply prefix the method followed by an underscore. For example if you want to call the super classes implementation of drawRect you call super_drawRect.

Each constructor method in the headers will automatically register and allocate an instance of the sub class being created. In the example below initWithFrame registers TTextField in the Objective-C runtime (if it did not exist), assigns a reference to the object (self) to the Objective-C object then call AddMethods to allow the user to add, or override methods in the class.

In the example below we created a new instance of TTextField (a subclass of NSTextField), override drawRect and then override the implemented method implemented_drawRect, where drawing is performed. Also note that we can call the super classes implementation with super_drawRect. The steps in order are:

  1. Override AddMethods.
  2. Override methods using override_theMethod.
  3. Override the implemented method (in the Pascal class) using implemented_theMethod.
  4. Optionally call the super class using super_theMethod.

type
  TTextField = class (NSTextField)
    procedure implemented_drawRect (rect: NSRect); override;
    procedure AddMethods; override;
  end;

procedure TTextField.implemented_drawRect (rect: NSRect);
begin
  super_drawRect(rect);
  NSRectFill(bounds);
end;

procedure TTextField.AddMethods;
begin
  override_drawRect;
end;

textField := TTextField.initWithFrame(textFieldRect);

Type safety

PasCocoa defines some additional types for each Cocoa class that help you protect against confusing wrappers with the actual Objective-C object. For example NSTextView declares these 2 types:

NSTextViewRef = id;
NSTextViewPointer = Pointer;

It is important in functions that return Cocoa objects you use the actual Cocoa object, not the wrapper. In the headers implemented methods that you can override, they are careful to request the “Ref” of the object as returning the wrapper will produce an error. For example if you override NSTextView.backgroundColor you are expected to an NSColor object, but not the wrapper.

function TTextView.implemented_backgroundColor: NSColorRef;
var
  color: NSColor;
begin
  color := NSColor.redColor;
  result := color.Handle; // return the Handle, not color.
  color.release; // retain count = -1, release the wrapper but not the Handle
end; 

Note in this example you use Handle to reference the Objcetive-C object. Similarly, in some places a pointer to an object is requested, in those cases use NS***Pointer.

Selectors

Selectors in Objective-C are defined as SEL = Pointer but in the headers a type SELString is accepted where a selector (SEL) would normally be used. This is because the methods in the headers automatically call sel_registerName for you.

Adding Observers to the Notification Center

Adding observer methods to a notification center is made possible using the same method as IBActions. For example if you want to add the selector processEditing: follow the example below. Note, when adding methods to the class they must follow that same format, a procedure with one parameter of type id.

type
  TTextDelegate = class (NSObject)
    procedure processEditing (sender: id);
    procedure AddMethods; override;
 end;

procedure TTextDelegate.processEditing (sender: id);
var
  notification: NSNotification;
begin
  notification := NSNotification.CreateWithHandle(sender);
  CFShow(notification.name);
end;

procedure TTextDelegate.AddMethods;
begin
  NSNotificationCenter.defaultCenter.addObserver_selector_name_object(self, 'processEditing:', NSTextStorageDidProcessEditingNotification, nil);

  AddObserver('processEditing:', Pointer(processEditing));
end;

This code adds the selector processEditing: to the default notification center and then calls AddObserver to add the method to the Objective-C runtime.

Toll-Free Bridges

Currently CoreFoundation types are preferred over their Cocoa counterparts because it’s safer to have all methods expecting an opaque type rather than an object. This means that methods that returns objects and implemented methods that generate wrappers will return the CoreFoundation type.  Ideally the methods would be able to get the type of the parameter at runtime and choose Cocoa or CoreFoundation. If you want to access the Cocoa version you can use alloc to gain quick inline access:

function TController.tableView_writeRows_toPasteboard(tableView: NSTableView; rows: CFArrayRef; pboard: NSPasteboard): LongBool;
begin
 if NSArray.alloc(rows).objectAtIndex(0) <> nil then
  result := true;
end;

A deferred wrapper will be created and auto-disposed allowing you to use an accessor method. This is the preferred method for “inline” access and Objective-C like syntax.

Methods that use toll-free bridge types will accept the CoreFoundation version, which means you must not pass wrappers to Cocoa objects even though they are “toll-free” bridges. In order to use a Cocoa object you must pass Handle which is the Objective-C object. For example:

someString := NSString.initWithString(CFSTR('some string value'));    // creates a NSString from CFString
newString := someString.stringWithString(someString.Handle);          // use the Handle instead of the wrapper

Because stringWithString requests CFStringRef you must pass Handle which is the Objective-C object, and a toll-free bridge.

 Dynamically Typed Objects (id or NSObjectRef)

Types of id (or NSObjectRef) are untyped Objective-C objects who’s type can dynamically change during runtime. In PasCocoa however we must manually create wrappers depending on what class the object should be. To gain quick inline access to accessor methods for any class use alloc. For example:

writeln(NSObject.alloc(anObject).description);

In that example we create a temporary wrapper to NSObject will be auto-released and invoke a method, all in a single line, thus making it “inline” access.

It is very important you remember to use Handle (the Objective-C object the class wraps) when passing arguments to Cocoa code. For example:

class function loadNibNamed_owner(nibName: NSString; owner: NSObjectRef): LongBool;
NSBundle.loadNibNamed_owner(CFSTR('MainMenu'), NSApp.Handle);

Notice “owner” is NSObjectRef so we pass NSApp.Handle (the Objective-C object), not NSApp (which is the Pascal wrapper). Confusing the 2 types will throw compiler errors but in some cases it may be tempting to type cast and be done with it. Don’t.

Protocols

Protocols in PasCocoa are plain procedural calls which accept the first argument as id (or NSObjectRef) and are prefixed by the name of the protocol (in the Cocoa headers) followed by an underscore. For example:


function NSObject_respondsToSelector(sourceObject: NSObject; aSelector: SELString): LongBool;

This function refers to the method respondsToSelector: in the protocol @protocol NSObject.

To do

  • NSObject is not fully implemented, including all it’s various protocols and categories, which are numerous.
  • Reading IBOutlets from NIBs. I think this is possible but you will still have to connect them manually in code. 🙁
  • @protocols are not yet integrated into classes which conform to them. This is complicated and may run into troubles.
  • WebKit API headers

Bugs

  • Calling a super class is not tested and likely has problems
  • Functions that return structures are still not well tested
  • Function pointers from callback structures in the headers are incomplete
  • Types are still not 100% correct in all places
  • There is no concrete way to know which methods are constructors in Objective-C. Furthermore, certain methods with alloc, init, copy included in the name are owned by YOU the user, not the class. If there are methods parsed wrong based on that sloppy logic that only humans can decode, the memory management may cause crashes.
  • I’m not going to guarantee all the memory management is perfect as it has not been tested for very long. Consider version one to be buggy.

PascalGladiator: Key Features

The key features of PascalGladiator have not been documented beyond a simple mention in a list, until now!

Reference Library.

Reference LibraryThis may be my favorite feature in PascalGladiator because of the hours it saves me switching to Safari to view the Apple reference library online or digging around the interfaces. Simply by contextual clicking on a selected word (and choosing “Look up … in reference”) it will query all the Carbon interfaces for functions of type definitions that match the string and show you a preview of where it exists. This is extremely useful for checking function parameters and record fields etc…

Eventually I would like this feature to resemble Xcode’s with actual HTML pages from the Apple reference as well, but that is for later. For now the system is fast and does exactly what you need.

Contextual Menu.

Contextual Menu

This was nearly the entire reason I decided to make PascalGladiator instead of using Xcode – the ability to navigate symbols by contextual clicking. I’m also proud to say contextual symbol navigation is better than Xcode!

First is basic navigation, by clicking on a symbol and choosing “Go to … in myfile.pas” you jump to that symbol. If there are multiple symbols with the same name they will all be displayed.

Second, if the symbol you select in an object or class an additional item “Go to object members of …” which lets you jump to any methods of the class. Also, the item “Go to class hierarchy for …” which lets you jump to any of the super-classes of the selected class. 

Targets.

targetsPascalGladiator lets you choose an unlimited number of targets for each project. Currently supported are Applications (bundles with nibs) and Dynamic Libraries. I was working on framework and static libraries but the work was not completed after having linker/FPC problems. I will come back to this.

Targets let you specify search paths for source files, libraries and frameworks, change FPC compiler settings and specify basics like output and input locations. 

To create a new project use the action menu in the toolbar below the project browser.

Go to Symbol.

goto-symbolI got this idea from TextMate after seeing how useful it was and my own problem of always performing searches to find symbol definitions in a file. This is certainly faster and brings you exactly to the right location instead of jumping around searching.

Command-shift-T and you’re there.

 

 

Class Browser.

classbrowserThis feature needs some work but is still good for reference, but not so much navigation like was intended. Basically you get a list of all the classes in the project and upon selecting one you see the sub-classes and methods, along with a source line and file location. Good for overviewing the project and looking at method parameters.

This feature will see improvement in versions to come.

How to use the macro system

Both WebScripter and PascalGladiator’s editor share the same macro system but it has not been documented in PascalGladiator. The following explanation is modified from the WebScripter manual and please note there is no graphical editor in PascalGladiator. You can however edit the .plist manually (no problem since you’re a Mac programmer) in PascalGladiator.app/Contents/CodeSense/Pascal.macros.plist.

Topics

  • 5.0 Using Macros
  • 5.1 Using The Contextual Menu
  • 5.2 Macro Editor
  • 5.3 Macro Syntax
  • 5.4 Variables
  • 5.5 UNIX Shell Macros
  • 5.6 Output Methods

5.0 Using Macros

To invoke macros from the editor (using the contextual menu is also possible) type the macros command enclosed by [ and ] brackets (they are auto-paired by default so this is 1 key motion) and press the Tab key. Depending on the macros output method the results will be inserted into the document or otherwise.

The PHP macro shown below (with the command name func) will insert an empty function into the document and move the cursor to the proper location.

[func]

Parameters

Optionally macros support parameters which give the macro additional information and make them dynamic. Parameters are placed within ( and ) characters and separated with commas “,”. As explained in the section Macro Syntax parameters are defined as $1, $2, $3 etc… respectively. Not all macros support parameters so you should inspect the macros you intend to use in the editor window before using them. Also note that by holding the cursor over a macro in the menu and it’s syntax will be shown in a floating help window.

The example shown below expands upon the previous PHP macro but with parameters. The first parameter DoSomething is used for the functions name.

[func(DoSomething)]

 

Below is the macro definition for the previous 2 examples. More information on the syntax can be found here.

function $1 ([$2]) {
        $CURSOR
}

 

Pipes

It is possible to override the output method of a macro by using pipes (named after the UNIX feature). To use pipes insert the > character after the full command.

Consider the example below that prints the output of the link macro to the console instead of the default location.

[link(www.web-scripter.com) > console]

5.1 Using The Contextual Menu

Macros can be inserted into the open document by using the contextual menu. When using the contextual menu it will take the current selection from the document and pass it to the macro as the first parameter ($1). This has the effect of wrapping the selection with the macro (providing the macro contains the $1 parameter).

5.2 Macro Editor

No graphical macro editor in PascalGladiator for now, sorry!

5.3 Macro Syntax

Macros follow a simple syntax that is easy to learn so you can start writing macros right away.

Macros have the following syntax concepts:

  • Parameters.
  • Empty Parameter.
  • Default Values.
  • Optional Parameters.
  • Interpolated Shell Code.
  • Positioning the cursor.
  • Built-in Variables.

Parameters

Parameters allow the user to send data into the macro while typing and really are what makes macros a powerful feature. Parameters take the form of the $ character followed by a number representing the index of the parameter.

      The Macro: <a href="$1">
      Typed: [link(www.apple.com)]
      Becomes: <a href="www.apple.com">

Optional Parameters

Text wrapped in [ and ] brackets (a parameter must be within the brackets also) are optional on condition that the parameter inside the brackets is not empty. This feature is useful if you want your macro to omit certain information if the user has not specified a parameter.

For example take the link macro below (for printing an HTML link) which will omit the name attribute if the second ($2) parameter is not present.

      The Macro: <a href="$1" [name="$2"]>
      Typed: [link(www.apple.com)]
      Becomes: <a href="www.apple.com">

Interpolated Shell Code

You can include shell code (explained here) into macros which execute the command like from the shell. To interpolate shell code into macros place the code inside back ticks (`).

For example this trivial macro which uses the UNIX command whoami which prints the name of the logged in user.

      The Macro: Hello world, this is `whoami`.
      Becomes: Hello world, this is macuser.

Empty Parameters

Some times you might be using a macro that contains multiple parameters and would like to use the second parameter but not the first. To tell the parser to ignore the parameter you can insert the ^ character instead of a value.

As an example we will expand on the macro shown in Optional Parameters. Note that if the empty parameter was not used the second would become the first and you would not get the results you were expecting.

[link(^,Apple.com)]

Default Values

If you leave a parameter for a macro blank a default value can be inserted instead. Default values are within { and } curly brackets and must follow directly after the parameter.

In the following example if the first parameter ($1) was omitted the text “www.domain.com” would be inserted instead.

<a href="$1{www.domain.com}" [name="$2"]>

Positioning the cursor.

If the macros output method is default then you can specify where the cursor is to be set in the document by using the $CURSOR variable.

Built-in Variables

There are a number of built-in variables that provide dynamic information which are mainly used for shell macros. Built-in variables follow the same syntax as parameters and are prefixed by the $ character.

Currently the supported variables are:

  • $FILE. The name of the current document.
  • $PATH. The absolute path of the current document.
  • $SUPPORT. The absolute path of the SharedSupport folder in the application package.

5.4 Variables

In the macro editor you can add variables which are global to all macros. Variables are useful for including dynamic values which could affect multiple macros.

To add new variables:

  • Click the popup button with the gear icon in the macro editor.
  • Select Add Variable from the menu.

 

For the following example assume you have created a variable named SERVER with the value “web-scripter.com” and defined the fictional macro connect which opens a FTP connection. Note that you should not include the dollar sign ($) before the variable name.

      The Macro: ftp_connect("$SERVER", "$1", "$2");
      Typed: [conn(user,****)]
      Becomes: ftp_connect("web-scripter.com", "user", "****");

 

Using the variable $SERVER will now insert the proper value into all macros.

5.5 UNIX Shell Macros

WebScripter allows you to script macro functionality by executing the text like a command from the shell. Using shell macros is the gateway to UNIX and will allow you to add dynamic functionality to WebScripter.

To use shell macros set the action in the macro editor to Shell and the text will be treated like that typed at the command line.

As an example take the following simple UNIX command which will take the path of the document and sort it’s contents. To make the command useful you would set the output method to replace which would override the document with the results from the command.

cat < $PATH | sort

 

The HTMLTidy integration in WebScripter is implemented as a shell macro. Here’s how the command looks:

$SUPPORT/tidy -i -q -wrap 0 -mac "$PATH"

 

Using the $SUPPORT variable it finds the tidy program in the application package, sets some options then passes the documents path in. Because the output method is replace the output overwrites the current document.

5.6 Output Methods

When editing macros you can choose from a list of output methods which control how the results from the macro are displayed.

  • Default. Output is written to the open document at the cursor offset or replacing the current the selection.
  • Popup. Output is displayed in a floating help window.
  • URL. If the output is a valid URL it is opened in the default web browser.
  • Replace. Output replaces the contents of the document.
  • Console. Output will open in a built-in terminal split view.
  • Error List. Output is displayed in list form from a built-in split view. Note that output must be formatted properly.

Formatting Error Lists

There is not error list feature is PascalGladiator.

PascalGladiator: Outstanding Bugs

The latest release 0.4 introduced some nasty bugs with all the changes that were made porting all the code to FPC and the code folding which really did a number on the syntax parser/text editor.  I didn’t really want to release this version but I felt if I didn’t you wouldn’t get a native Intel version that could run on 10.5 for many more months. Sorry guys!

Outstanding bugs since 0.4:

  • Sometimes files open with garble. Don’t save! Just close the file and open it again. There is a problem with WASTE and loading files in a thread.
  • Opening files while debugging crashes.
  • The debugger still causes some leaking in the regex library which causes the application to parse files very slow after the debugger has been run. The only cure is to quit the debugging sessions.
  • Breaks points are not synched properly after multiple debugging sessions. Quit the application and try again.
  • In 0.4b Compile Syntax is crashing. Just open the files and they will be compiled and saved as you go along.

WebScripter hold ups

3 months after the first Intel native release and still I have not produced anything like I had hoped. I made a terrible mistake in deciding what the first new feature I should add was: code folding. This was a intensely complicated feature to implement and complicated the editor down to every detail from copy/pasting, saving/loading and typing/syntax styling. Let it be known, WebScripter does have a pretty nice implementation working but the system has put such a strain on the text editor API WASTE it has forced to remove it altogether. This was a long time coming considering the crippling speed issue and developer failing to provide support. He is btw basically quitting WASTE, I should have known this 2 years ago…

 

Code Folding Preview
Next version preview (2.1)

I wrote about this headache before regarding PascalGladiator but the root is in WebScripter. This means before the next version I will be up-rooting the text editor and implementing the Cocoa system NSTextView using the new experiemental PasCocoa Objective-C runtime wrapper. I just can’t accept that I am developing programmer tools that rely on a text editor at the core but editing files around 1000 lines is too slow to use. Before code folding it was still a joke, but now it’s just silly.

However I still was able to create some new features that are in development but near the end.

First is the Reference Mode. I wanted this feature for a while now as I’m sick of switching back and forth between browsers and editors to get function arguments and the likes. What’s special about the system in WebScripter is it allows you to design search rules (using Regular Expressions) that can crawl and index a site like a search engine. There will be basics pre-loaded with the release but you can customize and add new web sites on your own. After a site has been indexed you can search the contents from the book mode pane (seen in the screen shot above) or contextual click on code and it will bring you right to the page you need in the reference library. Really useful feature and it’s totally customizable to the user.

Second is inline error checking. I felt the error checking process was intrusive (bringing down a list above the editor, however this will remain available) and that the information could be contained in the gutter using icons and floating help windows. In PHP which has great error handling you can see the stack trace in the gutter and the value of variables by dragging the cursor over them in the text editor. Additionally, real time syntax checks will be available as you type.

But the changes I really wanted to make are more towards user experience and simplifying the preview/run/error system which is just cluttered as of now.  This should have all happened by now if not for the the mistakes I made. Until next time…