Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Plug-in conversion of the Dialog 2 testing framework. This should com…

…pile and accept commands, e.g.

echo '{ menuItems = ({title = 'foo';});}' | "$DIALOG" menu

Note: currently I’ve set it up to hijack the $DIALOG environment variable, this has been working fine for me but I’m not sure if it’s a long-term solution (is the plug-in load order consistent?).
When tm_dialog2 is called it checks the first character of the argument list, and if it’s a ‘-’ then it replaces itself with the corresponding call to tm_dialog



git-svn-id: http://svn.textmate.org/branches/WIP/Tools/Dialog2@8484 dfb7d73b-c2ec-0310-8fea-fb051d288c6d
  • Loading branch information...
commit 5080020bd41732311252cf3c4ec9d2326d361cd3 1 parent 8a3f37c
@ciaran ciaran authored
Showing with 3,095 additions and 0 deletions.
  1. +19 −0 Commands/ExtendedPopUp/IncrementalPopUpMenu.nib/classes.nib
  2. +16 −0 Commands/ExtendedPopUp/IncrementalPopUpMenu.nib/info.nib
  3. BIN  Commands/ExtendedPopUp/IncrementalPopUpMenu.nib/keyedobjects.nib
  4. +16 −0 Commands/ExtendedPopUp/TMDBorderLessWindow.h
  5. +54 −0 Commands/ExtendedPopUp/TMDBorderLessWindow.m
  6. +47 −0 Commands/ExtendedPopUp/TMDIncrementalPopUpMenu.h
  7. +394 −0 Commands/ExtendedPopUp/TMDIncrementalPopUpMenu.mm
  8. +206 −0 Commands/ExtendedPopUp/extendedmenu.mm
  9. +13 −0 Commands/HTMLTips/HTMLTip.nib/classes.nib
  10. +16 −0 Commands/HTMLTips/HTMLTip.nib/info.nib
  11. BIN  Commands/HTMLTips/HTMLTip.nib/keyedobjects.nib
  12. +23 −0 Commands/HTMLTips/TMDHTMLTips.h
  13. +109 −0 Commands/HTMLTips/TMDHTMLTips.mm
  14. +87 −0 Commands/HTMLTips/htmltips.mm
  15. +124 −0 Commands/alert.mm
  16. +24 −0 Commands/help.mm
  17. +80 −0 Commands/menu.mm
  18. +23 −0 Commands/quit.mm
  19. +12 −0 Commands/window/TMDChameleon.h
  20. +52 −0 Commands/window/TMDChameleon.mm
  21. +10 −0 Commands/window/ValueTransformers.h
  22. +126 −0 Commands/window/ValueTransformers.mm
  23. +397 −0 Commands/window/window.mm
  24. +37 −0 Dialog2.h
  25. +74 −0 Dialog2.mm
  26. +190 −0 Dialog2.tmproj
  27. +440 −0 Dialog2.xcodeproj/project.pbxproj
  28. +7 −0 Dialog2_Prefix.pch
  29. BIN  English.lproj/InfoPlist.strings
  30. +26 −0 Info.plist
  31. +21 −0 OptionParser.h
  32. +230 −0 OptionParser.mm
  33. +9 −0 TMDCommand.h
  34. +55 −0 TMDCommand.mm
  35. +158 −0 tm_dialog2.mm
