[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: ispell.el doesn't find all of aspell's dictionaries
From: |
Magnus Henoch |
Subject: |
Re: ispell.el doesn't find all of aspell's dictionaries |
Date: |
Sat, 09 Jul 2005 17:22:59 +0200 |
User-agent: |
Gnus/5.110004 (No Gnus v0.4) Emacs/22.0.50 (berkeley-unix) |
Juri Linkov <address@hidden> writes:
>> There is one problem with this code: the dictionary list in the menu
>> bar is only updated when ispell.el is loaded (probably due to a call
>> to an auto-loaded function). So before any ispell-* command is run,
>> the menu shows the static list of ispell dictionaries, and if new
>> dictionaries are added, the menu is not updated. I'm not sure what
>> can/should be done about that.
>>
>> Some ideas:
>>
>> 1. Have a menu item, "Update Dictionary List", to check again.
>>
>> 2. If checking is fast, check whenever the user is about to
>> specify a dictionary.
>
> Rechecking the dictionary list is needed also after changing the
> program name in `ispell-program-name' (also don't forget to call
> `ispell-kill-ispell').
Looking closer at it, I see that the dictionary menu is far too long.
It extends beyond the bottom of the screen, so it isn't very useful.
As there is a "Change Dictionary" menu item just above, I propose that
the dictionary list in the menu be removed. (I've done so in my patch
below)
>> In the mean time, it would be useful for people to start testing your
>> patch, so that by the time your papers have arrived, it will be
>> thoroughly ready to go.
>
> I tested the patch and discovered several problems:
>
>> + (let ((dictionaries
>> + (split-string
>> + (with-temp-buffer
>> + (call-process ispell-program-name nil t nil "dicts")
>
> `aspell dicts' returns plain dictionary names like
> `en_GB-ize-w_accents', but misses readable aliases like `english'.
> Is it possible for aspell to return all aliases as well?
>
> Aspell aliases will also make many aspell dictionary names compatible
> with ispell dictionary names, so it would be good if users will be able
> to use the same dictionary names for aspell and ispell without the need
> to care about differences.
Good point. I've added code to find all aliases. Now it should be
entirely compatible with any way of specifying dictionaries for
Ispell.
>> + (list dict-name
>> + "[[:alpha:]]"
>> + "[^[:alpha:]]"
>
> This code doesn't take into account the real charsets used in
> dictionaries. Maybe it should extract the `charset' field
> from `dat' files?
Is that important? Aspell can handle anything we throw at it, as long
as it is UTF-8.
>> + (defun aspell-find-dictonaries ()
> ===========
> Typo. Use a spell checker to check your code ;-)
Thanks ;-)
In this new patch I've also included your changes for user awareness
of which program is being used, and changed aspell-* to
ispell-aspell-*.
*** orig/lisp/textmodes/ispell.el
--- mod/lisp/textmodes/ispell.el
***************
*** 862,870 ****
--- 862,981 ----
)
"Non-nil means that the OS supports asynchronous processes.")
+ ;; Make ispell.el work better with aspell.
+
+ (defvar ispell-aspell-have-dictionaries nil
+ "Non-nil if we have queried aspell for dictionaries at least once.")
+
+ (defun ispell-aspell-find-dictionaries ()
+ "Find aspell's dictionaries, and record into `ispell-dictionary-alist'."
+ (interactive)
+ (unless ispell-really-aspell
+ (error "This function only works with aspell."))
+ (let ((dictionaries
+ (split-string
+ (with-temp-buffer
+ (call-process ispell-program-name nil t nil "dicts")
+ (buffer-string)))))
+ (setq ispell-dictionary-alist
+ (mapcar #'ispell-aspell-find-dictionary dictionaries))
+ (ispell-aspell-add-aliases)
+ ;; Add a default entry
+ (let* ((english-dict (assoc "en" ispell-dictionary-alist))
+ (default-dict (cons nil (cdr english-dict))))
+ (push default-dict ispell-dictionary-alist))
+ (setq ispell-aspell-have-dictionaries t)))
+
+ (defvar ispell-aspell-data-dir nil
+ "Data directory of aspell.")
+
+ (defvar ispell-aspell-dict-dir nil
+ "Dictionary directory of aspell.")
+
+ (defun ispell-aspell-get-config-value (key)
+ "Return value of aspell configuration option KEY.
+ Assumes that value contains no whitespace."
+ (with-temp-buffer
+ (call-process ispell-program-name nil t nil "config" key)
+ (car (split-string (buffer-string)))))
+
+ (defun ispell-aspell-find-data-dir ()
+ "Find aspell's data directory and set `ispell-aspell-data-dir'.
+ Return ispell-aspell-data-dir."
+ (setq ispell-aspell-data-dir (ispell-aspell-get-config-value "data-dir")))
+
+ (defun ispell-aspell-find-dict-dir ()
+ "Find aspell's dictionary directory and set `ispell-aspell-dict-dir'.
+ Return ispell-aspell-dict-dir."
+ (setq ispell-aspell-dict-dir (ispell-aspell-get-config-value "dict-dir")))
+
+ (defun ispell-aspell-find-dictionary (dict-name)
+ (let* ((lang ;; Strip out region, variant, etc.
+ (and (string-match "^[[:alpha:]]+" dict-name)
+ (match-string 0 dict-name)))
+ (data-file
+ (concat (or ispell-aspell-data-dir (ispell-aspell-find-data-dir))
+ "/" lang ".dat"))
+ otherchars)
+ ;; This file really should exist; there is no sensible recovery.
+ (with-temp-buffer
+ (insert-file-contents data-file)
+ ;; There is zero or one line with special characters declarations.
+ (when (search-forward-regexp "^special" nil t)
+ (let ((specials (split-string
+ (buffer-substring (point)
+ (progn (end-of-line) (point))))))
+ ;; The line looks like: special ' -** - -** . -** : -*-
+ ;; -** means that this character
+ ;; - doesn't appear at word start
+ ;; * may appear in the middle of a word
+ ;; * may appear at word end
+ ;; `otherchars' is about the middle case.
+ (while specials
+ (when (eq (aref (cadr specials) 1) ?*)
+ (push (car specials) otherchars))
+ (setq specials (cddr specials))))))
+ (list dict-name
+ "[[:alpha:]]"
+ "[^[:alpha:]]"
+ (regexp-opt otherchars)
+ t ; We can't tell, so set this to t
+ (list "-d" dict-name "--encoding=utf-8")
+ nil ; aspell doesn't support this
+ ;; Here we specify the encoding to use while communicating with
+ ;; aspell. This doesn't apply to command line arguments, so
+ ;; just don't pass words to spellcheck as arguments...
+ 'utf-8)))
+
+ (defun ispell-aspell-add-aliases ()
+ "Find aspell's dictionary aliases and add them to
`ispell-dictionary-alist'."
+ (let ((aliases (file-expand-wildcards
+ (concat (or ispell-aspell-dict-dir
+ (ispell-aspell-find-dict-dir))
+ "/*.alias"))))
+ (dolist (alias-file aliases)
+ (with-temp-buffer
+ (insert-file-contents alias-file)
+ ;; Look for a line "add FOO.multi", extract FOO
+ (when (search-forward-regexp "^add \\([^.]+\\)\\.multi" nil t)
+ (let* ((aliasname (file-name-sans-extension
+ (file-name-nondirectory alias-file)))
+ (already-exists-p (assoc aliasname ispell-dictionary-alist))
+ (realname (match-string 1))
+ (realdict (assoc realname ispell-dictionary-alist)))
+ (when (and realdict (not already-exists-p))
+ (push (cons aliasname (cdr realdict))
ispell-dictionary-alist))))))))
+
(defun ispell-valid-dictionary-list ()
"Returns a list of valid dictionaries.
The variable `ispell-library-directory' defines the library location."
+ ;; If Ispell is really Aspell, query it for the dictionary list.
+ (when (and (not ispell-aspell-have-dictionaries)
+ (condition-case ()
+ (progn (ispell-check-version) t)
+ (error nil))
+ ispell-really-aspell)
+ (ispell-aspell-find-dictionaries))
(let ((dicts (append ispell-local-dictionary-alist ispell-dictionary-alist))
(dict-list (cons "default" nil))
name load-dict)
***************
*** 875,881 ****
(if (and
name
;; include all dictionaries if lib directory not known.
! (or (not ispell-library-directory)
(file-exists-p (concat ispell-library-directory
"/" name ".hash"))
(file-exists-p (concat ispell-library-directory "/" name ".has"))
--- 986,994 ----
(if (and
name
;; include all dictionaries if lib directory not known.
! ;; For Aspell, we already know which dictionaries exist.
! (or ispell-really-aspell
! (not ispell-library-directory)
(file-exists-p (concat ispell-library-directory
"/" name ".hash"))
(file-exists-p (concat ispell-library-directory "/" name ".has"))
***************
*** 887,922 ****
(setq dict-list (cons name dict-list))))
dict-list))
- ;;;###autoload
- (if ispell-menu-map-needed
- (let ((dicts (if (fboundp 'ispell-valid-dictionary-list)
- (ispell-valid-dictionary-list)
- ;; This case is used in loaddefs.el
- ;; since ispell-valid-dictionary-list isn't defined then.
- (mapcar (lambda (x) (or (car x) "default"))
- ispell-dictionary-alist)))
- (dict-map (make-sparse-keymap "Dictionaries")))
- (setq ispell-menu-map (make-sparse-keymap "Spell"))
- ;; add the dictionaries to the bottom of the list.
- (if (not dicts)
- (define-key ispell-menu-map [default]
- '("Select Default Dict"
- "Dictionary for which Ispell was configured"
- . (lambda () (interactive)
- (ispell-change-dictionary "default")))))
- (fset 'ispell-dict-map dict-map)
- (define-key ispell-menu-map [dictionaries]
- `(menu-item "Select Dict" ispell-dict-map))
- (dolist (name dicts)
- (define-key dict-map (vector (intern name))
- (cons (concat "Select " (capitalize name) " Dict")
- `(lambda () (interactive)
- (ispell-change-dictionary ,name)))))))
-
;;; define commands in menu in opposite order you want them to appear.
;;;###autoload
(if ispell-menu-map-needed
(progn
(define-key ispell-menu-map [ispell-change-dictionary]
'(menu-item "Change Dictionary..." ispell-change-dictionary
:help "Supply explicit dictionary file name"))
--- 1000,1010 ----
(setq dict-list (cons name dict-list))))
dict-list))
;;; define commands in menu in opposite order you want them to appear.
;;;###autoload
(if ispell-menu-map-needed
(progn
+ (setq ispell-menu-map (make-sparse-keymap "Spell"))
(define-key ispell-menu-map [ispell-change-dictionary]
'(menu-item "Change Dictionary..." ispell-change-dictionary
:help "Supply explicit dictionary file name"))
***************
*** 1660,1666 ****
;; setup the *Choices* buffer with valid data.
(save-excursion
(set-buffer (get-buffer-create ispell-choices-buffer))
! (setq mode-line-format (concat "-- %b -- word: " word))
;; XEmacs: no need for horizontal scrollbar in choices window
(with-no-warnings
(and (fboundp 'set-specifier)
--- 1748,1757 ----
;; setup the *Choices* buffer with valid data.
(save-excursion
(set-buffer (get-buffer-create ispell-choices-buffer))
! (setq mode-line-format
! (concat "-- %b -- word: " word
! " -- dict: " (or ispell-current-dictionary "default")
! " -- prog: " (file-name-nondirectory
ispell-program-name)))
;; XEmacs: no need for horizontal scrollbar in choices window
(with-no-warnings
(and (fboundp 'set-specifier)
***************
*** 1820,1828 ****
(erase-buffer)
(setq count ?0
skipped 0
! mode-line-format (concat
! "-- %b -- word: "
! new-word)
miss (lookup-words new-word)
choices miss
line ispell-choices-win-default-height)
--- 1911,1920 ----
(erase-buffer)
(setq count ?0
skipped 0
! mode-line-format
! (concat "-- %b -- word: " new-word
! " -- dict: "
! ispell-alternate-dictionary)
miss (lookup-words new-word)
choices miss
line ispell-choices-win-default-height)
***************
*** 2513,2521 ****
(rstart (make-marker)))
(unwind-protect
(save-excursion
! (message "Spell checking %s using %s dictionary..."
(if (and (= reg-start (point-min)) (= reg-end (point-max)))
(buffer-name) "region")
(or ispell-current-dictionary "default"))
;; Returns cursor to original location.
(save-window-excursion
--- 2605,2614 ----
(rstart (make-marker)))
(unwind-protect
(save-excursion
! (message "Spell checking %s using %s with %s dictionary..."
(if (and (= reg-start (point-min)) (= reg-end (point-max)))
(buffer-name) "region")
+ (file-name-nondirectory ispell-program-name)
(or ispell-current-dictionary "default"))
;; Returns cursor to original location.
(save-window-excursion
***************
*** 2533,2539 ****
(set-marker skip-region-start (- (point) (length key)))
(goto-char reg-start)))
(let (message-log-max)
! (message "Continuing spelling check using %s dictionary..."
(or ispell-current-dictionary "default")))
(set-marker rstart reg-start)
(set-marker ispell-region-end reg-end)
--- 2626,2633 ----
(set-marker skip-region-start (- (point) (length key)))
(goto-char reg-start)))
(let (message-log-max)
! (message "Continuing spelling check using %s with %s
dictionary..."
! (file-name-nondirectory ispell-program-name)
(or ispell-current-dictionary "default")))
(set-marker rstart reg-start)
(set-marker ispell-region-end reg-end)
***************
*** 2610,2616 ****
(if (not recheckp) (set-marker ispell-region-end nil))
;; Only save if successful exit.
(ispell-pdict-save ispell-silently-savep)
! (message "Spell-checking done")))))
(defun ispell-begin-skip-region-regexp ()
--- 2704,2712 ----
(if (not recheckp) (set-marker ispell-region-end nil))
;; Only save if successful exit.
(ispell-pdict-save ispell-silently-savep)
! (message "Spell-checking using %s with %s dictionary done"
! (file-name-nondirectory ispell-program-name)
! (or ispell-current-dictionary "default"))))))
(defun ispell-begin-skip-region-regexp ()