Using Dictionary.app’s thesaurus function programmatically on OSX (preferably via Ruby) Using Dictionary.app’s thesaurus function programmatically on OSX (preferably via Ruby) ruby ruby

Using Dictionary.app’s thesaurus function programmatically on OSX (preferably via Ruby)


Unfortunately the only programmatic interface to this (Dictionary Services) doesn't support setting a dictionary.

However, it does consult the dictionary preferences to use the first dictionary specified, so you could potentially, in very ugly fashion, reset the preferences so the thesaurus is the only dictionary available.

This is really disgusting and likely to break if breathed upon, but it should work:

/* compile with:   gcc -o thesaurus -framework CoreServices -framework Foundation thesaurus.m*/#import <Foundation/Foundation.h>#include <CoreServices/CoreServices.h>int main(int argc, char *argv[]) {  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];  NSMutableDictionary *dictionaryPrefs =    [[userDefaults persistentDomainForName:@"com.apple.DictionaryServices"] mutableCopy];  NSArray *activeDictionaries = [dictionaryPrefs objectForKey:@"DCSActiveDictionaries"];  [dictionaryPrefs setObject:    [NSArray arrayWithObject:@"/Library/Dictionaries/Oxford American Writer's Thesaurus.dictionary"]                      forKey:@"DCSActiveDictionaries"];  [userDefaults setPersistentDomain:dictionaryPrefs forName:@"com.apple.DictionaryServices"];  NSString *word = [NSString stringWithUTF8String:argv[1]];  puts([(NSString *)DCSCopyTextDefinition(NULL, (CFStringRef)word,                                          CFRangeMake(0, [word length])) UTF8String]);  [dictionaryPrefs setObject:activeDictionaries forKey: @"DCSActiveDictionaries"];  [userDefaults setPersistentDomain:dictionaryPrefs forName:@"com.apple.DictionaryServices"];}

And use it as:

% ./thesaurus stringnoun 1 twine, cord, yarn, thread, strand.2 chain, group, firm, company.3 series, succession, chain, sequence, run, streak.4 line, train, procession, queue, file, column, convoy, cavalcade.[...]


I've updated the code to work for 10.7 & 10.8. All credit to Nicholas Riley; I wouldn't have been able to write it without him!

I've modified it slightly to allow you to choose the Dictionary for the lookup, use it like: $dictionary $PATH_TO_DICT $word

#import <Foundation/Foundation.h>#include <CoreServices/CoreServices.h>NSUserDefaults* GetUserDefaults() {  return [NSUserDefaults standardUserDefaults];}NSMutableDictionary* GetGlobalDomain() {  NSUserDefaults *userDefaults = GetUserDefaults();  NSMutableDictionary *dictionaryPrefs =    [[userDefaults persistentDomainForName:@"Apple Global Domain"] mutableCopy];  return dictionaryPrefs;}NSMutableDictionary* GetDictionaryPreferences() {   return [[GetGlobalDomain() objectForKey:@"com.apple.DictionaryServices"] mutableCopy];}NSArray* GetCurrentDictionaryList() {  return [GetDictionaryPreferences() objectForKey:@"DCSActiveDictionaries"];}void SetUserDictPreferences(NSArray* array) {  NSMutableDictionary *currentPref = GetDictionaryPreferences();  [currentPref setObject:array forKey:@"DCSActiveDictionaries"];  NSDictionary *immutPref = [NSDictionary dictionaryWithDictionary:currentPref];  NSMutableDictionary *g = GetGlobalDomain();  [g setObject:immutPref forKey:@"com.apple.DictionaryServices"];  NSUserDefaults *defaults = GetUserDefaults();  [defaults setPersistentDomain:g forName:@"Apple Global Domain"];}int main(int argc, char *argv[]) {  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  NSArray *currentPrefs = GetCurrentDictionaryList();  NSString *dict = [NSString stringWithUTF8String:argv[1]];  NSString *word = [NSString stringWithUTF8String:argv[2]];  SetUserDictPreferences([NSArray arrayWithObject:dict]);  puts([(NSString *)DCSCopyTextDefinition(NULL, (CFStringRef)word,                                          CFRangeMake(0, [word length])) UTF8String]);  SetUserDictPreferences(currentPrefs);}