From b00f110f6c4e00bd6af6b9a1e12f0a2e25303998 Mon Sep 17 00:00:00 2001 From: Reuben Thomas Date: Sun, 4 Dec 2016 22:39:27 +0000 Subject: [PATCH 25/25] Add Enchant support to ispell.el MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lisp/textmodes/ispell.el (ispell-program-name): Add “enchant”. (ispell-really-enchant): Add variable. (ispell-check-version): If using Enchant, check it’s new enough (at least 1.6.1). (Like the ispell check, this is absolute: cannot work without.) (ispell-enchant-dictionary-alist): Add variable. (ispell-find-enchant-dictionaries): Add function, based on ispell-find-aspell-dictionaries. (ispell-set-spellchecker-params): Allow dictionary auto-detection for Enchant, and call ispell-find-enchant-dictionaries to find them. Use old ispell name to locale mapping code for Enchant too. (ispell-send-replacement): Make it work with Enchant. --- lisp/textmodes/ispell.el | 77 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el index 37a6ffc..19a2e02 100644 --- a/lisp/textmodes/ispell.el +++ b/lisp/textmodes/ispell.el @@ -208,6 +208,10 @@ ispell-choices-win-default-height :type 'integer :group 'ispell) +;; XXX Add enchant to this list once enchant >= 1.6.1 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") @@ -605,6 +609,8 @@ ispell-really-aspell "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 @@ -739,17 +745,26 @@ ispell-check-version (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 "1.6.1") (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" @@ -1173,6 +1188,34 @@ ispell-find-hunspell-dictionaries (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-find-enchant-dictionaries () + "Find Enchant's dictionaries, and record in `ispell-enchant-dictionary-alist'." + (let* ((dictionaries + (split-string + (with-temp-buffer + (ispell-call-process ispell-program-name nil t nil "-D") + (buffer-string)))) + (found + (mapcar #'(lambda (lang) + `(,lang "[[:alpha:]]" "[^[:alpha:]]" "['.’-]" 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:]]" "['.’-]" 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 @@ -1198,7 +1241,7 @@ ispell-set-spellchecker-params (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 @@ -1206,11 +1249,14 @@ ispell-set-spellchecker-params (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 @@ -1219,17 +1265,19 @@ ispell-set-spellchecker-params 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)) @@ -1254,7 +1302,7 @@ ispell-set-spellchecker-params (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))) @@ -1296,7 +1344,7 @@ ispell-set-spellchecker-params (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) @@ -1732,9 +1780,10 @@ ispell-accept-output (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")))) -- 2.7.4