Permalink
Browse files

Add TmuxGateway, a module that communicates the tmux protocol. Add Tm…

…uxController, a module that coordinates high-level administration of a tmux connection. Add support for Tmux escape code in VT100Terminal. Modify PTYSession to switch into gateway mode when the tmux escape code is received. Add code for reconstructing a window and split panes from a tmux layout. Add code to parse layout strings from tmux's new list-windows -C command. Add TSVParser to simplify tab-separated value documents.
  • Loading branch information...
1 parent 471a2dc commit c22b5dc928204a0293cd1c52457d23421bb93c26 @gnachman gnachman committed Nov 28, 2011
View
@@ -33,6 +33,8 @@
#import "FindViewController.h"
#import "ITAddressBookMgr.h"
#import "LineBuffer.h"
+#import "TmuxGateway.h"
+#import "TmuxController.h"
#include <sys/time.h>
@@ -69,7 +71,7 @@ typedef enum {
@class PTYTab;
@class SessionView;
-@interface PTYSession : NSResponder <FindViewControllerDelegate>
+@interface PTYSession : NSResponder <FindViewControllerDelegate, TmuxGatewayDelegate>
{
// Owning tab.
PTYTab* tab_;
@@ -231,6 +233,15 @@ typedef enum {
FindContext tailFindContext_;
NSTimer *tailFindTimer_;
+
+ enum {
+ TMUX_NONE,
+ TMUX_GATEWAY,
+ TMUX_CLIENT
+ } tmuxMode_;
+ TmuxGateway *tmuxGateway_;
+ TmuxController *tmuxController_;
+ int tmuxPane_;
}
// Return the current pasteboard value as a string.
@@ -279,6 +290,8 @@ typedef enum {
inView:(SessionView*)sessionView
inTab:(PTYTab*)theTab
forObjectType:(iTermObjectType)objectType;
++ (NSDictionary *)arrangementFromTmuxParsedLayout:(NSDictionary *)parseNode
+ bookmark:(Bookmark *)bookmark;
- (void)runCommandWithOldCwd:(NSString*)oldCWD
@@ -526,6 +539,12 @@ typedef enum {
- (void)sendHexCode:(NSString *)codes;
- (void)sendText:(NSString *)text;
+- (void)startTmuxMode;
+- (int)tmuxPane;
+- (void)setTmuxPane:(int)windowPane;
+- (void)setTmuxController:(TmuxController *)tmuxController;
+
+- (TmuxController *)tmuxController;
@end
@@ -65,12 +65,14 @@ typedef enum {
- (NSColor*)color;
@end
+@class TmuxController;
+
// This class is 1:1 with windows. It controls the tabs, bottombar, toolbar,
// fullscreen, and coordinates resizing of sessions (either session-initiated
// or window-initiated).
// OS 10.5 doesn't support window delegates
@interface PseudoTerminal : NSWindowController <
- PTYTabViewDelegateProtocol,
+ PTYTabViewDelegateProtocol,
PTYWindowDelegateProtocol,
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
NSWindowDelegate,
@@ -132,14 +134,14 @@ NSWindowDelegate,
// Is the transparency setting respected?
BOOL useTransparency_;
-
+
// Is this a full screenw indow?
BOOL _fullScreen;
// When you enter full-screen mode the old frame size is saved here. When
// full-screen mode is exited that frame is restored.
NSRect oldFrame_;
-
+
// When you enter fullscreen mode, the old use transparency setting is
// saved, and then restored when you exit FS unless it was changed
// by the user.
@@ -246,6 +248,10 @@ NSWindowDelegate,
BOOL wellFormed_;
BOOL exitingLionFullscreen_;
+
+ // If this window is a tmux client, this is the window number defined by
+ // the tmux server.
+ int tmuxWindow_;
}
+ (void)drawArrangementPreview:(NSDictionary*)terminalArrangement
@@ -687,6 +693,8 @@ NSWindowDelegate,
+ (PseudoTerminal*)terminalWithArrangement:(NSDictionary*)arrangement;
- (void)loadArrangement:(NSDictionary *)arrangement;
- (NSDictionary*)arrangement;
+- (void)loadTmuxLayout:(NSString *)layout window:(int)window tmuxController:(TmuxController *)tmuxController;
+- (int)tmuxWindow;
- (void)appendTab:(PTYTab*)theTab;
@@ -148,6 +148,7 @@
// iTerm extension
#define ITERM_GROWL 5000
+#define UNDERSCORE_TMUX1 5001
#define VT100CSIPARAM_MAX 16
@@ -359,6 +360,8 @@ typedef enum {
- (void)cleanStream;
- (void)putStreamData:(NSData*)data;
- (VT100TCC)getNextToken;
+- (NSData *)streamData;
+- (void)clearStream;
- (void)saveCursorAttributes;
- (void)restoreCursorAttributes;
@@ -108,6 +108,7 @@
- (NSArray*)sortedEncodingList;
- (void)addBookmarksToMenu:(NSMenu *)aMenu startingAt:(int)startingAt;
- (void)addBookmarksToMenu:(NSMenu *)aMenu withSelector:(SEL)selector openAllSelector:(SEL)openAllSelector startingAt:(int)startingAt;
+- (PseudoTerminal *)openWindow;
- (id)launchBookmark:(NSDictionary *)bookmarkData
inTerminal:(PseudoTerminal *)theTerm
disableLionFullscreen:(BOOL)disableLionFullscreen;
View
@@ -47,6 +47,8 @@
#import "MovePaneController.h"
#import "Trigger.h"
#import "Coprocess.h"
+#import "TmuxGateway.h"
+#import "TmuxLayoutParser.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
@@ -69,6 +71,7 @@ @implementation PTYSession
static NSString* SESSION_ARRANGEMENT_ROWS = @"Rows";
static NSString* SESSION_ARRANGEMENT_BOOKMARK = @"Bookmark";
static NSString* SESSION_ARRANGEMENT_WORKING_DIRECTORY = @"Working Directory";
+static NSString* SESSION_ARRANGEMENT_TMUX_PANE = @"Tmux Pane";
// init/dealloc
- (id)init
@@ -151,6 +154,8 @@ - (void)dealloc
[updateTimer release];
[originalAddressBookEntry release];
[liveSession_ release];
+ [tmuxGateway_ release];
+ [tmuxController_ release];
[SHELL release];
SHELL = nil;
@@ -314,6 +319,10 @@ + (PTYSession*)sessionFromArrangement:(NSDictionary*)arrangement
[aSession divorceAddressBookEntryFromPreferences];
}
+ NSNumber *n = [arrangement objectForKey:SESSION_ARRANGEMENT_TMUX_PANE];
+ if (n) {
+ [aSession setTmuxPane:[n intValue]];
+ }
return aSession;
}
@@ -689,6 +698,12 @@ - (void)terminate
if (EXIT) {
[self _maybeWarnAboutShortLivedSessions];
}
+ if (tmuxMode_ == TMUX_CLIENT) {
+ [tmuxController_ deregisterWindow:[[tab_ realParentWindow] tmuxWindow] windowPane:tmuxPane_];
+ }
+ [tmuxController_ release];
+ tmuxController_ = nil;
+
// The source pane may have just exited. Dogs and cats living together!
// Mass hysteria!
[[MovePaneController sharedInstance] exitMovePaneMode];
@@ -776,6 +791,13 @@ - (void)readTask:(NSData*)data
int length = [data length];
DebugLog([NSString stringWithFormat:@"readTask called with %d bytes. The last byte is %d", (int)length, (int)bytes[length-1]]);
}
+ if (tmuxMode_ == TMUX_GATEWAY) {
+ data = [tmuxGateway_ readTask:data];
+ if (!data) {
+ // All data was consumed.
+ return;
+ }
+ }
[TERMINAL putStreamData:data];
@@ -784,6 +806,7 @@ - (void)readTask:(NSData*)data
// while loop to process all the tokens we can get
while (!EXIT &&
TERMINAL &&
+ tmuxMode_ != TMUX_GATEWAY &&
((token = [TERMINAL getNextToken]),
token.type != VT100_WAIT &&
token.type != VT100CC_NULL)) {
@@ -2795,6 +2818,18 @@ - (NSDictionary*)arrangement
return result;
}
++ (NSDictionary *)arrangementFromTmuxParsedLayout:(NSDictionary *)parseNode
+ bookmark:(Bookmark *)bookmark
+{
+ NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:3];
+ [result setObject:[parseNode objectForKey:kLayoutDictWidthKey] forKey:SESSION_ARRANGEMENT_COLUMNS];
+ [result setObject:[parseNode objectForKey:kLayoutDictHeightKey] forKey:SESSION_ARRANGEMENT_ROWS];
+ [result setObject:bookmark forKey:SESSION_ARRANGEMENT_BOOKMARK];
+ [result setObject:@"" forKey:SESSION_ARRANGEMENT_WORKING_DIRECTORY];
+ [result setObject:[parseNode objectForKey:kLayoutDictWindowPaneKey] forKey:SESSION_ARRANGEMENT_TMUX_PANE];
+ return result;
+}
+
- (void)updateScroll
{
if (![(PTYScroller*)([SCROLLVIEW verticalScroller]) userScroll]) {
@@ -3267,6 +3302,68 @@ - (BOOL)wantsContentChangedNotification
[TEXTVIEW initialFindContext]->substring != nil;
}
+- (void)startTmuxMode
+{
+ if (tmuxMode_ != TMUX_NONE) {
+ return;
+ }
+ tmuxMode_ = TMUX_GATEWAY;
+ tmuxGateway_ = [[TmuxGateway alloc] initWithDelegate:self];
+ tmuxController_ = [[TmuxController alloc] initWithGateway:tmuxGateway_];
+ [SCREEN setString:@"** TMUX MODE STARTED **" ascii:YES];
+ [tmuxController_ openWindowsInitial];
+ [tmuxGateway_ readTask:[TERMINAL streamData]];
+ [TERMINAL clearStream];
+}
+
+- (int)tmuxPane
+{
+ return tmuxPane_;
+}
+
+- (void)setTmuxPane:(int)windowPane
+{
+ tmuxPane_ = windowPane;
+ tmuxMode_ = TMUX_CLIENT;
+}
+
+- (void)setTmuxController:(TmuxController *)tmuxController
+{
+ [tmuxController_ autorelease];
+ tmuxController_ = [tmuxController retain];
+}
+
+#pragma mark tmux gateway delegate methods
+// TODO (also, capture and throw away keyboard input)
+
+- (TmuxController *)tmuxController
+{
+ return tmuxController_;
+}
+
+- (void)tmuxUpdateLayoutForWindow:(int)windowId
+{
+}
+
+- (void)tmuxWindowsDidChange
+{
+}
+
+- (void)tmuxHostDisconnected
+{
+}
+
+- (void)tmuxWriteData:(NSData *)data
+{
+ NSLog(@"Write to tmux: \"%@\"", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
+ [self writeTask:data];
+}
+
+- (void)tmuxReadTask:(NSData *)data
+{
+ [self readTask:data];
+}
+
@end
@implementation PTYSession (ScriptingSupport)
View
@@ -184,7 +184,7 @@ static const int MIN_SESSION_COLUMNS = 2;
- (PTYSession*)_recursiveSessionAtPoint:(NSPoint)point relativeTo:(NSView*)node;
+ (void)drawArrangementPreview:(NSDictionary*)arrangement frame:(NSRect)frame;
-+ (void)openTabWithArrangement:(NSDictionary*)arrangement inTerminal:(PseudoTerminal*)term;
++ (PTYTab *)openTabWithArrangement:(NSDictionary*)arrangement inTerminal:(PseudoTerminal*)term;
- (NSDictionary*)arrangement;
- (BOOL)hasMaximizedPane;
@@ -206,6 +206,8 @@ static const int MIN_SESSION_COLUMNS = 2;
- (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex;
- (void)_recursiveRemoveView:(NSView*)theView;
++ (PTYTab *)openTabWithTmuxLayout:(NSMutableDictionary *)parseTree inTerminal:(PseudoTerminal *)term;
+
@end
Oops, something went wrong.

0 comments on commit c22b5dc

Please sign in to comment.