;;; flyspell.el --- on-the-fly spell checker
-;; Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
;; Author: Manuel Serrano <Manuel.Serrano@unice.fr>
;; Keywords: convenience
;; To enable Flyspell in text representing computer programs, type
;; M-x flyspell-prog-mode.
;; In that mode only text inside comments is checked.
-;;
+;;
;; Note: consider setting the variable ispell-parser to `tex' to
;; avoid TeX command checking; use `(setq ispell-parser 'tex)'.
-;;
+;;
;; Some user variables control the behavior of flyspell. They are
;; those defined under the `User variables' comment.
;;; Code:
+
(require 'ispell)
;*---------------------------------------------------------------------*/
"Spell checking on the fly."
:tag "FlySpell"
:prefix "flyspell-"
+ :group 'ispell
:group 'processes)
;*---------------------------------------------------------------------*/
:group 'flyspell
:type 'boolean)
+(defcustom flyspell-issue-message-flag t
+ "*Non-nil means that Flyspell emits messages when checking words."
+ :group 'flyspell
+ :type 'boolean)
+
(defcustom flyspell-incorrect-hook nil
"*List of functions to be called when incorrect words are encountered.
Each function is given three arguments: the beginning and the end
:version "21.1"
:type 'hook)
-(defcustom flyspell-default-dictionary "american"
+(defcustom flyspell-default-dictionary nil
"A string that is the name of the default dictionary.
This is passed to the `ispell-change-dictionary' when flyspell is started.
-If the variables `ispell-local-dictionary' or `ispell-dictionary' are non nil
-when flyspell is started, the value of that variables is used instead
-of `flyspell-default-dictionary' to select the default dictionary."
+If the variable `ispell-local-dictionary' or `ispell-dictionary' is non-nil
+when flyspell is started, the value of that variable is used instead
+of `flyspell-default-dictionary' to select the default dictionary.
+Otherwise, if `flyspell-default-dictionary' is nil, it means to use
+Ispell's ultimate default dictionary."
:group 'flyspell
:version "21.1"
- :type 'string)
+ :type '(choice string (const :tag "Default" nil)))
(defcustom flyspell-tex-command-regexp
"\\(\\(begin\\|end\\)[ \t]*{\\|\\(cite[a-z*]*\\|label\\|ref\\|eqref\\|usepackage\\|documentclass\\)[ \t]*\\(\\[[^]]*\\]\\)?{[^{}]*\\)"
:group 'flyspell
:version "21.1"
:type 'boolean)
-
+
;;;###autoload
(defcustom flyspell-mode-line-string " Fly"
"*String displayed on the modeline when flyspell is active.
Set this to nil if you don't want a modeline indicator."
:group 'flyspell
- :type 'string)
+ :type '(choice string (const :tag "None" nil)))
(defcustom flyspell-large-region 1000
"*The threshold that determines if a region is small.
:version "21.1"
:type 'number)
+(defcustom flyspell-insert-function (function insert)
+ "*Function for inserting word by flyspell upon correction."
+ :group 'flyspell
+ :type 'function)
+
+(defcustom flyspell-before-incorrect-word-string nil
+ "String used to indicate an incorrect word starting."
+ :group 'flyspell
+ :type '(choice string (const nil)))
+
+(defcustom flyspell-after-incorrect-word-string nil
+ "String used to indicate an incorrect word ending."
+ :group 'flyspell
+ :type '(choice string (const nil)))
+
;*---------------------------------------------------------------------*/
;* Mode specific options */
;* ------------------------------------------------------------- */
(defun mail-mode-flyspell-verify ()
"This function is used for `flyspell-generic-check-word-p' in Mail mode."
(let ((in-headers (save-excursion
- (re-search-forward mail-header-separator nil t)))
+ ;; When mail-header-separator is "",
+ ;; it is likely to be found in both directions.
+ (not (re-search-backward (concat "^" (regexp-quote mail-header-separator) "$") nil t))))
(in-signature (save-excursion
(re-search-backward message-signature-separator nil t))))
(cond (in-headers
;*---------------------------------------------------------------------*/
;* The minor mode declaration. */
;*---------------------------------------------------------------------*/
+(eval-when-compile (defvar flyspell-local-mouse-map))
+
+;;;###autoload
(defvar flyspell-mode nil)
(make-variable-buffer-local 'flyspell-mode)
(define-key map "\M-\t" #'flyspell-auto-correct-word)))
map))
+;;;###autoload
+(defvar flyspell-mode-map (make-sparse-keymap))
+
+;; mouse, keyboard bindings and misc definition
+(when (or (assoc 'flyspell-mode minor-mode-map-alist)
+ (setq minor-mode-map-alist
+ (cons (cons 'flyspell-mode flyspell-mode-map)
+ minor-mode-map-alist)))
+ (define-key flyspell-mode-map "\M-\t" 'flyspell-auto-correct-word))
+
;; the name of the overlay property that defines the keymap
(defvar flyspell-overlay-keymap-property-name 'keymap)
;* Highlighting */
;*---------------------------------------------------------------------*/
(defface flyspell-incorrect-face
- '((((class color)) (:foreground "OrangeRed" :bold t :underline t))
- (t (:bold t)))
+ (if (eq flyspell-emacs 'xemacs)
+ '((((class color)) (:foreground "OrangeRed" :bold t :underline t))
+ (t (:bold t)))
+ '((((class color)) (:foreground "OrangeRed" :weight bold :underline t))
+ (t (:weight bold))))
"Face used for marking a misspelled word in Flyspell."
:group 'flyspell)
(defface flyspell-duplicate-face
- '((((class color)) (:foreground "Gold3" :bold t :underline t))
- (t (:bold t)))
+ (if (eq flyspell-emacs 'xemacs)
+ '((((class color)) (:foreground "Gold3" :bold t :underline t))
+ (t (:bold t)))
+ '((((class color)) (:foreground "Gold3" :weight bold :underline t))
+ (t (:weight bold))))
"Face used for marking a misspelled word that appears twice in the buffer.
See also `flyspell-duplicate-distance'."
:group 'flyspell)
The default flyspell behavior is to highlight incorrect words.
With no argument, this command toggles Flyspell mode.
With a prefix argument ARG, turn Flyspell minor mode on iff ARG is positive.
-
+
Bindings:
\\[ispell-word]: correct words (using Ispell).
\\[flyspell-auto-correct-word]: automatically correct word.
;;;###autoload
(add-minor-mode 'flyspell-mode
'flyspell-mode-line-string
- nil
+ flyspell-mode-map
nil
'flyspell-mode)
;* For remembering buffers running flyspell */
;*---------------------------------------------------------------------*/
(defvar flyspell-buffers nil)
-
+
;*---------------------------------------------------------------------*/
;* flyspell-minibuffer-p ... */
;*---------------------------------------------------------------------*/
(let ((ws (get-buffer-window-list buffer t)))
(and (consp ws) (window-minibuffer-p (car ws)))))
+;*---------------------------------------------------------------------*/
+;* flyspell-version ... */
+;*---------------------------------------------------------------------*/
+;;;###autoload
+(defun flyspell-version ()
+ "The flyspell version"
+ (interactive)
+ "1.6h")
+
;*---------------------------------------------------------------------*/
;* flyspell-accept-buffer-local-defs ... */
;*---------------------------------------------------------------------*/
(ispell-accept-buffer-local-defs)
(if (not (and (eq flyspell-dash-dictionary ispell-dictionary)
(eq flyspell-dash-local-dictionary ispell-local-dictionary)))
- ;; the dictionary as changed
+ ;; the dictionary has changed
(progn
(setq flyspell-dash-dictionary ispell-dictionary)
(setq flyspell-dash-local-dictionary ispell-local-dictionary)
;*---------------------------------------------------------------------*/
;* flyspell-mode-on ... */
;*---------------------------------------------------------------------*/
-(eval-when-compile (defvar flyspell-local-mouse-map))
-
(defun flyspell-mode-on ()
"Turn Flyspell mode on. Do not use this; use `flyspell-mode' instead."
(setq ispell-highlight-face 'flyspell-incorrect-face)
;; otherwise it could be too late, the local dictionary may
;; be forgotten!
(flyspell-accept-buffer-local-defs)
- ;; we put the `flyspel-delayed' property on some commands
+ ;; we put the `flyspell-delayed' property on some commands
(flyspell-delay-commands)
- ;; we put the `flyspel-deplacement' property on some commands
+ ;; we put the `flyspell-deplacement' property on some commands
(flyspell-deplacement-commands)
;; we bound flyspell action to post-command hook
(add-hook 'post-command-hook (function flyspell-post-command-hook) t t)
(if mode-predicate
(setq flyspell-generic-check-word-p mode-predicate)))
;; the welcome message
- (if (and flyspell-issue-welcome-flag (interactive-p))
+ (if (and flyspell-issue-message-flag
+ flyspell-issue-welcome-flag
+ (interactive-p))
(let ((binding (where-is-internal 'flyspell-auto-correct-word
nil 'non-ascii)))
(message
(format "Welcome to flyspell. Use %s or Mouse-2 to correct words."
(key-description binding))
"Welcome to flyspell. Use Mouse-2 to correct words."))))
-
;; we end with the flyspell hooks
(run-hooks 'flyspell-mode-hook))
(= flyspell-pre-point (+ (point) 1)))
nil)
((and (symbolp this-command)
+ (not executing-kbd-macro)
(or (get this-command 'flyspell-delayed)
(and (get this-command 'flyspell-deplacement)
(eq flyspell-previous-command this-command)))
(insert (format " cache-start: %S\n" flyspell-word-cache-start))
(insert (format " cache-end : %S\n" flyspell-word-cache-end))
(goto-char (point-max)))))
-
+
;*---------------------------------------------------------------------*/
;* flyspell-debug-signal-word-checked ... */
;*---------------------------------------------------------------------*/
(if flyspell-sort-corrections
(sort (car (cdr (cdr poss))) 'string<)
(car (cdr (cdr poss)))))))
- (message (format "mispelling `%s' %S" word replacements))))
+ (if flyspell-issue-message-flag
+ (message (format "mispelling `%s' %S" word replacements)))))
;*---------------------------------------------------------------------*/
;* flyspell-word ... */
(setq flyspell-ispell-casechars-cache ispell-casechars)
(setq flyspell-casechars-cache ispell-casechars)
flyspell-casechars-cache))))
-
+
;*---------------------------------------------------------------------*/
;* flyspell-get-not-casechars-cache ... */
;*---------------------------------------------------------------------*/
(goto-char beg)
(let ((count 0))
(while (< (point) end)
- (if (= count 100)
+ (if (and flyspell-issue-message-flag (= count 100))
(progn
(message "Spell Checking...%d%%"
(* 100 (/ (float (- (point) beg)) (- end beg))))
(if (and (< (point) end) (> (point) (+ cur 1)))
(backward-char 1)))))
(backward-char 1)
- (message "Spell Checking completed.")
+ (if flyspell-issue-message-flag (message "Spell Checking completed."))
(flyspell-word)))
;*---------------------------------------------------------------------*/
(goto-char (match-end 0))
(set-buffer flyspell-large-region-buffer)
(goto-char flyspell-large-region-beg)
- (message "Spell Checking...%d%% [%s]"
- (* 100 (/ (float (- (point) start)) size))
- word)
+ (if flyspell-issue-message-flag
+ (message "Spell Checking...%d%% [%s]"
+ (* 100 (/ (float (- (point) start)) size))
+ word))
(if (search-forward word flyspell-large-region-end t)
(progn
(setq flyspell-large-region-beg (point))
(set-buffer buffer))
(goto-char (point-max)))))
;; we are done
- (message "Spell Checking completed.")
+ (if flyspell-issue-message-flag (message "Spell Checking completed."))
;; ok, we are done with pointing out incorrect words, we just
;; have to kill the temporary buffer
(kill-buffer flyspell-external-ispell-buffer)
(setq flyspell-external-ispell-buffer nil)))
-
+
;*---------------------------------------------------------------------*/
;* flyspell-large-region ... */
;*---------------------------------------------------------------------*/
(set-buffer buffer)
(erase-buffer)
;; this is done, we can start checking...
- (message "Checking region...")
+ (if flyspell-issue-message-flag (message "Checking region..."))
(set-buffer curbuf)
(let ((c (apply 'call-process-region beg
end
ispell-personal-dictionary)))))
(setq args (append args ispell-extra-args))
args))))
- (if (= c 0)
+ (if (eq c 0)
(flyspell-external-point-words)
(error "Can't check region...")))))
(overlay-put flyspell-overlay 'face face)
(overlay-put flyspell-overlay 'mouse-face mouse-face)
(overlay-put flyspell-overlay 'flyspell-overlay t)
+ (overlay-put flyspell-overlay 'evaporate t)
+ (overlay-put flyspell-overlay 'help-echo "mouse-2: correct word at point")
(if flyspell-use-local-map
- (overlay-put flyspell-overlay
- flyspell-overlay-keymap-property-name
- flyspell-mouse-map))
+ (overlay-put flyspell-overlay
+ flyspell-overlay-keymap-property-name
+ flyspell-mouse-map))
+ (when (eq face 'flyspell-incorrect-face)
+ (and (stringp flyspell-before-incorrect-word-string)
+ (overlay-put flyspell-overlay 'before-string
+ flyspell-before-incorrect-word-string))
+ (and (stringp flyspell-after-incorrect-word-string)
+ (overlay-put flyspell-overlay 'after-string
+ flyspell-after-incorrect-word-string)))
flyspell-overlay))
-
+
;*---------------------------------------------------------------------*/
;* flyspell-highlight-incorrect-region ... */
;*---------------------------------------------------------------------*/
;; now we can use a new overlay
(setq flyspell-overlay
(make-flyspell-overlay beg end
- 'flyspell-incorrect-face 'highlight))))))
+ 'flyspell-incorrect-face
+ 'highlight))))))
;*---------------------------------------------------------------------*/
;* flyspell-highlight-duplicate-region ... */
;; now we can use a new overlay
(setq flyspell-overlay
(make-flyspell-overlay beg end
- 'flyspell-duplicate-face 'highlight)))))
+ 'flyspell-duplicate-face
+ 'highlight)))))
;*---------------------------------------------------------------------*/
;* flyspell-auto-correct-cache ... */
(defun flyspell-abbrev-table ()
(if flyspell-use-global-abbrev-table-p
global-abbrev-table
- local-abbrev-table))
+ (or local-abbrev-table global-abbrev-table)))
+
+;*---------------------------------------------------------------------*/
+;* flyspell-define-abbrev ... */
+;*---------------------------------------------------------------------*/
+(defun flyspell-define-abbrev (name expansion)
+ (let ((table (flyspell-abbrev-table)))
+ (when table
+ (define-abbrev table name expansion))))
;*---------------------------------------------------------------------*/
;* flyspell-auto-correct-word ... */
;; we have already been using the function at the same location
(let* ((start (car flyspell-auto-correct-region))
(len (cdr flyspell-auto-correct-region)))
+ (flyspell-unhighlight-at start)
(delete-region start (+ start len))
(setq flyspell-auto-correct-ring (cdr flyspell-auto-correct-ring))
(let* ((word (car flyspell-auto-correct-ring))
(flyspell-change-abbrev (flyspell-abbrev-table)
flyspell-auto-correct-word
word)
- (define-abbrev (flyspell-abbrev-table)
- flyspell-auto-correct-word word)))
- (insert word)
+ (flyspell-define-abbrev flyspell-auto-correct-word word)))
+ (funcall flyspell-insert-function word)
(flyspell-word)
(flyspell-display-next-corrections flyspell-auto-correct-ring))
(flyspell-ajust-cursor-point pos (point) old-max)
(rplacd l (cons (car poss) replacements)))
(setq flyspell-auto-correct-ring
replacements)
+ (flyspell-unhighlight-at start)
(delete-region start end)
- (insert new-word)
+ (funcall flyspell-insert-function new-word)
(if flyspell-abbrev-p
(if (flyspell-already-abbrevp
(flyspell-abbrev-table) word)
(flyspell-abbrev-table)
word
new-word)
- (define-abbrev (flyspell-abbrev-table)
- word new-word)))
+ (flyspell-define-abbrev word new-word)))
(flyspell-word)
(flyspell-display-next-corrections
(cons new-word flyspell-auto-correct-ring))
old-max))))))))))
(setq flyspell-auto-correct-pos (point))
(ispell-pdict-save t)))))
-
+
+;*---------------------------------------------------------------------*/
+;* flyspell-auto-correct-previous-pos ... */
+;*---------------------------------------------------------------------*/
+(defvar flyspell-auto-correct-previous-pos nil
+ "Holds the start of the first incorrect word before point.")
+
+;*---------------------------------------------------------------------*/
+;* flyspell-auto-correct-previous-hook ... */
+;*---------------------------------------------------------------------*/
+(defun flyspell-auto-correct-previous-hook ()
+ "Hook to track successive calls to `flyspell-auto-correct-previous-word'.
+Sets flyspell-auto-correct-previous-pos to nil"
+ (interactive)
+ (remove-hook 'pre-command-hook (function flyspell-auto-correct-previous-hook) t)
+ (unless (eq this-command (function flyspell-auto-correct-previous-word))
+ (setq flyspell-auto-correct-previous-pos nil)))
+
+;*---------------------------------------------------------------------*/
+;* flyspell-auto-correct-previous-word ... */
+;*---------------------------------------------------------------------*/
+(defun flyspell-auto-correct-previous-word (position)
+ "*Auto correct the first mispelled word that occurs before point."
+ (interactive "d")
+
+ (add-hook 'pre-command-hook
+ (function flyspell-auto-correct-previous-hook) t t)
+
+ (save-excursion
+ (unless flyspell-auto-correct-previous-pos
+ ;; only reset if a new overlay exists
+ (setq flyspell-auto-correct-previous-pos nil)
+
+ (let ((overlay-list (overlays-in (point-min) position))
+ (new-overlay 'dummy-value))
+
+ ;; search for previous (new) flyspell overlay
+ (while (and new-overlay
+ (or (not (flyspell-overlay-p new-overlay))
+ ;; check if its face has changed
+ (not (eq (get-char-property
+ (overlay-start new-overlay) 'face)
+ 'flyspell-incorrect-face))))
+ (setq new-overlay (car-safe overlay-list))
+ (setq overlay-list (cdr-safe overlay-list)))
+
+ ;; if nothing new exits new-overlay should be nil
+ (if new-overlay;; the length of the word may change so go to the start
+ (setq flyspell-auto-correct-previous-pos
+ (overlay-start new-overlay)))))
+
+ (when flyspell-auto-correct-previous-pos
+ (save-excursion
+ (goto-char flyspell-auto-correct-previous-pos)
+ (let ((ispell-following-word t));; point is at start
+ (if (numberp flyspell-auto-correct-previous-pos)
+ (goto-char flyspell-auto-correct-previous-pos))
+ (flyspell-auto-correct-word))
+ ;; the point may have moved so reset this
+ (setq flyspell-auto-correct-previous-pos (point))))))
+
;*---------------------------------------------------------------------*/
;* flyspell-correct-word ... */
;*---------------------------------------------------------------------*/
(if (eq replace 'buffer)
(ispell-add-per-file-word-list word)))
(replace
+ (flyspell-unhighlight-at cursor-location)
(let ((new-word (if (atom replace)
replace
(car replace)))
(if (not (equal new-word (car poss)))
(let ((old-max (point-max)))
(delete-region start end)
- (insert new-word)
+ (funcall flyspell-insert-function new-word)
(if flyspell-abbrev-p
- (define-abbrev (flyspell-abbrev-table)
- word
- new-word))
+ (flyspell-define-abbrev word new-word))
(flyspell-ajust-cursor-point save
cursor-location
old-max)))))
(progn
(delete-region start end)
(goto-char start)
- (insert new-word)
+ (funcall flyspell-insert-function new-word)
(if flyspell-abbrev-p
- (define-abbrev (flyspell-abbrev-table)
- word
- new-word))))
+ (flyspell-define-abbrev word new-word))))
(flyspell-ajust-cursor-point save cursor-location old-max)))))
;*---------------------------------------------------------------------*/
(list
(list (concat "Save affix: " (car affix))
'save)
- '("Accept (session)" accept)
+ '("Accept (session)" session)
'("Accept (buffer)" buffer))
'(("Save word" save)
("Accept (session)" session)
menu))))
;*---------------------------------------------------------------------*/
-;* Some example functions for real autocorrecting */
+;* Some example functions for real autocorrecting */
;*---------------------------------------------------------------------*/
-
(defun flyspell-maybe-correct-transposition (beg end poss)
"Check replacements for transposed characters.
;*---------------------------------------------------------------------*/
(defun flyspell-change-abbrev (table old new)
(set (abbrev-symbol old table) new))
-
+
(provide 'flyspell)
+;;; arch-tag: 05d915b9-e9cf-44fb-9137-fc28f5eaab2a
;;; flyspell.el ends here