Dear Mr. Davidson / to whom it may concern:

Just had a little time to work on the project/problem (hope I'm not the only one) and found out that:
Steps to reproduce pt. 16 and Actual Results pt. 4 should sound now:
4) If the "new" method introduced in 10.6 – spellServer:checkString:offset:types:options:orthography:wordCount: is called instead of "old" one – spellServer:findMisspelledWordInString:language:wordCount:countOnly: then suggestions for completions (- spellServer:suggestGuessesForWord:word inLanguage:) IS NOT called when right-clicking misspelled word. Suggestions however show up in how Spelling and Grammar panel. => HOWEVER This is valid to only some applications (tested on 4 Apple apps)
I.e.,
In Apple provided TextEdit.app, Stickies.app the behaviour is as described above. Thus meaning that error is in "client side" (NSSpellChecker implementation in those apps). In Mail.app and Safari.app the suggestions are delivered on ctrl+click even when only spellServer:checkString:offset:types:options:orthography:wordCount: is implemented leaving "old method" out.

Resumē:
Yes, the old method should be fully implemented anyway, as such relatively wide used apps as OOo3, NeoO3 that takes advance of syswide spellcheck, are calling old method. Just want to point out the inconsistency of Apple apps in 10.6., where the behaviour cannot be expected/predicted. Developing a spellserver for osx means primary verifying that it works on systems bundled software!, then iwork, iweb packages and then 3rd parties, and doing so by following sdk documentation. As it seems, somebody doesn't follow sdk documentation that has been written by "himself"... Exactly this point of the story is the most frustrating.

Should I file bugreports against TextEdit, Stickies and who-nows-how- more osx bundled apps? I understand that ~90% of osx users doesn't have any relevance to this topic - there is no bug - as they belong to the group of ApleSpell.service registred languages (my guess). The other 9% are using probably OpenSpell on 10.6 now and do not cry that automatic language option is not working (yet). The left 1% will be affected by those couple custom spellchecker developers for osx out there, that are/will face the issues. Before 10.6. (10.4&5) custom spellserver was the only way for Latvian a.o. languages; now in 10.6. I'm willing to extend it with numerous features, that again would bring better and more specific solution for the language than OSX provided "out of box" OpenSpell... please, allow me. :))

Many thanks in advance,
Reinis Adovics


On 09.10.2009., at 17:38, MacProjects wrote:

Just submitted in bug reporter.

Bug ID# 7290111

Problem Report Title: NSSpellServer: OSX 10.6. Error in automatic language detection.
Product: Mac OSX
Version/Build Number: 10B504
Classification: Serious Bug
Is It Reproducible?: Always

NSSpellServer: OSX 10.6. Error in automatic language detection for any 3rd party spellcheck including OpenSpell

Summary:
After creating a new spelling checker (service) that’s available to any application and adding it to "Automatic by language" setup in System Preferences 1) NSSpellServer fails to use this spellchecker (registered language (s)) when "Automatic by language" spelling is used. 2) When spelling with "Automatic by language" option NSSpellServer calls only some of the necessary methods to the service. 3) Spellcheck is run only after user selects its registered language in an applications Spelling options, then user has to switch back for "Automatic by language". 4) Implementing – spellServer:checkString:offset:types:options:orthography:wordCount: invokes unexpected behaviour when right-clicking misspelled word.

