From efe6dfa7f34a4f8e9ddc7ece8b63296ae57a2262 Mon Sep 17 00:00:00 2001 From: Michael Descy Date: Fri, 18 Mar 2016 22:02:15 -0400 Subject: [PATCH 1/4] Closes Issue #86: Autocompletion should not close as user types suitable characters #86. --- TodoTxtMac/TTMFieldEditor.m | 67 ++++++++++++++++++++++++++++---- TodoTxtMac/TodoTxtMac-Info.plist | 2 +- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/TodoTxtMac/TTMFieldEditor.m b/TodoTxtMac/TTMFieldEditor.m index 0a4eca9..44eec2b 100644 --- a/TodoTxtMac/TTMFieldEditor.m +++ b/TodoTxtMac/TTMFieldEditor.m @@ -107,17 +107,26 @@ - (void)doCompletion:(NSTimer*)timer { * addresses (with "@"). */ - (void)keyUp:(NSEvent*)event { - // Start the completion timer if the user types an "@" or "+". - if ([[event characters] isEqualToString:@"@"] || [[event characters] isEqualToString:@"+"]) { - [self startCompletionTimer]; - } else { - [self stopCompletionTimer]; + // Start the completion timer if the range for user completion starts with "@" or "+". + NSString *partialRange = [[self string] substringWithRange:self.rangeForUserCompletion]; + if ([partialRange hasPrefix:@"@"] || [partialRange hasPrefix:@"+"]) { + + // Don't trigger autocompletion if user is deleting... + if (![self keyCharFromEventIsPerformingDeletion:event]) { + [self startCompletionTimer]; + } } // Call the super so we don't override any other behaviors. [super keyUp:event]; } +- (BOOL)keyCharFromEventIsPerformingDeletion:(NSEvent*)event { + NSString *passedChar = [event charactersIgnoringModifiers]; + unichar keyChar = [passedChar characterAtIndex:0]; + return (keyChar == NSBackspaceCharacter || keyChar == NSDeleteCharacter); +} + /*! * @method completionsForPartialWordRange:indexOfSelectedItem: * @abstract This method returns autocompletion suggestions based on the range it receives. @@ -130,9 +139,9 @@ - (NSArray*)completionsForPartialWordRange:(NSRange)charRange NSString *partialString = [[self string] substringWithRange:charRange]; if ([partialString hasPrefix:@"+"]) { - return self.projectsArray; + return [self partialCompletionsFromSourceArray:self.projectsArray partialString:partialString]; } else if ([partialString hasPrefix:@"@"]) { - return self.contextsArray; + return [self partialCompletionsFromSourceArray:self.contextsArray partialString:partialString]; } else { // Call the super method to get the default behavior. // This allows for the user to type Esc and still trigger autocompletion. @@ -140,6 +149,21 @@ - (NSArray*)completionsForPartialWordRange:(NSRange)charRange } } +- (NSArray*)partialCompletionsFromSourceArray:(NSArray*)sourceArray + partialString:(NSString*)partialString{ + if (sourceArray == nil) { + return nil; + } + + NSMutableArray *returnArray = [[NSMutableArray alloc] init]; + for (NSString *str in sourceArray) { + if ([str hasPrefix:partialString]) { + [returnArray addObject:str]; + } + } + return returnArray; +} + /*! * @method rangeForUserCompletion: * @abstract This method returns the range to be replaced by autocompletion. @@ -161,9 +185,38 @@ - (NSRange)rangeForUserCompletion { superRange.length = 1; } + // Look 1 character back from the superRange. + // If it is a "@" or "+", extend the superRange back to include that character. + // This is necessary for autocompletion to work properly for contexts and projects. + NSString *leadingCharacter = [self leadingCharacterToLeftOfRange:superRange]; + if ([leadingCharacter isEqualToString:@"@"] || [leadingCharacter isEqualToString:@"+"]) { + if (superRange.location > 0) { + superRange.location -= 1; + superRange.length += 1; + } + } + return superRange; } +- (NSString*)leadingCharacterToLeftOfRange:(NSRange)range { + if (range.location == 0) { + return [[self string] substringWithRange:range]; + } + + NSRange newRange = NSMakeRange(range.location - 1, 1); + return [[self string] substringWithRange:newRange]; +} + +- (NSString*)stringForRangeWithAdditionalLeadingCharacter:(NSRange)range { + if (range.location == 0) { + return [[self string] substringWithRange:range]; + } + + NSRange newRange = NSMakeRange(range.location - 1, range.length + 1); + return [[self string] substringWithRange:newRange]; +} + /*! * @method: cancelOperation: * @abstract This method undoes all changes of the text field being edited when the user hits Esc, diff --git a/TodoTxtMac/TodoTxtMac-Info.plist b/TodoTxtMac/TodoTxtMac-Info.plist index 205704c..5ceb6a9 100644 --- a/TodoTxtMac/TodoTxtMac-Info.plist +++ b/TodoTxtMac/TodoTxtMac-Info.plist @@ -42,7 +42,7 @@ CFBundleSignature ???? CFBundleVersion - 2006 + 2007 LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion From df26c65e5011454fdc85ef8d803c7b0f1a85f6de Mon Sep 17 00:00:00 2001 From: Michael Descy Date: Mon, 21 Mar 2016 23:09:38 -0400 Subject: [PATCH 2/4] Closes Issue #92: Bug: pressing 'enter' or 'U' doesn't update task. --- TodoTxtMac/TTMTableView.m | 2 +- TodoTxtMac/TodoTxtMac-Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TodoTxtMac/TTMTableView.m b/TodoTxtMac/TTMTableView.m index d251c83..b236ea8 100644 --- a/TodoTxtMac/TTMTableView.m +++ b/TodoTxtMac/TTMTableView.m @@ -135,7 +135,7 @@ - (void)keyDown:(NSEvent *)theEvent { // update task (send Enter/Return to super) if (keyChar == NSEnterCharacter || keyChar == '\r' || keyChar == 'u') { - [self translateKeyDownEvent:theEvent toKeyDown:'u' sendToControl:self]; + [self translateKeyDownEvent:theEvent toKeyDown:'u' sendToControl:[self window]]; return; } diff --git a/TodoTxtMac/TodoTxtMac-Info.plist b/TodoTxtMac/TodoTxtMac-Info.plist index 5ceb6a9..4ab1940 100644 --- a/TodoTxtMac/TodoTxtMac-Info.plist +++ b/TodoTxtMac/TodoTxtMac-Info.plist @@ -42,7 +42,7 @@ CFBundleSignature ???? CFBundleVersion - 2007 + 2008 LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion From 2703cd5a65b2a3839ec02db432146a0d1cb693f9 Mon Sep 17 00:00:00 2001 From: Michael Descy Date: Tue, 22 Mar 2016 19:51:42 -0400 Subject: [PATCH 3/4] Improved autocompletion behavior. Related to Issue #86. - Autocompletion is now based on case-insensitive input. - The Enter key no longer triggers the autocompletion timer to begin. This fixes a bug in which pressing Enter after autocompleting will not end editing. --- TodoTxtMac/TTMFieldEditor.m | 19 ++++++++++++++----- TodoTxtMac/TodoTxtMac-Info.plist | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/TodoTxtMac/TTMFieldEditor.m b/TodoTxtMac/TTMFieldEditor.m index 44eec2b..7c0097c 100644 --- a/TodoTxtMac/TTMFieldEditor.m +++ b/TodoTxtMac/TTMFieldEditor.m @@ -111,8 +111,9 @@ - (void)keyUp:(NSEvent*)event { NSString *partialRange = [[self string] substringWithRange:self.rangeForUserCompletion]; if ([partialRange hasPrefix:@"@"] || [partialRange hasPrefix:@"+"]) { - // Don't trigger autocompletion if user is deleting... - if (![self keyCharFromEventIsPerformingDeletion:event]) { + // Don't trigger autocompletion time if user is pressing a deletion key or pressing Enter + unichar keyChar = [self keyCharFromEvent:event]; + if (![self keyCharIsADeletionKey:keyChar] && ![self keyCharIsEnterKey:keyChar]) { [self startCompletionTimer]; } } @@ -121,10 +122,18 @@ - (void)keyUp:(NSEvent*)event { [super keyUp:event]; } -- (BOOL)keyCharFromEventIsPerformingDeletion:(NSEvent*)event { +- (BOOL)keyCharIsADeletionKey:(unichar)keyChar { + return (keyChar == NSBackspaceCharacter || keyChar == NSDeleteCharacter); +} + +- (BOOL)keyCharIsEnterKey:(unichar)keyChar { + return (keyChar == NSEnterCharacter || keyChar == '\r'); +} + +- (unichar)keyCharFromEvent:(NSEvent*)event { NSString *passedChar = [event charactersIgnoringModifiers]; unichar keyChar = [passedChar characterAtIndex:0]; - return (keyChar == NSBackspaceCharacter || keyChar == NSDeleteCharacter); + return keyChar; } /*! @@ -157,7 +166,7 @@ - (NSArray*)partialCompletionsFromSourceArray:(NSArray*)sourceArray NSMutableArray *returnArray = [[NSMutableArray alloc] init]; for (NSString *str in sourceArray) { - if ([str hasPrefix:partialString]) { + if ([[str uppercaseString] hasPrefix:[partialString uppercaseString]]) { [returnArray addObject:str]; } } diff --git a/TodoTxtMac/TodoTxtMac-Info.plist b/TodoTxtMac/TodoTxtMac-Info.plist index 4ab1940..bfdc5c4 100644 --- a/TodoTxtMac/TodoTxtMac-Info.plist +++ b/TodoTxtMac/TodoTxtMac-Info.plist @@ -42,7 +42,7 @@ CFBundleSignature ???? CFBundleVersion - 2008 + 2009 LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion From 4bb0227491401e82430f37e4a9c4e70d1ff6436f Mon Sep 17 00:00:00 2001 From: Michael Descy Date: Tue, 22 Mar 2016 22:01:46 -0400 Subject: [PATCH 4/4] Bumped version number to 2.1.1. --- TodoTxtMac/TTMFilters.xib | 22 +++++++++++----------- TodoTxtMac/TodoTxtMac-Info.plist | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/TodoTxtMac/TTMFilters.xib b/TodoTxtMac/TTMFilters.xib index 20d40b7..0c68415 100644 --- a/TodoTxtMac/TTMFilters.xib +++ b/TodoTxtMac/TTMFilters.xib @@ -1,8 +1,8 @@ - + - + @@ -524,7 +524,7 @@ - + @@ -1016,7 +1016,7 @@ - + @@ -1508,7 +1508,7 @@ - + @@ -2000,7 +2000,7 @@ - + @@ -2492,7 +2492,7 @@ - + @@ -2984,7 +2984,7 @@ - + @@ -3476,7 +3476,7 @@ - + @@ -3968,7 +3968,7 @@ - + @@ -4460,7 +4460,7 @@ - + diff --git a/TodoTxtMac/TodoTxtMac-Info.plist b/TodoTxtMac/TodoTxtMac-Info.plist index bfdc5c4..a85d93b 100644 --- a/TodoTxtMac/TodoTxtMac-Info.plist +++ b/TodoTxtMac/TodoTxtMac-Info.plist @@ -38,11 +38,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.1.0 + 2.1.1 CFBundleSignature ???? CFBundleVersion - 2009 + 2010 LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion