diff options
Diffstat (limited to 'lisp/textmodes/ispell.el')
-rw-r--r-- | lisp/textmodes/ispell.el | 688 |
1 files changed, 191 insertions, 497 deletions
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el index 0cedf86bb73..7551d2fde97 100644 --- a/lisp/textmodes/ispell.el +++ b/lisp/textmodes/ispell.el @@ -1,14 +1,9 @@ -;;; ispell.el --- interface to International Ispell Versions 3.1 and 3.2 +;;; ispell.el --- interface to International Ispell Versions 3.1 and 3.2 -*- lexical-binding:t -*- ;; Copyright (C) 1994-1995, 1997-2016 Free Software Foundation, Inc. ;; Author: Ken Stevens <k.stevens@ieee.org> -;; Maintainer: Ken Stevens <k.stevens@ieee.org> -;; Stevens Mod Date: Mon Jan 7 12:32:44 PST 2003 -;; Stevens Revision: 3.6 ;; Status : Release with 3.1.12+ and 3.2.0+ ispell. -;; Bug Reports : ispell-el-bugs@itcorp.com -;; Web Site : http://kdstevens.com/~stevens/ispell-page.html ;; Keywords: unix wp ;; This file is part of GNU Emacs. @@ -46,9 +41,9 @@ ;; your own dictionaries. ;; Depending on the mail system you use, you may want to include these: -;; (add-hook 'news-inews-hook 'ispell-message) -;; (add-hook 'mail-send-hook 'ispell-message) -;; (add-hook 'mh-before-send-letter-hook 'ispell-message) +;; (add-hook 'news-inews-hook #'ispell-message) +;; (add-hook 'mail-send-hook #'ispell-message) +;; (add-hook 'mh-before-send-letter-hook #'ispell-message) ;; Ispell has a TeX parser and a nroff parser (the default). ;; The parsing is controlled by the variable ispell-parser. Currently @@ -123,153 +118,16 @@ ;; Recursive edits (?C-r or ?R) inside a keyboard text replacement check (?r) ;; can cause misalignment errors. -;; HISTORY - -;; Modifications made in latest versions: - -;; Revision 3.6 2003/01/07 12:32:44 kss -;; Removed extra -d LIB in dictionary defs. (Pavel Janik) -;; Filtered process calls with duplicate dictionary entries. -;; Fixed bug where message-text-end is inside a mime skipped region. -;; Minor fixes to get ispell menus right in XEmacs -;; Fixed skip regexp so it doesn't match stuff like `/.\w'. -;; Detecting dictionary change not working. Fixed. kss -;; function `ispell-change-dictionary' now only completes valid dicts. - -;; Revision 3.5 2001/7/11 18:43:57 kss -;; Added fix for aspell to work in XEmacs (ispell-check-version). -;; Added Portuguese dictionary definition. -;; New feature: MIME mail message support, Fcc support. -;; Bug fix: retain comment syntax on lines with region skipping. (TeX $ bug...) -;; Improved allocation for graphic mode lines. (Miles Bader) -;; Support -v flag for old versions of aspell. (Eli Zaretskii) -;; Clear minibuffer on ^G from ispell-help (Tak Ota) - -;; Revision 3.4 2000/8/4 09:41:50 kss -;; Support new color display functions. -;; Fixed misalignment offset bug when replacing a string after a shift made. -;; Set to standard Author/Maintainer heading, -;; ensure localwords lists are separated from the text by newline. (Dave Love) -;; Added dictionary definition for Italian (William Deakin) -;; HTML region skipping greatly improved. (Chuck D. Phillips) -;; improved menus. Fixed regexp matching http/email addresses. -;; one arg always for XEmacs sleep-for (gunnar Evermann) -;; support for synchronous processes (Eli Zaretskii) - -;; Revision 3.3 1999/11/29 11:38:34 kss -;; Only word replacements entered in from the keyboard are rechecked. -;; This fixes a bug in tex parsing and misalignment. -;; Exceptions exist for recursive edit and query-replace, with tex error -;; condition tested. Recursive editing improved. -;; XEmacs repair for when `enable-multibyte-characters' defined - Didier Verna. -;; ispell-help fixed for XEmacs. Choices minibuffer now displayed in XEmacs. -;; Only list valid dictionaries in Spell menu. Russian dictionary doesn't allow -;; run-together words, and uses koi8-r font. Don't skip text in html <TT> -;; fonts. - -;; Revision 3.2 1999/5/7 14:25:14 kss -;; Accept ispell versions 3.X.Y where X>=1 -;; fine tuned latex region skipping. Fixed bug in ispell-word that did not -;; point in right place on words < 2 chars. Simplified ispell-minor-mode. -;; Fixed bug in TeX parsing when math commands are in the comments. -;; Removed calls to `when' macro. - -;; Revision 3.1 1998/12/1 13:21:52 kss -;; Improved and fixed customize support. -;; Improved and fixed comments in variables and messages. -;; A coding system is now required for all languages. -;; casechars improved for castellano, castellano8, and norsk dictionaries. -;; Dictionary norsk7-tex removed. Dictionary polish added. -;; Dictionaries redefined at load-time to support dictionary changes. -;; Menu redefined at load time to support dictionary changes. -;; ispell-check-version added as an alias for `check-ispell-version'. -;; Spelling suggestions returned in order generated by ispell. -;; Small bug fixed in matching ispell error messages. -;; Robustness added to ensure `case-fold-search' doesn't get redefined. -;; Fixed bug that didn't respect case of word in `ispell-complete-word'. -;; Multibyte character coding support added for process interactions. -;; Ensure ispell process has terminated before starting new process. -;; This can otherwise confuse process filters and hang ispell. -;; Improved skipping support for SGML. -;; Fixed bug using ^M rather than \r in `ispell-minor-check'. -;; Improved message reference matching in `ispell-message'. -;; Fixed bug in returning to nroff mode from tex mode. - -;;; Compatibility code for XEmacs and (not too) older emacsen: - -(eval-and-compile ;; Protect against declare-function undefined in XEmacs - (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))) - -(declare-function ispell-check-minver "ispell" (v1 v2)) -(declare-function ispell-looking-back "ispell" - (regexp &optional limit &rest ignored)) - -(if (fboundp 'version<=) - (defalias 'ispell-check-minver 'version<=) - (defun ispell-check-minver (minver version) - "Check if string VERSION is at least string MINVER. -Both must be in [0-9]+.[0-9]+... format. This is a fallback -compatibility function in case `version<=' is not available." - (let ((pending t) - (return t) - start-ver start-mver) - ;; Loop until an absolute greater or smaller condition is reached - ;; or until no elements are left in any of version and minver. In - ;; this case version is exactly the minimal, so return OK. - (while pending - (let (ver mver) - (if (string-match "[0-9]+" version start-ver) - (setq start-ver (match-end 0) - ver (string-to-number (match-string 0 version)))) - (if (string-match "[0-9]+" minver start-mver) - (setq start-mver (match-end 0) - mver (string-to-number (match-string 0 minver)))) - - (if (or ver mver) - (progn - (or ver (setq ver 0)) - (or mver (setq mver 0)) - ;; If none of below conditions match, this element is the - ;; same. Go checking next element. - (if (> ver mver) - (setq pending nil) - (if (< ver mver) - (setq pending nil - return nil)))) - (setq pending nil)))) - return))) - -;; XEmacs does not have looking-back -(if (fboundp 'looking-back) - (defalias 'ispell-looking-back 'looking-back) - (defun ispell-looking-back (regexp &optional limit &rest ignored) - "Return non-nil if text before point matches regular expression REGEXP. -Like `looking-at' except matches before point, and is slower. -LIMIT if non-nil speeds up the search by specifying a minimum -starting position, to avoid checking matches that would start -before LIMIT. - -This is a stripped down compatibility function for use when -full featured `looking-back' function is missing." - (save-excursion - (re-search-backward (concat "\\(?:" regexp "\\)\\=") limit t)))) - -;;; XEmacs21 does not have `with-no-warnings'. Taken from org mode. -(defmacro ispell-with-no-warnings (&rest body) - (cons (if (fboundp 'with-no-warnings) 'with-no-warnings 'progn) body)) - ;;; Code: +(eval-when-compile (require 'cl-lib)) + (defvar mail-yank-prefix) (defgroup ispell nil "User variables for Emacs ispell interface." :group 'applications) -(if (not (fboundp 'buffer-substring-no-properties)) - (defun buffer-substring-no-properties (start end) - (buffer-substring start end))) - (defalias 'check-ispell-version 'ispell-check-version) ;;; ********************************************************************** @@ -402,19 +260,15 @@ Always stores Fcc copy of message when nil." (defcustom ispell-grep-command - ;; MS-Windows/MS-DOS have `egrep' as a Unix shell script, so they - ;; cannot invoke it. Use "grep -E" instead (see ispell-grep-options - ;; below). - (if (memq system-type '(windows-nt ms-dos)) "grep" "egrep") + "grep" "Name of the grep command for search processes." :type 'string :group 'ispell) (defcustom ispell-grep-options - (if (memq system-type '(windows-nt ms-dos)) "-Ei" "-i") + "-Ei" "String of options to use when running the program in `ispell-grep-command'. -Should probably be \"-i\" or \"-e\". -Some machines (like the NeXT) don't support \"-i\"." +Should probably be \"-Ei\"." :type 'string :group 'ispell) @@ -491,9 +345,7 @@ window system by evaluating the following on startup to set this variable: ;;;###autoload (defcustom ispell-personal-dictionary nil "File name of your personal spelling dictionary, or nil. -If nil, the default personal dictionary, (\"~/.ispell_DICTNAME\" for ispell or -\"~/.aspell.LANG.pws\" for Aspell) is used, where DICTNAME is the name of your -default dictionary and LANG the two letter language code." +If nil, the default personal dictionary for your spelling checker is used." :type '(choice file (const :tag "default" nil)) :group 'ispell) @@ -810,29 +662,11 @@ here just for backwards compatibility.") "Alist with known matching locales for standard dict names in `ispell-dictionary-base-alist'.") -(defvar ispell-emacs-alpha-regexp - (if (string-match "^[[:alpha:]]+$" "abcde") - "[[:alpha:]]" - nil) - "[[:alpha:]] if Emacs supports [:alpha:] regexp, nil -otherwise (current XEmacs does not support it).") ;;; ********************************************************************** ;;; The following are used by ispell, and should not be changed. ;;; ********************************************************************** - - -;; The version must be 3.1 or greater for this version of ispell.el -;; There is an incompatibility between version 3.1.12 and lower versions. -(defconst ispell-required-version '(3 1 12) - "Ispell versions with which this version of ispell.el is known to work.") -(defvar ispell-offset -1 - "Offset that maps protocol differences between ispell 3.1 versions.") - -(defconst ispell-version "ispell.el 3.6 - 7-Jan-2003") - - (defun ispell-check-version (&optional interactivep) "Ensure that `ispell-program-name' is valid and has the correct version. Returns version number if called interactively. @@ -848,7 +682,12 @@ Otherwise returns the library directory name, if that is defined." (let ((default-directory (or (and (boundp 'temporary-file-directory) temporary-file-directory) default-directory)) - result status ispell-program-version) + (get-config-var + (lambda (var) + (when (re-search-forward + (concat var " = \\\"\\(.+?\\)\\\"") nil t) + (match-string 1)))) + result libvar status ispell-program-version) (with-temp-buffer (setq status (ispell-call-process @@ -862,17 +701,19 @@ Otherwise returns the library directory name, if that is defined." (if (string-match "\\`aspell" speller) "-v" "-vv")))) (goto-char (point-min)) (if interactivep - ;; Report version information of ispell and ispell.el + ;; Report version information of ispell (progn (end-of-line) - (setq result (concat (buffer-substring-no-properties (point-min) - (point)) - ", " - ispell-version)) + (setq result (buffer-substring-no-properties (point-min) + (point))) (message "%s" result)) - ;; return library directory. - (if (re-search-forward "LIBDIR = \\\"\\([^ \t\n]*\\)\\\"" nil t) - (setq result (match-string 1)))) + ;; return LIBDIR or LIBRARYVAR (overrides LIBDIR) env. + (progn + (setq result (funcall get-config-var "LIBDIR") + libvar (funcall get-config-var "LIBRARYVAR")) + (when libvar + (setq libvar (getenv libvar)) + (unless (member libvar '(nil "")) (setq result libvar))))) (goto-char (point-min)) (if (not (memq status '(0 nil))) (error "%s exited with %s %s" ispell-program-name @@ -886,8 +727,7 @@ Otherwise returns the library directory name, if that is defined." ;; Make sure these variables are (re-)initialized to the default value (setq ispell-really-aspell nil - ispell-aspell-supports-utf8 nil - ispell-really-hunspell nil + ispell-really-hunspell nil ispell-encoding8-command nil) (goto-char (point-min)) @@ -901,29 +741,26 @@ Otherwise returns the library directory name, if that is defined." nil t) (match-string 1))))) - (let ((aspell-minver "0.50") - (aspell8-minver "0.60") - (ispell0-minver "3.1.0") - (ispell-minver "3.1.12") - (hunspell8-minver "1.1.6")) - - (if (ispell-check-minver ispell0-minver ispell-program-version) - (or (ispell-check-minver ispell-minver ispell-program-version) - (setq ispell-offset 0)) - (error "%s release %s or greater is required" - ispell-program-name - ispell-minver)) + (let* ((aspell8-minver "0.60") + (ispell-minver "3.1.12") + (hunspell8-minver "1.1.6") + (minver (cond + ((not (version<= ispell-minver ispell-program-version)) + ispell-minver) + ((and ispell-really-aspell + (not (version<= aspell8-minver ispell-really-aspell))) + aspell8-minver)))) + + (if minver + (error "%s release %s or greater is required" + ispell-program-name + minver)) (cond (ispell-really-aspell - (if (ispell-check-minver aspell-minver ispell-really-aspell) - (if (ispell-check-minver aspell8-minver ispell-really-aspell) - (progn - (setq ispell-aspell-supports-utf8 t) - (setq ispell-encoding8-command "--encoding="))) - (setq ispell-really-aspell nil))) + (setq ispell-encoding8-command "--encoding=")) (ispell-really-hunspell - (if (ispell-check-minver hunspell8-minver ispell-really-hunspell) + (if (version<= hunspell8-minver ispell-really-hunspell) (setq ispell-encoding8-command "-i") (setq ispell-really-hunspell nil)))))) result)) @@ -942,6 +779,8 @@ Otherwise returns the library directory name, if that is defined." (setq default-directory (expand-file-name "~/"))) (apply 'call-process-region args))) +(defvar ispell-debug-buffer) + (defun ispell-create-debug-buffer (&optional append) "Create an ispell debug buffer for debugging output. If APPEND is non-nil, append the info to previous buffer if exists, @@ -972,22 +811,10 @@ See `ispell-buffer-with-debug' for an example of use." ;; Redo menu when loading ispell to get dictionary modifications (setq ispell-menu-map nil) -;;;###autoload -(defvar ispell-menu-xemacs nil - "Spelling menu for XEmacs. -If nil when package is loaded, a standard menu will be set, -and added as a submenu of the \"Edit\" menu.") - -;; Break out XEmacs menu and split into several calls to avoid having -;; long lines in loaddefs.el. Detect need off following constant. - ;;; Set up dictionary ;;;###autoload (defvar ispell-menu-map-needed - ;; only needed when not version 18 and not XEmacs. - (and (not ispell-menu-map) - (not (featurep 'xemacs)) - 'reload)) + (unless ispell-menu-map 'reload)) (defvar ispell-library-directory (condition-case () (ispell-check-version) @@ -999,11 +826,7 @@ and added as a submenu of the \"Edit\" menu.") (defvar ispell-async-processp (and (fboundp 'delete-process) (fboundp 'process-send-string) - (fboundp 'accept-process-output) - ;;(fboundp 'make-process) - ;;(fboundp 'set-process-filter) - ;;(fboundp 'process-kill-without-query) - ) + (fboundp 'accept-process-output)) "Non-nil means that the OS supports asynchronous processes.") ;; Make ispell.el work better with aspell. @@ -1013,9 +836,7 @@ and added as a submenu of the \"Edit\" menu.") Internal use.") (defun ispell-find-aspell-dictionaries () - "Find Aspell's dictionaries, and record in `ispell-dictionary-alist'." - (unless (and ispell-really-aspell ispell-encoding8-command) - (error "This function only works with Aspell >= 0.60")) + "Find Aspell's dictionaries, and record in `ispell-aspell-dictionary-alist'." (let* ((dictionaries (split-string (with-temp-buffer @@ -1182,15 +1003,15 @@ all uninitialized dicts using that affix file." (if (cadr (assoc tmp-dict ispell-dictionary-alist)) (ispell-print-if-debug "ispell-hfde: %s already expanded; skipping.\n" tmp-dict) - (add-to-list 'use-for-dicts tmp-dict)))))) + (cl-pushnew tmp-dict use-for-dicts :test #'equal)))))) (ispell-print-if-debug "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))) + (cl-pushnew (if (member (car entry) use-for-dicts) + (cons (car entry) dict-args-cdr) + entry) + newlist :test #'equal)) (setq ispell-dictionary-alist newlist)))) (defun ispell-parse-hunspell-affix-file (dict-key) @@ -1235,7 +1056,7 @@ did." (chars-list (append otherchars-string nil))) (setq chars-list (delq ?\ chars-list)) (dolist (ch chars-list) - (add-to-list 'otherchars-list ch))))) + (cl-pushnew ch otherchars-list :test #'equal))))) ;; Cons the argument for the -d switch. (setq dict-arg (concat dict-arg (if (> (length dict-arg) 0) ",") @@ -1246,7 +1067,7 @@ did." "[[:alpha:]]" "[^[:alpha:]]" (if otherchars-list - (regexp-opt (mapcar 'char-to-string otherchars-list)) + (regexp-opt (mapcar #'char-to-string otherchars-list)) "") t ; many-otherchars-p: We can't tell, set to t. (list "-d" dict-arg) @@ -1268,7 +1089,7 @@ in the list must have an affix file where Hunspell affix files are kept." (or (assoc first-dict ispell-local-dictionary-alist) (assoc first-dict ispell-dictionary-alist) (error "Unknown dictionary: %s" first-dict))) - (add-to-list 'ispell-dictionary-alist (list dict '())) + (cl-pushnew (list dict '()) ispell-dictionary-alist :test #'equal) (ispell-hunspell-fill-dictionary-entry dict)) (defun ispell-find-hunspell-dictionaries () @@ -1308,8 +1129,8 @@ entries if a specific dictionary was found." (ispell-print-if-debug "++ 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))) + (cl-pushnew (list basename affix-file) + ispell-hunspell-dict-paths-alist :test #'equal)) (ispell-print-if-debug "-- ispell-fhd: Skipping entry: %s\n" dict))))) ;; Remove entry from aliases alist if explicit dict was found. @@ -1319,7 +1140,7 @@ entries if a specific dictionary was found." (ispell-print-if-debug "-- ispell-fhd: Excluding %s alias. Standalone dict found.\n" (car dict)) - (add-to-list 'newlist dict))) + (cl-pushnew dict newlist :test #'equal))) (setq ispell-dicts-name2locale-equivs-alist newlist)) ;; Add known hunspell aliases (dolist (dict-equiv ispell-dicts-name2locale-equivs-alist) @@ -1337,22 +1158,20 @@ entries if a specific dictionary was found." ispell-hunspell-dict-paths-alist)))) (ispell-print-if-debug "++ 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)))))) + (cl-pushnew (list dict-equiv-key affix-file) + ispell-hunspell-dict-paths-alist :test #'equal))))) ;; 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)))))) + (list (cons nil (cdr hunspell-default-dict-entry)))) + (dolist (dict (mapcar #'car ispell-hunspell-dict-paths-alist)) + (cl-pushnew (if (string= dict hunspell-default-dict) + hunspell-default-dict-entry + (list dict)) + ispell-hunspell-dictionary-alist :test #'equal)))) ;; Set params according to the selected spellchecker @@ -1379,11 +1198,9 @@ aspell is used along with Emacs).") (setq ispell-library-directory (ispell-check-version)) t) (error nil)) - ispell-encoding8-command - ispell-emacs-alpha-regexp) + ispell-encoding8-command) ;; 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:] + ;; ispell and supports a way to set communication to UTF-8. (if ispell-really-aspell (or ispell-aspell-dictionary-alist (ispell-find-aspell-dictionaries)) @@ -1397,9 +1214,8 @@ aspell is used along with Emacs).") ;; 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-encoding8-command - ispell-emacs-alpha-regexp) - (if ispell-really-aspell + (if ispell-encoding8-command + (if ispell-really-aspell ispell-aspell-dictionary-alist (if ispell-really-hunspell ispell-hunspell-dictionary-alist)) @@ -1443,80 +1259,83 @@ aspell is used along with Emacs).") (setq skip-dict t))) (unless skip-dict - (add-to-list 'tmp-dicts-alist - (list - dict-name ; dict name - (nth 1 adict) ; casechars - (nth 2 adict) ; not-casechars - (nth 3 adict) ; otherchars - (nth 4 adict) ; many-otherchars-p - ispell-args ; ispell-args - (nth 6 adict) ; extended-character-mode - (nth 7 adict) ; dict encoding - )))) + (cl-pushnew (list + dict-name ; dict name + (nth 1 adict) ; casechars + (nth 2 adict) ; not-casechars + (nth 3 adict) ; otherchars + (nth 4 adict) ; many-otherchars-p + ispell-args ; ispell-args + (nth 6 adict) ; extended-character-mode + (nth 7 adict) ; dict encoding + ) + tmp-dicts-alist :test #'equal))) (setq ispell-dictionary-base-alist tmp-dicts-alist)))) (run-hooks 'ispell-initialize-spellchecker-hook) - ;; Add dicts to ``ispell-dictionary-alist'' unless already present. + ;; Add dicts to `ispell-dictionary-alist' unless already present. (dolist (dict (append found-dicts-alist ispell-base-dicts-override-alist ispell-dictionary-base-alist)) (unless (assoc (car dict) all-dicts-alist) - (add-to-list 'all-dicts-alist dict))) + (push dict all-dicts-alist))) (setq ispell-dictionary-alist all-dicts-alist)) - ;; If Emacs flavor supports [:alpha:] use it for global dicts. If - ;; spellchecker also supports UTF-8 via command-line option use it + ;; If spellchecker supports UTF-8 via command-line option, use it ;; in communication. This does not affect definitions in your ;; init file. - (if ispell-emacs-alpha-regexp - (let (tmp-dicts-alist) - (dolist (adict ispell-dictionary-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))))) + (let (tmp-dicts-alist) + (dolist (adict ispell-dictionary-alist) + (cl-pushnew (if (cadr adict) ;; Do not touch hunspell uninitialized entries + (list + (nth 0 adict) ; dict name + (nth 1 adict) ; casechars + (nth 2 adict) ; 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))) + adict) + tmp-dicts-alist :test #'equal)) + (setq ispell-dictionary-alist tmp-dicts-alist)))) (defun ispell-valid-dictionary-list () "Return a list of valid dictionaries. The variable `ispell-library-directory' defines their location." ;; Initialize variables and dictionaries alists for desired spellchecker. - ;; Make sure ispell.el is loaded to avoid some autoload loops in XEmacs - ;; (and may be others) + ;; Make sure ispell.el is loaded to avoid some autoload loops. (if (featurep 'ispell) (ispell-set-spellchecker-params)) (let ((dicts (append ispell-local-dictionary-alist ispell-dictionary-alist)) (dict-list (cons "default" nil)) - name dict-bname) + (dict-locate + (lambda (dict &optional dir) + (locate-file (file-name-nondirectory dict) + `(,(or dir (file-name-directory dict))) + (unless (file-name-extension dict) '(".hash" ".has"))))) + name dict-explt dict-bname) (dolist (dict dicts) (setq name (car dict) - dict-bname (or (car (cdr (member "-d" (nth 5 dict)))) - name)) - ;; Include if the dictionary is in the library, or dir not defined. - (if (and - name - ;; For Aspell, we already know which dictionaries exist. - (or ispell-really-aspell - ;; Include all dictionaries if lib directory not known. - ;; Same for Hunspell, where ispell-library-directory is nil. - (not ispell-library-directory) - (file-exists-p (concat ispell-library-directory - "/" dict-bname ".hash")) - (file-exists-p (concat ispell-library-directory - "/" dict-bname ".has")))) + ;; Explicitly (via ispell-args) specified dictionary. + dict-explt (car (cdr (member "-d" (nth 5 dict)))) + dict-bname (or dict-explt name)) + (if (and name + (or + ;; Include all for Aspell (we already know existing dicts) + ispell-really-aspell + ;; Include all if `ispell-library-directory' is nil (Hunspell) + (not ispell-library-directory) + ;; If explicit (-d with an absolute path) and existing dict. + (and dict-explt + (file-name-absolute-p dict-explt) + (funcall dict-locate dict-explt)) + ;; If dict located in `ispell-library-directory'. + (funcall dict-locate dict-bname ispell-library-directory))) (push name dict-list))) dict-list)) @@ -1592,65 +1411,8 @@ The variable `ispell-library-directory' defines their location." (define-key ispell-menu-map [ispell-buffer] `(menu-item ,(purecopy "Spell-Check Buffer") ispell-buffer :help ,(purecopy "Check spelling of selected buffer"))) - ;;(put 'ispell-region 'menu-enable 'mark-active) (fset 'ispell-menu-map (symbol-value 'ispell-menu-map)))) -;;; XEmacs versions 19 & 20 -(if (and (featurep 'xemacs) - (featurep 'menubar) - ;;(null ispell-menu-xemacs) - (not (and (boundp 'infodock-version) infodock-version))) - (let ((dicts (if (fboundp 'ispell-valid-dictionary-list) - (reverse (ispell-valid-dictionary-list)))) - (current-menubar (or current-menubar default-menubar)) - (menu - '(["Help" (describe-function 'ispell-help) t] - ;;["Help" (popup-menu ispell-help-list) t] - ["Check Message" ispell-message t] - ["Check Buffer" ispell-buffer t] - ["Check Comments" ispell-comments-and-strings t] - ["Check Word" ispell-word t] - ["Check Region" ispell-region (or (not zmacs-regions) (mark))] - ["Continue Check" ispell-continue t] - ["Complete Word Frag"ispell-complete-word-interior-frag t] - ["Complete Word" ispell-complete-word t] - ["Kill Process" (ispell-kill-ispell nil 'clear) t] - ["Customize..." (customize-group 'ispell) t] - ;; flyspell-mode may not be bound... - ;;["flyspell" flyspell-mode - ;; :style toggle :selected flyspell-mode ] - "-" - ["Save Personal Dict"(ispell-pdict-save t t) t] - ["Change Dictionary" ispell-change-dictionary t]))) - (if (null dicts) - (setq dicts (cons "default" nil))) - (dolist (name dicts) - (setq menu (append menu - (list - (vector - (concat "Select " (capitalize name)) - (list 'ispell-change-dictionary name) - t))))) - (setq ispell-menu-xemacs menu) - (if current-menubar - (progn - (if (car (find-menu-item current-menubar '("Cmds"))) - (progn - ;; XEmacs 21.2 - (delete-menu-item '("Cmds" "Spell-Check")) - (add-menu '("Cmds") "Spell-Check" ispell-menu-xemacs)) - ;; previous - (delete-menu-item '("Edit" "Spell")) ; in case already defined - (add-menu '("Edit") "Spell" ispell-menu-xemacs)))))) - -(defalias 'ispell-int-char - ;; Allow incrementing characters as integers in XEmacs 20 - (if (and (featurep 'xemacs) - (fboundp 'int-char)) - 'int-char - ;; Emacs and XEmacs 19 or earlier - 'identity)) - ;;; ********************************************************************** @@ -1664,17 +1426,8 @@ used as key in `ispell-local-dictionary-alist' and `ispell-dictionary-alist'.") This is passed to the Ispell process using the `-p' switch.") (defun ispell-decode-string (str) - "Decodes multibyte character strings. -Protects against bogus binding of `enable-multibyte-characters' in XEmacs." - ;; FIXME: enable-multibyte-characters is read-only, so bogus bindings are - ;; really nasty (they signal an error in Emacs): Who does that? --Stef - (if (and (or (featurep 'xemacs) - (and (boundp 'enable-multibyte-characters) - enable-multibyte-characters)) - (fboundp 'decode-coding-string) - (ispell-get-coding-system)) - (decode-coding-string str (ispell-get-coding-system)) - str)) + "Decodes multibyte character strings." + (decode-coding-string str (ispell-get-coding-system))) ;; Return a string decoded from Nth element of the current dictionary. (defun ispell-get-decoded-string (n) @@ -1875,6 +1628,7 @@ Valid forms include: ("\\\\add\\(tocontents\\|vspace\\)" ispell-tex-arg-end) ("\\\\\\([aA]lph\\|arabic\\)" ispell-tex-arg-end) ;;("\\\\author" ispell-tex-arg-end) + ("\\\\cref" ispell-tex-arg-end) ("\\\\bibliographystyle" ispell-tex-arg-end) ("\\\\makebox" ispell-tex-arg-end 0) ("\\\\e?psfig" ispell-tex-arg-end) @@ -2132,32 +1886,20 @@ quit spell session exited." (cond ((eq poss t) (or quietly (message "%s is correct" - (funcall ispell-format-word-function word))) - (and (featurep 'xemacs) - (extent-at start) - (and (fboundp 'delete-extent) - (delete-extent (extent-at start))))) + (funcall ispell-format-word-function word)))) ((stringp poss) (or quietly (message "%s is correct because of root %s" (funcall ispell-format-word-function word) - (funcall ispell-format-word-function poss))) - (and (featurep 'xemacs) - (extent-at start) - (and (fboundp 'delete-extent) - (delete-extent (extent-at start))))) + (funcall ispell-format-word-function poss)))) ((null poss) (message "Error checking word %s using %s with %s dictionary" (funcall ispell-format-word-function word) (file-name-nondirectory ispell-program-name) (or ispell-current-dictionary "default"))) (ispell-check-only ; called from ispell minor mode. - (if (fboundp 'make-extent) - (if (fboundp 'set-extent-property) - (let ((ext (make-extent start end))) - (set-extent-property ext 'face ispell-highlight-face) - (set-extent-property ext 'priority 2000))) - (beep) + (progn + (beep) (message "%s is incorrect" (funcall ispell-format-word-function word)))) (t ; prompt for correct word. @@ -2327,15 +2069,9 @@ Global `ispell-quit' set to start location to continue spell session." "-- %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 - (ispell-with-no-warnings - (and (fboundp 'set-specifier) - (boundp 'horizontal-scrollbar-visible-p) - (set-specifier horizontal-scrollbar-visible-p nil - (cons (current-buffer) nil)))) - (ispell-with-no-warnings - (and (boundp 'horizontal-scroll-bar) - (setq horizontal-scroll-bar nil))) + ;; No need for horizontal scrollbar in choices window + (with-no-warnings + (setq horizontal-scroll-bar nil)) (erase-buffer) (if guess (progn @@ -2358,12 +2094,12 @@ Global `ispell-quit' set to start location to continue spell session." ;; not so good if there are over 20 or 30 options, but then, if ;; there are that many you don't want to scan them all anyway... (while (memq count command-characters) ; skip command characters. - (setq count (ispell-int-char (1+ count)) + (setq count (1+ count) skipped (1+ skipped))) (insert "(" count ") " (car choices) " ") (setq choices (cdr choices) - count (ispell-int-char (1+ count)))) - (setq count (ispell-int-char (- count ?0 skipped)))) + count (1+ count))) + (setq count (- count ?0 skipped))) (run-hooks 'ispell-update-post-hook) @@ -2422,14 +2158,15 @@ Global `ispell-quit' set to start location to continue spell session." ((= char ?i) ; accept and insert word into pers dict (ispell-send-string (concat "*" word "\n")) (setq ispell-pdict-modified-p '(t)) ; dictionary modified! - (and (fboundp 'flyspell-unhighlight-at) - (flyspell-unhighlight-at start)) + (when (fboundp 'flyspell-unhighlight-at) + (flyspell-unhighlight-at start)) nil) ((or (= char ?a) (= char ?A)) ; accept word without insert (ispell-send-string (concat "@" word "\n")) - (add-to-list 'ispell-buffer-session-localwords word) - (and (fboundp 'flyspell-unhighlight-at) - (flyspell-unhighlight-at start)) + (cl-pushnew word ispell-buffer-session-localwords + :test #'equal) + (when (fboundp 'flyspell-unhighlight-at) + (flyspell-unhighlight-at start)) (or ispell-buffer-local-name ; session localwords might conflict (setq ispell-buffer-local-name (buffer-name))) (if (null ispell-pdict-modified-p) @@ -2509,13 +2246,12 @@ Global `ispell-quit' set to start location to continue spell session." (window-width)) (insert "\n")) (while (memq count command-characters) - (setq count (ispell-int-char (1+ count)) + (setq count (1+ count) skipped (1+ skipped))) (insert "(" count ") " (car choices) " ") (setq choices (cdr choices) - count (ispell-int-char (1+ count)))) - (setq count (ispell-int-char - (- count ?0 skipped)))) + count (1+ count))) + (setq count (- count ?0 skipped))) (setq textwin (selected-window)) (ispell-show-choices) (select-window textwin)))) @@ -2682,8 +2418,8 @@ SPC: Accept word this time. (defun ispell-lookup-words (word &optional lookup-dict) "Look up WORD in optional word-list dictionary LOOKUP-DICT. A `*' serves as a wild card. If no wild cards, `look' is used if it exists. -Otherwise the variable `ispell-grep-command' contains the command used to -search for the words (usually egrep). +Otherwise the variable `ispell-grep-command' contains the command +\(usually \"grep\") used to search for the words. Optional second argument contains the dictionary to use; the default is `ispell-alternate-dictionary', overridden by `ispell-complete-word-dict' @@ -2760,7 +2496,7 @@ if defined." ;; This is the case when a process dies or fails. The default behavior ;; in this case treats the next input received as fresh input. -(defun ispell-filter (process output) +(defun ispell-filter (_process output) "Output filter function for ispell, grep, and look." (let ((start 0) (continue t) @@ -2828,17 +2564,6 @@ Optional REFRESH will unhighlighted then highlight, using block cursor (if (eq 'block refresh) start (- start 2)) end t)))) -(defun ispell-highlight-spelling-error-xemacs (start end &optional highlight) - "Highlight the word from START to END using `isearch-highlight'. -When the optional third arg HIGHLIGHT is set, the word is highlighted, -otherwise it is displayed normally." - (if highlight - (isearch-highlight start end) - (isearch-dehighlight)) - ;;(sit-for 0) - ) - - (defun ispell-highlight-spelling-error-overlay (start end &optional highlight) "Highlight the word from START to END using overlays. When the optional third arg HIGHLIGHT is set, the word is highlighted @@ -2874,14 +2599,9 @@ The variable `ispell-highlight-face' selects the face to use for highlighting." (defun ispell-highlight-spelling-error (start end &optional highlight refresh) - (cond - ((featurep 'xemacs) - (ispell-highlight-spelling-error-xemacs start end highlight)) - ((and (featurep 'faces) - (or (and (fboundp 'display-color-p) (display-color-p)) - window-system)) - (ispell-highlight-spelling-error-overlay start end highlight)) - (t (ispell-highlight-spelling-error-generic start end highlight refresh)))) + (if (display-color-p) + (ispell-highlight-spelling-error-overlay start end highlight) + (ispell-highlight-spelling-error-generic start end highlight refresh))) (defun ispell-display-buffer (buffer) "Show BUFFER in new window above selected one. @@ -3040,17 +2760,14 @@ Keeps argument list for future Ispell invocations for no async support." (ispell-send-string "\032\n") ; so Ispell prints version and exits t))) - (defun ispell-init-process () "Check status of Ispell process and start if necessary." (let* (;; Basename of dictionary used by the spell-checker (dict-bname (or (car (cdr (member "-d" (ispell-get-ispell-args)))) ispell-current-dictionary)) - ;; The directory where process was started. - (current-ispell-directory default-directory) ;; The default directory for the process. ;; Use "~/" as default-directory unless using Ispell with per-dir - ;; personal dictionaries and not in a minibuffer under XEmacs + ;; personal dictionaries (default-directory (if (or ispell-really-aspell ispell-really-hunspell @@ -3063,9 +2780,8 @@ Keeps argument list for future Ispell invocations for no async support." ".ispell_" (or dict-bname "default"))))) - ;; Ispell, in a minibuffer, and XEmacs - (and (window-minibuffer-p) - (not (fboundp 'minibuffer-selected-window)))) + ;; Ispell, in a minibuffer + (window-minibuffer-p)) (expand-file-name "~/") (expand-file-name default-directory)))) ;; Check if process needs restart @@ -3097,29 +2813,21 @@ Keeps argument list for future Ispell invocations for no async support." (unless (equal ispell-process-directory (expand-file-name "~/")) ;; At this point, `ispell-process-directory' will be "~/" unless using - ;; Ispell with directory-specific dicts and not in XEmacs minibuffer. + ;; Ispell with directory-specific dicts. ;; If not, kill ispell process when killing buffer. It may be in a ;; removable device that would otherwise become un-mountable. (with-current-buffer - (if (and (window-minibuffer-p) ;; In minibuffer - (fboundp 'minibuffer-selected-window)) ;; Not XEmacs. + (if (window-minibuffer-p) ;; In minibuffer ;; In this case kill ispell only when parent buffer is killed ;; to avoid over and over ispell kill. (window-buffer (minibuffer-selected-window)) (current-buffer)) - ;; 'local does not automatically make hook buffer-local in XEmacs. - (if (featurep 'xemacs) - (make-local-hook 'kill-buffer-hook)) - (add-hook 'kill-buffer-hook + (add-hook 'kill-buffer-hook (lambda () (ispell-kill-ispell t)) nil 'local))) (if ispell-async-processp (set-process-filter ispell-process 'ispell-filter)) - ;; Protect against XEmacs bogus binding of `enable-multibyte-characters'. - (if (and (or (featurep 'xemacs) - (and (boundp 'enable-multibyte-characters) - enable-multibyte-characters)) - (fboundp 'set-process-coding-system) + (if (and enable-multibyte-characters ;; Evidently, some people use the synchronous mode even ;; when async subprocesses are supported, in which case ;; set-process-coding-system is bound, but @@ -3150,17 +2858,13 @@ Keeps argument list for future Ispell invocations for no async support." ;; Otherwise we get cool errors like "Can't open ". (sleep-for 1) (ispell-accept-output 3) - (error "%s" (mapconcat 'identity ispell-filter "\n")))) + (error "%s" (mapconcat #'identity ispell-filter "\n")))) (setq ispell-filter nil) ; Discard version ID line (let ((extended-char-mode (ispell-get-extended-character-mode))) (if extended-char-mode ; ~ extended character mode (ispell-send-string (concat extended-char-mode "\n")))) - (if ispell-async-processp - (if (featurep 'emacs) - (set-process-query-on-exit-flag ispell-process nil) - (if (fboundp 'set-process-query-on-exit-flag) - (set-process-query-on-exit-flag ispell-process nil) - (process-kill-without-query ispell-process))))))) + (when ispell-async-processp + (set-process-query-on-exit-flag ispell-process nil))))) ;;;###autoload (defun ispell-kill-ispell (&optional no-error clear) @@ -3172,9 +2876,7 @@ With CLEAR, buffer session localwords are cleaned." ;; to optimize the common cases. (run-hooks 'ispell-kill-ispell-hook) (if (or clear - (if (featurep 'xemacs) - (interactive-p) - (called-interactively-p 'interactive))) + (called-interactively-p 'interactive)) (setq ispell-buffer-session-localwords nil)) (if (not (and ispell-process (eq (ispell-process-status) 'run))) @@ -3206,7 +2908,7 @@ By just answering RET you can find out what the current dictionary is." (list (completing-read "Use new dictionary (RET for current, SPC to complete): " (and (fboundp 'ispell-valid-dictionary-list) - (mapcar 'list (ispell-valid-dictionary-list))) + (mapcar #'list (ispell-valid-dictionary-list))) nil t) current-prefix-arg)) (ispell-set-spellchecker-params) ; Initialize variables and dicts alists @@ -3223,9 +2925,7 @@ By just answering RET you can find out what the current dictionary is." ;; Specified dictionary is the default already. Could reload ;; the dictionaries if needed. (ispell-internal-change-dictionary) - (and (if (featurep 'xemacs) - (interactive-p) - (called-interactively-p 'interactive)) + (when (called-interactively-p 'interactive) (message "No change, using %s dictionary" dict))) (t ; reset dictionary! (if (or (assoc dict ispell-local-dictionary-alist) @@ -3412,7 +3112,7 @@ ispell-region: Search for first region to skip after (ispell-begin-skip-region-r Includes `ispell-skip-region-alist' plus tex, tib, html, and comment keys. Must be called after `ispell-buffer-local-parsing' due to dependence on mode." (mapconcat - 'identity + #'identity (delq nil (list ;; messages @@ -3638,7 +3338,10 @@ Returns the sum SHIFT due to changes in word replacements." ;; Markers can move with highlighting! This destroys ;; end of region markers line-end and ispell-region-end (let ((word-start - (copy-marker (+ ispell-start ispell-offset (car (cdr poss))))) + ;; There is a -1 offset here as the string is escaped + ;; with '^' to prevent us accidentally sending any + ;; ispell commands. + (copy-marker (+ ispell-start -1 (car (cdr poss))))) (word-len (length (car poss))) (line-end (copy-marker ispell-end)) (line-start (copy-marker ispell-start)) @@ -3869,7 +3572,7 @@ Standard ispell choices are then available." (setq case-fold-search nil) ; Try and respect case of word. (cond ((string-equal (upcase word) word) - (setq possibilities (mapcar 'upcase possibilities))) + (setq possibilities (mapcar #'upcase possibilities))) ((eq (upcase (aref word 0)) (aref word 0)) (setq possibilities (mapcar (function (lambda (pos) @@ -4103,10 +3806,10 @@ The `X' command aborts sending the message so that you can edit the buffer. To spell-check whenever a message is sent, include the appropriate lines in your init file: - (add-hook \\='message-send-hook \\='ispell-message) ;; GNUS 5 - (add-hook \\='news-inews-hook \\='ispell-message) ;; GNUS 4 - (add-hook \\='mail-send-hook \\='ispell-message) - (add-hook \\='mh-before-send-letter-hook \\='ispell-message) + (add-hook \\='message-send-hook #\\='ispell-message) ;; GNUS 5 + (add-hook \\='news-inews-hook #\\='ispell-message) ;; GNUS 4 + (add-hook \\='mail-send-hook #\\='ispell-message) + (add-hook \\='mh-before-send-letter-hook #\\='ispell-message) You can bind this to the key C-c i in GNUS or mail by adding to `news-reply-mode-hook' or `mail-mode-hook' the following lambda expression: @@ -4135,29 +3838,23 @@ You can bind this to the key C-c i in GNUS or mail by adding to (point-max))) (t (min (point-max) (funcall ispell-message-text-end)))))) (default-prefix ; Vanilla cite prefix (just used for cite-regexp) - (if (and (boundp 'mail-yank-prefix) mail-yank-prefix) - (ispell-non-empty-string mail-yank-prefix) + (if (ispell-non-empty-string mail-yank-prefix) " \\|\t")) (cite-regexp ;Prefix of quoted text (cond - ((functionp 'sc-cite-regexp) ; sc 3.0 - (ispell-with-no-warnings + ((functionp 'sc-cite-regexp) ; supercite >= 3.0 + (with-no-warnings (concat "\\(" (sc-cite-regexp) "\\)" "\\|" (ispell-non-empty-string sc-reference-tag-string)))) - ((boundp 'sc-cite-regexp) ; sc 2.3 - (concat "\\(" sc-cite-regexp "\\)" "\\|" - (ispell-with-no-warnings - (ispell-non-empty-string sc-reference-tag-string)))) - ((or (equal major-mode 'news-reply-mode) ;GNUS 4 & below - (equal major-mode 'message-mode)) ;GNUS 5 + ((equal major-mode 'message-mode) ; GNUS >= 5 (concat "In article <" "\\|" "[^,;&+=\n]+ <[^,;&+=]+> writes:" "\\|" - (ispell-with-no-warnings message-cite-prefix-regexp) + (with-no-warnings message-cite-prefix-regexp) "\\|" default-prefix)) ((equal major-mode 'mh-letter-mode) ; mh mail message (concat "[^,;&+=\n]+ writes:" "\\|" - (ispell-with-no-warnings + (with-no-warnings (ispell-non-empty-string mh-ins-buf-prefix)))) ((not internal-messagep) ; Assume nn sent us this message. (concat "In [a-zA-Z.]+ you write:" "\\|" @@ -4381,8 +4078,8 @@ Both should not be used to define a buffer-local dictionary." ;; Returns optionally adjusted region-end-point. -;; If comment-padright is defined, newcomment must be loaded. -(declare-function comment-add "newcomment" (arg)) +;; If comment-normalize-vars is defined, newcomment must be loaded. +(declare-function comment-normalize-vars "newcomment" (&optional noerror)) (defun ispell-add-per-file-word-list (word) "Add WORD to the per-file word list." @@ -4408,16 +4105,12 @@ Both should not be used to define a buffer-local dictionary." (unless found (newline)) (insert (if comment-start (concat - (if (fboundp 'comment-padright) - ;; Try and use the proper comment marker, - ;; e.g. ";;" rather than ";". - (progn - ;; XEmacs: comment-normalize-vars - ;; (newcomment.el) only in >= 21.5 - (and (fboundp 'comment-normalize-vars) - (comment-normalize-vars)) - (comment-padright comment-start - (comment-add nil))) + (progn + ;; Try and use the proper comment marker, + ;; e.g. ";;" rather than ";". + (comment-normalize-vars) + (comment-padright comment-start + (comment-add nil)) comment-start) " ") "") @@ -4428,6 +4121,7 @@ Both should not be used to define a buffer-local dictionary." (insert comment-end))))) (insert (concat " " word)))))))) +;;FIXME: Use `user-error' instead! (add-to-list 'debug-ignored-errors "^No word found to check!$") (provide 'ispell) @@ -4465,6 +4159,6 @@ Both should not be used to define a buffer-local dictionary." ; LocalWords: minipage pers dict unhighlight buf grep sync prev inc ; LocalWords: fn oldot NB AIX msg init read's bufs pt cmd Quinlan eg ; LocalWords: uuencoded unidiff sc nn VM SGML eval IspellPersDict -; LocalWords: lns XEmacs HTML casechars Multibyte +; LocalWords: lns HTML casechars Multibyte ;;; ispell.el ends here |