xuchunyang / osx-dictionary.el

Mac OS X Dictionary.app interface for Emacs
138 stars 23 forks source link

Re-enable support for custom dictionaries on OS X Sierra #17

Open ylluminarious opened 7 years ago

ylluminarious commented 7 years ago

As evidenced by #12, Sierra broke some things with its new Dictionary API. The critical error documented therein was resolved via this commit: https://github.com/xuchunyang/osx-dictionary.el/commit/5b4ab15892b6a3d49ebbaa8a64a9e0ccc201fa71. However, said commit removes support for custom dictionaries and also the thesaurus. I may have part of a solution to bring back support for both of these, which is something that I (and probably many others) would enjoy having support for.

I tried out this answer on StackOverflow, which is about programatic support for accessing the OS X thesaurus, and despite its age, it seems to still work. I saved the given code as 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 compiled with:

$ gcc -o thesaurus -framework CoreServices -framework Foundation thesaurus.m

And then I used it like so:

$ ./thesaurus test
test ▶noun 1 a series of scientific tests: trial, experiment, test case, case study, pilot study, trial run, tryout, dry run; check, e
xamination, assessment, evaluation, appraisal, investigation, inspection, analysis, scrutiny, study, probe, exploration; screening, wo
rkup; technical assay. 2 candidates may be required to take a test: exam, examination, quiz.▶verb 1 a small-scale prototype was tested
: try out, put to the test, put through its paces, experiment with, pilot; check, examine, assess, evaluate, appraise, investigate, an
alyze, scrutinize, study, probe, explore, trial; sample; screen; technical assay. 2 such behavior would test any marriage: put a strai
n on, strain, tax, try; make demands on, stretch, challenge.                                                                         

$ ./thesaurus string
string ▶noun 1 a knotted piece of string: twine, cord, yarn, thread, strand. 2 a string of convenience stores: chain, group, firm, com
pany. 3 a string of convictions: series, succession, chain, sequence, run, streak. 4 a string of wagons: line, train, procession, queu
e, file, column, convoy, cavalcade. 5 a string of pearls: strand, rope, necklace. 6 a guaranteed loan with no strings: condition, qual
ification, provision, proviso, caveat, stipulation, rider, prerequisite, limitation, limit, constraint, restriction; informal catch.▶v
erb 1 lights were strung across the promenade: hang, suspend, sling, stretch, run; thread, loop, festoon. 2 beads strung on a silver c
hain: thread, loop, link.PHRASES string along 1 must your sister always string along? go along, come too, accompany someone, join some
one. 2 I think Daisy is just stringing poor Dave along: mislead, deceive, take advantage of, dupe, hoax, fool, make a fool of, play wi
th, toy with, dally with, trifle with; informal lead up the garden path, take for a ride. string out 1 stringing out a story: spin out
, drag out, lengthen. 2 airfields strung out along the Gulf: spread out, space out, distribute, scatter. string up informal Dawes and 
his boys went after Lucius, threatening to string him up: hang, lynch, gibbet.                                                       

$ system_profiler SPSoftwareDataType
Software:

    System Software Overview:

      System Version: macOS 10.12.4 (16E191a)
      Kernel Version: Darwin 16.5.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
      Computer Name: [REDACTED]
      User Name: [REDACTED]
      Secure Virtual Memory: Enabled
      System Integrity Protection: Disabled
      Time since boot: [REDACTED]

$ 

As you can see, this new code seems to work fine on Sierra, aside from the text output being somewhat messy (which is actually unimportant). To explain what this code basically does (as I understand it): it sets the user's main dictionary preference to the thesaurus and then retrieves some data from it and writes it out to the stdout. The important part here is that it sets the user's main dictionary to whatever is specified (in this case, the thesaurus).

Keep in mind that this change propagates across the whole system, so anything that uses the dictionary will be affected, including osx-dictionary.el. I actually tested it out and this change also works with osx-dictionary.el as I was able to get thesaurus output for a given query. The only problem was that I had to reset my dictionary preferences in Dictionary.app > Dictionary > Preferences.... If this solution is implemented, the user's preferences ought to be restored after the query to the desired dictionary is complete.

I personally lack the necessary skills to implement these changes, but I presume that you can, @xuchunyang. These changes would certainly be appreciated by myself, along with many others.

Thanks.

jxy commented 6 years ago

Would you guys consider separating the objC bits to a separate package that just do one thing: looking up argv[1] and send result to stdout, for either dictionary or thesaurus?