Copyright ©1995 by NeXT Computer, Inc.  All Rights Reserved.

NXSpellServer

Inherits From: Object
Declared In: appkit/NXSpellServer.h

The NXSpellServer class gives you a way to make your particular spelling checker a service that's available to any application. A service is an application that declares its availability in a standard way, so that any other applications that wish to use it can do so.  (See the discussion of "Services" under "Other Features," later in this chapter.)

The spelling checker bundled with NEXTSTEP makes itself available in this way.  If you build a spelling checker that makes use of the NXSpellServer class and list it as an available service, then users of any application that makes use of NXSpellChecker or includes a Services menu will see your spelling checker as one of the available dictionaries, along with the one provided by NeXT.

To make use of NXSpellServer, you write a small program that creates an NXSpellServer instance and a delegate that responds to messages asking it to find a misspelled word and to suggest guesses for a misspelled word.  Send the NXSpellServer registerLanguage: messages to tell it the languages your delegate can handle.

The program that runs your spelling checker should not be built as an Application Kit application, but as a simple program. Suppose you supply spelling checkers under the vendor name "Acme."  Suppose the file containing the code for your delegate is called AcmeEnglishSpellChecker.  Then the following might be your program's main:

void main()
{
NXSpellServer *aServer = [[NXSpellServer alloc] init];
if ([aServer registerLanguage:"English" byVendor:"Acme"]) {
[aServer setDelegate:[AcmeEnglishSpellChecker new]];
[aServer run];
fprintf(stderr, "Unexpected death of Acme SpellChecker!\n");
} else {
fprintf(stderr, "Unable to check in Acme SpellChecker.\n");
}
}

Your delegate is an instance of a custom subclass.  (It's simplest to make it a subclass of Object, but that's not a requirement.) Given a text stream, your delegate must be able to find a misspelled word by implementing the method spellServer:findMisspelledWord:length:inLanguage:inTextStream:startingAt:wordCount:countOnly:.  Usually, this method also reports the number of words it has scanned, but that isn't mandatory.

Optionally, the delegate may also suggest corrections for misspelled words.  It does so by implementing the method spellServer:suggestGuessesForWord:inLanguage:



Service Availability Notice

When there's more than one spelling checker available, the user selects the one desired.  The application that requests a spelling check uses an NXSpellChecker object, and it provides a Spelling Panel; in the panel there's a pop-up list of available spelling checkers.  Your spelling checker appears in that list if it has a service descriptor.

A service descriptor is an entry in a text file called services.  Usually it's located within the bundle that also contains your spelling checker's executable file.  The bundle (or directory) that contains the services file must have a name ending in ".service" or ".app".  The system looks for service bundles in the directories ~/Apps/LocalApps, and /NextApps.

A service availability notice has a standard format, illustrated in the following example for the Acme spelling checker:

Spell Checker:  Acme
Language:  French
Language:  English
Executable:  franglais.daemon

The first line identifies the type of service; for a spelling checker, it must say "Spell Checker:" followed by your vendor name. The next line contains the English name of a language your spelling checker is prepared to check.  The language should be one of those registered with NeXT Developer Support.   If your program can check more than one language, use an additional line for each additional language.  The last line of a descriptor gives the name of the service's executable file.  (It requires a complete path if it's in a different directory.)

When there's a service descriptor for your Acme spelling checker and also a service descriptor for the checker provided with NEXTSTEP, a user looking at the Spelling Panel's pop-up list would see:

English (Acme)
English (NeXT)
French (Acme)


Illustrative Sequence of Messages to an NXSpellServer

The act of checking spelling usually involves the interplay of objects in two classes: the user application's NXSpellChecker (which responds to interactions with the user) and your spelling checker's NXSpellServer (which provides the application interface for your spelling checker).  You can see the interaction between the two in the following list of steps involved in finding a misspelled word.

