julian
julian

Reputation: 157

Making autocomplete case-insensitive

I'm implementing an autocomplete in cocoa for an OSX application and thus far I've got it all pinned down. The one hangup is that the autocomplete is case-sensitive and that's not really what I want/need. Ideally the autocomplete will be case INSENSITIVE. Relevant code below:

    @implementation autocompleteController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.textField.delegate = self;
}

-(void)controlTextDidChange:(NSNotification *)obj{
    NSTextView * fieldEditor = [[obj userInfo] objectForKey:@"NSFieldEditor"];
    if (self.isAutocompleting == NO  && !self.backspaceKey) {
        self.isAutocompleting = YES;
        self.lastEntry = [[[fieldEditor string] capitalizedString] copy];
        [fieldEditor complete:nil];
        self.isAutocompleting = NO;
    }
    if (self.backspaceKey) {
        self.backspaceKey = NO;
    }
}

-(NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index{
    NSMutableArray * suggestions = [NSMutableArray array];
    NSArray * possibleStrings = @[@"TEST", @"ABC", @"abc", @"amauroy", @"AMA", @"amazing"];

    if (!self.lastEntry || !possibleStrings) {
        return nil;
    }
    for (NSString * string in possibleStrings) {
        if ([string hasPrefix:self.lastEntry]) {
            [suggestions addObject:string];
        }
    }
    return suggestions;
}

-(BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector{
    if (commandSelector == @selector(deleteBackward:)) {
        self.backspaceKey = YES;
    }
    return NO;
}

@end

Upvotes: 2

Views: 654

Answers (2)

Caleb
Caleb

Reputation: 124997

As Pro Blaster points out, the problem is with the following line:

if ([string hasPrefix:self.lastEntry]) {

Your autocompletion is case-sensitive because -hasPrefix: is case-sensitive. One approach is to convert everything to lower case (upper case would also work, of course). Another is to write a case-insensitive version of -hasPrefix: and add it to NSString using a category, like this:

@interface NSString (autocomplete)

- (BOOL)hasPrefixIgnoringCase:(NSString*)aString;

@end;

@implementation NSString (autocomplete)

- (BOOL)hasPrefixIgnoringCase:(NSString*)aString
{
    NSRange *prefix = [self rangeOfString:aString options:NSCaseInsensitiveSearch];
    return prefix.location == 0 && prefix.length == aString.length;
}

@end

Then use that method in your code:

if ([string hasPrefixIgnoringCase:self.lastEntry]) {

Note: The provided code is untested. The concept is sound, but you may find a syntax error or two.

Upvotes: 3

Pro Blaster
Pro Blaster

Reputation: 491

I did this once.
You would do so by replacing :

for (NSString * string in possibleStrings) {
    if ([string hasPrefix:self.lastEntry]) {
        [suggestions addObject:string];
    }
}
return suggestions

with:

for (NSString * string in possibleStrings) {
    if ([[string lowercaseString] hasPrefix:[self.lastEntry lowercaseString]]) {
        [suggestions addObject:string];
    }
}
return suggestions;

Upvotes: 2

Related Questions