Skip to content

Commit

Permalink
Offer to repair saved arrangements when a profile exists with the sam…
Browse files Browse the repository at this point in the history
…e name as the profile a session was created with.
  • Loading branch information
gnachman committed Jan 5, 2017
1 parent f819ed6 commit afd8a89
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 14 deletions.
4 changes: 4 additions & 0 deletions sources/PTYSession.h
Expand Up @@ -433,6 +433,10 @@ typedef enum {

#pragma mark - methods

+ (NSDictionary *)repairedArrangement:(NSDictionary *)arrangement
replacingProfileWithGUID:(NSString *)badGuid
withProfile:(Profile *)goodProfile;

+ (BOOL)handleShortcutWithoutTerminal:(NSEvent*)event;
+ (void)selectMenuItem:(NSString*)theName;

Expand Down
67 changes: 53 additions & 14 deletions sources/PTYSession.m
Expand Up @@ -90,6 +90,7 @@
static const NSInteger kMinimumUnicodeVersion = 8;
static const NSInteger kMaximumUnicodeVersion = 9;

static NSString *const PTYSessionDidRepairSavedArrangement = @"PTYSessionDidRepairSavedArrangement";

// The format for a user defaults key that recalls if the user has already been pestered about
// outdated key mappings for a give profile. The %@ is replaced with the profile's GUID.
Expand Down Expand Up @@ -421,6 +422,12 @@ @implementation PTYSession {
// Touch bar labels for function keys.
NSMutableDictionary<NSString *, NSString *> *_keyLabels;
NSMutableArray<iTermKeyLabels *> *_keyLabelsStack;

// If the session was created from a saved arrangement with a missing profile then this records
// the GUID of the missing profile. If the saved arrangement gets repaired then a notification
// is posted and all sessions with that bogus GUID can hide their profile and reload their
// profile.
NSString *_missingSavedArrangementProfileGUID;
}

+ (void)registerSessionInArrangement:(NSDictionary *)arrangement {
Expand Down Expand Up @@ -519,6 +526,10 @@ - (instancetype)init {
selector:@selector(applicationWillTerminate:)
name:iTermApplicationWillTerminate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(savedArrangementWasRepaired:)
name:PTYSessionDidRepairSavedArrangement
object:nil];
[self updateVariables];
}
return self;
Expand Down Expand Up @@ -584,6 +595,7 @@ - (void)iterm_dealloc {
[_throughputEstimator release];
[_keyLabels release];
[_keyLabelsStack release];
[_missingSavedArrangementProfileGUID release];
[[NSNotificationCenter defaultCenter] removeObserver:self];

if (_dvrDecoder) {
Expand Down Expand Up @@ -733,6 +745,19 @@ - (void)setSizeFromArrangement:(NSDictionary*)arrangement {
[[arrangement objectForKey:SESSION_ARRANGEMENT_ROWS] intValue])];
}

+ (NSDictionary *)repairedArrangement:(NSDictionary *)arrangement
replacingProfileWithGUID:(NSString *)badGuid
withProfile:(Profile *)goodProfile {
if ([arrangement[SESSION_ARRANGEMENT_BOOKMARK][KEY_GUID] isEqualToString:badGuid]) {
NSMutableDictionary *result = [[arrangement mutableCopy] autorelease];
result[SESSION_ARRANGEMENT_BOOKMARK_NAME] = goodProfile[KEY_NAME];
result[SESSION_ARRANGEMENT_BOOKMARK] = goodProfile;
return result;
} else {
return arrangement;
}
}

+ (PTYSession *)sessionFromArrangement:(NSDictionary *)arrangement
inView:(SessionView *)sessionView
withDelegate:(id<PTYSessionDelegate>)delegate
Expand All @@ -751,33 +776,34 @@ + (PTYSession *)sessionFromArrangement:(NSDictionary *)arrangement
DLog(@"Can't find profile %@ guid %@", missingProfileName, arrangement[SESSION_ARRANGEMENT_BOOKMARK][KEY_GUID]);
if (![iTermAdvancedSettingsModel noSyncSuppressMissingProfileInArrangementWarning]) {
NSString *notice;
NSArray<NSString *> *actions = @[ @"Don't Warn Again" ];
NSString *savedArranagementName = [[iTermController sharedInstance] savedArrangementNameBeingRestored];
if ([[ProfileModel sharedInstance] bookmarkWithName:missingProfileName]) {
notice = [NSString stringWithFormat:@"This session's profile, “%@”, no longer exists, although a profile with that name happens to exist.", missingProfileName];
if (savedArranagementName) {
actions = [actions arrayByAddingObject:@"Repair Saved Arrangement"];
}
} else {
notice = [NSString stringWithFormat:@"This session's profile, “%@”, no longer exists.", missingProfileName];
}
Profile *thisProfile = arrangement[SESSION_ARRANGEMENT_BOOKMARK];
aSession->_missingSavedArrangementProfileGUID = [thisProfile[KEY_GUID] copy];
announcement =
[iTermAnnouncementViewController announcementWithTitle:notice
style:kiTermAnnouncementViewStyleWarning
withActions:@[ @"Don't Warn Again", @"Debug Info", ]
withActions:actions
completion:^(int selection) {
if (selection == 0) {
[iTermAdvancedSettingsModel setNoSyncSuppressMissingProfileInArrangementWarning:YES];
} else if (selection == 1) {
Profile *thisProfile = arrangement[SESSION_ARRANGEMENT_BOOKMARK];
Profile *originalProfile = [[ProfileModel sharedInstance] bookmarkWithGuid:arrangement[SESSION_ARRANGEMENT_BOOKMARK][KEY_GUID]];
// Repair
Profile *similarlyNamedProfile = [[ProfileModel sharedInstance] bookmarkWithName:missingProfileName];
[[NSAlert alertWithMessageText:@"Missing Profile Debug Info"
defaultButton:@"OK"
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"This profile:\n GUID=%@\n name=%@.\nIts original profile:\n GUID=%@\n name=%@\nSimilarly named profile\n GUID=%@\n name=%@",
thisProfile[KEY_GUID],
thisProfile[KEY_NAME],
originalProfile[KEY_GUID],
originalProfile[KEY_NAME],
similarlyNamedProfile[KEY_GUID],
similarlyNamedProfile[KEY_NAME]] runModal];
[[iTermController sharedInstance] repairSavedArrangementNamed:savedArranagementName
replacingMissingGUID:thisProfile[KEY_GUID]
withGUID:similarlyNamedProfile[KEY_GUID]];
[[NSNotificationCenter defaultCenter] postNotificationName:PTYSessionDidRepairSavedArrangement
object:thisProfile[KEY_GUID]
userInfo:@{ @"new profile": similarlyNamedProfile }];
}
}];
announcement.dismissOnKeyDown = YES;
Expand Down Expand Up @@ -3969,6 +3995,19 @@ - (void)applicationWillTerminate:(NSNotification *)notification {
[self tmuxDetach];
}

- (void)savedArrangementWasRepaired:(NSNotification *)notification {
if ([notification.object isEqual:_missingSavedArrangementProfileGUID]) {
Profile *newProfile = notification.userInfo[@"new profile"];
_isDivorced = NO;
[_overriddenFields removeAllObjects];
[_originalProfile release];
_originalProfile = nil;
self.profile = newProfile;
[self setPreferencesFromAddressBookEntry:newProfile];
[self dismissAnnouncementWithIdentifier:@"ThisProfileNoLongerExists"];
}
}

- (void)synchronizeTmuxFonts:(NSNotification *)notification
{
if (!_exited && [self isTmuxClient]) {
Expand Down
4 changes: 4 additions & 0 deletions sources/PTYTab.h
Expand Up @@ -93,6 +93,10 @@
hSpacing:(double)hs
vSpacing:(double)vs;

+ (NSDictionary *)repairedArrangement:(NSDictionary *)arrangement
replacingProfileWithGUID:(NSString *)badGuid
withProfile:(Profile *)goodProfile;

// init/dealloc
- (instancetype)initWithSession:(PTYSession*)session;
- (instancetype)initWithRoot:(NSSplitView *)root
Expand Down
32 changes: 32 additions & 0 deletions sources/PTYTab.m
Expand Up @@ -2287,6 +2287,27 @@ + (__kindof NSView *)_recusiveRestoreSplitters:(NSDictionary<NSString *, id> *)a
}
}

+ (NSDictionary *)recursiveRepairedArrangementNode:(NSDictionary *)arrangement
replacingProfileWithGUID:(NSString *)badGuid
withProfile:(Profile *)goodProfile {
if ([[arrangement objectForKey:TAB_ARRANGEMENT_VIEW_TYPE] isEqualToString:VIEW_TYPE_SPLITTER]) {
NSMutableArray *repairedSubviews = [NSMutableArray array];
for (NSDictionary<NSString *, id> *subArrangement in arrangement[SUBVIEWS]) {
[repairedSubviews addObject:[PTYTab recursiveRepairedArrangementNode:subArrangement
replacingProfileWithGUID:badGuid
withProfile:goodProfile]];
}
NSMutableDictionary *result = [[arrangement mutableCopy] autorelease];
result[SUBVIEWS] = repairedSubviews;
return result;
} else {
NSDictionary *repairedSession = [PTYSession repairedArrangement:arrangement[TAB_ARRANGEMENT_SESSION] replacingProfileWithGUID:badGuid withProfile:goodProfile];
NSMutableDictionary *result = [[arrangement mutableCopy] autorelease];
result[TAB_ARRANGEMENT_SESSION] = repairedSession;
return result;
}
}

- (PTYSession *)_recursiveRestoreSessions:(NSDictionary<NSString *, id> *)arrangement
atNode:(__kindof NSView *)view
inTab:(PTYTab *)theTab
Expand Down Expand Up @@ -2462,6 +2483,17 @@ + (PTYTab *)tabWithArrangement:(NSDictionary*)arrangement
return theTab;
}

+ (NSDictionary *)repairedArrangement:(NSDictionary *)arrangement
replacingProfileWithGUID:(NSString *)badGuid
withProfile:(Profile *)goodProfile {
NSDictionary *newRoot = [PTYTab recursiveRepairedArrangementNode:arrangement[TAB_ARRANGEMENT_ROOT]
replacingProfileWithGUID:badGuid
withProfile:goodProfile];
NSMutableDictionary *result = [[arrangement mutableCopy] autorelease];
result[TAB_ARRANGEMENT_ROOT] = newRoot;
return result;
}

// This can only be used in conjunction with
// +[tabWithArrangement:inTerminal:hasFlexibleView:viewMap:].
- (void)didAddToTerminal:(NSWindowController<iTermWindowController> *)term
Expand Down
4 changes: 4 additions & 0 deletions sources/PseudoTerminal.h
Expand Up @@ -231,6 +231,10 @@ extern NSString *const kCurrentSessionDidChange;
// Return the smallest allowable width for this terminal.
- (float)minWidth;

+ (NSDictionary *)repairedArrangement:(NSDictionary *)arrangement
replacingProfileWithGUID:(NSString *)badGuid
withProfile:(Profile *)goodProfile;

// Load an arrangement into an empty window.
- (BOOL)loadArrangement:(NSDictionary *)arrangement;

Expand Down
11 changes: 11 additions & 0 deletions sources/PseudoTerminal.m
Expand Up @@ -2161,6 +2161,17 @@ - (void)hideAfterOpening
afterDelay:0];
}

