summaryrefslogtreecommitdiff
path: root/modules/flyspell-config.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
committerCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
commit754bbf7a25a8dda49b5d08ef0d0443bbf5af0e36 (patch)
treef1190704f78f04a2b0b4c977d20fe96a828377f1 /modules/flyspell-config.el
new repository
Diffstat (limited to 'modules/flyspell-config.el')
-rw-r--r--modules/flyspell-config.el191
1 files changed, 191 insertions, 0 deletions
diff --git a/modules/flyspell-config.el b/modules/flyspell-config.el
new file mode 100644
index 00000000..6109eebc
--- /dev/null
+++ b/modules/flyspell-config.el
@@ -0,0 +1,191 @@
+;;; flyspell-config.el --- Spell Check Configuration -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;; Spell-Checking: Flyspell
+;; C-' is now my main interface for all spell checking. It checks one word, then
+;; you may proceed to your next misspelling by selecting 'C-' again.
+
+;; Flyspell will automatically run in a mode that's appropriate for the buffer type
+;; - if it's a programming mode, it will only check comments
+;; - if in text mode, it will check everything
+;; - otherwise it will turn off.
+;; This check happens on every mode switch.
+
+;; If you want flyspell on in another mode (say fundamental mode), or you'd like it off
+;; to keep it from distracting, you can toggle flyspell's state with 'C-c f'
+
+;; The nicest thing is that each spell correction creates an abbrev. This essentially is a shortcut
+;; that expands that same misspelling to the correct spelling the next time it's typed. That
+;; idea comes courtesy Artur Malabarba, and it's increased my overall typing speed.
+;;
+;; Use M-o to get to 'other options', including saving to your personal dictionary.
+
+;;; Code:
+
+;; ------------------------ Reclaim Flyspell Keybinding ------------------------
+;; remove one of flyspell's many greedy keyboard bindings
+;; this is now used for my personal-keymap
+
+(eval-after-load "flyspell"
+ '(define-key flyspell-mode-map (kbd "C-;") nil))
+
+;; --------------------------------- Flyspell --------------------------------
+;; there's some ispell settings here as well.
+
+(use-package flyspell
+ :defer .5
+ :ensure nil ;; built-in
+ :config
+ (setq ispell-alternate-dictionary (concat user-emacs-directory "assets/english-words.txt"))
+ (setq ispell-dictionary "american") ; better for aspell
+ (setq ispell-extra-args '("--sug-mode=ultra" "-W" "3" "--lang=en_US"))
+ (setq ispell-list-command "--list") ;; in aspell "-l" means --list, not --lang
+ (setq ispell-local-dictionary "en_US")
+ (setq ispell-program-name "aspell") ;; use aspell instead of ispell
+ (setq ispell-local-dictionary-alist '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "['‘’]"
+ t ; Many other characters
+ ("-d" "en_US") nil utf-8)))
+
+ (setq ispell-personal-dictionary
+ (concat sync-dir "aspell-personal-dictionary")) ;; personal directory goes with sync'd files
+ (setq flyspell-issue-message-flag nil) ;; don't print message for every word when checking
+ (add-to-list 'ispell-skip-region-alist '("^#+BEGIN_SRC" . "^#+END_SRC"))) ;; skip code blocks in org mode
+
+
+(use-package flyspell-correct
+ :defer 1
+ :after flyspell
+ :bind
+ (:map flyspell-mode-map
+ ("C-'" . cj/flyspell-then-abbrev))) ;; disallow other entries to spelling corrections
+
+
+(use-package flyspell-correct-ivy
+ :defer 1
+ :after (ivy flyspell-correct)
+ :init
+ (setq flyspell-correct-interface #'flyspell-correct-ivy)) ;; use ivy as the flyspell interface
+
+
+;; ------------------------ Flyspell On For Buffer Type ------------------------
+;; check strings and comments in prog mode; everything in text mode
+
+(defun flyspell-on-for-buffer-type ()
+ "Enable Flyspell appropriately for the major mode and check the current buffer.
+If flyspell is already enabled, do nothing. If the mode is derived from
+`prog-mode', enable `flyspell-prog-mode' so only strings and comments get
+checked. If the buffer is text based `flyspell-mode' is enabled to check
+all text. Otherwise, flyspell is turned off."
+ (interactive)
+ (if (not (symbol-value flyspell-mode)) ; if not already on
+ (progn
+ (if (derived-mode-p 'prog-mode)
+ (progn
+ (flyspell-prog-mode)
+ (flyspell-buffer)))
+ (if (derived-mode-p 'text-mode)
+ (progn
+ (flyspell-mode 1)
+ (flyspell-buffer))
+ ;; else
+ (progn
+ (flyspell-mode 0))))))
+(add-hook 'after-change-major-mode-hook 'flyspell-on-for-buffer-type)
+(add-hook 'find-file-hook 'flyspell-on-for-buffer-type)
+
+;; ---------------------------- Flyspell Then Abbrev ---------------------------
+;; A stroke of genius from Artur Malabarba.
+;; http://endlessparentheses.com/ispell-and-abbrev-the-perfect-auto-correct.html
+;; Spell checks backwards (after you've noticed a typo). Corrects, then automatically
+;; creates an abbrev to autocorrect the same misspelling.
+;; Bound to C-; above.
+
+(setq save-abbrevs 'silently)
+(setq-default abbrev-mode t)
+
+(defun cj/flyspell-then-abbrev (p)
+ "Call `ispell-word', then create an abbrev for it.
+With prefix P, create local abbrev. Otherwise it will
+be global."
+ (interactive "P")
+ (save-excursion
+ (if (flyspell-goto-previous-word (point))
+ (let ((bef (downcase (or (thing-at-point 'word)
+ "")))
+ aft)
+ (call-interactively 'flyspell-correct-at-point)
+ (setq aft (downcase
+ (or (thing-at-point 'word) "")))
+ (unless (or (string= aft bef)
+ (string= aft "")
+ (string= bef ""))
+ (message "\"%s\" now expands to \"%s\" %sally"
+ bef aft (if p "loc" "glob"))
+ (define-abbrev
+ (if p local-abbrev-table global-abbrev-table)
+ bef aft)))
+ (message "Cannot find a misspelled word"))))
+
+(defun flyspell-goto-previous-word (position)
+ "Go to the first misspelled word that occurs before point.
+But don't look beyond what's visible on the screen."
+ (interactive "d")
+ (let ((top (window-start))
+ (bot (window-end)))
+ (save-restriction
+ (narrow-to-region top bot)
+ (overlay-recenter (point))
+ (add-hook 'pre-command-hook
+ (function flyspell-auto-correct-previous-hook) t t)
+ (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))))
+ (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)))))
+ (if (not flyspell-auto-correct-previous-pos)
+ nil
+ (goto-char flyspell-auto-correct-previous-pos)
+ t))))
+
+;; ------------------------------ Flyspell Toggle ------------------------------
+;; easy toggling flyspell which also leverages the 'for-buffer-type' functionality.
+
+(defun flyspell-toggle ()
+ "Turn Flyspell on if it is off, or off if it is on.
+When turning on,it uses `flyspell-on-for-buffer-type' so code-vs-text is
+handled appropriately."
+ (interactive)
+ (if (symbol-value flyspell-mode)
+ (progn ; flyspell is on, turn it off
+ (message "Flyspell off")
+ (flyspell-mode -1))
+ ;; else - flyspell is off, turn it on
+ (progn
+ (flyspell-on-for-buffer-type)
+ (message "Flyspell on"))))
+(global-set-key (kbd "C-c f") 'flyspell-toggle )
+
+
+;; -------------------------------- Ispell STFU --------------------------------
+;; tell ispell where to send it's spurious error messages
+
+(advice-add 'ispell-lookup-words :around
+ (lambda (orig &rest args)
+ (shut-up (apply orig args))))
+
+(provide 'flyspell-config)
+;;; flyspell-config.el ends here.