2010-07-07 17:40:50 +00:00
|
|
|
/**
|
|
|
|
* \file AppleSpeller.m
|
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
|
|
|
* \author Stephan Witt
|
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
2010-07-11 21:30:47 +00:00
|
|
|
#import <Carbon/Carbon.h>
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
|
|
|
|
#import <AvailabilityMacros.h>
|
2010-07-07 17:40:50 +00:00
|
|
|
|
|
|
|
#include "support/AppleSpeller.h"
|
|
|
|
|
|
|
|
typedef struct AppleSpellerRec {
|
|
|
|
NSSpellChecker * checker;
|
2010-07-11 21:30:47 +00:00
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
|
2010-07-07 17:40:50 +00:00
|
|
|
NSInteger doctag;
|
|
|
|
#else
|
|
|
|
int doctag;
|
|
|
|
#endif
|
2010-08-22 13:55:28 +00:00
|
|
|
NSArray * suggestions;
|
|
|
|
NSArray * misspelled;
|
2010-07-07 17:40:50 +00:00
|
|
|
} AppleSpellerRec ;
|
|
|
|
|
|
|
|
|
|
|
|
AppleSpeller newAppleSpeller(void)
|
|
|
|
{
|
|
|
|
AppleSpeller speller = calloc(1, sizeof(AppleSpellerRec));
|
|
|
|
speller->checker = [NSSpellChecker sharedSpellChecker];
|
|
|
|
speller->doctag = [NSSpellChecker uniqueSpellDocumentTag];
|
2010-08-22 13:55:28 +00:00
|
|
|
speller->suggestions = nil;
|
|
|
|
speller->misspelled = nil;
|
2010-07-07 17:40:50 +00:00
|
|
|
return speller;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void freeAppleSpeller(AppleSpeller speller)
|
|
|
|
{
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
|
|
|
[speller->checker closeSpellDocumentWithTag:speller->doctag];
|
|
|
|
|
2010-08-22 13:55:28 +00:00
|
|
|
[speller->suggestions release];
|
|
|
|
[speller->misspelled release];
|
|
|
|
|
2010-07-07 17:40:50 +00:00
|
|
|
[pool release];
|
|
|
|
|
|
|
|
free(speller);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-05 19:00:57 +00:00
|
|
|
static NSString * toString(const char * word)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
|
|
|
return [[NSString alloc] initWithBytes:word length:strlen(word) encoding:NSUTF8StringEncoding];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-22 13:55:28 +00:00
|
|
|
static NSString * toLanguage(AppleSpeller speller, const char * lang)
|
|
|
|
{
|
|
|
|
NSString * result = nil;
|
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
NSString * lang_ = toString(lang);
|
|
|
|
if ([NSSpellChecker instancesRespondToSelector:@selector(availableLanguages)]) {
|
|
|
|
NSArray * languages = [speller->checker availableLanguages];
|
|
|
|
|
|
|
|
for (NSString *element in languages) {
|
2010-12-20 21:45:41 +00:00
|
|
|
if (0 == [element caseInsensitiveCompare:lang_]) {
|
2010-08-22 13:55:28 +00:00
|
|
|
result = element;
|
|
|
|
break;
|
|
|
|
} else if ([lang_ hasPrefix:element]) {
|
|
|
|
result = element;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[lang_ release];
|
|
|
|
[pool release];
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
SpellCheckResult AppleSpeller_check(AppleSpeller speller, const char * word, const char * lang)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
|
|
|
if (!speller->checker || !lang || !word)
|
2010-08-05 20:10:40 +00:00
|
|
|
return SPELL_CHECK_FAILED;
|
2010-07-07 17:40:50 +00:00
|
|
|
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2010-08-05 19:00:57 +00:00
|
|
|
NSString * word_ = toString(word);
|
|
|
|
NSString * lang_ = toString(lang);
|
2010-08-22 13:55:28 +00:00
|
|
|
SpellCheckResult result = SPELL_CHECK_FAILED;
|
|
|
|
int start = 0;
|
2010-09-06 06:55:31 +00:00
|
|
|
int length = [word_ length];
|
|
|
|
|
2010-08-22 13:55:28 +00:00
|
|
|
[speller->misspelled release];
|
|
|
|
speller->misspelled = nil;
|
2010-07-07 17:40:50 +00:00
|
|
|
|
2010-09-06 06:55:31 +00:00
|
|
|
while (result == SPELL_CHECK_FAILED && start < length) {
|
2010-08-22 13:55:28 +00:00
|
|
|
NSRange match = [speller->checker
|
|
|
|
checkSpellingOfString:word_
|
|
|
|
startingAt:start
|
|
|
|
language:lang_
|
2010-12-20 21:45:41 +00:00
|
|
|
wrap:(BOOL)NO
|
2010-08-22 13:55:28 +00:00
|
|
|
inSpellDocumentWithTag:speller->doctag
|
|
|
|
wordCount:NULL];
|
|
|
|
|
|
|
|
result = match.length == 0 ? SPELL_CHECK_OK : SPELL_CHECK_FAILED;
|
|
|
|
if (result == SPELL_CHECK_OK) {
|
|
|
|
if ([NSSpellChecker instancesRespondToSelector:@selector(hasLearnedWord:)]) {
|
|
|
|
if ([speller->checker hasLearnedWord:word_])
|
|
|
|
result = SPELL_CHECK_LEARNED;
|
|
|
|
}
|
|
|
|
} else {
|
2011-02-20 11:12:35 +00:00
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
|
2010-12-16 07:58:38 +00:00
|
|
|
NSUInteger capacity = [speller->misspelled count] + 1;
|
2011-02-20 11:12:35 +00:00
|
|
|
#else
|
|
|
|
int capacity = [speller->misspelled count] + 1;
|
|
|
|
#endif
|
2010-08-22 13:55:28 +00:00
|
|
|
NSMutableArray * misspelled = [NSMutableArray arrayWithCapacity:capacity];
|
|
|
|
[misspelled addObjectsFromArray:speller->misspelled];
|
|
|
|
[misspelled addObject:[NSValue valueWithRange:match]];
|
|
|
|
[speller->misspelled release];
|
|
|
|
speller->misspelled = [[NSArray arrayWithArray:misspelled] retain];
|
|
|
|
start = match.location + match.length + 1;
|
|
|
|
}
|
2010-08-05 20:10:40 +00:00
|
|
|
}
|
|
|
|
|
2010-07-07 17:40:50 +00:00
|
|
|
[word_ release];
|
|
|
|
[lang_ release];
|
|
|
|
[pool release];
|
|
|
|
|
2010-08-22 13:55:28 +00:00
|
|
|
return [speller->misspelled count] ? SPELL_CHECK_FAILED : result;
|
2010-07-07 17:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
void AppleSpeller_ignore(AppleSpeller speller, const char * word)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2010-08-05 19:00:57 +00:00
|
|
|
NSString * word_ = toString(word);
|
2010-07-07 17:40:50 +00:00
|
|
|
|
|
|
|
[speller->checker ignoreWord:word_ inSpellDocumentWithTag:(speller->doctag)];
|
|
|
|
|
|
|
|
[word_ release];
|
|
|
|
[pool release];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
size_t AppleSpeller_makeSuggestion(AppleSpeller speller, const char * word, const char * lang)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
|
|
|
if (!speller->checker || !word || !lang)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2010-08-05 19:00:57 +00:00
|
|
|
NSString * word_ = toString(word);
|
|
|
|
NSString * lang_ = toString(lang);
|
2010-07-11 22:04:29 +00:00
|
|
|
NSArray * result ;
|
2010-07-07 17:40:50 +00:00
|
|
|
|
2010-07-11 21:30:47 +00:00
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
|
2010-07-07 17:40:50 +00:00
|
|
|
// Mac OS X 10.6 only
|
|
|
|
NSInteger slen = [word_ length];
|
|
|
|
NSRange range = { 0, slen };
|
2010-07-11 21:30:47 +00:00
|
|
|
|
|
|
|
if ([NSSpellChecker instancesRespondToSelector:@selector(guessesForWordRange:)]) {
|
|
|
|
result = [speller->checker guessesForWordRange:range
|
|
|
|
inString:word_
|
|
|
|
language:lang_
|
|
|
|
inSpellDocumentWithTag:speller->doctag];
|
|
|
|
} else {
|
|
|
|
[speller->checker setLanguage:lang_];
|
2010-07-11 22:04:29 +00:00
|
|
|
result = [speller->checker guessesForWord:word_];
|
2010-07-11 21:30:47 +00:00
|
|
|
}
|
2010-07-07 17:40:50 +00:00
|
|
|
#else
|
|
|
|
[speller->checker setLanguage:lang_];
|
2010-07-11 22:04:29 +00:00
|
|
|
result = [speller->checker guessesForWord:word_];
|
2010-07-07 17:40:50 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
[word_ release];
|
|
|
|
[lang_ release];
|
|
|
|
|
2010-08-22 13:55:28 +00:00
|
|
|
[speller->suggestions release];
|
|
|
|
speller->suggestions = [[NSArray arrayWithArray:result] retain];
|
2010-07-07 17:40:50 +00:00
|
|
|
|
|
|
|
[pool release];
|
2010-08-22 13:55:28 +00:00
|
|
|
return [speller->suggestions count];
|
2010-07-07 17:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
const char * AppleSpeller_getSuggestion(AppleSpeller speller, size_t pos)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
|
|
|
const char * result = 0;
|
2010-08-22 13:55:28 +00:00
|
|
|
if (pos < [speller->suggestions count]) {
|
|
|
|
result = [[speller->suggestions objectAtIndex:pos] UTF8String] ;
|
2010-07-07 17:40:50 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
void AppleSpeller_learn(AppleSpeller speller, const char * word)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
2010-07-11 21:30:47 +00:00
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
|
2010-07-07 17:40:50 +00:00
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2010-08-05 19:00:57 +00:00
|
|
|
NSString * word_ = toString(word);
|
2010-07-07 17:40:50 +00:00
|
|
|
|
2010-08-05 20:10:40 +00:00
|
|
|
if ([NSSpellChecker instancesRespondToSelector:@selector(learnWord:)])
|
2010-07-11 21:30:47 +00:00
|
|
|
[speller->checker learnWord:word_];
|
2010-07-07 17:40:50 +00:00
|
|
|
|
|
|
|
[word_ release];
|
|
|
|
[pool release];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
void AppleSpeller_unlearn(AppleSpeller speller, const char * word)
|
2010-08-05 20:10:40 +00:00
|
|
|
{
|
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
NSString * word_ = toString(word);
|
|
|
|
|
|
|
|
if ([NSSpellChecker instancesRespondToSelector:@selector(unlearnWord:)])
|
|
|
|
[speller->checker unlearnWord:word_];
|
|
|
|
|
|
|
|
[word_ release];
|
|
|
|
[pool release];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
int AppleSpeller_numMisspelledWords(AppleSpeller speller)
|
2010-07-07 17:40:50 +00:00
|
|
|
{
|
2010-08-22 13:55:28 +00:00
|
|
|
return [speller->misspelled count];
|
|
|
|
}
|
2010-07-07 17:40:50 +00:00
|
|
|
|
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
void AppleSpeller_misspelledWord(AppleSpeller speller, int index, int * start, int * length)
|
2010-08-22 13:55:28 +00:00
|
|
|
{
|
2011-02-20 11:12:35 +00:00
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
|
2010-12-16 07:58:38 +00:00
|
|
|
NSRange range = [[speller->misspelled objectAtIndex:(NSUInteger)index] rangeValue];
|
2011-02-20 11:12:35 +00:00
|
|
|
#else
|
|
|
|
NSRange range = [[speller->misspelled objectAtIndex:index] rangeValue];
|
|
|
|
#endif
|
2010-08-22 13:55:28 +00:00
|
|
|
*start = range.location;
|
|
|
|
*length = range.length;
|
|
|
|
}
|
2010-07-07 17:40:50 +00:00
|
|
|
|
2010-08-22 13:55:28 +00:00
|
|
|
|
2010-09-04 07:48:15 +00:00
|
|
|
int AppleSpeller_hasLanguage(AppleSpeller speller, const char * lang)
|
2010-08-22 13:55:28 +00:00
|
|
|
{
|
|
|
|
return toLanguage(speller, lang) != nil;
|
2010-07-07 17:40:50 +00:00
|
|
|
}
|