The user of an application selects a menu item to request a spelling check.  The application sends a message to its NXSpellChecker object.  The NXSpellChecker in turn sends a corresponding message to the appropriate NXSpellServer.
The NXSpellServer receives the message asking it to check the spelling of a text stream.  It forwards the message to its delegate.
The delegate searches for a misspelled word.  If it finds one, it returns YES and identifies the word's location in the text stream.
The NXSpellServer receives a message asking it to suggest guesses for the correct spelling of a misspelled word, and forwards the message to its delegate.
As the delegate finds each possible correction, it sends an addGuess: message to the NXSpellServer, causing it to append each new word to a list of guesses.  When the delegate method returns, the NXSpellServer returns the completed list to the NXSpellChecker that initiated the request.
The NXSpellServer doesn't know what the user does with the errors its delegate has found or with the guesses its delegate has proposed.  (Perhaps the user corrects the document, perhaps by selecting a correction from the NXSpellChecker's display of guesses; but that's outside the NXSpellServer's purview.) However, if the user presses the Learn or Forget buttons (thereby causing the NXSpellChecker to revise the user's word list), the NXSpellServer receives a notification of the word thus learned or forgotten.  It's up to you whether your spell checker acts on this information.  If the user presses the Ignore button, the NXSpellServer is not notified (but the next time that word occurs in the text, the method isInUserDictionary:caseSensitive: will report YES rather than NO).
Once the NXSpellServer delegate has reported a misspelled word, it has completed its search.  Of course, it's likely that the user's application will then send a new message, this time asking the NXSpellServer to check a text stream that is in fact the part of the text it didn't get to earlier.



Method Types

Setting the delegate setDelegate:
delegate
Registering your service registerLanguage:byVendor:
Starting your service run
Checking user dictionaries isInUserDictionary:caseSensitive:
Receiving alternatives addGuess:



Instance Methods



addGuess:
addGuess:(const char *)guess

Appends a word to the list of possible corrections for a misspelled word.  The delegate's implementation of spellServer:suggestGuessesForWord:inLanguage: should invoke this method in order to append each new guess that it finds to the list that the NXSpellServer is compiling.



delegate
delegate

Returns the NXSpellServer's delegate.

See also:  setDelegate:



isInUserDictionary:caseSensitive:
(BOOL)isInUserDictionary:(const char *)word caseSensitive:(BOOL)flag

Reports whether a word is in the user's list of learned words, or the document's list of words to ignore.  The first argument is a word to be checked.  The second is YES when the comparison is to be case-sensitive.

Returns YES if the word is acceptable to the user.



registerLanguage:byVendor:
(BOOL)registerLanguage:(const char *)language byVendor:(const char *)vendor

Notifies the NXSpellServer of a language your spelling checker can check.  The argument language is the English name of a language on NeXT's list of languages.  The argument vendor identifies the vendor (to distinguish your spelling checker from those that others may offer for the same language).  If your spelling checker supports more than one language, it should invoke this method once for each language.  Registering a language/vendor combination causes it to appear in the Spelling Panel's pop-up labeled "Dictionary".  Returns YES when the language is registered, NO if for some reason it can't be registered.



run
run

Starts a loop in which the NXSpellServer awaits requests for its services.  This loop normally runs forever.



setDelegate:
setDelegate:anObject

Appoints the object identified in the argument as the delegate of your NXSpellServer.  Since the delegate is where the real work is done, this is an essential step before your program sends the NXSpellServer its run message.  Returns the delegate.

See also:  delegate



Methods Implemented by the Delegate

The real work of checking is done not by the NXSpellServer but by its delegate.  The method sender:findMisspelledWord:... does the actual checking.  The method sender:suggestGuessesForWord:... is optional; if implemented, it supplies a list of possible corrections for a misspelled word.



spellServer:didForgetWord:inLanguage:
(void)spellServer:(NXSpellServer *)sender
didForgetWord:(const char *)word
inLanguage:(const char *)language

Notification to the NXSpellServer's delegate that the user has pressed Forget in an NXSpellChecker's Spelling Panel (and presumably the NXSpellChecker has removed the word from the user's list of acceptable words).  If the delegate maintains a similar auxiliary word list, it may wish to edit its list accordingly.

See also:  spellServer:didLearnWord:inLanguage:



spellServer:didLearnWord:inLanguage:
(void)spellServer:(NXSpellServer *)sender
didLearnWord:(const char *)word
inLanguage:(const char *)language

Notification to the NXSpellServer's delegate that the user has pressed Learn in an NXSpellChecker's Spelling Panel (and presumably the NXSpellChecker has removed the word from the user's list of acceptable words).  If the delegate maintains a similar auxiliary word list, it may wish to edit it accordingly.

See also:  spellServer:didForgetWord:inLanguage:



spellServer:findMisspelledWord:length:inLanguage:
inTextStream:startingAt:wordCount:countOnly:
(BOOL)spellServer:(NXSpellServer *)sender
findMisspelledWord:(int *)start
length:(int *)length
inLanguage:(const char *)language
inTextStream:(id <NXReadOnlyTextStream>)textStream
startingAt:(int)startPosition
wordCount:(int *)number
countOnly:(BOOL)flag

Searches the text stream for a misspelled word.  textStream identifies the text stream to be checked.  startPosition is the offset of the current character.  language identifies the language of the text stream.

start, length, and number are pointers to values that the method will set.  The method identifies a misspelled word by putting its offset in the text stream into start and its length into length.  These values (like startPosition) are the number of characters, which may be less than the offset in bytes if the text stream contains multibyte characters.  The method puts the number of words it has checked into number.  Thus, number will contain the number of words that precede the misspelled word, or the number of words in the entire text end if no word is misspelled.  If for some reason the method is unable to count words, it should set number to 1.

When flag is YES, the method simply counts the words from startingPoint to the end of the text stream, without checking their spelling.

When the method finds a misspelled word, it should then invoke the NXSpellServer's method isInUserDictionary:caseSensitive: to discover whether the word is acceptable to the user or to the document.  It should end its search and return YES only if it has found a word that is not acceptable to either of them.

Returns YES if a misspelled word has been found, and sets start and length to identify the misspelling.  Returns NO if the search reaches the end of the text stream without encountering a misspelled word, or whenever flag is YES.



spellServer:suggestGuessesForWord:inLanguage:
(void)spellServer:(NXSpellServer *)sender
suggestGuessesForWord:(const char *)word
inLanguage:(const char *)language

Searches for words that (by whatever criterion it chooses to adopt) seem possible corrections for the misspelled example it receives as word.  For each candidate that it finds, it sends an addGuess: message to the NXSpellServer object, which takes care of accumulating the suggested words.