Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ To use, just click on the new button and instantly opens a new terminal window.

### Settings

To configure which terminal application to use (defaults to Terminal.app):

```bash
# Use Terminal.app (default)
defaults write name.tuley.jay.cd-to cdto-terminal-app -string "Terminal"

# Use iTerm2
defaults write name.tuley.jay.cd-to cdto-terminal-app -string "iTerm"

# Or use bundle identifiers
defaults write name.tuley.jay.cd-to cdto-terminal-app -string "com.apple.Terminal"
defaults write name.tuley.jay.cd-to cdto-terminal-app -string "com.googlecode.iterm2"
```

To turn on feature that identifies automatically opened Terminal windows, and closes them when using *cd to*.

```bash
Expand Down
88 changes: 88 additions & 0 deletions cd to .../cd to .../iTerm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* iTerm.h
* Scripting Bridge header for iTerm2
*/

#import <AppKit/AppKit.h>
#import <ScriptingBridge/ScriptingBridge.h>

@class iTermApplication, iTermWindow, iTermTab, iTermSession;

enum iTermSaveOptions {
iTermSaveOptionsYes = 'yes ',
iTermSaveOptionsNo = 'no ',
iTermSaveOptionsAsk = 'ask '
};
typedef enum iTermSaveOptions iTermSaveOptions;

@protocol iTermGenericMethods

- (void) closeSaving:(iTermSaveOptions)saving savingIn:(NSURL *)savingIn;
- (BOOL) exists;

@end

// The iTerm application
@interface iTermApplication : SBApplication

- (SBElementArray<iTermWindow *> *) windows;
- (SBElementArray<iTermWindow *> *) terminalWindows;

@property (copy, readonly) NSString *name;
@property (readonly) BOOL frontmost;
@property (copy, readonly) NSString *version;

- (void) activate;
- (iTermWindow *) createWindowWithDefaultProfileCommand:(NSString *)command;

@end

// An iTerm window
@interface iTermWindow : SBObject <iTermGenericMethods>

- (SBElementArray<iTermTab *> *) tabs;
- (SBElementArray<iTermTab *> *) currentTabs;

@property (copy, readonly) NSString *name;
- (NSString *) id;
@property NSInteger index;
@property NSRect bounds;
@property (readonly) BOOL closeable;
@property (readonly) BOOL miniaturizable;
@property BOOL miniaturized;
@property (readonly) BOOL resizable;
@property BOOL visible;
@property (readonly) BOOL zoomable;
@property BOOL zoomed;
@property BOOL frontmost;
@property NSPoint position;

- (iTermTab *) currentTab;
- (iTermSession *) currentSession;

@end

// An iTerm tab
@interface iTermTab : SBObject <iTermGenericMethods>

- (SBElementArray<iTermSession *> *) sessions;

@property (copy, readonly) NSString *name;
- (iTermSession *) currentSession;

@end

// An iTerm session
@interface iTermSession : SBObject <iTermGenericMethods>

@property (copy, readonly) NSString *contents;
@property (copy, readonly) NSString *name;
@property (copy, readonly) NSString *uniqueID;
@property (copy, readonly) NSArray<NSString *> *columns;
@property (copy, readonly) NSArray<NSString *> *rows;
@property (copy) NSString *backgroundColor;
@property (copy, readonly) NSString *tty;

- (void) writeContentsOfFile:(NSString *)contentsOfFile text:(NSString *)text;

@end
156 changes: 107 additions & 49 deletions cd to .../cd to .../main.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,102 @@

#import "Finder.h"
#import "Terminal.h"
#import "iTerm.h"

NSUInteger linesOfHistory(TerminalTab* tab) {
NSString* hist = [[tab history] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
return [[hist componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] count];
}

void openInTerminal(NSURL* url) {
TerminalApplication* terminal = [SBApplication applicationWithBundleIdentifier:@"com.apple.Terminal"];

TerminalWindow* win = nil;
if ([[terminal windows] count] == 1){
//get front most and then reference by id
win = [[terminal windows] objectAtLocation:@1];
win = [[terminal windows] objectWithID: [NSNumber numberWithInteger:win.id]];
}
[terminal open:@[url]];
//get front most and then reference by id
TerminalWindow* newWin = [[terminal windows] objectAtLocation:@1];
newWin = [[terminal windows] objectWithID: [NSNumber numberWithInteger:newWin.id]];
TerminalTab* newTab = [[newWin tabs] objectAtLocation:@1];

NSString* setName = [[NSUserDefaults standardUserDefaults] stringForKey:@"cdto-new-window-setting"];
if(setName != nil && ![setName isEqualToString:@""]) { //setting set
TerminalSettingsSet* chosenSet = nil;
for (TerminalSettingsSet *set in [terminal settingsSets]) {
if([[set name] isEqualToString:setName]){
chosenSet = set;
}
}
if(chosenSet != nil){
newTab.currentSettings = chosenSet;
}
}

if([[NSUserDefaults standardUserDefaults] boolForKey:@"cdto-close-default-window"]){ //close first launch window
if([[win tabs] count] == 1){
TerminalTab* tab = [[win tabs]objectAtLocation:@1];
if(![tab busy]){
//if history has same number of lines as new window
// assume automatically opened new window, and close it
NSUInteger oldTabLines = linesOfHistory(tab);
while([newTab busy]){
[NSThread sleepForTimeInterval:0.1f];
}
NSUInteger newTabLines = linesOfHistory(newTab);
if(oldTabLines == newTabLines){
[win closeSaving:TerminalSaveOptionsNo savingIn:nil];
}
}
}
}

[terminal activate];
}

void openIniTerm(NSURL* url) {
NSString* path = [url path];

// Escape single quotes in the path for AppleScript
NSString* escapedPath = [path stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"];

// Use AppleScript for more reliable iTerm integration
NSString* script = [NSString stringWithFormat:
@"tell application \"iTerm\"\n"
@" activate\n"
@" try\n"
@" set newWindow to (create window with default profile)\n"
@" tell current session of newWindow\n"
@" write text \"cd '%@'; clear\"\n"
@" end tell\n"
@" on error\n"
@" tell current window\n"
@" tell current session\n"
@" write text \"cd '%@'; clear\"\n"
@" end tell\n"
@" end tell\n"
@" end try\n"
@"end tell", escapedPath, escapedPath];

NSAppleScript* appleScript = [[NSAppleScript alloc] initWithSource:script];
NSDictionary* errorInfo = nil;
[appleScript executeAndReturnError:&errorInfo];

if (errorInfo) {
// Fallback to Terminal if iTerm fails
NSLog(@"iTerm failed, falling back to Terminal: %@", errorInfo);
openInTerminal(url);
}
}

int main(int argc, const char * argv[]) {
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
FinderApplication* finder = [SBApplication applicationWithBundleIdentifier:@"com.apple.Finder"];

TerminalApplication* terminal = [SBApplication applicationWithBundleIdentifier:@"com.apple.Terminal"];


FinderItem *target = [(NSArray*)[[finder selection] get] firstObject];
FinderFinderWindow* findWin = [[finder FinderWindows] objectAtLocation:@1];
findWin = [[finder FinderWindows] objectWithID:[NSNumber numberWithInteger: findWin.id]];
Expand All @@ -32,65 +115,40 @@ int main(int argc, const char * argv[]) {
target = [[findWin target] get];
selected = false;
}

NSDictionary* itemProperties = [target properties];
id originalItem = [itemProperties objectForKey:@"originalItem"];
if (originalItem != nil && originalItem != [NSNull null]){
target = originalItem;
}

NSString* fileUrl = [target URL];
if(fileUrl != nil && ![fileUrl hasSuffix:@"/"] && selected){
fileUrl = [fileUrl stringByDeletingLastPathComponent];
}

NSURL* url = [NSURL URLWithString:fileUrl];
if (url != nil){
TerminalWindow* win = nil;
if ([[terminal windows] count] == 1){
//get front most and then reference by id
win = [[terminal windows] objectAtLocation:@1];
win = [[terminal windows] objectWithID: [NSNumber numberWithInteger:win.id]];
// Get terminal preference from defaults
NSString* terminalApp = [[NSUserDefaults standardUserDefaults] stringForKey:@"cdto-terminal-app"];

// Normalize the terminal app identifier
if (terminalApp == nil || [terminalApp isEqualToString:@""]) {
terminalApp = @"com.apple.Terminal"; // Default to Terminal.app
} else if ([terminalApp caseInsensitiveCompare:@"Terminal"] == NSOrderedSame) {
terminalApp = @"com.apple.Terminal";
} else if ([terminalApp caseInsensitiveCompare:@"iTerm"] == NSOrderedSame ||
[terminalApp caseInsensitiveCompare:@"iTerm2"] == NSOrderedSame) {
terminalApp = @"com.googlecode.iterm2";
}
[terminal open:@[url]];
//get front most and then reference by id
TerminalWindow* newWin = [[terminal windows] objectAtLocation:@1];
newWin = [[terminal windows] objectWithID: [NSNumber numberWithInteger:newWin.id]];
TerminalTab* newTab = [[newWin tabs] objectAtLocation:@1];

NSString* setName = [[NSUserDefaults standardUserDefaults] stringForKey:@"cdto-new-window-setting"];
if(setName != nil && ![setName isEqualToString:@""]) { //setting set
TerminalSettingsSet* chosenSet = nil;
for (TerminalSettingsSet *set in [terminal settingsSets]) {
if([[set name] isEqualToString:setName]){
chosenSet = set;
}
}
if(chosenSet != nil){
newTab.currentSettings = chosenSet;
}
}

if([[NSUserDefaults standardUserDefaults] boolForKey:@"cdto-close-default-window"]){ //close first launch window
if([[win tabs] count] == 1){
TerminalTab* tab = [[win tabs]objectAtLocation:@1];
if(![tab busy]){
//if history has same number of lines as new window
// assume automatically opened new window, and close it
NSUInteger oldTabLines = linesOfHistory(tab);
while([newTab busy]){
[NSThread sleepForTimeInterval:0.1f];
}
NSUInteger newTabLines = linesOfHistory(newTab);
if(oldTabLines == newTabLines){
[win closeSaving:TerminalSaveOptionsNo savingIn:nil];
}
}
}

// Open in the appropriate terminal
if ([terminalApp isEqualToString:@"com.googlecode.iterm2"]) {
openIniTerm(url);
} else {
// Default to Terminal.app for any unknown values
openInTerminal(url);
}


[terminal activate];
}
}
}
2 changes: 2 additions & 0 deletions cd to .../cd to.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
699EB3D2234DBB0700CC2315 /* Finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Finder.h; sourceTree = "<group>"; };
699EB3D3234DBB0700CC2315 /* Terminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Terminal.h; sourceTree = "<group>"; };
699EB3D4234DC4D800CC2315 /* AppIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon.icns; sourceTree = "<group>"; };
699EB3D6234DBB0700CC2315 /* iTerm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTerm.h; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -56,6 +57,7 @@
699EB3D4234DC4D800CC2315 /* AppIcon.icns */,
699EB3D2234DBB0700CC2315 /* Finder.h */,
699EB3D3234DBB0700CC2315 /* Terminal.h */,
699EB3D6234DBB0700CC2315 /* iTerm.h */,
699EB3BF234DBA0D00CC2315 /* Assets.xcassets */,
699EB3C4234DBA0D00CC2315 /* Info.plist */,
699EB3C5234DBA0D00CC2315 /* main.m */,
Expand Down