adium-1.4 2646:e6cf2d4672e5: Control more directly the completio...

commits at adium.im commits at adium.im
Mon Oct 26 01:21:49 UTC 2009


details:	http://hg.adium.im/adium-1.4/rev/e6cf2d4672e5
revision:	2646:e6cf2d4672e5
author:		Zachary West <zacw at adium.im>
date:		Sun Oct 25 21:21:42 2009 -0400

Control more directly the completion range for group chats. Fixes #13237.

We now go back to the nearest whitespace and see if it would autocomplete any nicks at that point. If it would, we perform the autocompletion starting at that point. If it doesn't, we let the OS do its normal thing.

This fixes autocompleting things like "[mynick]" or the channel name (such as "#adium") since they start with non-word characters, but are perfectly valid.

diffs (178 lines):

diff -r cdc1b3a12cf7 -r e6cf2d4672e5 Frameworks/Adium Framework/Source/AIMessageEntryTextView.h
--- a/Frameworks/Adium Framework/Source/AIMessageEntryTextView.h	Sat Oct 24 18:29:49 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIMessageEntryTextView.h	Sun Oct 25 21:21:42 2009 -0400
@@ -26,6 +26,7 @@
  * @brief Should the tab key trigger an autocomplete?
  */
 - (BOOL)textViewShouldTabComplete:(NSTextView *)inTextView;
+- (NSRange)textView:(NSTextView *)inTextView rangeForCompletion:(NSRange)completionRange;
 - (void)textViewDidCancel:(NSTextView *)inTextView;
 @end
 
diff -r cdc1b3a12cf7 -r e6cf2d4672e5 Frameworks/Adium Framework/Source/AIMessageEntryTextView.m
--- a/Frameworks/Adium Framework/Source/AIMessageEntryTextView.m	Sat Oct 24 18:29:49 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIMessageEntryTextView.m	Sun Oct 25 21:21:42 2009 -0400
@@ -1504,6 +1504,18 @@
 										group:PREF_GROUP_DUAL_WINDOW_INTERFACE];
 }
 
+#pragma mark Autocompleting
+- (NSRange)rangeForUserCompletion
+{
+	NSRange completionRange = [super rangeForUserCompletion];
+	
+	if ([self.delegate respondsToSelector:@selector(textView:rangeForCompletion:)]) {
+		completionRange = [self.delegate textView:self rangeForCompletion:completionRange];
+	}
+	
+	return completionRange;
+}
+
 #pragma mark Writing Direction
 - (void)toggleBaseWritingDirection:(id)sender
 {
diff -r cdc1b3a12cf7 -r e6cf2d4672e5 Plugins/Dual Window Interface/AIMessageViewController.m
--- a/Plugins/Dual Window Interface/AIMessageViewController.m	Sat Oct 24 18:29:49 2009 -0400
+++ b/Plugins/Dual Window Interface/AIMessageViewController.m	Sun Oct 25 21:21:42 2009 -0400
@@ -90,6 +90,8 @@
 - (void)setUserListVisible:(BOOL)inVisible;
 - (void)setupShelfView;
 - (void)updateUserCount;
+
+- (NSArray *)contactsMatchingBeginningString:(NSString *)partialWord;
 @end
 
 @implementation AIMessageViewController
@@ -974,6 +976,12 @@
 }
 
 #pragma mark Autocompletion
