:type 'integer
:group 'ispell)
+;; XXX Add enchant to this list once enchant >= 2.1.0 is widespread.
+;; Before that, adding it is useless, as if it is found, it will just
+;; cause an error; and one of the other spelling engines below is
+;; almost certainly installed in any case, for enchant to use.
(defcustom ispell-program-name
(or (executable-find "aspell")
(executable-find "ispell")
"Non-nil if we can use Aspell extensions.")
(defvar ispell-really-hunspell nil
"Non-nil if we can use Hunspell extensions.")
+(defvar ispell-really-enchant nil
+ "Non-nil if we can use Enchant extensions.")
(defvar ispell-encoding8-command nil
"Command line option prefix to select encoding if supported, nil otherwise.
If setting the encoding is supported by spellchecker and is selectable from
(and (search-forward-regexp
"(but really Hunspell \\([0-9]+\\.[0-9\\.-]+\\)?)"
nil t)
+ (match-string 1)))
+ (setq ispell-really-enchant
+ (and (search-forward-regexp
+ "(but really Enchant \\([0-9]+\\.[0-9\\.-]+\\)?)"
+ nil t)
(match-string 1)))))
(let* ((aspell8-minver "0.60")
(ispell-minver "3.1.12")
(hunspell8-minver "1.1.6")
+ (enchant-minver "2.1.0")
(minver (cond
((not (version<= ispell-minver ispell-program-version))
ispell-minver)
((and ispell-really-aspell
(not (version<= aspell8-minver ispell-really-aspell)))
- aspell8-minver))))
+ aspell8-minver)
+ ((and ispell-really-enchant
+ (not (version<= enchant-minver ispell-really-enchant)))
+ enchant-minver))))
(if minver
(error "%s release %s or greater is required"
(list dict))
ispell-hunspell-dictionary-alist :test #'equal))))
+;; Make ispell.el work better with enchant.
+
+(defvar ispell-enchant-dictionary-alist nil
+ "An alist of parsed Enchant dicts and associated parameters.
+Internal use.")
+
+(defun ispell--call-enchant-lsmod (&rest args)
+ "Call enchant-lsmod with ARGS and return the output as string."
+ (with-output-to-string
+ (with-current-buffer
+ standard-output
+ (apply 'ispell-call-process
+ (concat ispell-program-name "-lsmod") nil t nil args))))
+
+(defun ispell--get-extra-word-characters (&optional lang)
+ "Get the extra word characters for LANG as a character class.
+If LANG is omitted, get the extra word characters for the default language."
+ (concat "[" (string-trim-right (apply 'ispell--call-enchant-lsmod
+ (append '("-word-chars") (if lang `(,lang))))) "]"))
+
+(defun ispell-find-enchant-dictionaries ()
+ "Find Enchant's dictionaries, and record in `ispell-enchant-dictionary-alist'."
+ (let* ((dictionaries
+ (split-string
+ (ispell--call-enchant-lsmod "-list-dicts" (buffer-string)) " ([^)]+)\n"))
+ (found
+ (mapcar #'(lambda (lang)
+ `(,lang "[[:alpha:]]" "[^[:alpha:]]"
+ ,(ispell--get-extra-word-characters) t nil nil utf-8))
+ dictionaries)))
+ ;; Merge into FOUND any elements from the standard ispell-dictionary-base-alist
+ ;; which have no element in FOUND at all.
+ (dolist (dict ispell-dictionary-base-alist)
+ (unless (assoc (car dict) found)
+ (setq found (nconc found (list dict)))))
+ (setq ispell-enchant-dictionary-alist found)
+ ;; Add a default entry
+ (let ((default-dict
+ `(nil "[[:alpha:]]" "[^[:alpha:]]"
+ ,(ispell--get-extra-word-characters)
+ t nil nil utf-8)))
+ (push default-dict ispell-enchant-dictionary-alist))))
+
;; Set params according to the selected spellchecker
(defvar ispell-last-program-name nil
(setq ispell-library-directory (ispell-check-version))
t)
(error nil))
- ispell-encoding8-command)
+ (or ispell-encoding8-command ispell-really-enchant))
;; auto-detection will only be used if spellchecker is not
;; ispell and supports a way to set communication to UTF-8.
(if ispell-really-aspell
(ispell-find-aspell-dictionaries))
(if ispell-really-hunspell
(or ispell-hunspell-dictionary-alist
- (ispell-find-hunspell-dictionaries)))))
+ (ispell-find-hunspell-dictionaries))
+ (if ispell-really-enchant
+ (or ispell-enchant-dictionary-alist
+ (ispell-find-enchant-dictionaries))))))
;; Substitute ispell-dictionary-alist with the list of
;; dictionaries corresponding to the given spellchecker.
- ;; If a recent aspell or hunspell, use the list of really
+ ;; With programs that support it, use the list of really
;; installed dictionaries and add to it elements of the original
;; list that are not present there. Allow distro info.
(let ((found-dicts-alist
ispell-aspell-dictionary-alist
(if ispell-really-hunspell
ispell-hunspell-dictionary-alist))
- nil))
+ (if ispell-really-enchant
+ ispell-enchant-dictionary-alist
+ nil)))
(ispell-dictionary-base-alist ispell-dictionary-base-alist)
ispell-base-dicts-override-alist ; Override only base-dicts-alist
all-dicts-alist)
;; While ispell and aspell (through aliases) use the traditional
- ;; dict naming originally expected by ispell.el, hunspell
- ;; uses locale based names with no alias. We need to map
+ ;; dict naming originally expected by ispell.el, hunspell & Enchant
+ ;; use locale-based names with no alias. We need to map
;; standard names to locale based names to make default dict
- ;; definitions available for hunspell.
- (if ispell-really-hunspell
+ ;; definitions available to these programs.
+ (if (or ispell-really-hunspell ispell-really-enchant)
(let (tmp-dicts-alist)
(dolist (adict ispell-dictionary-base-alist)
(let* ((dict-name (nth 0 adict))
(setq ispell-args
(nconc ispell-args (list "-d" dict-equiv)))
(message
- "ispell-set-spellchecker-params: Missing Hunspell equiv for \"%s\". Skipping."
+ "ispell-set-spellchecker-params: Missing equivalent for \"%s\". Skipping."
dict-name)
(setq skip-dict t)))
(nth 4 adict) ; many-otherchars-p
(nth 5 adict) ; ispell-args
(nth 6 adict) ; extended-character-mode
- (if ispell-encoding8-command
+ (if (or ispell-encoding8-command ispell-really-enchant)
'utf-8
(nth 7 adict)))
adict)
(erase-buffer)))))))
(defun ispell-send-replacement (misspelled replacement)
- "Notify Aspell that MISSPELLED should be spelled REPLACEMENT.
-This allows improving the suggestion list based on actual misspellings."
- (and ispell-really-aspell
+ "Notify spell checker that MISSPELLED should be spelled REPLACEMENT.
+This allows improving the suggestion list based on actual misspellings.
+Only works for Aspell and Enchant."
+ (and (or ispell-really-aspell ispell-really-enchant)
(ispell-send-string (concat "$$ra " misspelled "," replacement "\n"))))