3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
11 #import <Cocoa/Cocoa.h>
13 #import <AvailabilityMacros.h>
15 #include "support/AppleSpeller.h"
17 typedef struct AppleSpellerRec {
18 NSSpellChecker * checker;
19 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
24 NSArray * suggestions;
29 AppleSpeller newAppleSpeller(void)
31 AppleSpeller speller = calloc(1, sizeof(AppleSpellerRec));
32 speller->checker = [NSSpellChecker sharedSpellChecker];
33 speller->doctag = [NSSpellChecker uniqueSpellDocumentTag];
34 speller->suggestions = nil;
35 speller->misspelled = nil;
40 void freeAppleSpeller(AppleSpeller speller)
42 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
44 [speller->checker closeSpellDocumentWithTag:speller->doctag];
46 [speller->suggestions release];
47 [speller->misspelled release];
55 static NSString * toString(const char * word)
57 return [[NSString alloc] initWithBytes:word length:strlen(word) encoding:NSUTF8StringEncoding];
61 static NSString * toLanguage(AppleSpeller speller, const char * lang)
63 NSString * result = nil;
64 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
65 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
66 NSString * lang_ = toString(lang);
67 if ([NSSpellChecker instancesRespondToSelector:@selector(availableLanguages)]) {
68 NSArray * languages = [speller->checker availableLanguages];
70 for (NSString *element in languages) {
71 if (0 == [element caseInsensitiveCompare:lang_]) {
74 } else if ([lang_ hasPrefix:element]) {
86 SpellCheckResult AppleSpeller_check(AppleSpeller speller, const char * word, const char * lang)
88 if (!speller->checker || !lang || !word)
89 return SPELL_CHECK_FAILED;
91 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
92 NSString * word_ = toString(word);
93 NSString * lang_ = toString(lang);
94 SpellCheckResult result = SPELL_CHECK_FAILED;
96 int length = [word_ length];
98 [speller->misspelled release];
99 speller->misspelled = nil;
101 while (result == SPELL_CHECK_FAILED && start < length) {
102 NSRange match = [speller->checker
103 checkSpellingOfString:word_
107 inSpellDocumentWithTag:speller->doctag
110 result = match.length == 0 ? SPELL_CHECK_OK : SPELL_CHECK_FAILED;
111 if (result == SPELL_CHECK_OK) {
112 if ([NSSpellChecker instancesRespondToSelector:@selector(hasLearnedWord:)]) {
113 if ([speller->checker hasLearnedWord:word_])
114 result = SPELL_CHECK_LEARNED;
117 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
118 NSUInteger capacity = [speller->misspelled count] + 1;
120 int capacity = [speller->misspelled count] + 1;
122 NSMutableArray * misspelled = [NSMutableArray arrayWithCapacity:capacity];
123 [misspelled addObjectsFromArray:speller->misspelled];
124 [misspelled addObject:[NSValue valueWithRange:match]];
125 [speller->misspelled release];
126 speller->misspelled = [[NSArray arrayWithArray:misspelled] retain];
127 start = match.location + match.length + 1;
135 return [speller->misspelled count] ? SPELL_CHECK_FAILED : result;
139 void AppleSpeller_ignore(AppleSpeller speller, const char * word)
141 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
142 NSString * word_ = toString(word);
144 [speller->checker ignoreWord:word_ inSpellDocumentWithTag:(speller->doctag)];
151 size_t AppleSpeller_makeSuggestion(AppleSpeller speller, const char * word, const char * lang)
153 if (!speller->checker || !word || !lang)
156 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
157 NSString * word_ = toString(word);
158 NSString * lang_ = toString(lang);
161 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
162 // Mac OS X 10.6 only
163 NSInteger slen = [word_ length];
164 NSRange range = { 0, slen };
166 result = [speller->checker guessesForWordRange:range
169 inSpellDocumentWithTag:speller->doctag];
171 [speller->checker setLanguage:lang_];
172 result = [speller->checker guessesForWord:word_];
178 [speller->suggestions release];
179 speller->suggestions = [[NSArray arrayWithArray:result] retain];
182 return [speller->suggestions count];
186 const char * AppleSpeller_getSuggestion(AppleSpeller speller, size_t pos)
188 const char * result = 0;
189 if (pos < [speller->suggestions count]) {
190 result = [[speller->suggestions objectAtIndex:pos] UTF8String] ;
196 void AppleSpeller_learn(AppleSpeller speller, const char * word)
198 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
199 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
200 NSString * word_ = toString(word);
202 if ([NSSpellChecker instancesRespondToSelector:@selector(learnWord:)])
203 [speller->checker learnWord:word_];
211 void AppleSpeller_unlearn(AppleSpeller speller, const char * word)
213 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
214 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
215 NSString * word_ = toString(word);
217 if ([NSSpellChecker instancesRespondToSelector:@selector(unlearnWord:)])
218 [speller->checker unlearnWord:word_];
226 int AppleSpeller_numMisspelledWords(AppleSpeller speller)
228 return [speller->misspelled count];
232 void AppleSpeller_misspelledWord(AppleSpeller speller, int index, int * start, int * length)
234 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
235 NSRange range = [[speller->misspelled objectAtIndex:(NSUInteger)index] rangeValue];
237 NSRange range = [[speller->misspelled objectAtIndex:index] rangeValue];
239 *start = range.location;
240 *length = range.length;
244 int AppleSpeller_hasLanguage(AppleSpeller speller, const char * lang)
246 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
247 return toLanguage(speller, lang) != nil;