Skip to content

Instantly share code, notes, and snippets.

@vaiorabbit
Created November 5, 2016 13:26
Show Gist options
  • Save vaiorabbit/69743316138258a2a18f9de8c6dcf526 to your computer and use it in GitHub Desktop.
Save vaiorabbit/69743316138258a2a18f9de8c6dcf526 to your computer and use it in GitHub Desktop.
Returns the definition of given word via Dictionary Services of macOS. (Install Ruby-FFI in advance)
# -*- coding: utf-8 -*-
# Usage : $ macOSDict.rb [word_to_look_up]
require 'ffi'
module MacOSDict
extend FFI::Library
# /System/Library/Frameworks/CoreFoundation.framework/Headers/CFBase.h
class CFRange < FFI::Struct
layout :location, :int64,
:length, :int64
end
KCFStringEncodingUTF8 = 0x08000100
APIEntry = Struct.new( :api_name, :api_args, :api_retval )
def self.load_lib(output_error = true)
libpath = [
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
"/System/Library/Frameworks/CoreServices.framework/Frameworks/DictionaryServices.framework/DictionaryServices",
]
ffi_lib(libpath[0])
ffi_lib(libpath[1])
@@api_signature = [
APIEntry.new( :CFStringGetCStringPtr, [:pointer, :uint32], :pointer ),
APIEntry.new( :CFStringCreateWithCString, [:pointer, :pointer, :uint32], :pointer ),
APIEntry.new( :CFStringGetLength, [:pointer], :int64 ),
APIEntry.new( :CFStringGetBytes, [:pointer], :int64 ),
APIEntry.new( :CFStringGetCharacterAtIndex, [:pointer, :int64], :uint16 ),
APIEntry.new( :CFStringGetCString, [:pointer, :pointer, :int64, :uint32], :uint8 ),
APIEntry.new( :CFStringGetBytes, [:pointer, CFRange.by_value, :uint32, :uint8, :uint8, :pointer, :int64, :pointer], :int64 ),
APIEntry.new( :DCSGetTermRangeInString, [:pointer, :pointer, :int64], CFRange.by_value ),
APIEntry.new( :DCSCopyTextDefinition, [:pointer, :pointer, CFRange.by_value], :pointer ),
]
@@api_signature.each do |sig|
begin
attach_function( sig.api_name, sig.api_args, sig.api_retval )
rescue FFI::NotFoundError
$stderr.puts("[Warning] Failed to import #{sig}.") if output_error
end
end
end
end
include MacOSDict
if __FILE__ == $0
MacOSDict.load_lib()
query = ARGV[0]
term = CFStringCreateWithCString(nil, query, KCFStringEncodingUTF8)
term_range = DCSGetTermRangeInString(nil, term, 0)
def_text = DCSCopyTextDefinition(nil, term, term_range)
if def_text.null? == false
def_range = CFRange.new
def_range[:location] = 0
def_range[:length] = CFStringGetLength(def_text)
usedBufLen = ' ' * 8
CFStringGetBytes(def_text, def_range, KCFStringEncodingUTF8, 0, 1, nil, 0, usedBufLen)
result = ' ' * (usedBufLen.unpack("L")[0] + 1)
CFStringGetCString(def_text, result, result.length, KCFStringEncodingUTF8)
puts result
end
end
# Reference:
# /System/Library/Frameworks/CoreFoundation.framework/Headers/
# - CFBase.h
# - CFString.h
# /System/Library/Frameworks/CoreServices.framework/Frameworks/DictionaryServices.framework/Headers
# - DictionaryServices.h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment