| 315 | | // continue if necessary |
|---|
| 316 | | if( ! [partialCompletion isEqualToString:@""] ) { |
|---|
| 317 | | // compile list of possible completions |
|---|
| 318 | | NSArray *possibleNicks = [[self delegate] textView:self stringCompletionsForPrefix:partialCompletion]; |
|---|
| 319 | | NSString *name = nil; |
|---|
| 320 | | |
|---|
| 321 | | // insert word or suggestion |
|---|
| 322 | | if( [possibleNicks count] == 1 && ( curPos.location == [[self string] length] || [illegalCharacters characterIsMember:[[self string] characterAtIndex:curPos.location]] ) ) { |
|---|
| | 326 | // only allow an empty tab completion if the current position is zero, this feels best in practice |
|---|
| | 327 | if( curPos.location && ! [partialCompletion length] ) { |
|---|
| | 328 | NSBeep(); |
|---|
| | 329 | return YES; |
|---|
| | 330 | } |
|---|
| | 331 | |
|---|
| | 332 | // compile list of possible completions |
|---|
| | 333 | NSArray *possibleNicks = [[self delegate] textView:self stringCompletionsForPrefix:partialCompletion]; |
|---|
| | 334 | NSString *name = nil; |
|---|
| | 335 | |
|---|
| | 336 | // insert word or suggestion |
|---|
| | 337 | if( [possibleNicks count] == 1 && ( curPos.location == [[self string] length] || [illegalCharacters characterIsMember:[[self string] characterAtIndex:curPos.location]] ) ) { |
|---|
| | 338 | name = [possibleNicks objectAtIndex:0]; |
|---|
| | 339 | NSRange replacementRange = NSMakeRange( curPos.location - [partialCompletion length], [partialCompletion length] ); |
|---|
| | 340 | |
|---|
| | 341 | _ignoreSelectionChanges = YES; |
|---|
| | 342 | [self replaceCharactersInRange:replacementRange withString:name]; |
|---|
| | 343 | |
|---|
| | 344 | if( suffix && replacementRange.location == 0 ) [self insertText:@": "]; |
|---|
| | 345 | else if( suffix ) [self insertText:@" "]; |
|---|
| | 346 | _tabCompletting = NO; |
|---|
| | 347 | _ignoreSelectionChanges = NO; |
|---|
| | 348 | |
|---|
| | 349 | if( [[self delegate] respondsToSelector:@selector( textView:selectedCompletion:fromPrefix: )] ) |
|---|
| | 350 | [[self delegate] textView:self selectedCompletion:name fromPrefix:partialCompletion]; |
|---|
| | 351 | } else if( [possibleNicks count] > 1 ) { |
|---|
| | 352 | // since several are available, we highlight the modified text |
|---|
| | 353 | NSRange wordRange; |
|---|
| | 354 | BOOL full = YES; |
|---|
| | 355 | |
|---|
| | 356 | [_lastCompletionPrefix release]; |
|---|
| | 357 | _lastCompletionPrefix = [partialCompletion copyWithZone:nil]; |
|---|
| | 358 | |
|---|
| | 359 | if( curPos.location == [[self string] length] || [illegalCharacters characterIsMember:[[self string] characterAtIndex:curPos.location]] ) { |
|---|
| | 360 | wordRange = NSMakeRange( curPos.location - [partialCompletion length], [partialCompletion length] ); |
|---|
| 324 | | NSRange replacementRange = NSMakeRange( curPos.location - [partialCompletion length], [partialCompletion length] ); |
|---|
| 325 | | |
|---|
| 326 | | _ignoreSelectionChanges = YES; |
|---|
| 327 | | [self replaceCharactersInRange:replacementRange withString:name]; |
|---|
| 328 | | |
|---|
| 329 | | if( suffix && replacementRange.location == 0 ) [self insertText:@": "]; |
|---|
| 330 | | else if( suffix ) [self insertText:@" "]; |
|---|
| 331 | | _tabCompletting = NO; |
|---|
| 332 | | _ignoreSelectionChanges = NO; |
|---|
| 333 | | |
|---|
| 334 | | if( [[self delegate] respondsToSelector:@selector( textView:selectedCompletion:fromPrefix: )] ) |
|---|
| 335 | | [[self delegate] textView:self selectedCompletion:name fromPrefix:partialCompletion]; |
|---|
| 336 | | } else if( [possibleNicks count] > 1 ) { |
|---|
| 337 | | // since several are available, we highlight the modified text |
|---|
| 338 | | NSRange wordRange; |
|---|
| 339 | | BOOL full = YES; |
|---|
| 340 | | |
|---|
| 341 | | [_lastCompletionPrefix release]; |
|---|
| 342 | | _lastCompletionPrefix = [partialCompletion retain]; |
|---|
| 343 | | |
|---|
| 344 | | if( curPos.location == [[self string] length] || [illegalCharacters characterIsMember:[[self string] characterAtIndex:curPos.location]] ) { |
|---|
| 345 | | wordRange = NSMakeRange( curPos.location - [partialCompletion length], [partialCompletion length] ); |
|---|
| 346 | | name = [possibleNicks objectAtIndex:0]; |
|---|
| 347 | | } else { |
|---|
| 348 | | wordRange = [[self string] rangeOfCharacterFromSet:illegalCharacters options:0 range:NSMakeRange( curPos.location, [[self string] length] - curPos.location )]; |
|---|
| 349 | | if( wordRange.location == NSNotFound ) |
|---|
| 350 | | wordRange = NSMakeRange( NSMaxRange( wordStart ), [[self string] length] - NSMaxRange( wordStart )) ; |
|---|
| 351 | | else wordRange = NSMakeRange( NSMaxRange( wordStart ), wordRange.location - NSMaxRange( wordStart )); |
|---|
| 352 | | |
|---|
| 353 | | NSString *tempWord = [[self string] substringWithRange:wordRange]; |
|---|
| 354 | | BOOL keepSearching = YES; |
|---|
| 355 | | int count = 0; |
|---|
| 356 | | |
|---|
| 357 | | do { |
|---|
| 358 | | keepSearching = ! [[possibleNicks objectAtIndex:count] isEqualToString:tempWord]; |
|---|
| 359 | | } while ( ++count < [possibleNicks count] && keepSearching ); |
|---|
| 360 | | |
|---|
| 361 | | if( count == [possibleNicks count] ) count = 0; |
|---|
| 362 | | |
|---|
| 363 | | name = [possibleNicks objectAtIndex:count]; |
|---|
| 364 | | full = NO; |
|---|
| 365 | | } |
|---|
| 366 | | |
|---|
| 367 | | [_lastCompletionMatch release]; |
|---|
| 368 | | _lastCompletionMatch = [name retain]; |
|---|
| 369 | | |
|---|
| 370 | | if( suffix && wordRange.location == 0 ) name = [name stringByAppendingString:@": "]; |
|---|
| 371 | | else if( suffix ) name = [name stringByAppendingString:@" "]; |
|---|
| 372 | | |
|---|
| 373 | | _ignoreSelectionChanges = YES; |
|---|
| 374 | | [self replaceCharactersInRange:wordRange withString:( full ? name : _lastCompletionMatch )]; |
|---|
| 375 | | [self setSelectedRange:NSMakeRange( curPos.location, [name length] - [partialCompletion length] )]; |
|---|
| 376 | | _ignoreSelectionChanges = NO; |
|---|
| 378 | | NSBeep(); // no matches |
|---|
| 379 | | _tabCompletting = NO; |
|---|
| 380 | | } |
|---|
| | 363 | wordRange = [[self string] rangeOfCharacterFromSet:illegalCharacters options:0 range:NSMakeRange( curPos.location, [[self string] length] - curPos.location )]; |
|---|
| | 364 | if( wordRange.location == NSNotFound ) |
|---|
| | 365 | wordRange = NSMakeRange( NSMaxRange( wordStart ), [[self string] length] - NSMaxRange( wordStart )) ; |
|---|
| | 366 | else wordRange = NSMakeRange( NSMaxRange( wordStart ), wordRange.location - NSMaxRange( wordStart )); |
|---|
| | 367 | |
|---|
| | 368 | NSString *tempWord = [[self string] substringWithRange:wordRange]; |
|---|
| | 369 | BOOL keepSearching = YES; |
|---|
| | 370 | int count = 0; |
|---|
| | 371 | |
|---|
| | 372 | do { |
|---|
| | 373 | keepSearching = ! [[possibleNicks objectAtIndex:count] isEqualToString:tempWord]; |
|---|
| | 374 | } while ( ++count < [possibleNicks count] && keepSearching ); |
|---|
| | 375 | |
|---|
| | 376 | if( count == [possibleNicks count] ) count = 0; |
|---|
| | 377 | |
|---|
| | 378 | name = [possibleNicks objectAtIndex:count]; |
|---|
| | 379 | full = NO; |
|---|
| | 380 | } |
|---|
| | 381 | |
|---|
| | 382 | [_lastCompletionMatch release]; |
|---|
| | 383 | _lastCompletionMatch = [name copyWithZone:nil]; |
|---|
| | 384 | |
|---|
| | 385 | if( suffix && wordRange.location == 0 ) name = [name stringByAppendingString:@": "]; |
|---|
| | 386 | else if( suffix ) name = [name stringByAppendingString:@" "]; |
|---|
| | 387 | |
|---|
| | 388 | _ignoreSelectionChanges = YES; |
|---|
| | 389 | [self replaceCharactersInRange:wordRange withString:( full ? name : _lastCompletionMatch )]; |
|---|
| | 390 | [self setSelectedRange:NSMakeRange( curPos.location, [name length] - [partialCompletion length] )]; |
|---|
| | 391 | _ignoreSelectionChanges = NO; |
|---|