Steps to Reproduce:
// Any custom spellcheck
1) Set in System Preferences : Language & Text spelling to "Automatic by language"
2) Write, build and install a new spellcheck under /Library/Servces
4) Login/out (update dynamic services) for the new service to register. 5) Set the newly registered language delivered by the spell check as one of the languages for "Automatic by language" in System Preferences : Language & Text setup list. 6) Open any application that makes use of NSSpellChecker, i.e., TextEdit.
7) Write partly correct, partly incorrect text in the new language.
8) Try to spellcheck it. It fails to suggest words in intended language. 9) Look for spellcheck service in currently running processes. It isn't listed. But it should be run automatically as the registered language (service) is set in "Automatic by language" list in system preferences meaning OSX is providing user ability to check for custom languages/spellchecks that are added to "automatic" list. 10) Open up applications (TextEdit) Edit : Spelling and Grammar : Show Spelling and Grammar panel.
11) Select the newly registered language in languages list.
12) $ top or Activity Monitor reports that service is finally run.
13) Check text (write it partly correct, partly incorrect) in TextEdit for spelling issues.
14) Misspelled words are underlined.
15) Suggestions for partial world are shown correctly.
16) If spellcheck service (NSSpellServerDelegate) implements method
a) only – spellServer:findMisspelledWordInString:language:wordCount:countOnly:
• right-clicking misspelled word gives a list of possible corrections;
• Show Spelling and Grammar panel gives a list of possible corrections; b) both – spellServer:findMisspelledWordInString:language:wordCount:countOnly: and – spellServer:checkString:offset:types:options:orthography:wordCount:
• right-clicking misspelled word gives a list of possible corrections;
• Show Spelling and Grammar panel gives a list of possible corrections; c) only – spellServer:checkString:offset:types:options:orthography:wordCount: • right-clicking misspelled word DOESN'T give a list of possible corrections; • Show Spelling and Grammar panel gives a list of possible corrections; 17) Return to Show Spelling and Grammar panel and select "Automatic by language" in languages list. 18) Try to check for multiple languages (including the new one) that are set in Language & Text "Automatic by language" list. 19) The words in the new language are underlined as incorrect, as if application (NSSpellServer) couldn't detect the right language. 20) Debugging/ logging the new spellcheck service shows that neither spellServer:findMisspelledWordInString:language:wordCount:countOnly: or – spellServer:checkString:offset:types:options:orthography:wordCount: methods are called to NSSpellServer delegate at this point. 20) Right-click (or using Spelling and Grammar panel) for possible corrections for words (both - correct and incorrect ones, it doesn't matter as all are underlined) written in the new language. 21) The corrections that show up are supplied by the right spellcheck service - the new one 22) Debugging/ logging the new spellcheck service shows that – spellServer:suggestGuessesForWord:inLanguage: method IS called to NSSpellServer delegate at this point. 20) Press esc key for possible completions for words (both - correct and incorrect ones, it doesn't matter as all are underlined) written in the new language. 21) The completions that show up are supplied by the right spellcheck service - the new one 22) Debugging/ logging the new spellcheck service shows that – spellServer:suggestCompletionsForPartialWordRange:inString:language: method IS called to NSSpellServer delegate at this point.

---
// OpenSpell.service
23) Download a dic and aff file for some hunspell dictionary
24) Put it under ~/Library/Spelling
25) Set the new hunspell language (which is accordingly registered by OpenSpell.servce delivered by Apple) as one of the languages for "Automatic by language" in System Preferences : Language & Text setup list. 26) Repeat steps 6 - 16. OpenSpell also doesn't automatically launch itself in "Automatic by language" situation, even when its delegated languages are put in "Automatic by language" setup list, as well as it fails to bring usability in "Automatic by language" situation in general.

Expected Results:
After installing spelling checker in system and setting its registered language(s) as one for "Automatic by language" 1) spell checker service should launch (if not) on opening any application that makes use of NSSpellChecker so that user instantly could check spelling for mix of languages 2) NSSpellServer should completely detect what language is used, meaning, it correctly underlines misspelled words, gives completions, suggestions. 2) user should be able to check spelling, get suggestions, completions a.o. expected results when using spellcheck.

Actual Results:
See together with Steps to Reproduce
After installing spelling checker in system and setting its registered language(s) as one for "Automatic by language" 1) spell checker service did not launch on opening any application that makes use of NSSpellChecker. User has to go to Show Spelling and Grammar panel, select desired language so that service launches, then again select "Automatic by language". 2) In "Automatic by language" environment even correct words for the new language are underlined as – spellServer:findMisspelledWordInString:language:wordCount:countOnly: or – spellServer:checkString:offset:types:options:orthography:wordCount: are not called, NSSpellServer fails to address the right service. 3) However clicking those underlined words suggestions, completions are provided from the right spelling checker, that is, NSSpellServer addresses the right service. 4) If the "new" method introduced in 10.6 – spellServer:checkString:offset:types:options:orthography:wordCount: is called instead of "old" one – spellServer:findMisspelledWordInString:language:wordCount:countOnly: then suggestions for completions (- spellServer:suggestGuessesForWord:word inLanguage:) IS NOT called when right-clicking misspelled word. Suggestions however show up in how Spelling and Grammar panel. 5) That means that the developer that "must" include - spellServer:suggestGuessesForWord:word inLanguage: method to bring this f-ction to users cannot use the "new" method! That could be avoided in future by altering – spellServer:checkString:offset:types:options:orthography:wordCount: The return for this method could hold an NSTextCheckingResult by some type "a la" NSTextCheckingTypeSuggestions which could have constructor + (NSTextCheckingResult *)spellCheckingResultWithRange:(NSRange) range forSuggestions:(NSArray *)suggestions

