1/** 2 * \file AppleSpeller.m 3 * This file is part of LyX, the document processor. 4 * Licence details can be found in the file COPYING. 5 * 6 * \author Stephan Witt 7 * 8 * Full author contact details are available in file CREDITS. 9 */ 10 11#import <Cocoa/Cocoa.h> 12 13#import <AvailabilityMacros.h> 14 15#include "support/AppleSpeller.h" 16 17typedef struct AppleSpellerRec { 18 NSSpellChecker * checker; 19#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050) 20 NSInteger doctag; 21#else 22 int doctag; 23#endif 24 NSArray * suggestions; 25 NSArray * misspelled; 26} AppleSpellerRec ; 27 28 29AppleSpeller newAppleSpeller(void) 30{ 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; 36 return speller; 37} 38 39 40void freeAppleSpeller(AppleSpeller speller) 41{ 42 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 43 44 [speller->checker closeSpellDocumentWithTag:speller->doctag]; 45 46 [speller->suggestions release]; 47 [speller->misspelled release]; 48 49 [pool release]; 50 51 free(speller); 52} 53 54 55static NSString * toString(const char * word) 56{ 57 return [[NSString alloc] initWithBytes:word length:strlen(word) encoding:NSUTF8StringEncoding]; 58} 59 60 61static NSString * toLanguage(AppleSpeller speller, const char * lang) 62{ 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]; 69 70 for (NSString *element in languages) { 71 if (0 == [element caseInsensitiveCompare:lang_]) { 72 result = element; 73 break; 74 } else if ([lang_ hasPrefix:element]) { 75 result = element; 76 } 77 } 78 } 79 [lang_ release]; 80 [pool release]; 81#endif 82 return result; 83} 84 85 86SpellCheckResult AppleSpeller_check(AppleSpeller speller, const char * word, const char * lang) 87{ 88 if (!speller->checker || !lang || !word) 89 return SPELL_CHECK_FAILED; 90 91 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 92 NSString * word_ = toString(word); 93 NSString * lang_ = toString(lang); 94 SpellCheckResult result = SPELL_CHECK_FAILED; 95 int start = 0; 96 int length = [word_ length]; 97 98 [speller->misspelled release]; 99 speller->misspelled = nil; 100 101 while (result == SPELL_CHECK_FAILED && start < length) { 102 NSRange match = [speller->checker 103 checkSpellingOfString:word_ 104 startingAt:start 105 language:lang_ 106 wrap:(BOOL)NO 107 inSpellDocumentWithTag:speller->doctag 108 wordCount:NULL]; 109 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; 115 } 116 } else { 117#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050) 118 NSUInteger capacity = [speller->misspelled count] + 1; 119#else 120 int capacity = [speller->misspelled count] + 1; 121#endif 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; 128 } 129 } 130 131 [word_ release]; 132 [lang_ release]; 133 [pool release]; 134 135 return [speller->misspelled count] ? SPELL_CHECK_FAILED : result; 136} 137 138 139void AppleSpeller_ignore(AppleSpeller speller, const char * word) 140{ 141 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 142 NSString * word_ = toString(word); 143 144 [speller->checker ignoreWord:word_ inSpellDocumentWithTag:(speller->doctag)]; 145 146 [word_ release]; 147 [pool release]; 148} 149 150 151size_t AppleSpeller_makeSuggestion(AppleSpeller speller, const char * word, const char * lang) 152{ 153 if (!speller->checker || !word || !lang) 154 return 0; 155 156 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 157 NSString * word_ = toString(word); 158 NSString * lang_ = toString(lang); 159 NSArray * result ; 160 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 }; 165 166 result = [speller->checker guessesForWordRange:range 167 inString:word_ 168 language:lang_ 169 inSpellDocumentWithTag:speller->doctag]; 170#else 171 [speller->checker setLanguage:lang_]; 172 result = [speller->checker guessesForWord:word_]; 173#endif 174 175 [word_ release]; 176 [lang_ release]; 177 178 [speller->suggestions release]; 179 speller->suggestions = [[NSArray arrayWithArray:result] retain]; 180 181 [pool release]; 182 return [speller->suggestions count]; 183} 184 185 186const char * AppleSpeller_getSuggestion(AppleSpeller speller, size_t pos) 187{ 188 const char * result = 0; 189 if (pos < [speller->suggestions count]) { 190 result = [[speller->suggestions objectAtIndex:pos] UTF8String] ; 191 } 192 return result; 193} 194 195 196void AppleSpeller_learn(AppleSpeller speller, const char * word) 197{ 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); 201 202 if ([NSSpellChecker instancesRespondToSelector:@selector(learnWord:)]) 203 [speller->checker learnWord:word_]; 204 205 [word_ release]; 206 [pool release]; 207#endif 208} 209 210 211void AppleSpeller_unlearn(AppleSpeller speller, const char * word) 212{ 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); 216 217 if ([NSSpellChecker instancesRespondToSelector:@selector(unlearnWord:)]) 218 [speller->checker unlearnWord:word_]; 219 220 [word_ release]; 221 [pool release]; 222#endif 223} 224 225 226int AppleSpeller_numMisspelledWords(AppleSpeller speller) 227{ 228 return [speller->misspelled count]; 229} 230 231 232void AppleSpeller_misspelledWord(AppleSpeller speller, int index, int * start, int * length) 233{ 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]; 236#else 237 NSRange range = [[speller->misspelled objectAtIndex:index] rangeValue]; 238#endif 239 *start = range.location; 240 *length = range.length; 241} 242 243 244int AppleSpeller_hasLanguage(AppleSpeller speller, const char * lang) 245{ 246#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050) 247 return toLanguage(speller, lang) != nil; 248#else 249 return true; 250#endif 251} 252