mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 06:51:44 +00:00
Extend GSspell server to support multiple languages if aspell has
dictionaries for those languages installed. Note: At present, users or an administrator must manually update the Info.plist file of GSspell.service to really be able to use languages besides American English. Hints for a better solution welcome. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@29683 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4ac6fb3052
commit
692f101ea3
3 changed files with 278 additions and 100 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
|||
2010-02-20 Wolfgang Lux <wolfgang.lux@gmail.com>
|
||||
|
||||
* Tools/GSspell.m: Rewrite to support multiple languages. The
|
||||
spell server at runtime detects aspell's installed dictionaries
|
||||
and publishes each supported language.
|
||||
* Source/NSSpellChecker.m (-_popuplateDictionaryPulldown:): Sort
|
||||
dictionaries in the pop up menu.
|
||||
|
||||
Note: At present, users or an administrator must manually update
|
||||
the Info.plist file of GSspell.service to really be able to use
|
||||
languages besides American English.
|
||||
|
||||
2010-02-20 Wolfgang Lux <wolfgang.lux@gmail.com>
|
||||
|
||||
* Source/NSSpellChecker.m (-awakeFromNib): Set
|
||||
|
|
|
@ -236,7 +236,8 @@ static int __documentTag = 0;
|
|||
- (void)_populateDictionaryPulldown: (NSArray *)dictionaries
|
||||
{
|
||||
[_dictionaryPulldown removeAllItems];
|
||||
[_dictionaryPulldown addItemsWithTitles: dictionaries];
|
||||
[_dictionaryPulldown addItemsWithTitles:
|
||||
[dictionaries sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]];
|
||||
[_dictionaryPulldown selectItemWithTitle: _language];
|
||||
}
|
||||
|
||||
|
|
363
Tools/GSspell.m
363
Tools/GSspell.m
|
@ -3,10 +3,13 @@
|
|||
|
||||
GNUstep spell checker facility.
|
||||
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 2001, 2010 Free Software Foundation, Inc.
|
||||
|
||||
Author: Gregory John Casamento <greg_casamento@yahoo.com>
|
||||
Date: May 2001
|
||||
|
||||
Author: Wolfgang Lux <wolfgang.lux@gmail.com>
|
||||
Date: January 2010
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
|
@ -32,9 +35,10 @@
|
|||
#include "config.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <GNUstepBase/Unicode.h>
|
||||
|
||||
#ifdef HAVE_ASPELL_H
|
||||
#import <GNUstepBase/GSLocale.h>
|
||||
#import <GNUstepBase/Unicode.h>
|
||||
#include <aspell.h>
|
||||
#endif
|
||||
|
||||
|
@ -53,18 +57,205 @@
|
|||
}
|
||||
@end
|
||||
|
||||
|
||||
// The base class. Its spell checker just provides a dumb spell checker
|
||||
// for American English as fallback if aspell is not available.
|
||||
|
||||
@interface GNUSpellChecker : NSObject
|
||||
{
|
||||
#ifdef HAVE_ASPELL_H
|
||||
AspellConfig *config;
|
||||
AspellSpeller *speller;
|
||||
AspellDocumentChecker *checker;
|
||||
#endif
|
||||
}
|
||||
- (BOOL) registerLanguagesWithServer: (NSSpellServer *)aServer;
|
||||
- (NSArray *) languages;
|
||||
@end
|
||||
|
||||
@implementation GNUSpellChecker
|
||||
|
||||
- (BOOL) registerLanguagesWithServer: (NSSpellServer *)aServer
|
||||
{
|
||||
BOOL success = NO;
|
||||
NSEnumerator *langEnum;
|
||||
NSString *language;
|
||||
|
||||
langEnum = [[self languages] objectEnumerator];
|
||||
while ((language = [langEnum nextObject]) != nil)
|
||||
{
|
||||
if ([aServer registerLanguage: language byVendor: @"GNU"])
|
||||
{
|
||||
NSLog(@"Registered spell server for language %@", language);
|
||||
success = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Could not register spell server for language %@", language);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
- (NSArray *) languages
|
||||
{
|
||||
return [NSArray arrayWithObject: @"AmericanEnglish"];
|
||||
}
|
||||
|
||||
- (NSRange) spellServer: (NSSpellServer *)sender
|
||||
findMisspelledWordInString: (NSString *)stringToCheck
|
||||
language: (NSString *)language
|
||||
wordCount: (int *)wordCount
|
||||
countOnly: (BOOL)countOnly
|
||||
{
|
||||
NSRange r = NSMakeRange(0,0);
|
||||
|
||||
if (countOnly)
|
||||
{
|
||||
NSScanner *inputScanner = [NSScanner scannerWithString: stringToCheck];
|
||||
[inputScanner setCharactersToBeSkipped:
|
||||
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
while (![inputScanner isAtEnd])
|
||||
{
|
||||
[inputScanner scanUpToCharactersFromSet:
|
||||
[NSCharacterSet whitespaceAndNewlineCharacterSet]
|
||||
intoString: NULL];
|
||||
(*wordCount)++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"spellServer:findMisspelledWordInString:... invoked, "
|
||||
@"spell server not configured.");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
- (NSArray *) spellServer: (NSSpellServer *)sender
|
||||
suggestGuessesForWord: (NSString *)word
|
||||
inLanguage: (NSString *)language
|
||||
{
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
|
||||
NSLog(@"spellServer:suggestGuessesForWord:... invoked, "
|
||||
@"spell server not configured");
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
- (void) spellServer: (NSSpellServer *)sender
|
||||
didLearnWord: (NSString *)word
|
||||
inLanguage: (NSString *)language
|
||||
{
|
||||
NSLog(@"spellServer:didLearnWord:inLanguage: invoked, "
|
||||
@"spell server not configured");
|
||||
}
|
||||
|
||||
- (void) spellServer: (NSSpellServer *)sender
|
||||
didForgetWord: (NSString *)word
|
||||
inLanguage: (NSString *)language
|
||||
{
|
||||
NSLog(@"spellServer:didForgetWord:inLanguage: invoked, "
|
||||
@"spell server not configured");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#ifdef HAVE_ASPELL_H
|
||||
|
||||
// The real speller checker class provides spelling services for all
|
||||
// languages that aspell has dictionaries installed.
|
||||
|
||||
#define GNU_SPELL_CHECKER_CLASS GNUAspellSpellChecker
|
||||
@interface GNUAspellSpellChecker : GNUSpellChecker
|
||||
{
|
||||
NSDictionary *dictionaries;
|
||||
NSMutableDictionary *spellers, *documentCheckers;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GNUAspellSpellChecker
|
||||
|
||||
static NSDictionary *
|
||||
aspell_dictionaries()
|
||||
{
|
||||
AspellConfig *config;
|
||||
AspellDictInfoList *dictList;
|
||||
AspellDictInfoEnumeration *dictEnum;
|
||||
NSMutableDictionary *dictionaries;
|
||||
|
||||
config = new_aspell_config();
|
||||
dictList = get_aspell_dict_info_list(config);
|
||||
delete_aspell_config(config);
|
||||
|
||||
dictionaries = [[NSMutableDictionary alloc] initWithCapacity: 1];
|
||||
dictEnum = aspell_dict_info_list_elements(dictList);
|
||||
while (!aspell_dict_info_enumeration_at_end(dictEnum))
|
||||
{
|
||||
const AspellDictInfo *dict = aspell_dict_info_enumeration_next(dictEnum);
|
||||
/* The string encoding does not really matter here, since Aspell
|
||||
represents dictionary languages by a two letter ISO 639 language
|
||||
code followed by an optional two letter ISO 3166 country code,
|
||||
all of which are plain ASCII characters.
|
||||
Note that there may be multiple dictionaries for a language,
|
||||
but we are interested only in the supported languages.
|
||||
FIXME How can the user choose a particular dictionary variant
|
||||
from the Spelling panel? */
|
||||
NSString *dictLang = [NSString stringWithUTF8String: dict->code];
|
||||
NSString *language = GSLanguageFromLocale(dictLang);
|
||||
if (!language)
|
||||
language = dictLang;
|
||||
[dictionaries setObject: dictLang forKey: language];
|
||||
}
|
||||
delete_aspell_dict_info_enumeration(dictEnum);
|
||||
|
||||
return dictionaries;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if (![super init])
|
||||
return nil;
|
||||
|
||||
dictionaries = aspell_dictionaries();
|
||||
spellers = [[NSMutableDictionary alloc] initWithCapacity: 1];
|
||||
documentCheckers = [[NSMutableDictionary alloc] initWithCapacity: 1];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *) languages
|
||||
{
|
||||
return [dictionaries allKeys];
|
||||
}
|
||||
|
||||
- (AspellSpeller *) spellerForLanguage: (NSString *)language
|
||||
{
|
||||
AspellSpeller *speller = [[spellers objectForKey: language] pointerValue];
|
||||
if (!speller)
|
||||
{
|
||||
NSString *dictLang = [dictionaries objectForKey: language];
|
||||
if (dictLang)
|
||||
{
|
||||
AspellConfig *config = new_aspell_config();
|
||||
aspell_config_replace(config, "lang", [dictLang UTF8String]);
|
||||
speller = to_aspell_speller(new_aspell_speller(config));
|
||||
[spellers setObject: [NSValue valueWithPointer: speller]
|
||||
forKey: language];
|
||||
}
|
||||
}
|
||||
return speller;
|
||||
}
|
||||
|
||||
- (AspellDocumentChecker *) documentCheckerForLanguage: (NSString *)language
|
||||
{
|
||||
AspellDocumentChecker *checker =
|
||||
[[documentCheckers objectForKey: language] pointerValue];
|
||||
if (!checker)
|
||||
{
|
||||
AspellSpeller *speller = [self spellerForLanguage: language];
|
||||
checker =
|
||||
to_aspell_document_checker(new_aspell_document_checker(speller));
|
||||
[documentCheckers setObject: [NSValue valueWithPointer: checker]
|
||||
forKey: language];
|
||||
}
|
||||
return checker;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
uniLength(unsigned char *buf, unsigned int len)
|
||||
{
|
||||
|
@ -84,122 +275,93 @@ uniLength(unsigned char *buf, unsigned int len)
|
|||
return len;
|
||||
}
|
||||
|
||||
- (NSRange)spellServer:(NSSpellServer *)sender
|
||||
findMisspelledWordInString:(NSString *)stringToCheck
|
||||
language:(NSString *)language
|
||||
wordCount:(int *)wordCount
|
||||
countOnly:(BOOL)countOnly
|
||||
- (NSRange) spellServer: (NSSpellServer *)sender
|
||||
findMisspelledWordInString: (NSString *)stringToCheck
|
||||
language: (NSString *)language
|
||||
wordCount: (int *)wordCount
|
||||
countOnly: (BOOL)countOnly
|
||||
{
|
||||
NSRange r = NSMakeRange(0,0);
|
||||
const char *p;
|
||||
AspellToken token;
|
||||
AspellDocumentChecker *checker;
|
||||
int length;
|
||||
|
||||
#ifdef HAVE_ASPELL_H
|
||||
if (countOnly)
|
||||
{
|
||||
NSScanner *inputScanner = [NSScanner scannerWithString: stringToCheck];
|
||||
[inputScanner setCharactersToBeSkipped: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
while (![inputScanner isAtEnd])
|
||||
{
|
||||
[inputScanner scanUpToCharactersFromSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]
|
||||
intoString: NULL];
|
||||
(*wordCount)++;
|
||||
}
|
||||
return [super spellServer: sender
|
||||
findMisspelledWordInString: stringToCheck
|
||||
language: language
|
||||
wordCount: wordCount
|
||||
countOnly: countOnly];
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *p = [stringToCheck UTF8String];
|
||||
AspellToken token;
|
||||
int length = strlen(p);
|
||||
|
||||
aspell_document_checker_process(checker, p, length);
|
||||
token = aspell_document_checker_next_misspelling(checker);
|
||||
r = NSMakeRange(uniLength((unsigned char *)p, token.offset),
|
||||
uniLength((unsigned char *)p + token.offset, token.len));
|
||||
}
|
||||
#else
|
||||
NSLog(@"spellServer:findMisspelledWordInString:... invoked, spell server not configured.");
|
||||
#endif
|
||||
p = [stringToCheck UTF8String];
|
||||
length = strlen(p);
|
||||
|
||||
checker = [self documentCheckerForLanguage: language];
|
||||
aspell_document_checker_process(checker, p, length);
|
||||
token = aspell_document_checker_next_misspelling(checker);
|
||||
|
||||
return NSMakeRange(uniLength((unsigned char *)p, token.offset),
|
||||
uniLength((unsigned char *)p + token.offset, token.len));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
- (NSArray *)spellServer:(NSSpellServer *)sender
|
||||
suggestGuessesForWord:(NSString *)word
|
||||
inLanguage:(NSString *)language
|
||||
- (NSArray *) spellServer: (NSSpellServer *)sender
|
||||
suggestGuessesForWord: (NSString *)word
|
||||
inLanguage: (NSString *)language
|
||||
{
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
|
||||
#ifdef HAVE_ASPELL_H
|
||||
{
|
||||
const char *p = [word UTF8String];
|
||||
int len = strlen(p);
|
||||
int words = 0;
|
||||
const struct AspellWordList *list = aspell_speller_suggest(speller, p, len);
|
||||
AspellStringEnumeration *en;
|
||||
const char *p = [word UTF8String];
|
||||
int len = strlen(p);
|
||||
int words = 0;
|
||||
AspellSpeller *speller = [self spellerForLanguage: language];
|
||||
const struct AspellWordList *list = aspell_speller_suggest(speller, p, len);
|
||||
AspellStringEnumeration *en;
|
||||
|
||||
words = aspell_word_list_size(list);
|
||||
en = aspell_word_list_elements(list);
|
||||
words = aspell_word_list_size(list);
|
||||
en = aspell_word_list_elements(list);
|
||||
|
||||
// add them to the array.
|
||||
while (!aspell_string_enumeration_at_end(en))
|
||||
{
|
||||
const char *string = aspell_string_enumeration_next(en);
|
||||
NSString *word = [NSString stringWithUTF8String: string];
|
||||
[array addObject: word];
|
||||
}
|
||||
// add them to the array.
|
||||
while (!aspell_string_enumeration_at_end(en))
|
||||
{
|
||||
const char *string = aspell_string_enumeration_next(en);
|
||||
NSString *word = [NSString stringWithUTF8String: string];
|
||||
[array addObject: word];
|
||||
}
|
||||
|
||||
// cleanup.
|
||||
delete_aspell_string_enumeration(en);
|
||||
}
|
||||
#else
|
||||
NSLog(@"spellServer:suggestGuessesForWord:... invoked, spell server not configured");
|
||||
#endif
|
||||
// cleanup.
|
||||
delete_aspell_string_enumeration(en);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
- (void)spellServer:(NSSpellServer *)sender
|
||||
didLearnWord:(NSString *)word
|
||||
inLanguage:(NSString *)language
|
||||
- (void) spellServer: (NSSpellServer *)sender
|
||||
didLearnWord: (NSString *)word
|
||||
inLanguage: (NSString *)language
|
||||
{
|
||||
#ifdef HAVE_ASPELL_H
|
||||
{
|
||||
const char *aword = [word UTF8String];
|
||||
aspell_speller_add_to_personal(speller, aword, strlen(aword));
|
||||
NSLog(@"Not implemented");
|
||||
}
|
||||
#else
|
||||
NSLog(@"spellServer:didLearnWord:inLanguage: invoked, spell server not configured");
|
||||
#endif
|
||||
const char *aword = [word UTF8String];
|
||||
AspellSpeller *speller = [self spellerForLanguage: language];
|
||||
aspell_speller_add_to_personal(speller, aword, strlen(aword));
|
||||
}
|
||||
|
||||
- (void)spellServer:(NSSpellServer *)sender
|
||||
didForgetWord:(NSString *)word
|
||||
inLanguage:(NSString *)language
|
||||
- (void) spellServer: (NSSpellServer *)sender
|
||||
didForgetWord: (NSString *)word
|
||||
inLanguage: (NSString *)language
|
||||
{
|
||||
#ifdef HAVE_ASPELL_H
|
||||
NSLog(@"Not implemented");
|
||||
#else
|
||||
NSLog(@"spellServer:didForgetWord:inLanguage: invoked, spell server not configured");
|
||||
#endif
|
||||
}
|
||||
|
||||
- init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
#ifdef HAVE_ASPELL_H
|
||||
// initialization...
|
||||
config = new_aspell_config();
|
||||
aspell_config_replace(config, "lang", "en_US");
|
||||
speller = to_aspell_speller(new_aspell_speller(config));
|
||||
checker = to_aspell_document_checker(new_aspell_document_checker(speller));
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
// The main program
|
||||
#ifndef GNU_SPELL_CHECKER_CLASS
|
||||
#define GNU_SPELL_CHECKER_CLASS GNUSpellChecker
|
||||
#endif
|
||||
|
||||
#ifdef GNUSTEP
|
||||
int main(int argc, char** argv, char **env)
|
||||
#else
|
||||
|
@ -208,9 +370,12 @@ int main(int argc, char** argv)
|
|||
{
|
||||
CREATE_AUTORELEASE_POOL (_pool);
|
||||
NSSpellServer *aServer = [[NSSpellServer alloc] init];
|
||||
if ([aServer registerLanguage: @"AmericanEnglish" byVendor: @"GNU"]) //&&
|
||||
GNUSpellChecker *aSpellChecker = [[GNU_SPELL_CHECKER_CLASS alloc] init];
|
||||
|
||||
NSLog(@"NSLanguages = %@", [aSpellChecker languages]);
|
||||
if ([aSpellChecker registerLanguagesWithServer: aServer])
|
||||
{
|
||||
[aServer setDelegate: [[GNUSpellChecker alloc] init]];
|
||||
[aServer setDelegate: aSpellChecker];
|
||||
NSLog(@"Spell server started and waiting.");
|
||||
[aServer run];
|
||||
NSLog(@"Unexpected death of spell checker");
|
||||
|
|
Loading…
Reference in a new issue