Regression:
Tested on multiple macs (including intel core duo, intel core 2 duo, macbook, macbookpro, imac) running OSX 10.6.1. both after clean install and upgrade install from 10.6.
Spell checker built for OS 10.6.x only, using 10.6 SDK.

Notes:
Adding source for FooSpellChecker.source that registers Latvian language with dictionary ("hard coded") containing several words to reproduce the behaviour described above

////////////////////////
// main.m
////////////////////////

#import <Foundation/Foundation.h>
#import "FooSpellCheck.h"

int main()
{
        NSAutoreleasePool *autoreleasepool= [[NSAutoreleasePool alloc] init];
NSSpellServer *mySpellServer = [[[NSSpellServer alloc] init] autorelease];
        NSLog(@"New NSSpellServer instance starting.\n");
if ([mySpellServer registerLanguage:@"lv" byVendor:@"Apple"]) // Vendor (and key for NSSpellChecker in info.plist) "Whatever" can be used, don't help solving problem {
                NSLog(@"Latvian language registred.\n");
[mySpellServer setDelegate:[[[FooSpellCheckClass alloc] init] autorelease]];
                NSLog(@"Spell server delegate FooSpellCheck allocated.\n");
                [mySpellServer run];
fprintf(stderr, "Unexpected death of spellchecker FooSpellCheck! \n");
        } else {
fprintf(stderr, "NSSpellServer unable to register Latvian language. \n");
        }
        [autoreleasepool release];
        return 0;
}

////////////////////////
// FooSpellCheck.h
////////////////////////

#import <Foundation/Foundation.h>
#import <Foundation/NSSpellServer.h>

@interface FooSpellCheckClass : NSObject <NSSpellServerDelegate> {
        NSArray *wordsAray;
}
- (id <NSSpellServerDelegate>)init;
- (void) dealloc;
// New method: Search for a misspelled word in a given string
- (NSArray *)spellServer:(NSSpellServer *)sender checkString: (NSString *)stringToCheck offset:(NSUInteger)offset types: (NSTextCheckingTypes)checkingTypes options:(NSDictionary *)options orthography:(NSOrthography *)orthography wordCount:(NSInteger *) wordCount;
// Old method: Search for a misspelled word in a given string
- (NSRange)spellServer:(NSSpellServer *)sender findMisspelledWordInString:(NSString *)stringToCheck language: (NSString *)language wordCount:(NSInteger *)wordCount countOnly: (BOOL)countOnly; - (NSArray *)spellServer:(NSSpellServer *)sender suggestCompletionsForPartialWordRange:(NSRange)range inString: (NSString *)string language:(NSString *)language; - (NSArray *)spellServer:(NSSpellServer *)sender suggestGuessesForWord:(NSString *)word inLanguage:(NSString *) language; - (void)spellServer:(NSSpellServer *)sender didLearnWord:(NSString *) word inLanguage:(NSString *)language; - (void)spellServer:(NSSpellServer *)sender didForgetWord:(NSString *)word inLanguage:(NSString *)language;
- (BOOL)isWordCorrect:(NSString *)word;
- (NSRange)spellServer:(NSSpellServer *)sender checkGrammarInString: (NSString *)string language:(NSString *)language details:(NSArray **) outDetails;
@end

////////////////////////
// FooSpellCheck.m
////////////////////////

#import "FooSpellCheck.h"

@implementation FooSpellCheckClass

- (id <NSSpellServerDelegate>)init
{
        self = [super init];
   if ( self ) {
// set up dictionary for the language, array containing all correct Latvian words, to check against wordsAray = [NSArray arrayWithObjects :@"labdien ",@"kaut",@"kad",@"nezinu",@"nepareizs",@"draugs",@"interese",nil];
   }
   return self;
}

