Created
July 5, 2011 04:37
-
-
Save knu/1064253 to your computer and use it in GitHub Desktop.
Make iTerm2's copy also save the selected region in rich text format.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 9fbd75b0ba43d2e37aae4ed1b48752baa1908cd3 Mon Sep 17 00:00:00 2001 | |
From: Akinori MUSHA <[email protected]> | |
Date: Tue, 5 Jul 2011 11:00:32 +0900 | |
Subject: [PATCH] Make copy() also save the selected text in rich text format. | |
--- | |
Headers/iTerm/PTYTextView.h | 2 + | |
PTYTextView.m | 161 +++++++++++++++++++++++++++++++++++++++++- | |
2 files changed, 159 insertions(+), 4 deletions(-) | |
diff --git a/Headers/iTerm/PTYTextView.h b/Headers/iTerm/PTYTextView.h | |
index 48f3641..eb1aee9 100644 | |
--- a/Headers/iTerm/PTYTextView.h | |
+++ b/Headers/iTerm/PTYTextView.h | |
@@ -280,6 +280,7 @@ typedef struct PTYFontInfo PTYFontInfo; | |
- (void)rightMouseDragged:(NSEvent *)event; | |
- (void)scrollWheel:(NSEvent *)event; | |
- (NSString *)contentFromX:(int)startx Y:(int)starty ToX:(int)endx Y:(int)endy pad: (BOOL) pad; | |
+- (NSAttributedString *)attributedContentFromX:(int)startx Y:(int)starty ToX:(int)endx Y:(int)endy pad: (BOOL) pad; | |
- (NSString*)contentInBoxFromX:(int)startx Y:(int)starty ToX:(int)nonInclusiveEndx Y:(int)endy pad: (BOOL) pad; | |
- (NSString *)selectedText; | |
- (NSString *)selectedTextWithPad: (BOOL) pad; | |
@@ -526,6 +527,7 @@ typedef enum { | |
isComplex:(BOOL)complex | |
fgColor:(int)fgColor | |
renderBold:(BOOL*)renderBold; | |
+- (NSDictionary *)charAttributes:(screen_char_t)c; | |
- (PTYFontInfo*)getOrAddFallbackFont:(NSFont*)font; | |
- (void)releaseAllFallbackFonts; | |
diff --git a/PTYTextView.m b/PTYTextView.m | |
index ba05e3f..4f59c01 100644 | |
--- a/PTYTextView.m | |
+++ b/PTYTextView.m | |
@@ -2855,6 +2855,102 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) { | |
return result; | |
} | |
+static inline void appendToAttributedString(NSMutableAttributedString *target, NSString *source, NSDictionary *attributes) | |
+{ | |
+ NSAttributedString *string; | |
+ | |
+ if (attributes == nil) { | |
+ string = [[NSAttributedString alloc] initWithString:source]; | |
+ } else { | |
+ string = [[NSAttributedString alloc] initWithString:source | |
+ attributes:attributes]; | |
+ } | |
+ [target appendAttributedString:string]; | |
+ [string release]; | |
+} | |
+ | |
+- (NSAttributedString*)attributedContentInBoxFromX:(int)startx Y:(int)starty ToX:(int)nonInclusiveEndx Y:(int)endy pad: (BOOL) pad | |
+{ | |
+ int i; | |
+ NSMutableAttributedString* result = [[[NSMutableAttributedString alloc] initWithString:@""] autorelease]; | |
+ for (i = starty; i < endy; ++i) { | |
+ NSAttributedString* line = [self attributedContentFromX:startx Y:i ToX:nonInclusiveEndx Y:i pad:pad]; | |
+ [result appendAttributedString:line]; | |
+ if (i < endy-1) { | |
+ appendToAttributedString(result, @"\n", nil); | |
+ } | |
+ } | |
+ return result; | |
+} | |
+ | |
+- (NSAttributedString *)attributedContentFromX:(int)startx | |
+ Y:(int)starty | |
+ ToX:(int)nonInclusiveEndx | |
+ Y:(int)endy | |
+ pad:(BOOL) pad | |
+{ | |
+ int endx = nonInclusiveEndx-1; | |
+ int width = [dataSource width]; | |
+ NSMutableAttributedString* result = [[[NSMutableAttributedString alloc] initWithString:@""] autorelease]; | |
+ int y, x1, x2; | |
+ screen_char_t *theLine; | |
+ BOOL endOfLine; | |
+ int i; | |
+ | |
+ for (y = starty; y <= endy; y++) { | |
+ theLine = [dataSource getLineAtIndex:y]; | |
+ | |
+ x1 = y == starty ? startx : 0; | |
+ x2 = y == endy ? endx : width-1; | |
+ for ( ; x1 <= x2; x1++) { | |
+ screen_char_t c = theLine[x1]; | |
+ if (c.code == TAB_FILLER) { | |
+ // Convert orphan tab fillers (those without a subsequent | |
+ // tab character) into spaces. | |
+ if ([self isTabFillerOrphanAtX:x1 Y:y]) { | |
+ appendToAttributedString(result, @" ", [self charAttributes:c]); | |
+ } | |
+ } else if (c.code != DWC_RIGHT && | |
+ c.code != DWC_SKIP) { | |
+ if (c.code == 0) { // end of line? | |
+ // If there is no text after this, insert a hard line break. | |
+ endOfLine = YES; | |
+ for (i = x1 + 1; i <= x2 && endOfLine; i++) { | |
+ if (theLine[i].code != 0) { | |
+ endOfLine = NO; | |
+ } | |
+ } | |
+ if (endOfLine) { | |
+ if (pad) { | |
+ for (i = x1; i <= x2; i++) { | |
+ appendToAttributedString(result, @" ", [self charAttributes:theLine[i]]); | |
+ } | |
+ } | |
+ if (y < endy && theLine[width].code == EOL_HARD) { | |
+ appendToAttributedString(result, @"\n", [self charAttributes:theLine[width]]); | |
+ } | |
+ break; | |
+ } else { | |
+ // represent end-of-line blank with space | |
+ appendToAttributedString(result, @" ", [self charAttributes:c]); | |
+ } | |
+ } else if (x1 == x2 && | |
+ y < endy && | |
+ theLine[width].code == EOL_HARD) { | |
+ // Hard line break | |
+ appendToAttributedString(result, ScreenCharToStr(&c), [self charAttributes:c]); | |
+ appendToAttributedString(result, @"\n", [self charAttributes:theLine[width]]); | |
+ } else { | |
+ // Normal character | |
+ appendToAttributedString(result, ScreenCharToStr(&c), [self charAttributes:c]); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ return result; | |
+} | |
+ | |
- (IBAction)selectAll:(id)sender | |
{ | |
// set the selection region for the whole text | |
@@ -2897,6 +2993,31 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) { | |
} | |
} | |
+- (NSAttributedString *)selectedAttributedText | |
+{ | |
+ return [self selectedAttributedTextWithPad:NO]; | |
+} | |
+ | |
+- (NSAttributedString *)selectedAttributedTextWithPad:(BOOL)pad | |
+{ | |
+ if (startX <= -1) { | |
+ return nil; | |
+ } | |
+ if (selectMode == SELECT_BOX) { | |
+ return [self attributedContentInBoxFromX:startX | |
+ Y:startY | |
+ ToX:endX | |
+ Y:endY | |
+ pad:pad]; | |
+ } else { | |
+ return ([self attributedContentFromX:startX | |
+ Y:startY | |
+ ToX:endX | |
+ Y:endY | |
+ pad:pad]); | |
+ } | |
+} | |
+ | |
- (NSString *)content | |
{ | |
return [self contentFromX:0 | |
@@ -2942,13 +3063,21 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) { | |
- (void)copy:(id)sender | |
{ | |
NSPasteboard *pboard = [NSPasteboard generalPasteboard]; | |
- NSString *copyString; | |
- | |
- copyString = [self selectedText]; | |
+ NSString *copyString = [self selectedText]; | |
+ NSAttributedString *copyAttributedString = [self selectedAttributedText]; | |
if (copyString) { | |
- [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self]; | |
+ if (copyAttributedString) { | |
+ [pboard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, | |
+ NSRTFPboardType, nil] owner:self]; | |
+ } else { | |
+ [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self]; | |
+ } | |
[pboard setString:copyString forType:NSStringPboardType]; | |
+ if (copyAttributedString) { | |
+ NSData *RTFData = [copyAttributedString RTFFromRange:NSMakeRange(0, [copyAttributedString length]) documentAttributes:nil]; | |
+ [pboard setData:RTFData forType:NSRTFPboardType]; | |
+ } | |
} | |
[[PasteboardHistory sharedInstance] save:copyString]; | |
@@ -4229,6 +4358,30 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) { | |
return theFont; | |
} | |
+// Returns a dictionary to pass to NSAttributedString. | |
+- (NSDictionary *)charAttributes:(screen_char_t)c | |
+{ | |
+ NSColor *fgColor = [self colorForCode:c.foregroundColor alternateSemantics:c.alternateForegroundSemantics bold:c.bold]; | |
+ NSColor *bgColor = [self colorForCode:c.backgroundColor alternateSemantics:c.alternateBackgroundSemantics bold:false]; | |
+ int underlineStyle = c.underline ? (NSUnderlineStyleSingle|NSUnderlineByWordMask) : 0; | |
+ BOOL isBold = c.bold; | |
+ NSFont *font = [self getFontForChar:c.code | |
+ isComplex:c.complexChar | |
+ renderBold:&isBold]->font; | |
+ | |
+ if (isBold) { | |
+ font = [[NSFontManager sharedFontManager] convertFont: font | |
+ toHaveTrait: NSBoldFontMask]; | |
+ } | |
+ | |
+ return [NSDictionary dictionaryWithObjectsAndKeys: | |
+ fgColor, NSForegroundColorAttributeName, | |
+ bgColor, NSBackgroundColorAttributeName, | |
+ font, NSFontAttributeName, | |
+ [NSNumber numberWithInt:underlineStyle], NSUnderlineStyleAttributeName, | |
+ NULL]; | |
+} | |
+ | |
// Returns true if the sequence of characters starting at (x, y) is not repeated | |
// TAB_FILLERs followed by a tab. | |
- (BOOL)isTabFillerOrphanAtX:(int)x Y:(int)y | |
-- | |
1.7.5.2 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment