@@ -107,17 +107,35 @@ - (void)doCompletion:(NSTimer*)timer {
107107 * addresses (with "@").
108108 */
109109- (void )keyUp : (NSEvent *)event {
110- // Start the completion timer if the user types an "@" or "+".
111- if ([[event characters ] isEqualToString: @" @" ] || [[event characters ] isEqualToString: @" +" ]) {
112- [self startCompletionTimer ];
113- } else {
114- [self stopCompletionTimer ];
110+ // Start the completion timer if the range for user completion starts with "@" or "+".
111+ NSString *partialRange = [[self string ] substringWithRange: self .rangeForUserCompletion];
112+ if ([partialRange hasPrefix: @" @" ] || [partialRange hasPrefix: @" +" ]) {
113+
114+ // Don't trigger autocompletion time if user is pressing a deletion key or pressing Enter
115+ unichar keyChar = [self keyCharFromEvent: event];
116+ if (![self keyCharIsADeletionKey: keyChar] && ![self keyCharIsEnterKey: keyChar]) {
117+ [self startCompletionTimer ];
118+ }
115119 }
116120
117121 // Call the super so we don't override any other behaviors.
118122 [super keyUp: event];
119123}
120124
125+ - (BOOL )keyCharIsADeletionKey : (unichar )keyChar {
126+ return (keyChar == NSBackspaceCharacter || keyChar == NSDeleteCharacter);
127+ }
128+
129+ - (BOOL )keyCharIsEnterKey : (unichar )keyChar {
130+ return (keyChar == NSEnterCharacter || keyChar == ' \r ' );
131+ }
132+
133+ - (unichar )keyCharFromEvent : (NSEvent *)event {
134+ NSString *passedChar = [event charactersIgnoringModifiers ];
135+ unichar keyChar = [passedChar characterAtIndex: 0 ];
136+ return keyChar;
137+ }
138+
121139/* !
122140 * @method completionsForPartialWordRange:indexOfSelectedItem:
123141 * @abstract This method returns autocompletion suggestions based on the range it receives.
@@ -130,16 +148,31 @@ - (NSArray*)completionsForPartialWordRange:(NSRange)charRange
130148 NSString *partialString = [[self string ] substringWithRange: charRange];
131149
132150 if ([partialString hasPrefix: @" +" ]) {
133- return self.projectsArray ;
151+ return [ self partialCompletionsFromSourceArray: self .projectsArray partialString: partialString] ;
134152 } else if ([partialString hasPrefix: @" @" ]) {
135- return self.contextsArray ;
153+ return [ self partialCompletionsFromSourceArray: self .contextsArray partialString: partialString] ;
136154 } else {
137155 // Call the super method to get the default behavior.
138156 // This allows for the user to type Esc and still trigger autocompletion.
139157 return [super completionsForPartialWordRange: charRange indexOfSelectedItem: index];
140158 }
141159}
142160
161+ - (NSArray *)partialCompletionsFromSourceArray : (NSArray *)sourceArray
162+ partialString : (NSString *)partialString {
163+ if (sourceArray == nil ) {
164+ return nil ;
165+ }
166+
167+ NSMutableArray *returnArray = [[NSMutableArray alloc ] init ];
168+ for (NSString *str in sourceArray) {
169+ if ([[str uppercaseString ] hasPrefix: [partialString uppercaseString ]]) {
170+ [returnArray addObject: str];
171+ }
172+ }
173+ return returnArray;
174+ }
175+
143176/* !
144177 * @method rangeForUserCompletion:
145178 * @abstract This method returns the range to be replaced by autocompletion.
@@ -161,9 +194,38 @@ - (NSRange)rangeForUserCompletion {
161194 superRange.length = 1 ;
162195 }
163196
197+ // Look 1 character back from the superRange.
198+ // If it is a "@" or "+", extend the superRange back to include that character.
199+ // This is necessary for autocompletion to work properly for contexts and projects.
200+ NSString *leadingCharacter = [self leadingCharacterToLeftOfRange: superRange];
201+ if ([leadingCharacter isEqualToString: @" @" ] || [leadingCharacter isEqualToString: @" +" ]) {
202+ if (superRange.location > 0 ) {
203+ superRange.location -= 1 ;
204+ superRange.length += 1 ;
205+ }
206+ }
207+
164208 return superRange;
165209}
166210
211+ - (NSString *)leadingCharacterToLeftOfRange : (NSRange )range {
212+ if (range.location == 0 ) {
213+ return [[self string ] substringWithRange: range];
214+ }
215+
216+ NSRange newRange = NSMakeRange (range.location - 1 , 1 );
217+ return [[self string ] substringWithRange: newRange];
218+ }
219+
220+ - (NSString *)stringForRangeWithAdditionalLeadingCharacter : (NSRange )range {
221+ if (range.location == 0 ) {
222+ return [[self string ] substringWithRange: range];
223+ }
224+
225+ NSRange newRange = NSMakeRange (range.location - 1 , range.length + 1 );
226+ return [[self string ] substringWithRange: newRange];
227+ }
228+
167229/* !
168230 * @method: cancelOperation:
169231 * @abstract This method undoes all changes of the text field being edited when the user hits Esc,
0 commit comments