- (void) dealloc
{
   [super dealloc];
}

// New method: Search for a misspelled word in a given string
- (NSArray *)spellServer:(NSSpellServer *)sender
                         checkString:(NSString *)stringToCheck
                                  offset:(NSUInteger)offset
                                   types:(NSTextCheckingTypes)checkingTypes
                                 options:(NSDictionary *)options
                         orthography:(NSOrthography *)orthography
                           wordCount:(NSInteger *)wordCount
{
NSLog(@"FooSpellCheck. Unite (10.6. method) called. String to check: %...@\n",stringToCheck); NSScanner *stringToCheckScanner = [NSScanner scannerWithString:stringToCheck]; // create NSScanner object to scan stringToCheck NSCharacterSet *wordCharSet = [NSCharacterSet alphanumericCharacterSet]; // set allowed charsets for words - letters and numbers *wordCount = [[stringToCheck componentsSeparatedByString:@" "] count]; // get number of words in stringToCheck NSMutableArray *returnArray = [NSMutableArray array]; // create return array while (![stringToCheckScanner isAtEnd]) // while scanner is not at end
        {
[stringToCheckScanner scanUpToCharactersFromSet:wordCharSet intoString:nil]; // scans the string until a character from wordCharSet character set is encountered, send accumulating characters into nil if (![stringToCheckScanner isAtEnd]) // if scanner at this point is not at end (or characters from the set to be skipped remaining != TRUE), we have found a word
                {
                        NSString *wordToCheck; //create string object for word
[stringToCheckScanner scanCharactersFromSet:wordCharSet intoString:&wordToCheck]; // scan the stringToCheck as long as characters from wordCharSet are encountered
                        // and accumulate characters into wordToCheck
// if word is in dictionary (wordsAray) or or word is in user dictionary if ([self isWordCorrect:wordToCheck] || ([sender isWordInUserDictionaries:wordToCheck caseSensitive:YES]))
                        {
                                continue;
                        }
                        else
                        {
[returnArray addObject:[NSTextCheckingResult spellCheckingResultWithRange:NSMakeRange(offset + [stringToCheckScanner scanLocation] - [wordToCheck length], [wordToCheck length])]];
                        }
                }
        }
        return returnArray;
}


// Old method: Search for a misspelled word in a given string
- (NSRange)spellServer:(NSSpellServer *)sender findMisspelledWordInString:(NSString *)stringToCheck language: (NSString *)language wordCount:(NSInteger *)wordCount countOnly: (BOOL)countOnly
{
NSLog(@"FooSpellCheck. Old (10.4.,5. method) called. String to check: %...@\n",stringToCheck); NSScanner *stringToCheckScanner = [NSScanner scannerWithString:stringToCheck]; // create NSScanner object to scan stringToCheck NSCharacterSet *wordCharSet = [NSCharacterSet alphanumericCharacterSet]; // set allowed charsets for words - letters and numbers
        if (!countOnly) {  // if !countOnly, then we check spelling
while (![stringToCheckScanner isAtEnd]) // while scanner is not at end
                {
[stringToCheckScanner scanUpToCharactersFromSet:wordCharSet intoString:nil]; // scans the string until a character from wordCharSet character set is encountered, send accumulating characters into nil if (![stringToCheckScanner isAtEnd]) // if scanner at this point is not at end (or characters from the set to be skipped remaining != TRUE), we have found a word
                        {
                                NSString *wordToCheck; //create string object 
for word
[stringToCheckScanner scanCharactersFromSet:wordCharSet intoString:&wordToCheck]; // scan the stringToCheck as long as characters from wordCharSet are encountered
                                // and accumulate characters into wordToCheck
// if word is in dictionary (wordsAray) or or word is in user dictionary if ([self isWordCorrect:wordToCheck] || ([sender isWordInUserDictionaries:wordToCheck caseSensitive:YES]))
                                {
                                        continue;
                                }
                                else
                                {
return NSMakeRange ([stringToCheckScanner scanLocation] - [wordToCheck length], [wordToCheck length]);
                                }
                        }
                }
        }
        else
        { // else we count only the words in the string object
if (wordCount) *wordCount = [[stringToCheck componentsSeparatedByString:@" "] count]; // get number of words in stringToCheck
        }
return NSMakeRange (NSNotFound, 0); // if our scanner failed to return range, then simply return {0,0} range
}


