From 296634f40e0f04174c8a31bb171a2bf0cc13f85b Mon Sep 17 00:00:00 2001 From: Bjorn Winckler Date: Sat, 5 Apr 2008 15:24:25 +0200 Subject: [PATCH] Make copy/paste respect block-wise selections When text is copied inside Vim we put both the text and the motion type on the pasteboard. Text copied from outside Vim never contains the motion type so we have to guess between line and character-wise motion types in that case. --- src/MacVim/MMBackend.m | 2 + src/MacVim/MacVim.h | 7 ++- src/MacVim/MacVim.m | 6 +++ src/MacVim/gui_macvim.m | 98 ++++++++++++++++++++++++++++------------- 4 files changed, 82 insertions(+), 31 deletions(-) diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index 91250dcc14..ac714f8154 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -1262,6 +1262,8 @@ static NSString *MMSymlinkWarningString = - (BOOL)starRegisterToPasteboard:(byref NSPasteboard *)pboard { + // TODO: This method should share code with clip_mch_request_selection(). + if (VIsual_active && (State & NORMAL) && clip_star.available) { // If there is no pasteboard, return YES to indicate that there is text // to copy. diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index f824014f3a..aa49fc23f8 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -238,6 +238,12 @@ enum { + +// Vim pasteboard type (holds motion type + string) +extern NSString *VimPBoardType; + + + // Loads all fonts in the Resouces folder of the app bundle and returns a font // container reference (which should be used to deactivate the loaded fonts). ATSFontContainerRef loadFonts(); @@ -284,4 +290,3 @@ NSString *buildSearchTextCommand(NSString *searchText); // MacVim Apple Event Constants #define keyMMUntitledWindow 'MMuw' - diff --git a/src/MacVim/MacVim.m b/src/MacVim/MacVim.m index a2edd6cf0d..b702b542c5 100644 --- a/src/MacVim/MacVim.m +++ b/src/MacVim/MacVim.m @@ -111,6 +111,12 @@ NSString *MMLoginShellArgumentKey = @"MMLoginShellArgument"; +// Vim pasteboard type (holds motion type + string) +NSString *VimPBoardType = @"VimPBoardType"; + + + + ATSFontContainerRef loadFonts() { diff --git a/src/MacVim/gui_macvim.m b/src/MacVim/gui_macvim.m index 5abc1f9630..d5f8c16c17 100644 --- a/src/MacVim/gui_macvim.m +++ b/src/MacVim/gui_macvim.m @@ -480,44 +480,75 @@ clip_mch_own_selection(VimClipboard *cbd) clip_mch_request_selection(VimClipboard *cbd) { NSPasteboard *pb = [NSPasteboard generalPasteboard]; - NSString *pbType = [pb availableTypeFromArray: - [NSArray arrayWithObject:NSStringPboardType]]; - if (pbType) { - NSMutableString *string = + NSArray *supportedTypes = [NSArray arrayWithObjects:VimPBoardType, + NSStringPboardType, nil]; + NSString *bestType = [pb availableTypeFromArray:supportedTypes]; + if (!bestType) return; + + int motion_type = MCHAR; + NSString *string = nil; + + if ([bestType isEqual:VimPBoardType]) { + // This type should consist of an array with two objects: + // 1. motion type (NSNumber) + // 2. text (NSString) + // If this is not the case we fall back on using NSStringPboardType. + id plist = [pb propertyListForType:VimPBoardType]; + if ([plist isKindOfClass:[NSArray class]] && [plist count] == 2) { + id obj = [plist objectAtIndex:1]; + if ([obj isKindOfClass:[NSString class]]) { + motion_type = [[plist objectAtIndex:0] intValue]; + string = obj; + } + } + } + + if (!string) { + // Use NSStringPboardType. The motion type is set to line-wise if the + // string contains at least one EOL character, otherwise it is set to + // character-wise (block-wise is never used). + NSMutableString *mstring = [[pb stringForType:NSStringPboardType] mutableCopy]; + if (!mstring) return; // Replace unrecognized end-of-line sequences with \x0a (line feed). - NSRange range = { 0, [string length] }; - unsigned n = [string replaceOccurrencesOfString:@"\x0d\x0a" + NSRange range = { 0, [mstring length] }; + unsigned n = [mstring replaceOccurrencesOfString:@"\x0d\x0a" withString:@"\x0a" options:0 range:range]; if (0 == n) { - n = [string replaceOccurrencesOfString:@"\x0d" withString:@"\x0a" + n = [mstring replaceOccurrencesOfString:@"\x0d" withString:@"\x0a" options:0 range:range]; } // Scan for newline character to decide whether the string should be - // pasted linewise or characterwise. - int type = MCHAR; - if (0 < n || NSNotFound != [string rangeOfString:@"\n"].location) - type = MLINE; + // pasted line-wise or character-wise. + motion_type = MCHAR; + if (0 < n || NSNotFound != [mstring rangeOfString:@"\n"].location) + motion_type = MLINE; - char_u *str = (char_u*)[string UTF8String]; - int len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - -#ifdef FEAT_MBYTE - if (input_conv.vc_type != CONV_NONE) - str = string_convert(&input_conv, str, &len); -#endif - - if (str) - clip_yank_selection(type, str, len, cbd); - -#ifdef FEAT_MBYTE - if (input_conv.vc_type != CONV_NONE) - vim_free(str); -#endif + string = mstring; } + + if (!(MCHAR == motion_type || MLINE == motion_type || MBLOCK == motion_type + || MAUTO == motion_type)) + motion_type = MCHAR; + + char_u *str = (char_u*)[string UTF8String]; + int len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + +#ifdef FEAT_MBYTE + if (input_conv.vc_type != CONV_NONE) + str = string_convert(&input_conv, str, &len); +#endif + + if (str) + clip_yank_selection(motion_type, str, len, cbd); + +#ifdef FEAT_MBYTE + if (input_conv.vc_type != CONV_NONE) + vim_free(str); +#endif } @@ -534,8 +565,8 @@ clip_mch_set_selection(VimClipboard *cbd) // Get the text to put on the pasteboard. long_u llen = 0; char_u *str = 0; - int type = clip_convert_selection(&str, &llen, cbd); - if (type < 0) + int motion_type = clip_convert_selection(&str, &llen, cbd); + if (motion_type < 0) return; // TODO: Avoid overflow. @@ -554,9 +585,16 @@ clip_mch_set_selection(VimClipboard *cbd) NSString *string = [[NSString alloc] initWithBytes:str length:len encoding:NSUTF8StringEncoding]; + // See clip_mch_request_selection() for info on pasteboard types. NSPasteboard *pb = [NSPasteboard generalPasteboard]; - [pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] - owner:nil]; + NSArray *supportedTypes = [NSArray arrayWithObjects:VimPBoardType, + NSStringPboardType, nil]; + [pb declareTypes:supportedTypes owner:nil]; + + NSNumber *motion = [NSNumber numberWithInt:motion_type]; + NSArray *plist = [NSArray arrayWithObjects:motion, string, nil]; + [pb setPropertyList:plist forType:VimPBoardType]; + [pb setString:string forType:NSStringPboardType]; [string release];