+ (NSDictionary *)repairedArrangement:(NSDictionary *)arrangement replacingProfileWithGUID:(NSString *)badGuid withProfile:(Profile *)goodProfile {
NSMutableDictionary *mutableArrangement = [[arrangement mutableCopy] autorelease];
NSMutableArray *mutableTabs = [NSMutableArray array];

for (NSDictionary* tabArrangement in [arrangement objectForKey:TERMINAL_ARRANGEMENT_TABS]) {
[mutableTabs addObject:[PTYTab repairedArrangement:tabArrangement replacingProfileWithGUID:badGuid withProfile:(Profile *)goodProfile]];
}
mutableArrangement[TERMINAL_ARRANGEMENT_TABS] = mutableTabs;
return mutableArrangement;
}

- (BOOL)loadArrangement:(NSDictionary *)arrangement {
return [self loadArrangement:arrangement sessions:nil];
}
Expand Down
4 changes: 4 additions & 0 deletions sources/iTermController.h
Expand Up @@ -63,6 +63,7 @@ typedef NS_ENUM(NSUInteger, iTermHotkeyWindowType) {
@property(nonatomic, readonly) BOOL keystrokesBeingStolen;
@property(nonatomic, readonly) BOOL anyWindowIsMain;
@property(nonatomic, readonly) NSArray<iTermTerminalWindow *> *keyTerminalWindows;
@property(nonatomic, readonly) NSString *savedArrangementNameBeingRestored;

+ (iTermController*)sharedInstance;
+ (void)releaseSharedInstance;
Expand Down Expand Up @@ -93,6 +94,9 @@ typedef NS_ENUM(NSUInteger, iTermHotkeyWindowType) {

- (void)saveWindowArrangement:(BOOL)allWindows;
- (void)loadWindowArrangementWithName:(NSString *)theName;
- (void)repairSavedArrangementNamed:(NSString *)savedArrangementName
replacingMissingGUID:(NSString *)guidToReplace
withGUID:(NSString *)replacementGuid;

- (void)terminalWillClose:(PseudoTerminal*)theTerminalWindow;
- (void)addBookmarksToMenu:(NSMenu *)aMenu
Expand Down
18 changes: 18 additions & 0 deletions sources/iTermController.m
Expand Up @@ -366,6 +366,22 @@ - (NSString *)showAlertWithText:(NSString *)prompt defaultInput:(NSString *)defa
}
}

