mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
Initial support for hunspell dictionaries auto-detection (Bug#13639)
* textmodes/ispell.el (ispell-find-hunspell-dictionaries): Ask hunspell about available and default dictionaries. (ispell-parse-hunspell-affix-file): Extract relevant info from hunspell affix file. (ispell-hunspell-fill-dictionary-entry): Fill non-initialized `ispell-dictionary-alist' entry for given dictionary after info provided by `ispell-parse-hunspell-affix-file'. (ispell-hunspell-dict-paths-alist): New defvar to contain an alist of parsed hunspell dicts and associated affix files. (ispell-hunspell-dictionary-alist): New defvar to contain an alist of parsed hunspell dicts and associated parameters. (ispell-set-spellchecker-params): Call `ispell-find-hunspell-dictionaries' if hunspell and not previously done. (ispell-start-process): Call `ispell-hunspell-fill-dictionary-entry' for current dictionary if it is not initialized. Some additional details about the implementation: (ispell-hunspell-dict-paths-alist): Alist that contains a list of parsed hunspell dicts and associated affix files. (ispell-hunspell-dictionary-alist): Alist of parsed hunspell dicts and associated parameters. It is initially just a list of found dictionaries except for the default dictionary where is filled with proper parameters. When spellchecker is initialized by (ispell-set-spellchecker-params) if the conditions: is hunspell, communication can be set to UTF-8 and Emacs flavor supports [:alpha:] are matched installed hunspell dictionaries are parsed and info passed to `ispell-hunspell-dictionary-alist', either full for default dictionary or just name for other dictionaries. These entries are used for `ispell-dictionary-alist' if not overriden. Before starting hunspell process in (ispell-start-process), if `ispell-dictionary-alist' entry is not yet initialized (ispell-hunspell-fill-dictionary-entry) is called to fill that entry (and all pending entries using the same affix file) after info extracted by (ispell-parse-hunspell-affix-file) from the associated affix file. hunspell process will then be started as usual. This delayed procedure is used to avoid that in systems containing many hunspell dictionaries all affix files are parsed (if there are many, time may be noticeable) for just one used dictionary.
This commit is contained in:
parent
930de676ac
commit
ef3761e3f4
@ -1,3 +1,25 @@
|
||||
2013-02-28 Agustín Martín Domingo <agustin.martin@hispalinux.es>
|
||||
|
||||
Initial support for hunspell dictionaries auto-detection (Bug#13639)
|
||||
|
||||
* textmodes/ispell.el (ispell-find-hunspell-dictionaries):
|
||||
Ask hunspell about available and default dictionaries.
|
||||
(ispell-parse-hunspell-affix-file): Extract relevant info from
|
||||
hunspell affix file.
|
||||
(ispell-hunspell-fill-dictionary-entry): Fill non-initialized
|
||||
`ispell-dictionary-alist' entry for given dictionary after info
|
||||
provided by `ispell-parse-hunspell-affix-file'.
|
||||
(ispell-hunspell-dict-paths-alist): New defvar to contain an alist
|
||||
of parsed hunspell dicts and associated affix files.
|
||||
(ispell-hunspell-dictionary-alist): New defvar to contain an alist
|
||||
of parsed hunspell dicts and associated parameters.
|
||||
(ispell-set-spellchecker-params):
|
||||
Call `ispell-find-hunspell-dictionaries' if hunspell and not
|
||||
previously done.
|
||||
(ispell-start-process):
|
||||
Call `ispell-hunspell-fill-dictionary-entry' for current
|
||||
dictionary if it is not initialized.
|
||||
|
||||
2013-02-28 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
* imenu.el: Comment nitpicks.
|
||||
|
@ -1129,6 +1129,170 @@ Return the new dictionary alist."
|
||||
(push (cons aliasname (cdr realdict)) alist))))))
|
||||
alist))
|
||||
|
||||
;; Make ispell.el work better with hunspell.
|
||||
|
||||
(defvar ispell-hunspell-dict-paths-alist nil
|
||||
"Alist of parsed hunspell dicts and associated affix files.
|
||||
Will be used to parse corresponding .aff file and create associated
|
||||
parameters to be inserted into `ispell-hunspell-dictionary-alist'.
|
||||
Internal use.")
|
||||
|
||||
(defvar ispell-hunspell-dictionary-alist nil
|
||||
"Alist of parsed hunspell dicts and associated parameters.
|
||||
This alist will initially contain names of found dicts. Associated
|
||||
parameters will be added when dict is used for the first time.
|
||||
Internal use.")
|
||||
|
||||
(defun ispell-hunspell-fill-dictionary-entry (dict)
|
||||
"Fill `ispell-dictionary-alist' uninitialized entries for `DICT' and aliases.
|
||||
Value will be extracted from hunspell affix file and used for
|
||||
all uninitialized dicts using that affix file."
|
||||
(if (cadr (assoc dict ispell-dictionary-alist))
|
||||
(message "ispell-hfde: Non void entry for %s. Skipping.\n" dict)
|
||||
(let ((dict-alias (cadr (assoc dict ispell-hunspell-dictionary-equivs-alist)))
|
||||
(use-for-dicts (list dict))
|
||||
(dict-args-cdr (cdr (ispell-parse-hunspell-affix-file dict)))
|
||||
newlist)
|
||||
;; Get a list of unitialized dicts using the same affix file.
|
||||
(dolist (dict-equiv-alist-entry ispell-hunspell-dictionary-equivs-alist)
|
||||
(let ((dict-equiv-key (car dict-equiv-alist-entry))
|
||||
(dict-equiv-value (cadr dict-equiv-alist-entry)))
|
||||
(if (or (member dict dict-equiv-alist-entry)
|
||||
(member dict-alias dict-equiv-alist-entry))
|
||||
(dolist ( tmp-dict (list dict-equiv-key dict-equiv-value))
|
||||
(if (cadr (assoc tmp-dict ispell-dictionary-alist))
|
||||
(ispell-print-if-debug (format "ispell-hfde: %s already expanded. Skipping.\n" tmp-dict))
|
||||
(add-to-list 'use-for-dicts tmp-dict))))))
|
||||
(ispell-print-if-debug (format "ispell-hfde: Filling %s entry. Use for %s.\n" dict use-for-dicts))
|
||||
;; The final loop
|
||||
(dolist (entry ispell-dictionary-alist)
|
||||
(if (member (car entry) use-for-dicts)
|
||||
(add-to-list 'newlist
|
||||
(append (list (car entry)) dict-args-cdr))
|
||||
(add-to-list 'newlist entry)))
|
||||
(setq ispell-dictionary-alist newlist))))
|
||||
|
||||
(defun ispell-parse-hunspell-affix-file (dict-key)
|
||||
"Parse hunspell affix file to extract parameters for `DICT-KEY'.
|
||||
Return a list in `ispell-dictionary-alist' format."
|
||||
(let ((affix-file (cadr (assoc dict-key ispell-hunspell-dict-paths-alist))))
|
||||
(unless affix-file
|
||||
(error "ispell-phaf: No matching entry for %s.\n" dict-name))
|
||||
(if (file-exists-p affix-file)
|
||||
(let ((dict-name (file-name-sans-extension (file-name-nondirectory affix-file)))
|
||||
otherchars-string otherchars-list)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents affix-file)
|
||||
(setq otherchars-string
|
||||
(save-excursion
|
||||
(beginning-of-buffer)
|
||||
(if (search-forward-regexp "^WORDCHARS +" nil t )
|
||||
(buffer-substring (point)
|
||||
(progn (end-of-line) (point))))))
|
||||
;; Remove trailing whitespace and extra stuff. Make list if non-nil.
|
||||
(setq otherchars-list
|
||||
(if otherchars-string
|
||||
(split-string
|
||||
(if (string-match " +.*$" otherchars-string)
|
||||
(replace-match "" nil nil otherchars-string)
|
||||
otherchars-string)
|
||||
"" t)))
|
||||
|
||||
;; Fill dict entry
|
||||
(list dict-key
|
||||
"[[:alpha:]]"
|
||||
"[^[:alpha:]]"
|
||||
(if otherchars-list
|
||||
(regexp-opt otherchars-list)
|
||||
"")
|
||||
t ;; many-otherchars-p: We can't tell, set to t
|
||||
(list "-d" dict-name)
|
||||
nil ;; extended-char-mode: not supported by hunspell
|
||||
'utf-8)))
|
||||
(error "ispell-phaf: File \"%s\" not found.\n" affix-file))))
|
||||
|
||||
(defun ispell-find-hunspell-dictionaries ()
|
||||
"Look for installed hunspell dictionaries.
|
||||
Will initialize `ispell-hunspell-dictionary-alist' and
|
||||
`ispell-hunspell-dictionary-alist' after values found
|
||||
and remove `ispell-hunspell-dictionary-equivs-alist'
|
||||
entries if a specific dict was found."
|
||||
(let ((hunspell-found-dicts
|
||||
(split-string
|
||||
(with-temp-buffer
|
||||
(ispell-call-process ispell-program-name
|
||||
null-device
|
||||
t
|
||||
nil
|
||||
"-D")
|
||||
(buffer-string))
|
||||
"[\n\r]+"
|
||||
t))
|
||||
hunspell-default-dict
|
||||
hunspell-default-dict-entry)
|
||||
(dolist (dict hunspell-found-dicts)
|
||||
(let* ((full-name (file-name-nondirectory dict))
|
||||
(basename (file-name-sans-extension full-name))
|
||||
(affix-file (concat dict ".aff")))
|
||||
(if (string-match "\\.aff$" dict)
|
||||
;; Found default dictionary
|
||||
(if hunspell-default-dict
|
||||
(error "ispell-fhd: Default dict already defined as %s. Not using %s.\n"
|
||||
hunspell-default-dict dict)
|
||||
(setq affix-file dict)
|
||||
(setq hunspell-default-dict (list basename affix-file)))
|
||||
(if (and (not (assoc basename ispell-hunspell-dict-paths-alist))
|
||||
(file-exists-p affix-file))
|
||||
;; Entry has an associated .aff file and no previous value.
|
||||
(progn
|
||||
(ispell-print-if-debug
|
||||
(format "++ ispell-fhd: dict-entry:%s name:%s basename:%s affix-file:%s\n"
|
||||
dict full-name basename affix-file))
|
||||
(add-to-list 'ispell-hunspell-dict-paths-alist
|
||||
(list basename affix-file)))
|
||||
(ispell-print-if-debug
|
||||
(format "-- ispell-fhd: Skipping entry: %s\n" dict))))))
|
||||
;; Remove entry from aliases alist if explicit dict was found.
|
||||
(let (newlist)
|
||||
(dolist (dict ispell-hunspell-dictionary-equivs-alist)
|
||||
(if (assoc (car dict) ispell-hunspell-dict-paths-alist)
|
||||
(ispell-print-if-debug
|
||||
(format "-- ispell-fhd: Excluding %s alias. Standalone dict found.\n"
|
||||
(car dict)))
|
||||
(add-to-list 'newlist dict)))
|
||||
(setq ispell-hunspell-dictionary-equivs-alist newlist))
|
||||
;; Add known hunspell aliases
|
||||
(dolist (dict-equiv ispell-hunspell-dictionary-equivs-alist)
|
||||
(let ((dict-equiv-key (car dict-equiv))
|
||||
(dict-equiv-value (cadr dict-equiv))
|
||||
(exclude-aliases (list ;; Exclude TeX aliases
|
||||
"esperanto-tex"
|
||||
"francais7"
|
||||
"francais-tex"
|
||||
"norsk7-tex")))
|
||||
(if (and (assoc dict-equiv-value ispell-hunspell-dict-paths-alist)
|
||||
(not (assoc dict-equiv-key ispell-hunspell-dict-paths-alist))
|
||||
(not (member dict-equiv-key exclude-aliases)))
|
||||
(let ((affix-file (cadr (assoc dict-equiv-value ispell-hunspell-dict-paths-alist))))
|
||||
(ispell-print-if-debug (format "++ ispell-fhd: Adding alias %s -> %s.\n"
|
||||
dict-equiv-key affix-file))
|
||||
(add-to-list
|
||||
'ispell-hunspell-dict-paths-alist
|
||||
(list dict-equiv-key affix-file))))))
|
||||
;; Parse and set values for default dictionary.
|
||||
(setq hunspell-default-dict (car hunspell-default-dict))
|
||||
(setq hunspell-default-dict-entry
|
||||
(ispell-parse-hunspell-affix-file hunspell-default-dict))
|
||||
;; Create an alist of found dicts with only names, except for default dict.
|
||||
(setq ispell-hunspell-dictionary-alist
|
||||
(list (append (list nil) (cdr hunspell-default-dict-entry))))
|
||||
(dolist (dict (mapcar 'car ispell-hunspell-dict-paths-alist))
|
||||
(if (string= dict hunspell-default-dict)
|
||||
(add-to-list 'ispell-hunspell-dictionary-alist
|
||||
hunspell-default-dict-entry)
|
||||
(add-to-list 'ispell-hunspell-dictionary-alist
|
||||
(list dict))))))
|
||||
|
||||
;; Set params according to the selected spellchecker
|
||||
|
||||
(defvar ispell-last-program-name nil
|
||||
@ -1154,20 +1318,30 @@ aspell is used along with Emacs).")
|
||||
(setq ispell-library-directory (ispell-check-version))
|
||||
t)
|
||||
(error nil))
|
||||
ispell-really-aspell
|
||||
ispell-encoding8-command
|
||||
ispell-emacs-alpha-regexp)
|
||||
(unless ispell-aspell-dictionary-alist
|
||||
(ispell-find-aspell-dictionaries)))
|
||||
;; auto-detection will only be used if spellchecker is not
|
||||
;; ispell, supports a way to set communication to UTF-8 and
|
||||
;; Emacs flavor supports [:alpha:]
|
||||
(if ispell-really-aspell
|
||||
(or ispell-aspell-dictionary-alist
|
||||
(ispell-find-aspell-dictionaries))
|
||||
(if ispell-really-hunspell
|
||||
(or ispell-hunspell-dictionary-alist
|
||||
(ispell-find-hunspell-dictionaries)))))
|
||||
|
||||
;; Substitute ispell-dictionary-alist with the list of dictionaries
|
||||
;; corresponding to the given spellchecker. If a recent aspell, use
|
||||
;; the list of really installed dictionaries and add to it elements
|
||||
;; of the original list that are not present there. Allow distro info.
|
||||
;; 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
|
||||
;; installed dictionaries and add to it elements of the original
|
||||
;; list that are not present there. Allow distro info.
|
||||
(let ((found-dicts-alist
|
||||
(if (and ispell-really-aspell
|
||||
ispell-encoding8-command)
|
||||
ispell-aspell-dictionary-alist
|
||||
(if (and ispell-encoding8-command
|
||||
ispell-emacs-alpha-regexp)
|
||||
(if ispell-really-aspell
|
||||
ispell-aspell-dictionary-alist
|
||||
(if ispell-really-hunspell
|
||||
ispell-hunspell-dictionary-alist))
|
||||
nil))
|
||||
(ispell-dictionary-base-alist ispell-dictionary-base-alist)
|
||||
ispell-base-dicts-override-alist ; Override only base-dicts-alist
|
||||
@ -1237,19 +1411,21 @@ aspell is used along with Emacs).")
|
||||
(if ispell-emacs-alpha-regexp
|
||||
(let (tmp-dicts-alist)
|
||||
(dolist (adict ispell-dictionary-alist)
|
||||
(add-to-list 'tmp-dicts-alist
|
||||
(list
|
||||
(nth 0 adict) ; dict name
|
||||
"[[:alpha:]]" ; casechars
|
||||
"[^[:alpha:]]" ; not-casechars
|
||||
(nth 3 adict) ; otherchars
|
||||
(nth 4 adict) ; many-otherchars-p
|
||||
(nth 5 adict) ; ispell-args
|
||||
(nth 6 adict) ; extended-character-mode
|
||||
(if ispell-encoding8-command
|
||||
'utf-8
|
||||
(nth 7 adict)))))
|
||||
(setq ispell-dictionary-alist tmp-dicts-alist)))))
|
||||
(if (cadr adict) ;; Do not touch hunspell uninitialized entries
|
||||
(add-to-list 'tmp-dicts-alist
|
||||
(list
|
||||
(nth 0 adict) ; dict name
|
||||
"[[:alpha:]]" ; casechars
|
||||
"[^[:alpha:]]" ; not-casechars
|
||||
(nth 3 adict) ; otherchars
|
||||
(nth 4 adict) ; many-otherchars-p
|
||||
(nth 5 adict) ; ispell-args
|
||||
(nth 6 adict) ; extended-character-mode
|
||||
(if ispell-encoding8-command
|
||||
'utf-8
|
||||
(nth 7 adict))))
|
||||
(add-to-list 'tmp-dicts-alist adict)))
|
||||
(setq ispell-dictionary-alist tmp-dicts-alist)))))
|
||||
|
||||
(defun ispell-valid-dictionary-list ()
|
||||
"Return a list of valid dictionaries.
|
||||
@ -2737,6 +2913,12 @@ When asynchronous processes are not supported, `run' is always returned."
|
||||
Keeps argument list for future Ispell invocations for no async support."
|
||||
;; `ispell-current-dictionary' and `ispell-current-personal-dictionary'
|
||||
;; are properly set in `ispell-internal-change-dictionary'.
|
||||
|
||||
;; Parse hunspell affix file if using hunspell and entry is uninitialized.
|
||||
(if ispell-really-hunspell
|
||||
(or (cadr (assoc ispell-current-dictionary ispell-dictionary-alist))
|
||||
(ispell-hunspell-fill-dictionary-entry ispell-current-dictionary)))
|
||||
|
||||
(let* ((default-directory
|
||||
(if (and (file-directory-p default-directory)
|
||||
(file-readable-p default-directory))
|
||||
|
Loading…
Reference in New Issue
Block a user