Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit ebb9d8acd263f058686f4127189990d6c23704b6 @ciaran committed Nov 18, 2008
@@ -0,0 +1,6 @@
+build
+*.xcodeproj/*.pbxuser
+*.xcodeproj/*.perspectivev3
+*.xcodeproj/*.mode1v3
+*.xcodeproj/*.tm_build_errors
+*.tmproj

Large diffs are not rendered by default.

Oops, something went wrong.
Binary file not shown.
@@ -0,0 +1,37 @@
+<?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>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>sh.ciaranwal.terminal-colours</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSPrincipalClass</key>
+ <string>TerminalColours</string>
+ <key>SIMBLTargetApplications</key>
+ <array>
+ <dict>
+ <key>BundleIdentifier</key>
+ <string>com.apple.Terminal</string>
+ <key>MaxBundleVersion</key>
+ <string>240</string>
+ <key>MinBundleVersion</key>
+ <string>240</string>
+ </dict>
+ </array>
+ </dict>
+</plist>
@@ -0,0 +1,13 @@
+/*******************************************************************************
+ JRSwizzle.h
+ Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+ Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+ ***************************************************************************/
+
+#import <Foundation/Foundation.h>
+
+@interface NSObject (JRSwizzle)
++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_;
++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_;
+@end
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ JRSwizzle.m
+ Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+ Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+ ***************************************************************************/
+
+#import "JRSwizzle.h"
+#import <objc/objc-class.h>
+
+#define SetNSError(ERROR_VAR, FORMAT,...) \
+ if (ERROR_VAR) { \
+ NSString *errStr = [@"+[NSObject(JRSwizzle) jr_swizzleMethod:withMethod:error:]: " stringByAppendingFormat:FORMAT,##__VA_ARGS__]; \
+ *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \
+ code:-1 \
+ userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \
+ }
+
+@implementation NSObject (JRSwizzle)
+
++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ {
+#if OBJC_API_VERSION >= 2
+ Method origMethod = class_getInstanceMethod(self, origSel_);
+ if (!origMethod) {
+ SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
+ return NO;
+ }
+
+ Method altMethod = class_getInstanceMethod(self, altSel_);
+ if (!altMethod) {
+ SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
+ return NO;
+ }
+
+ class_addMethod(self,
+ origSel_,
+ class_getMethodImplementation(self, origSel_),
+ method_getTypeEncoding(origMethod));
+ class_addMethod(self,
+ altSel_,
+ class_getMethodImplementation(self, altSel_),
+ method_getTypeEncoding(altMethod));
+
+ method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_));
+ return YES;
+#else
+ // Scan for non-inherited methods.
+ Method directOriginalMethod = NULL, directAlternateMethod = NULL;
+
+ void *iterator = NULL;
+ struct objc_method_list *mlist = class_nextMethodList(self, &iterator);
+ while (mlist) {
+ int method_index = 0;
+ for (; method_index < mlist->method_count; method_index++) {
+ if (mlist->method_list[method_index].method_name == origSel_) {
+ assert(!directOriginalMethod);
+ directOriginalMethod = &mlist->method_list[method_index];
+ }
+ if (mlist->method_list[method_index].method_name == altSel_) {
+ assert(!directAlternateMethod);
+ directAlternateMethod = &mlist->method_list[method_index];
+ }
+ }
+ mlist = class_nextMethodList(self, &iterator);
+ }
+
+ // If either method is inherited, copy it up to the target class to make it non-inherited.
+ if (!directOriginalMethod || !directAlternateMethod) {
+ Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL;
+ if (!directOriginalMethod) {
+ inheritedOriginalMethod = class_getInstanceMethod(self, origSel_);
+ if (!inheritedOriginalMethod) {
+ SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
+ return NO;
+ }
+ }
+ if (!directAlternateMethod) {
+ inheritedAlternateMethod = class_getInstanceMethod(self, altSel_);
+ if (!inheritedAlternateMethod) {
+ SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
+ return NO;
+ }
+ }
+
+ int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1;
+ struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1)));
+ hoisted_method_list->method_count = hoisted_method_count;
+ Method hoisted_method = hoisted_method_list->method_list;
+
+ if (!directOriginalMethod) {
+ bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method));
+ directOriginalMethod = hoisted_method++;
+ }
+ if (!directAlternateMethod) {
+ bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method));
+ directAlternateMethod = hoisted_method;
+ }
+ class_addMethods(self, hoisted_method_list);
+ }
+
+ // Swizzle.
+ IMP temp = directOriginalMethod->method_imp;
+ directOriginalMethod->method_imp = directAlternateMethod->method_imp;
+ directAlternateMethod->method_imp = temp;
+
+ return YES;
+#endif
+}
+
++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ {
+ assert(0);
+ return NO;
+}
+
+@end
@@ -0,0 +1,7 @@
+#import <Cocoa/Cocoa.h>
+
+@interface TerminalColours : NSWindowController
++ (TerminalColours*)sharedInstance;
+- (void)orderFrontColourConfiguration:(id)sender;
+- (IBAction)orderOutConfiguration:(id)sender;
+@end
@@ -0,0 +1,187 @@
+#import "TerminalColours.h"
+#import "JRSwizzle.h"
+
+static NSString* colourKeys[] = {
+ @"noColour",
+ @"blackColour",
+ @"redColour",
+ @"greenColour",
+ @"yellowColour",
+ @"blueColour",
+ @"magentaColour",
+ @"cyanColour",
+ @"whiteColour",
+ @"brightBlackColour",
+ @"brightRedColour",
+ @"brightGreenColour",
+ @"brightYellowColour",
+ @"brightBlueColour",
+ @"brightMagentaColour",
+ @"brightCyanColour",
+ @"brightWhiteColour",
+};
+
+@interface NSObject (TTAppPrefsController_Methods)
++ (id)sharedPreferencesController;
+@end
+
+@implementation NSView (TTView)
+- (id)TerminalColours_colorForANSIColor:(unsigned int)index;
+{
+ id colour = nil;
+
+ if(index > 0)
+ colour = [[self performSelector:@selector(profile)] valueForKey:colourKeys[index]];
+
+ return colour ?: [self TerminalColours_colorForANSIColor:index];
+}
+@end
+
+@implementation NSObject (TTProfile_TerminalColours)
+// ===========================
+// = Setting/getting colours =
+// ===========================
+
+- (void)setColour:(id)value forKey:(NSString*)key
+{
+ NSMutableDictionary* values = [self valueForKey:@"values"];
+ [values setObject:value forKey:key];
+
+ // I can’t see what I need to do to notify that a setting has changed and refresh the display
+ // It’s probably done by something observing key paths, so this does the job
+ [self performSelector:@selector(setScriptCursorColor:) withObject:[self performSelector:@selector(scriptCursorColor)]];
+
+ // Saves the value
+ id prefsController = [NSClassFromString(@"TTAppPrefsController") sharedPreferencesController];
+ [prefsController observeValueForKeyPath:key ofObject:self change:nil context:NULL];
+}
+
+- (id)colourForKey:(NSString*)key
+{
+ NSMutableDictionary* values = [self valueForKey:@"values"];
+ id colour = [values objectForKey:key];
+ if([colour isKindOfClass:[NSData class]])
+ {
+ // We can’t swizzle initWithPropertyListRepresentation before the settings are loaded
+ // so we need to check and unarchive data here
+ [self setColour:[NSUnarchiver unarchiveObjectWithData:colour] forKey:key];
+ colour = [self colourForKey:key];
+ }
+ if(colour == nil && ![key isEqualToString:@"noColour"])
+ {
+ // redColor → vtRedColour – these are NSColor category methods
+ // added by Terminal which return the default colours
+ NSString* key = [NSString stringWithFormat:@"vt%c%@Color",
+ [key characterAtIndex:0] + ('A' - 'a'),
+ [key substringWithRange:NSMakeRange(1, [key length] - 7)]];
+ colour = [NSColor valueForKey:key];
+ }
+ return colour;
+}
+
+/*
+ These two are swizzled so that we can use bindings to set the colour values
+ from the nib
+*/
+- (id)TerminalColours_TTProfile_valueForKey:(NSString*)key;
+{
+ if([key hasSuffix:@"Colour"])
+ return [self colourForKey:key];
+ else
+ return [self TerminalColours_TTProfile_valueForKey:key];
+}
+
+- (void)TerminalColours_TTProfile_setValue:(id)value forKey:(NSString*)key;
+{
+ if([key hasSuffix:@"Colour"])
+ [self setColour:value forKey:key];
+ else
+ [self TerminalColours_TTProfile_setValue:value forKey:key];
+}
+
+// ==================
+// = Profile saving =
+// ==================
+
+// Save our custom colours into the profile plist
+- (id)TerminalColours_propertyListRepresentation;
+{
+ NSMutableDictionary* plist = [[self TerminalColours_propertyListRepresentation] mutableCopy];
+
+ for(size_t index = 0; index < sizeof(colourKeys) / sizeof(colourKeys[0]); index++)
+ {
+ NSString* colourKey = colourKeys[index];
+ if([self colourForKey:colourKey])
+ [plist setObject:[NSArchiver archivedDataWithRootObject:[self colourForKey:colourKey]] forKey:colourKey];
+ }
+
+ return [plist autorelease];
+}
+@end
+
+@implementation NSWindowController (PrefsWindowDidLoad)
+// Add the “More…” button to the text preferences section
+- (void)TerminalColours_TTAppPrefsController_windowDidLoad;
+{
+ [self TerminalColours_TTAppPrefsController_windowDidLoad];
+
+ id prefsController = [NSClassFromString(@"TTAppPrefsController") sharedPreferencesController];
+ NSView* windowSettingsView = [[[prefsController valueForKey:@"tabView"] tabViewItemAtIndex:1] view];
+ NSTabView* tabView = [[windowSettingsView subviews] objectAtIndex:0];
+ NSView* textPrefsView = [[tabView tabViewItemAtIndex:0] view];
+
+ NSButton* configureButton = [[NSButton alloc] init];
+ {
+ [configureButton setBezelStyle:NSRoundedBezelStyle];
+ [[configureButton cell] setControlSize:NSSmallControlSize];
+ [configureButton setTitle:@"More…"];
+ [configureButton sizeToFit];
+ [configureButton setTarget:[TerminalColours sharedInstance]];
+ [configureButton setAction:@selector(orderFrontColourConfiguration:)];
+ [configureButton setFrameOrigin:NSMakePoint(233, 128)];
+ [textPrefsView addSubview:configureButton];
+ }
+ [configureButton release];
+}
+@end
+
+@implementation TerminalColours
++ (void)load
+{
+ [NSClassFromString(@"TTProfile") jr_swizzleMethod:@selector(valueForKey:) withMethod:@selector(TerminalColours_TTProfile_valueForKey:) error:NULL];
+ [NSClassFromString(@"TTProfile") jr_swizzleMethod:@selector(setValue:forKey:) withMethod:@selector(TerminalColours_TTProfile_setValue:forKey:) error:NULL];
+
+ [NSClassFromString(@"TTView") jr_swizzleMethod:@selector(colorForANSIColor:) withMethod:@selector(TerminalColours_colorForANSIColor:) error:NULL];
+ [NSClassFromString(@"TTAppPrefsController") jr_swizzleMethod:@selector(windowDidLoad) withMethod:@selector(TerminalColours_TTAppPrefsController_windowDidLoad) error:NULL];
+ [NSClassFromString(@"TTProfile") jr_swizzleMethod:@selector(propertyListRepresentation) withMethod:@selector(TerminalColours_propertyListRepresentation) error:NULL];
+}
+
++ (TerminalColours*)sharedInstance
+{
+ static TerminalColours* plugin = nil;
+
+ if(plugin == nil)
+ plugin = [[TerminalColours alloc] init];
+
+ return plugin;
+}
+
+- (void)orderFrontColourConfiguration:(id)sender
+{
+ if(![self window])
+ [NSBundle loadNibNamed:@"Configuration" owner:self];
+ [NSApp beginSheet:[self window] modalForWindow:[sender window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
+}
+
+- (IBAction)orderOutConfiguration:(id)sender;
+{
+ [NSApp endSheet:[sender window]];
+ [[sender window] orderOut:self];
+}
+
+// For binding in the nib
+- (id)profilesController
+{
+ return [[NSClassFromString(@"TTAppPrefsController") sharedPreferencesController] performSelector:@selector(profilesController)];
+}
+@end
Oops, something went wrong.

0 comments on commit ebb9d8a

Please sign in to comment.