1 ;;; external-dict.el --- Query external dictionary like goldendict, Bob.app etc
3 ;; Authors: stardiviner <numbchild@gmail.com>
4 ;; Package-Requires: ((emacs "25.1"))
5 ;; Package-Version: 0.1
6 ;; Keywords: wp processes
7 ;; homepage: https://repo.or.cz/external-dict.el.git
8 ;; SPDX-License-Identifier: GPL-2.0-or-later
10 ;; You should have received a copy of the GNU General Public License
11 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
17 ;; (global-set-key (kbd "C-x d") 'external-dict-dwim)
18 ;; If invoke with [C-u] prefix, then it will raise the main window.
22 (declare-function ns-do-applescript
"nsfns.m" t
)
24 (defgroup external-dict nil
25 "Use external dictionary in Emacs."
26 :prefix
"external-dict-"
29 (defcustom external-dict-cmd
33 ((executable-find "goldendict")
34 '(:dict-program
"goldendict" :command-p t
))))
37 ((file-exists-p "/Applications/Easydict.app")
38 '(:dict-program
"Easydict.app" :command-p nil
))
39 ((file-exists-p "/Applications/Bob.app")
40 '(:dict-program
"Bob.app" :command-p nil
))
41 ((file-exists-p "/Applications/GoldenDict.app")
42 '(:dict-program
"GoldenDict.app" :command-p t
))
43 (t '(:dict-program
"Dictionary.app" :command-p t
)))))
44 "Specify external dictionary command."
46 :group
'external-dict
)
48 (defcustom external-dict-read-cmd
51 (cl-case (plist-get external-dict-cmd
:dict-program
)
55 ((executable-find "festival") "festival")
56 ((executable-find "espeak") "espeak")))))
58 (pcase (plist-get external-dict-cmd
:dict-program
)
60 ("GoldenDict.app" "say")
61 ("Dictionary.app" "say"))))
62 "Specify external tool command to read the query word.
63 If the value is nil, it will let dictionary handle it without invoke the command.
64 If the value is a command string, it will invoke the command to read the word."
68 (defun external-dict--get-text ()
69 "Get word or text from region selected, thing-at-point, or interactive input."
72 (let ((text (buffer-substring-no-properties (mark) (point))))
74 `(:type
:text
:text
,text
)))
75 ((and (thing-at-point 'word
)
76 (not (string-blank-p (substring-no-properties (thing-at-point 'word
)))))
77 (let ((word (substring-no-properties (thing-at-point 'word
))))
78 `(:type
:word
, :text
,word
)))
79 (t (let ((word (read-string "[external-dict.el] Query word: ")))
80 `(:type
:word
:text
,word
)))))
83 (defun external-dict-read-word (word)
84 "Auto pronounce the query word or read the text."
87 (pcase external-dict-read-cmd
89 (shell-command (concat "say " (shell-quote-argument word
))))
91 (shell-command (concat "festival --tts " (shell-quote-argument word
))))
93 (shell-command (concat "espeak " (shell-quote-argument word
))))))
95 ;;; [ macOS Dictionary.app ]
97 (defun external-dict-Dictionary.app
(word)
98 "Query TEXT like current symbol/world at point or region selected or input with macOS Dictionary.app."
102 (buffer-substring-no-properties (mark) (point)))
103 ((not (string-blank-p (substring-no-properties (thing-at-point 'word
))))
104 (substring-no-properties (thing-at-point 'word
)))
105 (t (read-string "[external-dict.el] Query word in macOS Dictionary.app: ")))))
107 (shell-command (format "open dict://\"%s\"" word
))
108 (external-dict-read-word word
))
111 (defun external-dict-goldendict--ensure-running ()
112 "Ensure goldendict program is running."
113 (unless (string-match "goldendict" (shell-command-to-string "ps -C 'goldendict' | sed -n '2p'"))
114 (start-process-shell-command
120 (defun external-dict-goldendict (word)
121 "Query current symbol/word at point or region selected with goldendict.
122 If you invoke command with `RAISE-MAIN-WINDOW' prefix \\<universal-argument>,
123 it will raise external dictionary main window."
124 (interactive (list (plist-get (external-dict--get-text) :text
)))
125 (external-dict-goldendict--ensure-running)
126 (let ((goldendict-cmd (cl-case system-type
127 (gnu/linux
(executable-find "goldendict"))
128 (darwin (or (executable-find "GoldenDict") (executable-find "goldendict")))
129 (t (plist-get external-dict-cmd
:dict-program
)))))
130 (if current-prefix-arg
132 (call-process goldendict-cmd nil nil nil
))
134 ;; pass the selection to shell command goldendict.
135 ;; use Goldendict API: "Scan Popup"
136 (call-process goldendict-cmd nil nil nil word
))
137 (external-dict-read-word word
)
140 ;;; alias for `external-dict-cmd' property `:dict-program' name under macOS.
141 (defalias 'external-dict-GoldenDict.app
'external-dict-goldendict
)
145 (defun external-dict-Bob.app-translate
(text)
146 "Bob.app translate TEXT."
147 (let ((path "translate")
148 (action "translateText")
151 (format "use scripting additions
152 use framework \"Foundation\"
153 on toJson(recordValue)
154 (((current application's NSString)'s alloc)'s initWithData:((current application's NSJSONSerialization)'s dataWithJSONObject:recordValue options:1 |error|:(missing value)) encoding:4) as string
157 set theRecord to {|path|: \"%s\", body: {action: \"%s\", |text|: \"%s\", windowLocation: \"center\", inputBoxState: \"alwaysUnfold\"}}
158 set theParameter to toJson(theRecord)
159 tell application id \"com.hezongyidev.Bob\" to request theParameter
163 (defun external-dict-Bob.app-dictionary
(word)
164 "macOS Bob.app query dictionary for WORD."
167 "tell application \"Bob\"
171 (external-dict-read-word word
))
173 (defun external-dict-Bob.app
()
174 "Translate text with Bob.app on macOS."
176 (let* ((return-plist (external-dict--get-text))
177 (type (plist-get return-plist
:type
))
178 (text (plist-get return-plist
:text
)))
181 (external-dict-Bob.app-dictionary text
))
183 (external-dict-Bob.app-translate text
)))))
185 (defun external-dict-Easydict.app
()
186 "Translate text with Easydict.app on macOS.
187 Easydict.app URL scheme easydict://query?text=good%20girl
188 You can open the URL scheme with shell command:
189 $ open \"easydict://query?text=good%20girl\"
192 (let* ((return-plist (external-dict--get-text))
193 (type (plist-get return-plist
:type
))
194 (text (plist-get return-plist
:text
)))
196 :name
"external-dict-Easydict.app"
197 :command
(list "open" (format "easydict://query?text=%s" (url-encode-url text
))))
198 ;; (external-dict-read-word word)
202 (defun external-dict-dwim ()
203 "Query current symbol/word at point or region selected with external dictionary."
205 (let ((dict-program (plist-get external-dict-cmd
:dict-program
)))
206 (call-interactively (intern (format "external-dict-%s" dict-program
)))))
210 (provide 'external-dict
)
212 ;;; external-dict.el ends here