summaryrefslogtreecommitdiff
path: root/lisp/textmodes/ispell.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/textmodes/ispell.el')
-rw-r--r--lisp/textmodes/ispell.el197
1 files changed, 107 insertions, 90 deletions
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index 65f61644b6d..14de77cd542 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -44,6 +44,7 @@
;; ispell-buffer
;; ispell-message
;; ispell-comments-and-strings
+;; ispell-comment-or-string-at-point
;; ispell-continue
;; ispell-complete-word
;; ispell-complete-word-interior-frag
@@ -197,14 +198,13 @@ Must be greater than 1."
: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")
(executable-find "hunspell")
+ ;; Enchant is commonly installed as `enchant-2', so use this
+ ;; name and avoid old versions of `enchant'.
+ (executable-find "enchant-2")
"ispell")
"Program invoked by \\[ispell-word] and \\[ispell-region] commands."
:type 'string
@@ -329,7 +329,7 @@ The function must take one string argument and return a string."
:group 'ispell)
;; FIXME framepop.el last updated c 2003 (?),
-;; probably something else replaces it these days.
+;; use posframe.
(defcustom ispell-use-framepop-p nil
"When non-nil ispell uses framepop to display choices in a dedicated frame.
You can set this variable to dynamically use framepop if you are in a
@@ -621,15 +621,6 @@ For Aspell, non-nil also means to try to automatically find its dictionaries.
Earlier Aspell versions do not consistently support charset encoding. Handling
this would require some extra guessing in `ispell-aspell-find-dictionary'.")
-(defvar ispell-aspell-supports-utf8 nil
- "Non-nil if Aspell has consistent command line UTF-8 support. Obsolete.
-ispell.el and flyspell.el will use for this purpose the more generic
-variable `ispell-encoding8-command' for both Aspell and Hunspell. Is left
-here just for backwards compatibility.")
-
-(make-obsolete-variable 'ispell-aspell-supports-utf8
- 'ispell-encoding8-command "23.1")
-
(defvar ispell-dicts-name2locale-equivs-alist
'(("american" "en_US")
("brasileiro" "pt_BR")
@@ -682,9 +673,7 @@ Otherwise returns the library directory name, if that is defined."
;; all versions, since versions earlier than 3.0.09 didn't identify
;; themselves on startup.
(interactive "p")
- (let ((default-directory (or (and (boundp 'temporary-file-directory)
- temporary-file-directory)
- default-directory))
+ (let ((default-directory (or temporary-file-directory default-directory))
(get-config-var
(lambda (var)
(when (re-search-forward
@@ -695,13 +684,9 @@ Otherwise returns the library directory name, if that is defined."
(with-temp-buffer
(setq status (ispell-call-process
ispell-program-name nil t nil
- ;; aspell doesn't accept the -vv switch.
(let ((case-fold-search
- (memq system-type '(ms-dos windows-nt)))
- (speller
- (file-name-nondirectory ispell-program-name)))
- ;; Assume anything that isn't `aspell' is Ispell.
- (if (string-match "\\`aspell" speller) "-v" "-vv"))))
+ (memq system-type '(ms-dos windows-nt))))
+ "-vv")))
(goto-char (point-min))
(if interactivep
;; Report version information of ispell
@@ -782,18 +767,23 @@ Otherwise returns the library directory name, if that is defined."
(setq ispell-really-hunspell nil))))))
result))
+(defmacro ispell-with-safe-default-directory (&rest body)
+ "Execute the forms in BODY with a reasonable
+`default-directory'."
+ (declare (indent 0) (debug t))
+ `(let ((default-directory default-directory))
+ (unless (file-accessible-directory-p default-directory)
+ (setq default-directory (expand-file-name "~/")))
+ ,@body))
+
(defun ispell-call-process (&rest args)
- "Like `call-process' but defend against bad `default-directory'."
- (let ((default-directory default-directory))
- (unless (file-accessible-directory-p default-directory)
- (setq default-directory (expand-file-name "~/")))
+ "Like `call-process', but defend against bad `default-directory'."
+ (ispell-with-safe-default-directory
(apply 'call-process args)))
(defun ispell-call-process-region (&rest args)
- "Like `call-process-region' but defend against bad `default-directory'."
- (let ((default-directory default-directory))
- (unless (file-accessible-directory-p default-directory)
- (setq default-directory (expand-file-name "~/")))
+ "Like `call-process-region', but defend against bad `default-directory'."
+ (ispell-with-safe-default-directory
(apply 'call-process-region args)))
(defvar ispell-debug-buffer)
@@ -1106,28 +1096,38 @@ to dictionaries found, and will remove aliases from the list
in `ispell-dicts-name2locale-equivs-alist' if an explicit
dictionary from that list was found."
(let ((hunspell-found-dicts
- (split-string
- (with-temp-buffer
- (ispell-call-process ispell-program-name
- null-device
- t
- nil
- "-D"
- ;; Use -a to prevent Hunspell from
- ;; trying to initialize its
- ;; curses/termcap UI, which causes it
- ;; to crash or fail to start in some
- ;; MS-Windows ports.
- "-a"
- ;; Hunspell 1.7.0 (and later?) won't
- ;; show LOADED DICTIONARY unless
- ;; there's at least one file argument
- ;; on the command line. So we feed
- ;; it with the null device.
- null-device)
- (buffer-string))
- "[\n\r]+"
- t))
+ (seq-filter
+ (lambda (str)
+ (when (string-match
+ ;; Hunspell gives this error when there is some
+ ;; installation problem, for example if $LANG is unset.
+ (concat "^Can't open affix or dictionary files "
+ "for dictionary named \"default\".$")
+ str)
+ (user-error "Hunspell error (is $LANG unset?): %s" str))
+ (file-name-absolute-p str))
+ (split-string
+ (with-temp-buffer
+ (ispell-call-process ispell-program-name
+ null-device
+ t
+ nil
+ "-D"
+ ;; Use -a to prevent Hunspell from
+ ;; trying to initialize its
+ ;; curses/termcap UI, which causes it
+ ;; to crash or fail to start in some
+ ;; MS-Windows ports.
+ "-a"
+ ;; Hunspell 1.7.0 (and later?) won't
+ ;; show LOADED DICTIONARY unless
+ ;; there's at least one file argument
+ ;; on the command line. So we feed
+ ;; it with the null device.
+ null-device)
+ (buffer-string))
+ "[\n\r]+"
+ t)))
hunspell-default-dict
hunspell-default-dict-entry
hunspell-multi-dict)
@@ -1217,13 +1217,14 @@ 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
+ (with-current-buffer standard-output
(apply #'ispell-call-process
(replace-regexp-in-string "enchant\\(-[0-9]\\)?\\'"
"enchant-lsmod\\1"
ispell-program-name)
- nil t nil args))))
+ ;; We discard stderr here because enchant-lsmod can emit
+ ;; unrelated warnings that will confuse us.
+ nil '(t nil) nil args))))
(defun ispell--get-extra-word-characters (&optional lang)
"Get the extra word characters for LANG as a character class.
@@ -1237,11 +1238,11 @@ If LANG is omitted, get the extra word characters for the default language."
"Find Enchant's dictionaries, and record in `ispell-enchant-dictionary-alist'."
(let* ((dictionaries
(split-string
- (ispell--call-enchant-lsmod "-list-dicts" (buffer-string)) " ([^)]+)\n"))
+ (ispell--call-enchant-lsmod "-list-dicts") " ([^)]+)\n" t))
(found
(mapcar #'(lambda (lang)
`(,lang "[[:alpha:]]" "[^[:alpha:]]"
- ,(ispell--get-extra-word-characters) t nil nil utf-8))
+ ,(ispell--get-extra-word-characters lang) 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.
@@ -2463,14 +2464,14 @@ SPC: Accept word this time.
(progn
(require 'ehelp)
(with-electric-help
- (function (lambda ()
- ;;This shouldn't be necessary: with-electric-help needs
- ;; an optional argument telling it about the smallest
- ;; acceptable window-height of the help buffer.
- ;;(if (< (window-height) 15)
- ;; (enlarge-window
- ;; (- 15 (ispell-adjusted-window-height))))
- (princ "Selections are:
+ (lambda ()
+ ;;This shouldn't be necessary: with-electric-help needs
+ ;; an optional argument telling it about the smallest
+ ;; acceptable window-height of the help buffer.
+ ;;(if (< (window-height) 15)
+ ;; (enlarge-window
+ ;; (- 15 (ispell-adjusted-window-height))))
+ (princ "Selections are:
DIGIT: Replace the word with a digit offered in the *Choices* buffer.
SPC: Accept word this time.
@@ -2490,7 +2491,7 @@ SPC: Accept word this time.
`C-l': Redraw screen.
`C-r': Recursive edit.
`C-z': Suspend Emacs or iconify frame.")
- nil))))
+ nil)))
(let ((help-1 (concat "[r/R]eplace word; [a/A]ccept for this session; "
@@ -3273,15 +3274,15 @@ otherwise, the current line is skipped."
Generated from `ispell-tex-skip-alists'."
(concat
;; raw tex keys
- (mapconcat (function (lambda (lst) (car lst)))
+ (mapconcat (lambda (lst) (car lst))
(car ispell-tex-skip-alists)
"\\|")
"\\|"
;; keys wrapped in begin{}
- (mapconcat (function (lambda (lst)
- (concat "\\\\begin[ \t\n]*{[ \t\n]*"
- (car lst)
- "[ \t\n]*}")))
+ (mapconcat (lambda (lst)
+ (concat "\\\\begin[ \t\n]*{[ \t\n]*"
+ (car lst)
+ "[ \t\n]*}"))
(car (cdr ispell-tex-skip-alists))
"\\|")))
@@ -3591,24 +3592,40 @@ Returns the sum SHIFT due to changes in word replacements."
;;;###autoload
-(defun ispell-comments-and-strings ()
- "Check comments and strings in the current buffer for spelling errors."
- (interactive)
- (goto-char (point-min))
+(defun ispell-comments-and-strings (&optional start end)
+ "Check comments and strings in the current buffer for spelling errors.
+If called interactively with an active region, check only comments and
+strings in the region.
+When called from Lisp, START and END buffer positions can be provided
+to limit the check."
+ (interactive (when (use-region-p) (list (region-beginning) (region-end))))
+ (unless end (setq end (point-max)))
+ (goto-char (or start (point-min)))
(let (state done)
(while (not done)
(setq done t)
- (setq state (parse-partial-sexp (point) (point-max)
- nil nil state 'syntax-table))
+ (setq state (parse-partial-sexp (point) end nil nil state 'syntax-table))
(if (or (nth 3 state) (nth 4 state))
(let ((start (point)))
- (setq state (parse-partial-sexp start (point-max)
+ (setq state (parse-partial-sexp start end
nil nil state 'syntax-table))
(if (or (nth 3 state) (nth 4 state))
(error "Unterminated string or comment"))
(save-excursion
(setq done (not (ispell-region start (point))))))))))
+;;;###autoload
+(defun ispell-comment-or-string-at-point ()
+ "Check the comment or string containing point for spelling errors."
+ (interactive)
+ (save-excursion
+ (let ((state (syntax-ppss)))
+ (if (or (nth 3 state) (nth 4 state))
+ (ispell-region (nth 8 state)
+ (progn (parse-partial-sexp (point) (point-max)
+ nil nil state 'syntax-table)
+ (point)))
+ (user-error "Not inside a string or comment")))))
;;;###autoload
(defun ispell-buffer ()
@@ -3687,11 +3704,10 @@ Standard ispell choices are then available."
((string-equal (upcase word) word)
(setq possibilities (mapcar #'upcase possibilities)))
((eq (upcase (aref word 0)) (aref word 0))
- (setq possibilities (mapcar (function
- (lambda (pos)
- (if (eq (aref word 0) (aref pos 0))
- pos
- (capitalize pos))))
+ (setq possibilities (mapcar (lambda (pos)
+ (if (eq (aref word 0) (aref pos 0))
+ pos
+ (capitalize pos)))
possibilities))))
(setq case-fold-search case-fold-search-val)
(save-window-excursion
@@ -3734,8 +3750,7 @@ looking for a dictionary, please see the distribution of the GNU ispell
program, or do an Internet search; there are various dictionaries
available on the net."
(interactive)
- (if (and (boundp 'transient-mark-mode) transient-mark-mode
- (boundp 'mark-active) mark-active)
+ (if (and transient-mark-mode mark-active)
(ispell-region (region-beginning) (region-end))
(ispell-buffer)))
@@ -3923,7 +3938,7 @@ in your init file:
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:
- (function (lambda () (local-set-key \"\\C-ci\" \\='ispell-message)))"
+ (lambda () (local-set-key \"\\C-ci\" \\='ispell-message))"
(interactive)
(save-excursion
(goto-char (point-min))
@@ -4200,7 +4215,7 @@ Both should not be used to define a buffer-local dictionary."
(let (line-okay search done found)
(while (not done)
(let ((case-fold-search nil))
- (setq search (search-forward ispell-words-keyword nil 'move)
+ (setq search (search-forward ispell-words-keyword nil t)
found (or found search)
line-okay (< (+ (length word) 1 ; 1 for space after word..
(progn (end-of-line) (current-column)))
@@ -4211,8 +4226,10 @@ Both should not be used to define a buffer-local dictionary."
(setq done t)
(if (null search)
(progn
- (open-line 1)
- (unless found (newline))
+ (if found (insert "\n") ;; after an existing LocalWords
+ (goto-char (point-max)) ;; no LocalWords, go to end of file
+ (open-line 1)
+ (newline))
(insert (if comment-start
(concat
(progn