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 if ([NSSpellChecker instancesRespondToSelector:@selector(guessesForWordRange:)]) {
167 result = [speller->checker guessesForWordRange:range
170 inSpellDocumentWithTag:speller->doctag];
172 [speller->checker setLanguage:lang_];
173 result = [speller->checker guessesForWord:word_];
176 [speller->checker setLanguage:lang_];
177 result = [speller->checker guessesForWord:word_];
183 [speller->suggestions release];
184 speller->suggestions = [[NSArray arrayWithArray:result] retain];
187 return [speller->suggestions count];
191 const char * AppleSpeller_getSuggestion(AppleSpeller speller, size_t pos)
193 const char * result = 0;
194 if (pos < [speller->suggestions count]) {
195 result = [[speller->suggestions objectAtIndex:pos] UTF8String] ;
201 void AppleSpeller_learn(AppleSpeller speller, const char * word)
203 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
204 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
205 NSString * word_ = toString(word);
207 if ([NSSpellChecker instancesRespondToSelector:@selector(learnWord:)])
208 [speller->checker learnWord:word_];
216 void AppleSpeller_unlearn(AppleSpeller speller, const char * word)
218 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
219 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
220 NSString * word_ = toString(word);
222 if ([NSSpellChecker instancesRespondToSelector:@selector(unlearnWord:)])
223 [speller->checker unlearnWord:word_];
231 int AppleSpeller_numMisspelledWords(AppleSpeller speller)
233 return [speller->misspelled count];
237 void AppleSpeller_misspelledWord(AppleSpeller speller, int index, int * start, int * length)
239 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
240 NSRange range = [[speller->misspelled objectAtIndex:(NSUInteger)index] rangeValue];
242 NSRange range = [[speller->misspelled objectAtIndex:index] rangeValue];
244 *start = range.location;
245 *length = range.length;
249 int AppleSpeller_hasLanguage(AppleSpeller speller, const char * lang)
251 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
252 return toLanguage(speller, lang) != nil;