+- (BOOL)canTabCompleteForPartialWord:(NSString *)partialWord
+{
+	return ([self contactsMatchingBeginningString:partialWord].count > 0 ||
+			[self.chat.displayName rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound);
+}
+
 /*!
  * @brief Should the tab key cause an autocompletion if possible?
  *
@@ -981,55 +989,90 @@
  */
 - (BOOL)textViewShouldTabComplete:(NSTextView *)inTextView
 {
-	return self.chat.isGroupChat;
+	if (self.chat.isGroupChat) {
+		NSRange completionRange = inTextView.rangeForUserCompletion;
+		NSString *partialWord = [inTextView.textStorage.string substringWithRange:completionRange];
+		return [self canTabCompleteForPartialWord:partialWord]; 
+	}
+	
+	return NO;
+}
+
+- (NSRange)textView:(NSTextView *)inTextView rangeForCompletion:(NSRange)charRange
+{
+	if (self.chat.isGroupChat && charRange.location > 0) {
+		NSString *partialWord = nil;
+		NSString *allText = [inTextView.textStorage.string substringWithRange:NSMakeRange(0, NSMaxRange(charRange))];
+		NSRange whitespacePosition = [allText rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet] options:NSBackwardsSearch];
+		
+		if (whitespacePosition.location == NSNotFound) {
+			// We went back to the beginning of the string and still didn't find a whitespace; use the whole thing.
+			partialWord = allText;
+			whitespacePosition = NSMakeRange(0, 0);
+		} else {
+			// We found a whitespace, use from it until our current position.
+			partialWord = [allText substringWithRange:NSMakeRange(NSMaxRange(whitespacePosition), allText.length - NSMaxRange(whitespacePosition))];
+		}
+		
+		// If this matches any contacts or the room name, use this new range for autocompletion.
+		if ([self canTabCompleteForPartialWord:partialWord]) {
+			charRange = NSMakeRange(NSMaxRange(whitespacePosition), allText.length - NSMaxRange(whitespacePosition));
+		}
+	}
+	
+	return charRange;
+}
+
+- (NSArray *)contactsMatchingBeginningString:(NSString *)partialWord
+{
+	NSMutableArray *contacts = [NSMutableArray array];
+	
+	for (AIListContact *listContact in self.chat) {
+		if ([listContact.UID rangeOfString:partialWord
+								   options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound ||
+			[listContact.formattedUID rangeOfString:partialWord
+											options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound ||
+			[listContact.displayName rangeOfString:partialWord
+										   options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound) {
+				[contacts addObject:listContact];
+		}
+	}
+	
+	return contacts;
 }
 
 - (NSArray *)textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index
 {
-	NSMutableArray	*completions;
+	NSMutableArray	*completions = nil;
 	
 	if (self.chat.isGroupChat) {
-		NSString		*partialWord = [[textView.textStorage attributedSubstringFromRange:charRange] string];
-		
+		NSString *suffix = nil;
+		NSString *partialWord = [textView.textStorage.string substringWithRange:charRange];
 		BOOL autoCompleteUID = [self.chat.account chatShouldAutocompleteUID:self.chat];
 		
-		NSString		*suffix;
+		//At the start of a line, append ": "
 		if (charRange.location == 0) {
-			//At the start of a line, append ": "
 			suffix = @": ";
-		} else {
-			suffix = nil;
 		}
 		
 		completions = [NSMutableArray array];
-		for(AIListContact *listContact in self.chat) {
-			if ([listContact.displayName rangeOfString:partialWord
-												 options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound ||
-				[listContact.formattedUID rangeOfString:partialWord
-												options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound ||
-				[listContact.UID rangeOfString:partialWord
-										 options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound) {
-
-				NSString *displayName = [self.chat aliasForContact:listContact];
-				
-				if (!displayName) {
-					displayName = autoCompleteUID ? listContact.formattedUID : listContact.displayName;
-				}
-
-				[completions addObject:(suffix ? [displayName stringByAppendingString:suffix] : displayName)];
-			}
+		
+		for (AIListContact *listContact in [self contactsMatchingBeginningString:partialWord]) {
+			NSString *displayName = [self.chat aliasForContact:listContact];
+			
+			if (!displayName)
+				displayName = autoCompleteUID ? listContact.formattedUID : listContact.displayName;
+			
+			[completions addObject:(suffix ? [displayName stringByAppendingString:suffix] : displayName)];
 		}
 		
-		if ([self.chat.name rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound) {
-			[completions addObject:self.chat.name];
+		if ([self.chat.displayName rangeOfString:partialWord options:(NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound) {
+			[completions addObject:self.chat.displayName];
 		}
 
 		if ([completions count]) {			
 			*index = 0;
 		}
-
-	} else {
-		completions = nil;
 	}
 
 	return [completions count] ? completions : words;




More information about the commits mailing list