View
19 Commands/ExtendedPopUp/IncrementalPopUpMenu.nib/classes.nib
@@ -0,0 +1,19 @@
+{
+ IBClasses = (
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {CLASS = TMDBorderLessWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; },
+ {
+ CLASS = TMDIncrementalPopUpMenu;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ anArrayController = NSArrayController;
+ controllerObject = id;
+ dummyWindow = NSWindow;
+ ed = id;
+ theTableView = id;
+ };
+ SUPERCLASS = NSWindowController;
+ }
+ );
+ IBVersion = 1;
+}
View
16 Commands/ExtendedPopUp/IncrementalPopUpMenu.nib/info.nib
@@ -0,0 +1,16 @@
+<?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>IBDocumentLocation</key>
+ <string>101 143 558 588 0 0 1280 1002 </string>
+ <key>IBFramework Version</key>
+ <string>446.1</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>5</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8R218</string>
+</dict>
+</plist>
View
BIN  Commands/ExtendedPopUp/IncrementalPopUpMenu.nib/keyedobjects.nib
Binary file not shown
View
16 Commands/ExtendedPopUp/TMDBorderLessWindow.h
@@ -0,0 +1,16 @@
+//
+// TMDBorderLessWindow.h
+// Dialog
+//
+// Created by Joachim Mårtensson on 2007-08-14.
+// Copyright 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface TMDBorderLessWindow : NSWindow {
+
+}
+- (BOOL)canBecomeMainWindow;
+@end
View
54 Commands/ExtendedPopUp/TMDBorderLessWindow.m
@@ -0,0 +1,54 @@
+//
+// TMDBorderLessWindow.m
+// Dialog
+//
+// Created by Joachim Mårtensson on 2007-08-14.
+// Copyright 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import "TMDBorderLessWindow.h"
+
+
+@implementation TMDBorderLessWindow
+
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(unsigned int)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag
+{
+ self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:NO];
+
+// [result setBackgroundColor:[NSColor clearColor]];
+ [self setAlphaValue:0];
+ [self setHasShadow:YES];
+ [self setOpaque:NO];
+//[self makeKeyWindow];
+ return self;
+}
+
+- (BOOL)canBecomeMainWindow
+{
+ return YES;
+}
+
+- (BOOL) canBecomeKeyWindow
+{
+ return YES;
+}
+
+-(BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+- (BOOL)showsResizeIndicator
+{
+ return NO;
+}
+
+-(BOOL)resignFirstResponder
+{
+ return NO;
+}
+
+@end
View
47 Commands/ExtendedPopUp/TMDIncrementalPopUpMenu.h
@@ -0,0 +1,47 @@
+//
+// TMDIncrementalPopUpMenu.h
+//
+// Created by Joachim MŒrtensson on 2007-08-10.
+// Copyright (c) 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#define MAX_ROWS 15
+
+@interface TMDIncrementalPopUpMenu : NSWindowController
+{
+ IBOutlet NSArrayController* anArrayController;
+ NSArray* suggestions;
+ NSMutableString* mutablePrefix;
+ NSString* staticPrefix;
+ NSArray* filtered;
+ NSString* shell;
+ NSMutableAttributedString* attrString;
+ IBOutlet id theTableView;
+ float stringWidth;
+ NSPoint caretPos;
+ BOOL isAbove;
+ NSRect mainScreen;
+ BOOL closeMe;
+ id ed;
+ id controllerObject;
+}
+- (id)initWithDictionary:(NSDictionary*)aDictionary
+ andEditor:(id)editor;
+- (void)filter;
+- (NSMutableString*)mutablePrefix;
+- (id)theTableView;
+- (void)keyDown:(NSEvent*)anEvent;
+- (void)tab;
+- (int)stringWidth;
+- (void)writeToTM:(NSString*)aString asSnippet:(BOOL)snippet;
+- (NSString*)executeShellCommand:(NSString*)command WithDictionary:(NSDictionary*)dict;
+- (NSArray*)filtered;
+- (void)setFiltered:(NSArray*)aValue;
+- (void)setCaretPos:(NSPoint)aPos;
+- (void)setMainScreen:(NSRect)aScreen;
+- (void)setAbove:(BOOL)aBool;
+- (void)completeAndInsertSnippet:(id)nothing;
+- (BOOL)getCloseStatus;
+
+@end
View
394 Commands/ExtendedPopUp/TMDIncrementalPopUpMenu.mm
@@ -0,0 +1,394 @@
+//
+// TMDIncrementalPopUpMenu.mm
+//
+// Created by Joachim MŒrtensson on 2007-08-10.
+// Copyright (c) 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import "TMDIncrementalPopUpMenu.h"
+@interface NSObject (OakTextView)
+- (id)insertSnippetWithOptions:(NSDictionary*)options;
+@end
+
+@implementation TMDIncrementalPopUpMenu
+- (id)initWithDictionary:(NSDictionary*)aDictionary andEditor:(id)editor
+{
+////NSLog(@"%@", aDictionary);
+ if(self = [super initWithWindowNibName:@"IncrementalPopUpMenu"])
+ //if(self = [super init])
+ {
+ mutablePrefix = [[NSMutableString alloc] init];
+
+ ed = [editor retain];
+ suggestions = [NSArray arrayWithArray:[aDictionary objectForKey:@"suggestions"]];
+
+ [mutablePrefix setString:[NSString stringWithString:[aDictionary objectForKey:@"currentWord"]]];
+ if([aDictionary objectForKey:@"staticPrefix"]){
+ staticPrefix = [NSString stringWithString:[aDictionary objectForKey:@"staticPrefix"]];
+ [staticPrefix retain];
+ }
+ else
+ {
+ staticPrefix = @"";
+ }
+ shell = nil;
+ if([aDictionary objectForKey:@"shell"]){
+ shell = [NSString stringWithString:[aDictionary objectForKey:@"shell"]];
+ [shell retain];
+ }
+ //NSPredicate* predicate = [NSPredicate predicateWithFormat:@"filterOn beginswith %@", [staticPrefix stringByAppendingString:mutablePrefix]];
+ suggestions = [suggestions retain];
+ //[self setFiltered:[suggestions filteredArrayUsingPredicate:predicate]];
+ attrString = [[NSMutableAttributedString alloc] initWithString:@"No completion found"];
+ [self filter];
+ closeMe = NO;
+ }
+ return self;
+}
+- (NSMutableString*)mutablePrefix;
+{
+ return mutablePrefix;
+}
+- (id)theTableView
+{
+ return theTableView;
+}
+// osascript -e 'tell application "TextMate" to activate'$'\n''tell application "System Events" to keystroke (ASCII character 8)'
+-(void)tab
+{
+ if([filtered count]>1)
+ {
+ NSEnumerator *enumerator = [filtered objectEnumerator];
+ id eachString;
+ id previousString = [[enumerator nextObject] objectForKey:@"filterOn"];
+ id dict;
+ while (dict = [enumerator nextObject] )
+ {
+
+ eachString = [dict objectForKey:@"filterOn"];
+ NSString *commonPrefix = [eachString commonPrefixWithString:previousString options:NSLiteralSearch];
+ previousString = commonPrefix;
+ }
+ NSString* tStatic;// = [staticPrefix copy];
+ NSString* temp = [staticPrefix stringByAppendingString:mutablePrefix];
+ //[tStatic release];
+ if([previousString length] > [temp length]){
+ if(previousString){
+ tStatic = [previousString substringFromIndex:[temp length]];
+ [mutablePrefix appendString:tStatic];
+ } else {//NSLog(@"previousString was nil !!!: []", temp);
+ //[temp release];
+ }
+
+ [self writeToTM:tStatic asSnippet:NO];
+ [self filter];
+ }
+
+ }
+ // [self close];
+}
+
+- (void)filter
+{
+ NSArray* myArray2;
+ if ([mutablePrefix length] > 0){
+ NSPredicate* predicate = [NSPredicate predicateWithFormat:@"filterOn beginswith %@", [staticPrefix stringByAppendingString:mutablePrefix]];
+ myArray2 = [suggestions filteredArrayUsingPredicate:predicate];
+
+ //[anArrayController rearrangeObjects];
+ } else {
+ myArray2 = suggestions;
+ }
+ NSPoint old = NSMakePoint([[self window] frame].origin.x,[[self window] frame].origin.y +[[self window] frame].size.height);
+ float newHeight = 0;
+ if([myArray2 count]>MAX_ROWS)
+ {
+ newHeight = [theTableView rowHeight]*MAX_ROWS*1.15;
+ }
+ else if([myArray2 count]>1)
+ {
+ newHeight = [theTableView rowHeight]*[myArray2 count]*1.15;
+ }
+ else
+ {
+ newHeight = [theTableView rowHeight] * 1.2;
+ }
+
+ float maxLen = 1;
+ NSString* item;
+ int i;
+ float maxWidth = [[self window] frame].size.width;
+ if([myArray2 count]>0)
+ {
+ for(i=0; i<[myArray2 count]; i++)
+ {
+ item = [[myArray2 objectAtIndex:i] objectForKey:@"title"];
+ if([item length]>maxLen)
+ maxLen = [item length];
+ }
+ maxWidth = maxLen*18;
+ maxWidth = (maxWidth>340) ? 340 : maxWidth;
+ }
+ if(caretPos.y>=0 && (isAbove || caretPos.y<newHeight))
+ {
+ [self setAbove:YES];
+ old.y = caretPos.y + (newHeight + [[NSUserDefaults standardUserDefaults] integerForKey:@"OakTextViewNormalFontSize"]*1.5);
+ }
+ if(caretPos.y<0 && (isAbove || (mainScreen.size.height-newHeight)<(caretPos.y*-1)))
+ {
+ old.y = caretPos.y + (newHeight + [[NSUserDefaults standardUserDefaults] integerForKey:@"OakTextViewNormalFontSize"]*1.5);
+ }
+ [[self window] setFrame:NSMakeRect(old.x,old.y-newHeight,maxWidth,newHeight) display:YES];
+ //NSLog(@"myArray2 retaincount %d",[myArray2 retainCount]);
+ //NSLog(@"filtered retaincount in filter %d",[filtered retainCount]);
+ //[self setValue:myArray2 forKey:@"filtered"];
+ [self setFiltered:myArray2];
+ //NSLog(@"filtered retaincount in filter after - %d",[filtered retainCount]);
+
+}
+- (void)windowDidLoad
+{
+ //NSLog(@"%d controller windowDidLoad",[controllerObject retainCount]);
+
+// [self showWindow:self];
+// [[self window] setContentView:theTableView];
+[[self window] setDelegate:self];
+ [self filter];
+ NSMutableAttributedString* s = [[NSMutableAttributedString alloc] initWithString:mutablePrefix];
+ [s addAttribute:NSFontAttributeName
+ value:[NSFont fontWithName:[[NSUserDefaults standardUserDefaults] stringForKey:@"OakTextViewNormalFontName"] ?:[[NSFont userFixedPitchFontOfSize:12.0] fontName]
+ size:[[NSUserDefaults standardUserDefaults] integerForKey:@"OakTextViewNormalFontSize"] ?: 12 ]
+ range:NSMakeRange(0,[mutablePrefix length])];
+ stringWidth = [s size].width;
+ [s release];
+}
+-(void)windowWillClose:(NSNotification*)aNotification
+{
+ //NSLog(@"windowDidClose");
+ if([controllerObject isKindOfClass:[NSObjectController class]])
+ //NSLog(@"is Kind of class");
+ [controllerObject unbind:@"contentObject"];
+ //NSLog(@"windowDidClose self %d",[self retainCount]);
+ //NSLog(@"%d arrayControll",[anArrayController retainCount]);
+ //NSLog(@"%d theTableView",[theTableView retainCount]);
+ //NSLog(@"%d static",[staticPrefix retainCount]);
+ //NSLog(@"%d controller",[controllerObject retainCount]);
+ //NSLog(@"%d mutablePrefix",[mutablePrefix retainCount]);
+ //NSLog(@"%d filtered",[filtered retainCount]);
+ //NSLog(@"%d shell",[shell retainCount]);
+ //NSLog(@"%d controller",[controllerObject retainCount]);
+}
+- (int) stringWidth;
+{ return stringWidth; }
+- (void)setCaretPos:(NSPoint)aPos
+{
+ caretPos = aPos;
+}
+- (void)setMainScreen:(NSRect)aScreen
+{
+ mainScreen = aScreen;
+}
+- (void)setAbove:(BOOL)aBool
+{
+ isAbove = aBool;
+}
+- (BOOL)getCloseStatus
+{
+ return closeMe;
+}
+- (void)awakeFromNib
+{
+ // [theTableView setNextResponder: self];
+ [theTableView setTarget:self];
+ [theTableView setDoubleAction:@selector(completeAndInsertSnippet:)];
+}
+- (void)completeAndInsertSnippet:(id)nothing
+{
+ if ([anArrayController selectionIndex] != NSNotFound){
+ id selection = [filtered objectAtIndex:[anArrayController selectionIndex]];
+ NSString* aString = [selection valueForKey:@"filterOn"];
+ NSString* temp = [staticPrefix stringByAppendingString:mutablePrefix];
+ //[temp retain];
+ if([temp length] > [aString length]){
+ ;
+ }
+ else if([aString length] > [temp length]){
+ NSString* temp2 = [aString substringFromIndex:[temp length]];
+ [self writeToTM:temp2 asSnippet:NO];
+ }
+ if([selection valueForKey:@"snippet"]){
+ //[self writeToTM:[[ob valueForKey:@"snippet"] copy] asSnippet:YES];
+ [self writeToTM:[selection valueForKey:@"snippet"] asSnippet:YES];
+ }
+ else if(shell)
+ {
+ //NSLog(@"shell");
+ NSString* fromShell =[[self executeShellCommand:shell WithDictionary:selection] retain];
+ [self writeToTM:fromShell asSnippet:YES];
+ }
+ closeMe = YES;
+ }
+}
+- (void)scrollLineUp:(id)sender
+{
+ int row = [anArrayController selectionIndex];
+ if (--row >= 0) [anArrayController setSelectionIndex:row];
+}
+-(void)scrollLineDown:(id)sender
+{
+ int row = [anArrayController selectionIndex];
+ if (++row < [filtered count]) [anArrayController setSelectionIndex:row];
+}
+- (void)moveToBeginningOfDocument:(id)sender
+{
+ [anArrayController setSelectionIndex:0];
+}
+- (void)moveToEndOfDocument:(id)sender
+{
+ [anArrayController setSelectionIndex:[filtered count]-1];
+}
+- (void)pageDown:(id)sender
+{
+ int oldIndex = [anArrayController selectionIndex];
+ if([filtered count]<(MAX_ROWS+1))
+ [anArrayController setSelectionIndex:[filtered count]-1];
+ else
+ {
+ if(oldIndex+MAX_ROWS>=[filtered count])
+ [anArrayController setSelectionIndex:[filtered count]-1];
+ else
+ [anArrayController setSelectionIndex:oldIndex+MAX_ROWS-1];
+ [[self theTableView] scrollRowToVisible:[anArrayController selectionIndex]];
+ }
+ //NSLog(@"%d arrayControll",[anArrayController retainCount]);
+ //NSLog(@"%d theTableView",[theTableView retainCount]);
+ //NSLog(@"%d static",[staticPrefix retainCount]);
+ //NSLog(@"%d controller",[controllerObject retainCount]);
+ //NSLog(@"%d mutablePrefix",[mutablePrefix retainCount]);
+ //NSLog(@"%d filtered",[filtered retainCount]);
+ //NSLog(@"%d shell",[shell retainCount]);
+ //NSLog(@"%d controller",[controllerObject retainCount]);
+
+}
+- (void)pageUp:(id)sender
+{
+ int oldIndex = [anArrayController selectionIndex];
+ if(oldIndex<MAX_ROWS)
+ [anArrayController setSelectionIndex:0];
+ else
+ {
+ [anArrayController setSelectionIndex:oldIndex-MAX_ROWS+1];
+ [[self theTableView] scrollRowToVisible:[anArrayController selectionIndex]];
+ }
+
+}
+- (void)keyDown:(NSEvent*)anEvent
+{
+
+ // //NSLog(@"%@ <-prefix", mutablePrefix);
+ NSString* aString = [anEvent characters];
+ unichar key = 0;
+ if([aString length] == 1){
+ key = [aString characterAtIndex:0];
+ if (key == NSBackspaceCharacter || key == NSDeleteCharacter){
+ [mutablePrefix deleteCharactersInRange:NSMakeRange([mutablePrefix length]-1,1)];
+ [self filter];
+ //[self close];
+ }
+ else if (key == NSUpArrowFunctionKey || key == NSDownArrowFunctionKey){
+ ; // we need to catch this since an empty tableView passes the event on here.
+ }
+ else if (key == NSPageUpFunctionKey || key == NSPageDownFunctionKey){
+ ; // we need to catch this since an empty tableView passes the event on here.
+ }
+ else if(key == NSCarriageReturnCharacter ){
+ [self completeAndInsertSnippet:nil];
+ //[self close];
+ } else if([aString isEqualToString:@"\t"]){
+ if([filtered count] == 1)
+ [self completeAndInsertSnippet:nil];
+ else
+ [self tab];
+ } else {
+
+ //[self interpretKeyEvents:[NSArray arrayWithObject:anEvent]];
+ [mutablePrefix appendString:aString];
+ //[mutablePrefix retain];
+ //[self writeToTM:aString asSnippet:NO];
+ [self filter];
+ }
+ }
+}
+-(NSString*)executeShellCommand:(NSString*)command WithDictionary:(NSDictionary*)dict
+{
+ NSString* stdIn = [dict description];
+ NSTask* task = [[ NSTask alloc ] init ];
+ [task setLaunchPath: @"/bin/sh"];
+ NSArray *arguments;
+ arguments = [NSArray arrayWithObjects:@"-c", command, nil];
+ [task setArguments: arguments];
+ [task setStandardInput:[[NSPipe alloc ] init]];
+ NSPipe *pipe;
+ pipe = [NSPipe pipe];
+ [task setStandardOutput: pipe];
+ NSFileHandle* taskInput = [[task standardInput ] fileHandleForWriting ];
+
+ //const char* cStringToSendToTask = [ stdIn UTF8String ];
+
+ [taskInput writeData: [stdIn dataUsingEncoding:NSUTF8StringEncoding]];
+ [taskInput closeFile];
+
+ NSFileHandle* taskOutput;
+ taskOutput = [pipe fileHandleForReading];
+
+ [task launch];
+
+ NSData *data;
+ data = [taskOutput readDataToEndOfFile];
+ NSString* r = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
+ return [r autorelease];
+}
+
+-(void)writeToTM:(NSString*)string asSnippet:(BOOL)snippet
+{
+ if(snippet){
+ if(id textView = [NSApp targetForAction:@selector(insertSnippetWithOptions:)]){
+ [textView insertSnippetWithOptions:[NSDictionary dictionaryWithObjectsAndKeys:string, @"content",nil]];
+ }
+ }
+ else
+ {
+ if(id textView = [NSApp targetForAction:@selector(insertText:)]){
+ [textView insertText:string];
+ }
+ }
+}
+
+- (NSArray*)filtered
+{
+ return filtered;
+}
+
+- (void)setFiltered:(NSArray*)aValue
+{
+ [aValue retain];
+ [filtered release];
+ filtered = aValue;
+
+ // NSArray* oldFiltered = filtered;
+ // filtered = [aValue retain];
+ // [oldFiltered release];
+}
+
+-(void)dealloc
+{
+ NSLog(@"%d staticPrefix",[staticPrefix retainCount]);
+ [staticPrefix release];
+ NSLog(@"%d staticPrefix",[staticPrefix retainCount]);
+ [mutablePrefix release];
+ [suggestions release];
+ if(shell)
+ [shell release];
+ [super dealloc];
+}
+@end
View
206 Commands/ExtendedPopUp/extendedmenu.mm
@@ -0,0 +1,206 @@
+#import "../../TMDCommand.h"
+#import "../../Dialog2.h"
+#import "TMDIncrementalPopUpMenu.h"
+
+// ==================
+// = Extended Popup =
+// ==================
+@interface NSObject (OakTextView)
+- (NSPoint)positionForWindowUnderCaret;
+@end
+
+@interface TMDXPopUp : TMDCommand
+{
+}
+@end
+
+@implementation TMDXPopUp
++ (void)load
+{
+ [TMDCommand registerObject:[self new] forCommand:@"extended-popup"];
+}
+
+- (void)handleCommand:(id)options
+{
+ NSDictionary* initialValues = [TMDCommand readPropertyList:[options objectForKey:@"stdin"]];
+ NSLog(@"initialValues: %@", initialValues);
+
+ NSPoint pos = NSZeroPoint;
+ if(id textView = [NSApp targetForAction:@selector(positionForWindowUnderCaret)])
+ pos = [textView positionForWindowUnderCaret];
+
+ NSRect mainScreen = [[NSScreen mainScreen] frame];
+ enumerate([NSScreen screens], NSScreen* candidate)
+ {
+ if(NSMinX([candidate frame]) == 0.0f && NSMinY([candidate frame]) == 0.0f)
+ mainScreen = [candidate frame];
+ }
+
+ pos = NSMakePoint(pos.x, pos.y);
+ TMDIncrementalPopUpMenu* xPopUp = [[TMDIncrementalPopUpMenu alloc] initWithDictionary:initialValues andEditor:nil];
+ NSLog(@"%d xpop",[xPopUp retainCount]);
+ [xPopUp setCaretPos:pos];
+ [xPopUp setMainScreen:mainScreen];
+ [xPopUp setAbove:NO];
+
+ int offx = (pos.x/mainScreen.size.width) + 1;
+ if((pos.x + [[xPopUp window] frame].size.width) > (mainScreen.size.width*offx))
+ pos.x = pos.x - [[xPopUp window] frame].size.width;
+ pos.x = pos.x - [xPopUp stringWidth];
+
+ if(pos.y>=0 && pos.y<[[xPopUp window] frame].size.height)
+ {
+ pos.y = pos.y + ([[xPopUp window] frame].size.height + [[NSUserDefaults standardUserDefaults] integerForKey:@"OakTextViewNormalFontSize"]*1.5);
+ [xPopUp setAbove:YES];
+ }
+ if(pos.y<0 && (mainScreen.size.height-[[xPopUp window] frame].size.height)<(pos.y*-1))
+ {
+ pos.y = pos.y + ([[xPopUp window] frame].size.height + [[NSUserDefaults standardUserDefaults] integerForKey:@"OakTextViewNormalFontSize"]*1.5);
+ [xPopUp setAbove:YES];
+ }
+ id extraChars;
+ if ([initialValues objectForKey:@"extraChars"])
+ extraChars = [initialValues objectForKey:@"extraChars"];
+ else
+ extraChars = [NSNull null];
+ [[xPopUp window] setFrameTopLeftPoint:pos];
+ [xPopUp showWindow:self];
+ int i;
+ for(i=0;i<=1000;i++)
+ {
+ [[xPopUp window] setAlphaValue:i*0.001];
+ }
+ NSLog(@"%d xpop before",[xPopUp retainCount]);
+ [self performSelector: @selector(eventHandlingForExtendedPopupMenu:)
+ withObject: [NSDictionary dictionaryWithObjectsAndKeys:xPopUp,@"xPopUp",extraChars,@"extraChars",nil]
+ afterDelay: 0.1];
+ [xPopUp release];
+ NSLog(@"%d xpop after",[xPopUp retainCount]);
+}
+
+-(void) eventHandlingForExtendedPopupMenu:(id)dict
+{
+ id extraChars = [dict objectForKey:@"extraChars"];
+ TMDIncrementalPopUpMenu* xPopUp = [dict objectForKey:@"xPopUp"];
+ NSLog(@"%d xpop eventHandlingForExtendedPopupMenu",[xPopUp retainCount]);
+ NSCharacterSet* whiteList;
+ if (extraChars == [NSNull null]){
+ whiteList = nil;
+ }
+ else{
+ whiteList = [NSCharacterSet characterSetWithCharactersInString:extraChars];
+ }
+ NSDate *distantFuture = [NSDate distantFuture];
+ NSEvent *event;
+ do{
+ event = [NSApp nextEventMatchingMask: NSAnyEventMask
+ untilDate: distantFuture
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+ if([xPopUp getCloseStatus])
+ break;
+ if (event != nil)
+ {
+ NSEventType t = [event type];
+ if(t == NSKeyDown){
+ NSString* aString = [event characters];
+ unsigned int flags = [event modifierFlags];
+ unichar key = 0;
+ if((flags & NSControlKeyMask) || (flags & NSAlternateKeyMask) || (flags & NSCommandKeyMask))
+ {
+ [NSApp sendEvent:event];
+ break;
+ }
+ else if([aString length] == 1){
+ key = [aString characterAtIndex:0];
+ if(key == NSCarriageReturnCharacter ){
+ [xPopUp keyDown:event];
+ break;
+ }
+ else if (key == NSBackspaceCharacter || key == NSDeleteCharacter){
+ [NSApp sendEvent:event];
+ if([[xPopUp mutablePrefix] length] > 0){
+ [xPopUp keyDown:event];
+ }
+ else{
+ break;
+ }
+ }else if ([event keyCode] == 53){
+ break;
+
+ }else if(key == NSTabCharacter)
+ {
+ if ([[xPopUp filtered] count] == 0){
+ [NSApp sendEvent:event];
+ break;
+ }
+ if ([[xPopUp filtered] count] == 1){
+ [xPopUp keyDown:event];
+ break;
+ }
+ [xPopUp keyDown:event];
+ }
+ else if (key == NSUpArrowFunctionKey || key == NSDownArrowFunctionKey)
+ {
+ [[xPopUp theTableView] keyDown:event];
+ }
+ else if (key == NSEndFunctionKey)
+ {
+ [xPopUp moveToEndOfDocument:self];
+ }
+ else if (key == NSHomeFunctionKey)
+ {
+ [xPopUp moveToBeginningOfDocument:self];
+ }
+ else if (key == NSPageDownFunctionKey)
+ {
+ [xPopUp pageDown:self];
+ }
+ else if (key == NSPageUpFunctionKey)
+ {
+ [xPopUp pageUp:self];
+ }
+ else if ([[NSCharacterSet alphanumericCharacterSet] characterIsMember:key] ||
+ (whiteList && [whiteList characterIsMember:key])) {
+ [NSApp sendEvent:event];
+ [xPopUp keyDown:event];
+ }else{
+ [NSApp sendEvent:event];
+ //[xPopUp keyDown:event];
+ break;
+ }
+ }
+ else{
+ [NSApp sendEvent:event];
+ //[xPopUp keyDown:event];
+ break;
+ }
+
+
+ }
+ else if(t == NSScrollWheel){
+ if([event deltaY] >= 0.0)
+ [xPopUp scrollLineUp:self];
+ else
+ [xPopUp scrollLineDown:self];
+ }else if(t == NSRightMouseDown || t == NSLeftMouseDown){
+ [NSApp sendEvent:event];
+ if(! NSPointInRect([NSEvent mouseLocation], [[xPopUp window] frame]))
+ break;
+ }
+ else
+ {
+ [NSApp sendEvent:event];
+ }
+
+
+ }
+ }
+ while(1);
+ [xPopUp close];
+ NSLog(@"windowDidClose xPopUp %d",[xPopUp retainCount]);
+ [xPopUp release];
+}
+
+
+@end
View
13 Commands/HTMLTips/HTMLTip.nib/classes.nib
@@ -0,0 +1,13 @@
+{
+ IBClasses = (
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {CLASS = TMDBorderLessWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; },
+ {
+ CLASS = TMDIncrementalPopUpMenu;
+ LANGUAGE = ObjC;
+ OUTLETS = {webView = WebView; };
+ SUPERCLASS = NSWindowController;
+ }
+ );
+ IBVersion = 1;
+}
View
16 Commands/HTMLTips/HTMLTip.nib/info.nib
@@ -0,0 +1,16 @@
+<?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>IBDocumentLocation</key>
+ <string>168 10 558 588 0 0 1440 878 </string>
+ <key>IBFramework Version</key>
+ <string>446.1</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>5</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8R2218</string>
+</dict>
+</plist>
View
BIN  Commands/HTMLTips/HTMLTip.nib/keyedobjects.nib
Binary file not shown
View
23 Commands/HTMLTips/TMDHTMLTips.h
@@ -0,0 +1,23 @@
+//
+// TMDIncrementalPopUpMenu.h
+//
+// Created by Ciarán Walsh on 2007-08-19.
+// Copyright (c) 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <WebKit/WebKit.h>
+
+#define TMD_TOOLTIP_PREFERENCES_IDENTIFIER @"TM Tooltip"
+
+@interface TMDHTMLTips : NSWindowController
+{
+ WebPreferences * webPreferences;
+
+ IBOutlet WebView *webView;
+}
+- (id)init;
+- (void)setHTML:(NSString *)html;
+- (void)sizeToContent;
+- (void)fade;
+@end
View
109 Commands/HTMLTips/TMDHTMLTips.mm
@@ -0,0 +1,109 @@
+//
+// TMDHTMLTips.mm
+//
+// Created by Ciarán Walsh on 2007-08-19.
+// Copyright (c) 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import "TMDHTMLTips.h"
+
+@implementation TMDHTMLTips
+- (id)init
+{
+ if(self = [super initWithWindowNibName:@"HTMLTip"]) {
+ NSLog(@"%s %@", __PRETTY_FUNCTION__, [[self window] class]);
+ webPreferences = [[WebPreferences alloc] initWithIdentifier:TMD_TOOLTIP_PREFERENCES_IDENTIFIER];
+ [webPreferences setJavaScriptEnabled:YES];
+ NSString *fontFamily = [[NSUserDefaults standardUserDefaults] stringForKey:@"OakTextViewNormalFontName"];
+ if (fontFamily == nil)
+ fontFamily = @"Monaco";
+ int fontSize = [[NSUserDefaults standardUserDefaults] integerForKey:@"OakTextViewNormalFontSize"];
+ if (fontSize == 0)
+ fontSize = 11;
+ [webPreferences setStandardFontFamily:fontFamily];
+ [webPreferences setDefaultFontSize:fontSize];
+
+ [webView setPreferencesIdentifier:TMD_TOOLTIP_PREFERENCES_IDENTIFIER];
+ [webView setFrameLoadDelegate:self];
+ }
+
+ return self;
+}
+
+- (void)setHTML:(NSString *)html
+{
+ NSLog(@"%s", __PRETTY_FUNCTION__);
+
+ NSString *content = @"<html>"
+ @"<head>"
+ @" <style type='text/css' media='screen'>"
+ @" body {"
+ @" background-color: #F6EDC3;"
+ @" border: 1px solid black;"
+ @" margin: 0;"
+ @" padding: 2px;"
+ @" overflow: hidden;"
+ @" display: table-cell;"
+ @" }"
+ @" </style>"
+ @"</head>"
+ @"<body>%@</body>"
+ @"</html>";
+ content = [NSString stringWithFormat:content, html];
+ [[webView mainFrame] loadHTMLString:content baseURL:nil];
+}
+
+- (void)sizeToContent
+{
+ NSPoint pos = NSMakePoint([[self window] frame].origin.x, [[self window] frame].origin.y + [[self window] frame].size.height);
+ id wsc = [webView windowScriptObject];
+ int height = [[wsc evaluateWebScript:@"document.body.offsetHeight + document.body.offsetTop;"] intValue];
+ int width = [[wsc evaluateWebScript:@"document.body.offsetWidth + document.body.offsetLeft;"] intValue];
+
+ // int height = [[webView stringByEvaluatingJavaScriptFromString:@"return document.body.offsetHeight + document.body.offsetTop;"] intValue];
+ // int width = [[webView stringByEvaluatingJavaScriptFromString:@"return document.body.offsetWidth + document.body.offsetLeft;"] intValue];
+ [[self window] setContentSize:NSMakeSize(width, height)];
+
+ int x_overlap = (pos.x + width) - [[NSScreen mainScreen] frame].size.width;
+ if (x_overlap > 0)
+ pos.x = pos.x - x_overlap;
+
+ int y_overlap = pos.y - height;
+ if (y_overlap < 0)
+ pos.y = pos.y - y_overlap;
+ [[self window] setFrameTopLeftPoint:pos];
+}
+
+- (void)fade
+{
+ if ([[self window] alphaValue] == 0.0) {
+ [self close];
+ } else {
+ [[self window] setAlphaValue:[[self window] alphaValue] - 0.25];
+ [self performSelector:@selector(fade) withObject:nil afterDelay:0.1];
+ }
+}
+
+// - (void)awakeFromNib
+// {
+// // NSLog(@"%s", __PRETTY_FUNCTION__);
+// // if (content) {
+// // NSLog(@"%s %@", __PRETTY_FUNCTION__, content);
+// // [webView setPreferencesIdentifier:TMD_TOOLTIP_PREFERENCES_IDENTIFIER];
+// // [webView setFrameLoadDelegate:self];
+// // [[webView mainFrame] loadHTMLString:content baseURL:nil];
+// // }
+// }
+
+-(void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ [self sizeToContent];
+ [self showWindow:self];
+}
+
+-(void)dealloc
+{
+ [webPreferences release];
+ [super dealloc];
+}
+@end
View
87 Commands/HTMLTips/htmltips.mm
@@ -0,0 +1,87 @@
+#import <Cocoa/Cocoa.h>
+#import <Foundation/Foundation.h>
+#import "../../TMDCommand.h"
+#import "../../Dialog2.h"
+#import "TMDHTMLTips.h"
+
+@interface NSObject (OakTextView)
+- (NSPoint)positionForWindowUnderCaret;
+@end
+
+@interface NSData (UTF8String)
+- (NSString *)UTF8String;
+@end
+
+@implementation NSData (UTF8String)
+- (NSString *)UTF8String
+{
+ char *string = new char[[self length] + 1];
+ strcpy(string, (const char*)[self bytes]);
+ string[[self length]] = '\0';
+ NSString *result = [NSString stringWithUTF8String:string];
+ return result;
+}
+@end
+
+@interface TMDHTMLTipsCommand : TMDCommand
+@end
+
+@implementation TMDHTMLTipsCommand
++ (void)load
+{
+ [TMDCommand registerObject:[self new] forCommand:@"html-tip"];
+}
+
+- (void)handleCommand:(NSDictionary *)options
+{
+ NSFileHandle *stdinFP = (NSFileHandle *)[options objectForKey:@"stdin"];
+ NSData *data = [stdinFP readDataToEndOfFile];
+
+ if ([data length] == 0)
+ return;
+
+ NSString *content = [data UTF8String];
+
+ NSPoint pos = NSZeroPoint;
+
+ if(id textView = [NSApp targetForAction:@selector(positionForWindowUnderCaret)])
+ pos = [textView positionForWindowUnderCaret];
+
+ TMDHTMLTips* tooltip = [[TMDHTMLTips alloc] init];
+ [tooltip setHTML:content];
+ NSLog(@"%s point: %@", __PRETTY_FUNCTION__, NSStringFromPoint(pos));
+ // pos.y = 900;
+ // pos.x = 0;
+ [[tooltip window] setFrameTopLeftPoint:pos];
+ NSLog(@"%s point: %@", __PRETTY_FUNCTION__, NSStringFromPoint([[tooltip window] frame].origin));
+
+ [self performSelector: @selector(eventHandlingForHTMLTip:)
+ withObject: tooltip
+ afterDelay: 0.1];
+}
+
+-(void) eventHandlingForHTMLTip:(TMDHTMLTips *)tooltip
+{
+ NSDate *distantFuture = [NSDate distantFuture];
+ NSEvent *event;
+
+ do {
+ event = [NSApp nextEventMatchingMask: NSAnyEventMask
+ untilDate: distantFuture
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+
+ if (event != nil)
+ {
+ NSEventType t = [event type];
+ [NSApp sendEvent:event];
+ if (t == NSKeyDown || t == NSMouseMoved || t == NSScrollWheel) {
+ break;
+ }
+ }
+ }
+ while(1);
+
+ [tooltip fade];
+}
+@end
View
124 Commands/alert.mm
@@ -0,0 +1,124 @@
+#import "../Dialog2.h"
+#import "../TMDCommand.h"
+
+// =========
+// = Alert =
+// =========
+
+@interface TMDAlertCommand : TMDCommand
+{
+}
+@end
+
+@implementation TMDAlertCommand
++ (void)load
+{
+ [super registerObject:[self new] forCommand:@"alert"];
+}
+
+- (void)handleCommand:(id)options
+{
+ NSFileHandle* fh = [options objectForKey:@"stderr"];
+ [fh writeData:[@"Alerts are not implemented yet." dataUsingEncoding:NSUTF8StringEncoding]];
+#if 0
+ NSAlertStyle alertStyle = NSInformationalAlertStyle;
+ NSAlert* alert;
+ NSDictionary* resultDict = nil;
+ NSArray* buttonTitles = [parameters objectForKey:@"buttonTitles"];
+ NSString* alertStyleString = [parameters objectForKey:@"alertStyle"];
+
+ alert = [[[NSAlert alloc] init] autorelease];
+
+ if([alertStyleString isEqualToString:@"warning"])
+ {
+ alertStyle = NSWarningAlertStyle;
+ }
+ else if([alertStyleString isEqualToString:@"critical"])
+ {
+ alertStyle = NSCriticalAlertStyle;
+ }
+ else if([alertStyleString isEqualToString:@"informational"])
+ {
+ alertStyle = NSInformationalAlertStyle;
+ }
+
+ [alert setAlertStyle:alertStyle];
+ [alert setMessageText:[parameters objectForKey:@"messageTitle"]];
+ [alert setInformativeText:[parameters objectForKey:@"informativeText"]];
+
+ // Setup buttons
+ if(buttonTitles != nil && [buttonTitles count] > 0)
+ {
+ unsigned int buttonCount = [buttonTitles count];
+
+ // NSAlert always preallocates the OK button.
+ // No -- docs are not entirely correct.
+// [[[alert buttons] objectAtIndex:0] setTitle:[buttonTitles objectAtIndex:0]];
+
+ for(unsigned int index = 0; index < buttonCount; index += 1)
+ {
+ NSString * buttonTitle = [buttonTitles objectAtIndex:index];
+
+ [alert addButtonWithTitle:buttonTitle];
+ }
+ }
+
+ // Show the alert
+ if(not modal)
+ {
+#if 1
+ // Not supported yet; needs same infrastructure as will be required for nib-based sheets.
+ [NSException raise:@"NotSupportedYet" format:@"Sheet alerts not yet supported."];
+#else
+ // Window-modal (sheet).NSWindowController
+ // Find the window corresponding to the given path
+
+ NSArray* windows = [NSApp windows];
+ NSWindow* chosenWindow = nil;
+
+ enumerate(windows, NSWindow * window)
+ {
+ OakDocumentController* documentController = [window controller];
+ if([documentController isKindOfClass:[OakDocumentController class]])
+ {
+ if(filePath == nil)
+ {
+ // Take first visible document window
+ if( [window isVisible] )
+ {
+ chosenWindow = window;
+ break;
+ }
+ }
+ else
+ {
+ // Find given document window
+ // TODO: documentWithContentsOfFile may be a better way to do this
+ // FIXME: standardize paths
+ if([[documentController->textDocument filename] isEqualToString:filePath])
+ {
+ chosenWindow = window;
+ break;
+ }
+ }
+ }
+ }
+
+ // Fall back to modal
+ if(chosenWindow == nil)
+ {
+ modal = YES;
+ }
+#endif
+ }
+
+ if(modal)
+ {
+ int alertResult = ([alert runModal] - NSAlertFirstButtonReturn);
+
+ resultDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:alertResult] forKey:@"buttonClicked"];
+ }
+ return resultDict;
+#endif
+}
+@end
View
24 Commands/help.mm
@@ -0,0 +1,24 @@
+#import "../TMDCommand.h"
+
+// ========
+// = Help =
+// ========
+
+@interface TMDHelpCommand : TMDCommand
+{
+}
+@end
+
+@implementation TMDHelpCommand
++ (void)load
+{
+ [TMDCommand registerObject:[self new] forCommand:@"help"];
+}
+
+- (void)handleCommand:(id)options
+{
+ NSFileHandle* fh = [options objectForKey:@"stderr"];
+ // [fh writeData:[@"Help is not yet implemented.\n" dataUsingEncoding:NSUTF8StringEncoding]];
+ [fh writeData:[[[TMDCommand registeredCommands] description] dataUsingEncoding:NSUTF8StringEncoding]];
+}
+@end
View
80 Commands/menu.mm
@@ -0,0 +1,80 @@
+#import <Carbon/Carbon.h>
+#import "../Dialog2.h"
+#import "../TMDCommand.h"
+
+// ========
+// = Menu =
+// ========
+
+@interface NSObject (OakTextView)
+- (NSPoint)positionForWindowUnderCaret;
+@end
+
+@interface TMDMenuCommand : TMDCommand
+{
+}
+@end
+
+@implementation TMDMenuCommand
++ (void)load
+{
+ [TMDCommand registerObject:[self new] forCommand:@"menu"];
+}
+
+- (void)handleCommand:(id)options
+{
+ MenuRef menu_ref;
+ CreateNewMenu(0 /* menu id */, kMenuAttrDoNotCacheImage, &menu_ref);
+ SetMenuFont(menu_ref, 0, [[NSUserDefaults standardUserDefaults] integerForKey:@"OakBundleManagerDisambiguateMenuFontSize"] ?: 12);
+
+ int item_id = 0, item_index = 0;
+ NSArray* menuItems = [[TMDCommand readPropertyList:[options objectForKey:@"stdin"]] objectForKey:@"menuItems"];
+ enumerate(menuItems, NSDictionary* menuItem)
+ {
+ if([[menuItem objectForKey:@"separator"] intValue])
+ {
+ AppendMenuItemTextWithCFString(menu_ref, CFSTR(""), kMenuItemAttrSeparator, item_index++, NULL);
+ }
+ else
+ {
+ MenuItemIndex index;
+ AppendMenuItemTextWithCFString(menu_ref, (CFStringRef)[menuItem objectForKey:@"title"], 0, item_index++, &index);
+ if(++item_id <= 10)
+ {
+ SetMenuItemCommandKey(menu_ref, index, NO, item_id == 10 ? '0' : '1' + (item_id-1));
+ SetMenuItemModifiers(menu_ref, index, kMenuNoCommandModifier);
+ }
+ // SetMenuItemIndent(menu_ref, index, 1);
+ }
+ // AppendMenuItemTextWithCFString(menu_ref, NULL, kMenuItemAttrSectionHeader, 0, NULL);
+ }
+
+ NSPoint pos = NSZeroPoint;
+ if(id textView = [NSApp targetForAction:@selector(positionForWindowUnderCaret)])
+ pos = [textView positionForWindowUnderCaret];
+
+ NSRect mainScreen = [[NSScreen mainScreen] frame];
+ enumerate([NSScreen screens], NSScreen* candidate)
+ {
+ if(NSMinX([candidate frame]) == 0.0f && NSMinY([candidate frame]) == 0.0f)
+ mainScreen = [candidate frame];
+ }
+
+ short top = lroundf(NSMaxY(mainScreen) - pos.y);
+ short left = lroundf(pos.x - NSMinX(mainScreen));
+ long res = PopUpMenuSelect(menu_ref, top, left, 0 /* pop-up item */);
+
+ NSMutableDictionary* selectedItem = [NSMutableDictionary dictionary];
+ if(res != 0)
+ {
+ MenuCommand cmd = 0;
+ GetMenuItemCommandID(menu_ref, res, &cmd);
+ [selectedItem setObject:[NSNumber numberWithUnsignedInt:(unsigned)cmd] forKey:@"selectedIndex"];
+ [selectedItem setObject:[menuItems objectAtIndex:(unsigned)cmd] forKey:@"selectedMenuItem"];
+ }
+
+ [TMDCommand writePropertyList:selectedItem toFileHandle:[options objectForKey:@"stdout"]];
+
+ DisposeMenu(menu_ref);
+}
+@end
View
23 Commands/quit.mm
@@ -0,0 +1,23 @@
+#import "../TMDCommand.h"
+
+// ========
+// = Quit =
+// ========
+
+@interface TMDQuitCommand : TMDCommand
+{
+}
+@end
+
+@implementation TMDQuitCommand
++ (void)load
+{
+ [TMDCommand registerObject:[self new] forCommand:@"quit"];
+}
+
+- (void)handleCommand:(id)options
+{
+ [NSApp terminate:self];
+}
+@end
+
View
12 Commands/window/TMDChameleon.h
@@ -0,0 +1,12 @@
+//
+// TMDChameleon.h
+// Created by Allan Odgaard on 2007-06-26.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface TMDChameleon : NSObject
+{
+}
++ (BOOL)createSubclassNamed:(NSString*)aName withValues:(NSDictionary*)values;
+@end
View
52 Commands/window/TMDChameleon.mm
@@ -0,0 +1,52 @@
+//
+// TMDChameleon.mm
+// Created by Allan Odgaard on 2007-06-26.
+//
+
+#import "TMDChameleon.h"
+#import <objc/objc-runtime.h>
+
+static NSMutableDictionary* DefaultValues = [NSMutableDictionary new];
+
+static Class find_root (Class cl)
+{
+ while(cl->super_class)
+ cl = cl->super_class;
+ return cl;
+}
+
+@implementation TMDChameleon
+- (id)init
+{
+ id res = [DefaultValues objectForKey:NSStringFromClass([self class])];
+ return [self release], [res mutableCopy];
+}
+
++ (BOOL)createSubclassNamed:(NSString*)aName withValues:(NSDictionary*)values
+{
+ [DefaultValues setObject:values forKey:aName];
+ if(NSClassFromString(aName))
+ return YES;
+
+ Class super_cl = [TMDChameleon class];
+
+ Class sub_cl = (Class)calloc(1, sizeof(objc_class));
+ Class meta_cl = (Class)calloc(1, sizeof(objc_class));
+
+ sub_cl->name = strdup([aName UTF8String]);
+ sub_cl->info = CLS_CLASS;
+ sub_cl->isa = meta_cl;
+ sub_cl->super_class = super_cl;
+ sub_cl->methodLists = (objc_method_list**)calloc(1, sizeof(objc_method_list*));
+
+ meta_cl->name = sub_cl->name;
+ meta_cl->info = CLS_META;
+ meta_cl->isa = find_root(super_cl)->isa;
+ meta_cl->super_class = super_cl->isa;
+ meta_cl->methodLists = (objc_method_list**)calloc(1, sizeof(objc_method_list*));
+
+ objc_addClass(sub_cl);
+
+ return YES;
+}
+@end
View
10 Commands/window/ValueTransformers.h
@@ -0,0 +1,10 @@
+#import <Cocoa/Cocoa.h>
+
+@interface OakIntArrayToIndexPathTransformer : NSValueTransformer
+@end
+
+@interface OakIntArrayToIndexSetTransformer : NSValueTransformer
+@end
+
+@interface OakStringToColorTransformer : NSValueTransformer
+@end
View
126 Commands/window/ValueTransformers.mm
@@ -0,0 +1,126 @@
+#import "ValueTransformers.h"
+#import "Dialog2.h"
+
+// ===================================================
+// = Int Array To Index Path Array Value Transformer =
+// ===================================================
+
+@implementation OakIntArrayToIndexPathTransformer
++ (Class)transformedValueClass { return [NSArray class]; }
++ (BOOL)allowsReverseTransformation { return YES; }
+
++ (void)load
+{
+ id transformer = [self new];
+ [NSValueTransformer setValueTransformer:transformer forName:@"OakIntArrayToIndexPathTransformer"];
+ [transformer release];
+}
+
+- (NSIndexPath*)arrayToIndexPath:(NSArray*)anArray
+{
+ NSIndexPath* indexPath = [[NSIndexPath new] autorelease];
+ enumerate(anArray, id index)
+ indexPath = [indexPath indexPathByAddingIndex:[index intValue]];
+ return indexPath;
+}
+
+- (id)transformedValue:(id)value
+{
+ NSMutableArray* res = [NSMutableArray array];
+ enumerate(value, NSArray* intArray)
+ [res addObject:[self arrayToIndexPath:intArray]];
+ return res;
+}
+
+- (NSArray*)indexPathToArray:(NSIndexPath*)anIndexPath
+{
+ NSMutableArray* array = [NSMutableArray array];
+ for(size_t i = 0; i < [anIndexPath length]; ++i)
+ [array addObject:[NSNumber numberWithUnsignedInt:[anIndexPath indexAtPosition:i]]];
+ return array;
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+ NSMutableArray* array = [NSMutableArray array];
+ enumerate(value, NSIndexPath* indexPath)
+ [array addObject:[self indexPathToArray:indexPath]];
+ return array;
+}
+@end
+
+// ============================================
+// = Int Array To Index Set Value Transformer =
+// ============================================
+
+@implementation OakIntArrayToIndexSetTransformer
++ (Class)transformedValueClass { return [NSIndexSet class]; }
++ (BOOL)allowsReverseTransformation { return YES; }
+
++ (void)load
+{
+ id transformer = [self new];
+ [NSValueTransformer setValueTransformer:transformer forName:@"OakIntArrayToIndexSetTransformer"];
+ [transformer release];
+}
+
+- (id)transformedValue:(id)value
+{
+ NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
+ enumerate(value, NSNumber* integer)
+ [indexSet addIndex:[integer intValue]];
+ return indexSet;
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+ NSMutableArray* array = [NSMutableArray array];
+ unsigned int buf[[value count]];
+ [(NSIndexSet*)value getIndexes:buf maxCount:[value count] inIndexRange:nil];
+ for(unsigned int i = 0; i != [value count]; i++)
+ [array addObject:[NSNumber numberWithUnsignedInt:buf[i]]];
+ return array;
+}
+@end
+
+// =============================================
+// = #RRGGBB String To Color Value Transformer =
+// =============================================
+
+static NSColor* NSColorFromString (NSString* aColor)
+{
+ if(!aColor || [aColor isEqualToString:@""])
+ return nil;
+
+ unsigned int red = 0, green = 0, blue = 0, alpha = 0xFF;
+ if(sscanf([aColor UTF8String], "#%02x%02x%02x%02x", &red, &green, &blue, &alpha) < 3)
+ return nil;
+
+ return [NSColor colorWithCalibratedRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
+}
+
+static NSString* NSStringFromColor (NSColor* aColor)
+{
+ if(aColor == nil)
+ return nil;
+
+ aColor = [aColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ if([aColor alphaComponent] != 1.0f)
+ return [NSString stringWithFormat:@"#%02X%02X%02X%02X", lroundf(255.0f*[aColor redComponent]), lroundf(255.0f*[aColor greenComponent]), lroundf(255.0f*[aColor blueComponent]), lroundf(255.0f*[aColor alphaComponent])];
+ else return [NSString stringWithFormat:@"#%02X%02X%02X", lroundf(255.0f*[aColor redComponent]), lroundf(255.0f*[aColor greenComponent]), lroundf(255.0f*[aColor blueComponent])];
+}
+
+@implementation OakStringToColorTransformer
++ (Class)transformedValueClass { return [NSColor class]; }
++ (BOOL)allowsReverseTransformation { return YES; }
+
+- (id)transformedValue:(id)value { return NSColorFromString(value); }
+- (id)reverseTransformedValue:(id)value { return NSStringFromColor(value); }
+
++ (void)load
+{
+ id transformer = [self new];
+ [NSValueTransformer setValueTransformer:transformer forName:@"OakStringToColorTransformer"];
+ [transformer release];
+}
+@end
View
397 Commands/window/window.mm
@@ -0,0 +1,397 @@
+#import <string>
+#import <vector>
+#import <sys/stat.h>
+#import "../../Dialog2.h"
+#import "../../TMDCommand.h"
+#import "../../OptionParser.h"
+
+// ==========
+// = Window =
+// ==========
+
+static unsigned int NibTokenCount = 0;
+static NSMutableDictionary* Nibs = [NSMutableDictionary new];
+
+@interface TMDNibController : NSObject
+{
+ NSArray* topLevelObjects;
+ NSWindow* window;
+ NSMutableDictionary* parameters;
+ NSMutableArray* fileHandles;
+ unsigned int token;
+ BOOL autoCloses;
+}
+- (NSWindow*)window;
+- (void)setWindow:(NSWindow*)aValue;
+- (NSString*)token;
+- (void)updateParametersWith:(id)plist;
+@end
+
+@interface TMDWindowCommand : TMDCommand
+{
+}
+@end
+
+// ==================
+// = Nib Controller =
+// ==================
+
+@implementation TMDNibController
+- (NSWindow*)window { return window; }
+- (id)parameters { return parameters; }
+- (NSString*)token { return [NSString stringWithFormat:@"%u", token]; }
+- (BOOL)autoCloses { return autoCloses; }
+
+- (void)setAutoCloses:(BOOL)flag { autoCloses = flag; }
+
+- (void)setWindow:(NSWindow*)aWindow
+{
+ if(window != aWindow)
+ {
+ [window setDelegate:nil];
+ [window release];
+ window = [aWindow retain];
+ [window setDelegate:self];
+ [window setReleasedWhenClosed:NO]; // incase this was set wrong in IB
+ }
+}
+
+- (void)setParameters:(id)someParameters
+{
+ if(parameters != someParameters)
+ {
+ [parameters release];
+ parameters = [someParameters retain];
+ }
+}
+
+- (void)updateParametersWith:(id)plist
+{
+ enumerate([plist allKeys], id key)
+ [parameters setValue:[plist valueForKey:key] forKey:key];
+}
+
+- (void)instantiateNib:(NSNib*)aNib
+{
+ BOOL didInstantiate = NO;
+ @try {
+ didInstantiate = [aNib instantiateNibWithOwner:self topLevelObjects:&topLevelObjects];
+ }
+ @catch(NSException* e) {
+ // our retain count is too high if we reach this branch (<rdar://4803521>) so no RAII idioms for Cocoa, which is why we have the didLock variable, etc.
+ NSLog(@"%s failed to instantiate nib (%@)", _cmd, [e reason]);
+ return;
+ }
+
+ [topLevelObjects retain];
+ enumerate(topLevelObjects, id object)
+ {
+ if([object isKindOfClass:[NSWindow class]])
+ [self setWindow:object];
+ }
+
+ if(!window)
+ {
+ NSLog(@"%s didn't find a window in nib", _cmd);
+ return;
+ }
+
+ // if(center)
+ // {
+ // if(NSWindow* keyWindow = [NSApp keyWindow])
+ // {
+ // NSRect frame = [window frame], parentFrame = [keyWindow frame];
+ // [window setFrame:NSMakeRect(NSMidX(parentFrame) - 0.5 * NSWidth(frame), NSMidY(parentFrame) - 0.5 * NSHeight(frame), NSWidth(frame), NSHeight(frame)) display:NO];
+ // }
+ // else
+ // {
+ // [window center];
+ // }
+ // }
+
+ [window makeKeyAndOrderFront:self];
+
+ // // TODO: When TextMate is capable of running script I/O in it's own thread(s), modal blocking
+ // // can go away altogether.
+ // if(isModal)
+ // [NSApp runModalForWindow:window];
+}
+
+- (id)initWithNibName:(NSString*)aName
+{
+ if(self = [super init])
+ {
+ if(![[NSFileManager defaultManager] fileExistsAtPath:aName])
+ {
+ NSLog(@"%s nib file not found: %@", _cmd, aName);
+ [self release];
+ return nil;
+ }
+
+ parameters = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
+ self, @"controller",
+ nil] retain];
+
+ NSNib* nib = [[[NSNib alloc] initWithContentsOfURL:[NSURL fileURLWithPath:aName]] autorelease];
+ if(!nib)
+ {
+ NSLog(@"%s failed loading nib: %@", _cmd, aName);
+ [self release];
+ return nil;
+ }
+
+ token = ++NibTokenCount;
+ [self instantiateNib:nib];
+ }
+ return self;
+}
+
+- (void)makeControllersCommitEditing
+{
+ enumerate(topLevelObjects, id object)
+ {
+ if([object respondsToSelector:@selector(commitEditing)])
+ [object commitEditing];
+ }
+
+ [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+- (void)tearDown
+{
+ [[self retain] autorelease];
+
+ [parameters removeObjectForKey:@"controller"];
+ // [self return:parameters]; // only if the non-async version is used
+
+ // if we do not manually unbind, the object in the nib will keep us retained, and thus we will never reach dealloc
+ enumerate(topLevelObjects, id object)
+ {
+ if([object isKindOfClass:[NSObjectController class]])
+ [object unbind:@"contentObject"];
+ }
+
+ [Nibs removeObjectForKey:[self token]];
+}
+
+- (void)dealloc
+{
+ NSLog(@"%s TMDNibController", _cmd);
+ [self setWindow:nil];
+ [self setParameters:nil];
+
+ NSLog(@"%s %@", _cmd, topLevelObjects);
+ enumerate(topLevelObjects, id object)
+ [object release];
+ [topLevelObjects release];
+
+ [fileHandles release];
+ [super dealloc];
+}
+
+- (void)windowWillClose:(NSNotification*)aNotification
+{
+ NSLog(@"%s", _cmd);
+ [self tearDown];
+}
+
+// ==================================
+// = Getting stuff from this window =
+// ==================================
+- (void)notifyFileHandle:(NSFileHandle*)aFileHandle
+{
+ if(!fileHandles)
+ fileHandles = [NSMutableArray new];
+ [fileHandles addObject:aFileHandle];
+}
+
+- (void)return:(id)res
+{
+ [self makeControllersCommitEditing];
+
+ enumerate(fileHandles, NSFileHandle* fileHandle)
+ [TMDCommand writePropertyList:res toFileHandle:fileHandle];
+
+ [fileHandles release];
+ fileHandles = nil;
+
+ if([self autoCloses])
+ [self tearDown];
+}
+
+// ================================================
+// = Faking a returnArgument:[…:]* implementation =
+// ================================================
+// returnArgument: implementation. See <http://lists.macromates.com/pipermail/textmate/2006-November/015321.html>
+- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector
+{
+ NSString* str = NSStringFromSelector(aSelector);
+ if([str hasPrefix:@"returnArgument:"])
+ {
+ std::string types;
+ types += @encode(void);
+ types += @encode(id);
+ types += @encode(SEL);
+
+ unsigned numberOfArgs = [[str componentsSeparatedByString:@":"] count];
+ while(numberOfArgs-- > 1)
+ types += @encode(id);
+
+ return [NSMethodSignature signatureWithObjCTypes:types.c_str()];
+ }
+ return [super methodSignatureForSelector:aSelector];
+}
+
+- (void)forwardInvocation:(NSInvocation*)invocation
+{
+ NSString* str = NSStringFromSelector([invocation selector]);
+ if([str hasPrefix:@"returnArgument:"])
+ {
+ NSArray* argNames = [str componentsSeparatedByString:@":"];
+
+ NSMutableDictionary* res = [NSMutableDictionary dictionary];
+ for(size_t i = 2; i < [[invocation methodSignature] numberOfArguments]; ++i)
+ {
+ id arg = nil;
+ if([invocation getArgument:&arg atIndex:i], arg)
+ [res setObject:arg forKey:[argNames objectAtIndex:i - 2]];
+ }
+
+ [self return:res];
+ }
+ else
+ {
+ [super forwardInvocation:invocation];
+ }
+}
+
+// ===============================
+// = The old performButtonClicl: =
+// ===============================
+- (IBAction)performButtonClick:(id)sender
+{
+ NSMutableDictionary* res = [[parameters mutableCopy] autorelease];
+ [res removeObjectForKey:@"controller"];
+
+ if([sender respondsToSelector:@selector(title)])
+ [res setObject:[sender title] forKey:@"returnButton"];
+ if([sender respondsToSelector:@selector(tag)])
+ [res setObject:[NSNumber numberWithInt:[sender tag]] forKey:@"returnCode"];
+
+ [self return:res];
+}
+@end
+
+// ===================
+// = Command handler =
+// ===================
+
+std::string find_nib (std::string nibName, std::string currentDirectory)
+{
+ std::vector<std::string> candidates;
+
+ if(nibName.find(".nib") == std::string::npos)
+ nibName += ".nib";
+
+ if(nibName.size() && nibName[0] != '/') // relative path
+ {
+ candidates.push_back(currentDirectory + "/" + nibName);
+
+ if(char const* bundleSupport = getenv("TM_BUNDLE_SUPPORT"))
+ candidates.push_back(bundleSupport + std::string("/nibs/") + nibName);
+
+ if(char const* supportPath = getenv("TM_SUPPORT_PATH"))
+ candidates.push_back(supportPath + std::string("/nibs/") + nibName);
+ }
+ else
+ {
+ candidates.push_back(nibName);
+ }
+
+ iterate(it, candidates)
+ {
+ fprintf(stderr, "candidate: %s\n", it->c_str());
+ struct stat sb;
+ if(stat(it->c_str(), &sb) == 0)
+ return *it;
+ }
+
+ fprintf(stderr, "nib could not be loaded: %s (does not exist)\n", nibName.c_str());
+ return "";
+}
+
+@implementation TMDWindowCommand
++ (void)load
+{
+ [super registerObject:[self new] forCommand:@"window"];
+}
+
+- (void)handleCommand:(id)options
+{
+ NSLog(@"%s TMDNib %@", _cmd, options);
+
+ NSArray* args = [options objectForKey:@"arguments"];
+
+ static option_t const expectedOptions[] =
+ {
+ { "c", "center", option_t::no_argument },
+ { "d", "defaults", option_t::required_argument, option_t::plist },
+ { "m", "modal", option_t::no_argument },
+ { "n", "new-items", option_t::required_argument, option_t::plist },
+ { "p", "parameters", option_t::required_argument, option_t::plist },
+ { "q", "quiet", option_t::no_argument },
+ };
+
+ NSDictionary* res = ParseOptions(args, expectedOptions);
+ NSLog(@"%s %@", _cmd, res);
+
+ NSString* command = [args objectAtIndex:2];
+ if([command isEqualToString:@"create"] || [command isEqualToString:@"show"])
+ {
+ char const* nibName = [[args lastObject] UTF8String];
+ char const* nibPath = [[options objectForKey:@"cwd"] UTF8String];
+ NSString* nib = [NSString stringWithUTF8String:find_nib(nibName ?: "", nibPath ?: "").c_str()];
+
+ TMDNibController* nibController = [[[TMDNibController alloc] initWithNibName:nib] autorelease];
+ [Nibs setObject:nibController forKey:[nibController token]];
+
+ NSFileHandle* fh = [options objectForKey:@"stdout"];
+ if([command isEqualToString:@"show"])
+ {
+ [nibController notifyFileHandle:fh];
+ [nibController setAutoCloses:YES];
+ }
+ else
+ {
+ [fh writeData:[[nibController token] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ }
+ else if([command isEqualToString:@"wait"])
+ {
+ NSString* token = [args lastObject];
+ TMDNibController* nibController = [Nibs objectForKey:token];
+ [nibController notifyFileHandle:[options objectForKey:@"stdout"]];
+ }
+ else if([command isEqualToString:@"update"])
+ {
+ NSString* token = [args lastObject];
+ TMDNibController* nibController = [Nibs objectForKey:token];
+ id newParameters = [TMDCommand readPropertyList:[options objectForKey:@"stdin"]];
+ [nibController updateParametersWith:newParameters];
+ }
+ else if([command isEqualToString:@"list"])
+ {
+ NSFileHandle* fh = [options objectForKey:@"stdout"];
+ enumerate([Nibs allKeys], NSString* token)
+ {
+ TMDNibController* nibController = [Nibs objectForKey:token];
+ [fh writeData:[[NSString stringWithFormat:@"%@ (%@)\n", token, [[nibController window] title]] dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ }
+ else if([command isEqualToString:@"close"])
+ {
+ NSString* token = [args lastObject];
+ [[Nibs objectForKey:token] tearDown];
+ }
+}
+@end
View
37 Dialog2.h
@@ -0,0 +1,37 @@
+#ifndef _DIALOG_H_
+#define _DIALOG_H_
+
+static NSString *DialogServerConnectionName = @"com.macromates.dialog";
+
+@protocol DialogServerProtocol
+- (void)hello:(id)anArgument;
+@end
+
+#ifndef enumerate
+#define enumerate(container,var) for(NSEnumerator* _enumerator = [container objectEnumerator]; var = [_enumerator nextObject]; )
+#endif
+
+inline char const* beginof (char const* cStr) { return cStr; }
+inline char const* endof (char const* cStr) { return cStr + strlen(cStr); }
+template <typename T, int N> T* beginof (T (&a)[N]) { return a; }
+template <typename T, int N> T* endof (T (&a)[N]) { return a + N; }
+template <typename T, int N, int M> T (*beginof(T (&m)[N][M]))[M] { return m; }
+template <typename T, int N, int M> T (*endof(T (&m)[N][M]))[M] { return m + N; }
+template <class T> typename T::const_iterator beginof (T const& c) { return c.begin(); }
+template <class T> typename T::const_iterator endof (T const& c) { return c.end(); }
+template <class T> typename T::iterator beginof (T& c) { return c.begin(); }
+template <class T> typename T::iterator endof (T& c) { return c.end(); }
+
+#ifndef foreach
+#define foreach(v,f,l) for(typeof(f) v = (f), _end = (l); v != _end; ++v)
+#endif
+
+#ifndef iterate
+#define iterate(v,c) foreach(v, beginof(c), endof(c))
+#endif
+
+#ifndef sizeofA
+#define sizeofA(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+#endif /* _DIALOG_H_ */
View
74 Dialog2.mm
@@ -0,0 +1,74 @@
+//
+// Dialog2.mm
+// Dialog2
+//
+// Created by Ciaran Walsh on 19/11/2007.
+// Copyright 2007 __MyCompanyName__. All rights reserved.
+//
+
+#import "Dialog2.h"
+#import "TMDCommand.h"
+
+@protocol TMPlugInController
+- (float)version;
+@end
+
+@interface Dialog2 : NSObject <DialogServerProtocol>
+{
+}
+- (id)initWithPlugInController:(id <TMPlugInController>)aController;
+@end
+
+
+@implementation Dialog2
+
+- (id)initWithPlugInController:(id <TMPlugInController>)aController
+{
+ NSApp = [NSApplication sharedApplication];
+ if (self = [self init]) {
+ NSConnection *connection = [NSConnection new];
+ [connection setRootObject:self];
+
+ if ([connection registerName:DialogServerConnectionName] == NO)
+ NSLog(@"couldn't setup dialog server."), NSBeep();
+ else if (NSString* path = [[NSBundle bundleForClass:[self class]] pathForResource:@"tm_dialog2" ofType:nil]) {
+ setenv("DIALOG_1", getenv("DIALOG"), 1);
+ setenv("DIALOG", [path UTF8String], 1);
+ }
+ }
+
+ return self;
+}
+
+- (void)dispatch:(id)options
+{
+ NSArray* args = [options objectForKey:@"arguments"];
+ NSString* cwd = [options objectForKey:@"cwd"];
+ NSFileHandle* stdin_fh = [NSFileHandle fileHandleForReadingAtPath:[options objectForKey:@"stdin"]];
+ NSFileHandle* stdout_fh = [NSFileHandle fileHandleForWritingAtPath:[options objectForKey:@"stdout"]];
+ NSFileHandle* stderr_fh = [NSFileHandle fileHandleForWritingAtPath:[options objectForKey:@"stderr"]];
+
+ NSDictionary* newOptions = [NSDictionary dictionaryWithObjectsAndKeys:
+ stdin_fh, @"stdin",
+ stdout_fh, @"stdout",
+ stderr_fh, @"stderr",
+ args, @"arguments",
+ cwd, @"cwd",
+ nil];
+
+ NSString* command = [args count] <= 1 ? @"help" : [args objectAtIndex:1];
+ if(id target = [TMDCommand objectForCommand:command])
+ [target performSelector:@selector(handleCommand:) withObject:newOptions];
+ else
+ [stderr_fh writeData:[@"unknown command, try help.\n" dataUsingEncoding:NSUTF8StringEncoding]];
+}
+
+- (void)hello:(id)options
+{
+ NSLog(@"%s %@", _cmd, options);
+ [self performSelector:@selector(dispatch:) withObject:options afterDelay:0.0];
+}
+@end
+/*
+echo '{ menuItems = ({title = 'foo';});}' | "$DIALOG2" menu
+*/
View
190 Dialog2.tmproj
@@ -0,0 +1,190 @@
+<?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>currentDocument</key>
+ <string>tm_dialog2.mm</string>
+ <key>documents</key>
+ <array>
+ <dict>
+ <key>expanded</key>
+ <true/>
+ <key>name</key>
+ <string>Dialog2</string>
+ <key>regexFolderFilter</key>
+ <string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+ <key>sourceDirectory</key>
+ <string></string>
+ </dict>
+ <dict>
+ <key>filename</key>
+ <string>test.m</string>
+ <key>lastUsed</key>
+ <date>2007-11-20T05:34:39Z</date>
+ </dict>
+ </array>
+ <key>fileHierarchyDrawerWidth</key>
+ <integer>235</integer>
+ <key>metaData</key>
+ <dict>
+ <key>Commands/alert.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>123</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>76</integer>
+ </dict>
+ <key>Commands/help.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>24</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>0</integer>
+ </dict>
+ <key>Commands/menu.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>78</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>31</integer>
+ </dict>
+ <key>Dialog2.h</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>8</integer>
+ <key>line</key>
+ <integer>6</integer>
+ </dict>
+ <key>columnSelection</key>
+ <true/>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>0</integer>
+ <key>selectFrom</key>
+ <dict>
+ <key>column</key>
+ <integer>13</integer>
+ <key>line</key>
+ <integer>6</integer>
+ </dict>
+ <key>selectTo</key>
+ <dict>
+ <key>column</key>
+ <integer>8</integer>
+ <key>line</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <key>Dialog2.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>35</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>21</integer>
+ </dict>
+ <key>OptionParser.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>14</integer>
+ <key>line</key>
+ <integer>15</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>0</integer>
+ </dict>
+ <key>TMDCommand.h</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>36</integer>
+ <key>line</key>
+ <integer>2</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>0</integer>
+ </dict>
+ <key>TMDCommand.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>21</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>0</integer>
+ </dict>
+ <key>tm_dialog2.mm</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>61</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>57</integer>
+ </dict>
+ </dict>
+ <key>openDocuments</key>
+ <array>
+ <string>Dialog2.mm</string>
+ <string>TMDCommand.h</string>
+ <string>TMDCommand.mm</string>
+ <string>Commands/help.mm</string>
+ <string>tm_dialog2.mm</string>
+ <string>Commands/menu.mm</string>
+ <string>Commands/alert.mm</string>
+ <string>OptionParser.mm</string>
+ <string>Dialog2.h</string>
+ </array>
+ <key>showFileHierarchyDrawer</key>
+ <false/>
+ <key>windowFrame</key>
+ <string>{{0, 4}, {1440, 874}}</string>
+</dict>
+</plist>
View
440 Dialog2.xcodeproj/project.pbxproj
@@ -0,0 +1,440 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 177E4DA309132A0F0064163D /* Dialog2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 177E4DA209132A0F0064163D /* Dialog2.mm */; };
+ 8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
+ 8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
+ 91D6F89E0CF23B0D000F8170 /* TMDCommand.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F89A0CF23B0D000F8170 /* TMDCommand.mm */; };
+ 91D6F8A40CF23B71000F8170 /* OptionParser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F8A30CF23B71000F8170 /* OptionParser.mm */; };
+ 91D6F8EE0CF23C2C000F8170 /* tm_dialog2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F8E40CF23C09000F8170 /* tm_dialog2.mm */; };
+ 91D6F8F90CF23D6E000F8170 /* tm_dialog2 in Resources */ = {isa = PBXBuildFile; fileRef = 91D6F8EA0CF23C23000F8170 /* tm_dialog2 */; };
+ 91D6F8FE0CF23E51000F8170 /* alert.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F8FD0CF23E51000F8170 /* alert.mm */; };
+ 91D6F9020CF23E79000F8170 /* help.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F9010CF23E79000F8170 /* help.mm */; };
+ 91D6F9050CF23E7F000F8170 /* quit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F9030CF23E7F000F8170 /* quit.mm */; };
+ 91D6F9060CF23E7F000F8170 /* menu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91D6F9040CF23E7F000F8170 /* menu.mm */; };
+ 91D6F90B0CF23EAE000F8170 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91D6F90A0CF23EAE000F8170 /* Carbon.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 91D6F8F30CF23C3D000F8170 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 089C1669FE841209C02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 91D6F8E90CF23C23000F8170 /* tm_dialog2 */;
+ remoteInfo = tm_dialog2;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ 177E4DA109132A0F0064163D /* Dialog2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dialog2.h; sourceTree = "<group>"; };
+ 177E4DA209132A0F0064163D /* Dialog2.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Dialog2.mm; sourceTree = "<group>"; };
+ 32DBCF630370AF2F00C91783 /* Dialog2_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dialog2_Prefix.pch; sourceTree = "<group>"; };
+ 8D5B49B6048680CD000E48DA /* Dialog2.tmplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Dialog2.tmplugin; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Info.plist; sourceTree = "<group>"; };
+ 91D6F89A0CF23B0D000F8170 /* TMDCommand.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = TMDCommand.mm; sourceTree = "<group>"; };
+ 91D6F89C0CF23B0D000F8170 /* TMDCommand.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TMDCommand.h; sourceTree = "<group>"; };
+ 91D6F8A30CF23B71000F8170 /* OptionParser.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = OptionParser.mm; sourceTree = "<group>"; };
+ 91D6F8E40CF23C09000F8170 /* tm_dialog2.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = tm_dialog2.mm; sourceTree = "<group>"; };
+ 91D6F8EA0CF23C23000F8170 /* tm_dialog2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tm_dialog2; sourceTree = BUILT_PRODUCTS_DIR; };
+ 91D6F8FD0CF23E51000F8170 /* alert.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = alert.mm; path = Commands/alert.mm; sourceTree = "<group>"; };
+ 91D6F9010CF23E79000F8170 /* help.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = help.mm; path = Commands/help.mm; sourceTree = "<group>"; };
+ 91D6F9030CF23E7F000F8170 /* quit.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = quit.mm; path = Commands/quit.mm; sourceTree = "<group>"; };
+ 91D6F9040CF23E7F000F8170 /* menu.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = menu.mm; path = Commands/menu.mm; sourceTree = "<group>"; };
+ 91D6F90A0CF23EAE000F8170 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+ D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D5B49B3048680CD000E48DA /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */,
+ 91D6F90B0CF23EAE000F8170 /* Carbon.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 91D6F8E80CF23C23000F8170 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 089C166AFE841209C02AAC07 /* Dialog2 */ = {
+ isa = PBXGroup;
+ children = (
+ 91D6F8FC0CF23E46000F8170 /* Commands */,
+ 08FB77AFFE84173DC02AAC07 /* Classes */,
+ 32C88E010371C26100C91783 /* Other Sources */,
+ 91D6F8E30CF23C00000F8170 /* tm_dialog2 */,
+ 089C167CFE841241C02AAC07 /* Resources */,
+ 089C1671FE841209C02AAC07 /* Frameworks and Libraries */,
+ 19C28FB8FE9D52D311CA2CBB /* Products */,
+ );
+ name = Dialog2;
+ sourceTree = "<group>";
+ };
+ 089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */,
+ 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */,
+ );
+ name = "Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C167CFE841241C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D5B49B7048680CD000E48DA /* Info.plist */,
+ 089C167DFE841241C02AAC07 /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77AFFE84173DC02AAC07 /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ 177E4DA209132A0F0064163D /* Dialog2.mm */,
+ 177E4DA109132A0F0064163D /* Dialog2.h */,
+ );
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 91D6F90A0CF23EAE000F8170 /* Carbon.framework */,
+ 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 089C167FFE841241C02AAC07 /* AppKit.framework */,
+ D2F7E65807B2D6F200F64583 /* CoreData.framework */,
+ 089C1672FE841209C02AAC07 /* Foundation.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ 19C28FB8FE9D52D311CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D5B49B6048680CD000E48DA /* Dialog2.tmplugin */,
+ 91D6F8EA0CF23C23000F8170 /* tm_dialog2 */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 32C88E010371C26100C91783 /* Other Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 91D6F8A30CF23B71000F8170 /* OptionParser.mm */,
+ 91D6F89A0CF23B0D000F8170 /* TMDCommand.mm */,
+ 91D6F89C0CF23B0D000F8170 /* TMDCommand.h */,
+ 32DBCF630370AF2F00C91783 /* Dialog2_Prefix.pch */,
+ );
+ name = "Other Sources";
+ sourceTree = "<group>";
+ };
+ 91D6F8E30CF23C00000F8170 /* tm_dialog2 */ = {
+ isa = PBXGroup;
+ children = (
+ 91D6F8E40CF23C09000F8170 /* tm_dialog2.mm */,
+ );
+ name = tm_dialog2;
+ sourceTree = "<group>";
+ };
+ 91D6F8FC0CF23E46000F8170 /* Commands */ = {
+ isa = PBXGroup;
+ children = (
+ 91D6F9030CF23E7F000F8170 /* quit.mm */,
+ 91D6F9040CF23E7F000F8170 /* menu.mm */,
+ 91D6F9010CF23E79000F8170 /* help.mm */,
+ 91D6F8FD0CF23E51000F8170 /* alert.mm */,
+ );
+ name = Commands;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8D5B49AC048680CD000E48DA /* Dialog2 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "Dialog2" */;
+ buildPhases = (
+ 8D5B49AF048680CD000E48DA /* Resources */,
+ 8D5B49B1048680CD000E48DA /* Sources */,
+ 8D5B49B3048680CD000E48DA /* Frameworks */,
+ 177E4DB50913322B0064163D /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 91D6F8F40CF23C3D000F8170 /* PBXTargetDependency */,
+ );
+ name = Dialog2;
+ productInstallPath = "$(HOME)/Library/Bundles";
+ productName = Dialog2;
+ productReference = 8D5B49B6048680CD000E48DA /* Dialog2.tmplugin */;
+ productType = "com.apple.product-type.bundle";
+ };
+ 91D6F8E90CF23C23000F8170 /* tm_dialog2 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 91D6F8F20CF23C2F000F8170 /* Build configuration list for PBXNativeTarget "tm_dialog2" */;
+ buildPhases = (
+ 91D6F8E70CF23C23000F8170 /* Sources */,
+ 91D6F8E80CF23C23000F8170 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tm_dialog2;
+ productName = tm_dialog2;
+ productReference = 91D6F8EA0CF23C23000F8170 /* tm_dialog2 */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 089C1669FE841209C02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "Dialog2" */;
+ compatibilityVersion = "Xcode 2.4";