// Possible word completions, based on a partially completed string
- (NSArray *)spellServer:(NSSpellServer *)sender suggestCompletionsForPartialWordRange:(NSRange)range inString: (NSString *)string language:(NSString *)language
{
NSLog(@"FooSpellCheck. Word completions asked for: %...@\n",[string substringWithRange:range]);
        // Return a simple array
return [NSArray arrayWithObjects:@"completion1", @"completion2", @"completion3", @"completion3", nil];
}

// Suggest guesses for the correct spelling of the given misspelled word - (NSArray *)spellServer:(NSSpellServer *)sender suggestGuessesForWord:(NSString *)word inLanguage:(NSString *)language
{
        NSLog(@"FooSpellCheck. Word suggestions asked for: %...@\n",word);
        // Return a simple array
return [NSArray arrayWithObjects:@"suggestion1", @"suggestion2", @"suggestion3", @"suggestion4", nil];
}


// User has added the specified word to the user’s list of acceptable words in the specified language. - (void)spellServer:(NSSpellServer *)sender didLearnWord:(NSString *) word inLanguage:(NSString *)language
{
        // do nothing
}

// User has removed the specified word from the user’s list of acceptable words in the specified language - (void)spellServer:(NSSpellServer *)sender didForgetWord:(NSString *)word inLanguage:(NSString *)language
{
        // do nothing
}

// Search for a grammar in a given string
- (NSRange)spellServer:(NSSpellServer *)sender checkGrammarInString: (NSString *)string language:(NSString *)language details:(NSArray **) outDetails
{
        // no gramatical issues found
        NSArray* myGrammaticalIssues = [NSArray array];
        *outDetails = myGrammaticalIssues;
        return NSMakeRange (NSNotFound, 0);
}

- (BOOL)isWordCorrect:(NSString *)word
{
        for(unsigned int i=0;i<[wordsAray count];i++) {
if ([[wordsAray objectAtIndex:i] caseInsensitiveCompare:word] == (NSComparisonResult)NSOrderedSame)
                        return TRUE;            
        }
        return FALSE;
}

@end

////////////////////////
// Info.plist
////////////////////////

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd ">
<plist version="1.0">
<dict>
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <key>CFBundleExecutable</key>
        <string>FooSpellCheck</string>
        <key>CFBundleGetInfoString</key>
        <string>FooSpellCheck</string>
        <key>CFBundleIconFile</key>
        <string></string>
        <key>CFBundleIdentifier</key>
        <string>my.company.FooSpellCheck</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundleName</key>
        <string>FooSpellCheck</string>
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
        <string>3.0</string>
        <key>CFBundleSignature</key>
        <string>krko</string>
        <key>CFBundleVersion</key>
        <string>3.0</string>
        <key>LSBackgroundOnly</key>
        <true/>
        <key>NSPrincipalClass</key>
        <string>FooSpellCheckClass</string>
        <key>NSServices</key>
        <array>
                <dict>
                        <key>NSExecutable</key>
                        <string>FooSpellCheck</string>
                        <key>NSLanguages</key>
                        <array>
                                <string>lv</string>
                        </array>
                        <key>NSPortName</key>
                        <string>FooSpellCheck</string>
                        <key>NSSpellChecker</key>
                        <string>Apple</string>
                </dict>
        </array>
</dict>
</plist>


///////////

Attaching source files in zip file.

Regards and hoping for the best,
Reinis Adovics



On 09.10.2009., at 06:35, Douglas Davidson wrote:

File a bug against NSSpellChecker and we will look into it.

Douglas Davidson


On Oct 8, 2009, at 1:35 PM, MacProjects <m...@krokoarch.lv> wrote:

Hello!

I'm maintaining system-wide Latvian spell checker for ~ 2 years. It works as intended on 10.4 and 10.5. Just made a dummy spellcheck for 10.6. checking out the new SDK. Works great... ...except for the (only) new "Automatic by Language" option introduced in 10.6.

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/mac%40krokoarch.lv

This email sent to m...@krokoarch.lv

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to