- (void)repairSavedArrangementNamed:(NSString *)savedArrangementName
replacingMissingGUID:(NSString *)guidToReplace
withGUID:(NSString *)replacementGuid {
NSArray *terminalArrangements = [WindowArrangements arrangementWithName:savedArrangementName];
Profile *goodProfile = [[ProfileModel sharedInstance] bookmarkWithGuid:replacementGuid];
if (goodProfile) {
NSMutableArray *repairedArrangements = [NSMutableArray array];
for (NSDictionary *terminalArrangement in terminalArrangements) {
[repairedArrangements addObject:[PseudoTerminal repairedArrangement:terminalArrangement
replacingProfileWithGUID:guidToReplace
withProfile:goodProfile]];
}
[WindowArrangements setArrangement:repairedArrangements withName:savedArrangementName];
}
}

- (void)saveWindowArrangement:(BOOL)allWindows {
NSString *name = [self showAlertWithText:@"Name for saved window arrangement:"
defaultInput:[NSString stringWithFormat:@"Arrangement %d", 1 + [WindowArrangements count]]];
Expand Down Expand Up @@ -423,12 +439,14 @@ - (void)tryOpenArrangement:(NSDictionary *)terminalArrangement {
}

- (void)loadWindowArrangementWithName:(NSString *)theName {
_savedArrangementNameBeingRestored = [[theName retain] autorelease];
NSArray *terminalArrangements = [WindowArrangements arrangementWithName:theName];
if (terminalArrangements) {
for (NSDictionary *terminalArrangement in terminalArrangements) {
[self tryOpenArrangement:terminalArrangement];
}
}
_savedArrangementNameBeingRestored = nil;
}

// Return all the terminals in the given screen.
Expand Down

0 comments on commit afd8a89

Please sign in to comment.