2020-01-09 18:41:48 -05:00
|
|
|
;;; checkers/spell/config.el -*- lexical-binding: t; -*-
|
2019-02-22 00:20:29 -05:00
|
|
|
|
2020-08-21 02:41:41 -04:00
|
|
|
;;
|
2020-08-23 18:48:50 -04:00
|
|
|
;;; Ispell
|
|
|
|
|
|
|
|
;; `elisp-mode' is loaded at startup. In order to lazy load its config we need
|
|
|
|
;; to pretend it isn't loaded
|
|
|
|
(delq! 'ispell features)
|
2020-08-21 02:41:41 -04:00
|
|
|
|
|
|
|
(global-set-key [remap ispell-word] #'+spell/correct)
|
2020-01-02 21:10:38 -05:00
|
|
|
|
2019-02-22 00:20:29 -05:00
|
|
|
(after! ispell
|
2019-07-28 22:55:18 +02:00
|
|
|
;; Don't spellcheck org blocks
|
|
|
|
(pushnew! ispell-skip-region-alist
|
|
|
|
'(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:")
|
|
|
|
'("#\\+BEGIN_SRC" . "#\\+END_SRC")
|
|
|
|
'("#\\+BEGIN_EXAMPLE" . "#\\+END_EXAMPLE"))
|
|
|
|
|
2020-08-26 13:57:06 +03:00
|
|
|
;; Enable either aspell, hunspell or enchant.
|
|
|
|
;; If no module flags are given, enable either aspell, hunspell or enchant
|
|
|
|
;; if their binary is found.
|
|
|
|
;; If one of the flags `+aspell', `+hunspell' or `+enchant' is given,
|
|
|
|
;; only enable that spell checker.
|
2019-04-02 14:03:27 -04:00
|
|
|
(pcase (cond ((featurep! +aspell) 'aspell)
|
|
|
|
((featurep! +hunspell) 'hunspell)
|
2020-08-26 13:57:06 +03:00
|
|
|
((featurep! +enchant) 'enchant)
|
|
|
|
((executable-find "aspell") 'aspell)
|
|
|
|
((executable-find "hunspell") 'hunspell)
|
|
|
|
((executable-find "enchant-2") 'enchant))
|
2019-04-02 14:03:27 -04:00
|
|
|
(`aspell
|
|
|
|
(setq ispell-program-name "aspell"
|
2020-08-23 02:32:58 -04:00
|
|
|
ispell-extra-args '("--sug-mode=ultra"
|
2020-09-09 23:04:38 +02:00
|
|
|
"--run-together"))
|
2020-08-23 02:32:58 -04:00
|
|
|
|
|
|
|
(unless ispell-aspell-dict-dir
|
|
|
|
(setq ispell-aspell-dict-dir
|
|
|
|
(ispell-get-aspell-config-value "dict-dir")))
|
|
|
|
(unless ispell-aspell-data-dir
|
|
|
|
(setq ispell-aspell-data-dir
|
|
|
|
(ispell-get-aspell-config-value "data-dir")))
|
|
|
|
(unless ispell-personal-dictionary
|
|
|
|
(setq ispell-personal-dictionary
|
|
|
|
(expand-file-name (concat "ispell/" ispell-dictionary ".pws")
|
|
|
|
doom-etc-dir)))
|
2019-03-18 15:52:32 +01:00
|
|
|
|
2019-07-28 14:52:59 +02:00
|
|
|
(add-hook! 'text-mode-hook
|
2020-01-09 18:41:48 -05:00
|
|
|
(defun +spell-remove-run-together-switch-for-aspell-h ()
|
2019-07-22 23:34:23 +02:00
|
|
|
(setq-local ispell-extra-args (remove "--run-together" ispell-extra-args))))
|
2019-03-18 15:52:32 +01:00
|
|
|
|
2020-01-09 18:41:48 -05:00
|
|
|
(defun +spell-init-ispell-extra-args-a (orig-fun &rest args)
|
2019-07-22 23:34:23 +02:00
|
|
|
:around '(ispell-word flyspell-auto-correct-word)
|
2019-04-02 14:03:27 -04:00
|
|
|
(let ((ispell-extra-args (remove "--run-together" ispell-extra-args)))
|
|
|
|
(ispell-kill-ispell t)
|
|
|
|
(apply orig-fun args)
|
2019-07-22 23:34:23 +02:00
|
|
|
(ispell-kill-ispell t))))
|
2019-03-18 15:52:32 +01:00
|
|
|
|
2019-04-02 14:03:27 -04:00
|
|
|
(`hunspell
|
2019-05-06 19:39:35 -04:00
|
|
|
(setq ispell-program-name "hunspell"))
|
2019-02-22 00:20:29 -05:00
|
|
|
|
2020-08-26 13:57:06 +03:00
|
|
|
(`enchant
|
|
|
|
(setq ispell-program-name "enchant-2"))
|
|
|
|
|
|
|
|
(_ (doom-log "Spell checker not found. Either install `aspell', `hunspell' or `enchant'"))))
|
2019-02-22 00:20:29 -05:00
|
|
|
|
|
|
|
|
2020-08-23 18:48:50 -04:00
|
|
|
;;
|
|
|
|
;;; Implementations
|
|
|
|
|
2020-08-26 21:40:53 -04:00
|
|
|
(eval-if! (not (featurep! +flyspell))
|
2020-08-23 18:48:50 -04:00
|
|
|
|
2020-11-13 20:51:54 +01:00
|
|
|
(use-package! spell-fu
|
|
|
|
:when (executable-find "aspell")
|
|
|
|
:hook (text-mode . spell-fu-mode)
|
|
|
|
:general ([remap ispell-word] #'+spell/correct)
|
|
|
|
:preface
|
2020-08-23 18:48:50 -04:00
|
|
|
(defvar +spell-correct-interface
|
|
|
|
(cond ((featurep! :completion ivy)
|
|
|
|
#'+spell-correct-ivy-fn)
|
|
|
|
((featurep! :completion helm)
|
|
|
|
#'+spell-correct-helm-fn)
|
|
|
|
(#'+spell-correct-generic-fn))
|
2020-11-13 20:51:54 +01:00
|
|
|
"Function to use to display corrections.")
|
2020-08-23 18:48:50 -04:00
|
|
|
|
2020-11-13 15:37:20 +01:00
|
|
|
:init
|
2020-08-23 18:48:50 -04:00
|
|
|
(defvar +spell-excluded-faces-alist
|
|
|
|
'((markdown-mode
|
|
|
|
. (markdown-code-face
|
|
|
|
markdown-html-attr-name-face
|
|
|
|
markdown-html-attr-value-face
|
|
|
|
markdown-html-tag-name-face
|
2021-05-29 11:57:55 -04:00
|
|
|
markdown-inline-code-face
|
2020-08-23 18:48:50 -04:00
|
|
|
markdown-link-face
|
|
|
|
markdown-markup-face
|
2021-05-29 11:57:55 -04:00
|
|
|
markdown-plain-url-face
|
2020-08-23 18:48:50 -04:00
|
|
|
markdown-reference-face
|
|
|
|
markdown-url-face))
|
|
|
|
(org-mode
|
|
|
|
. (org-block
|
|
|
|
org-block-begin-line
|
|
|
|
org-block-end-line
|
|
|
|
org-code
|
|
|
|
org-date
|
2021-07-28 14:00:02 -04:00
|
|
|
org-footnote
|
2020-08-23 18:48:50 -04:00
|
|
|
org-formula
|
|
|
|
org-latex-and-related
|
|
|
|
org-link
|
|
|
|
org-meta-line
|
|
|
|
org-property-value
|
|
|
|
org-ref-cite-face
|
|
|
|
org-special-keyword
|
|
|
|
org-tag
|
|
|
|
org-todo
|
|
|
|
org-todo-keyword-done
|
|
|
|
org-todo-keyword-habt
|
|
|
|
org-todo-keyword-kill
|
|
|
|
org-todo-keyword-outd
|
|
|
|
org-todo-keyword-todo
|
|
|
|
org-todo-keyword-wait
|
2020-08-24 16:16:19 +03:00
|
|
|
org-verbatim))
|
|
|
|
(latex-mode
|
|
|
|
. (font-latex-math-face
|
|
|
|
font-latex-sedate-face
|
|
|
|
font-lock-function-name-face
|
|
|
|
font-lock-keyword-face
|
|
|
|
font-lock-variable-name-face)))
|
2020-08-23 18:48:50 -04:00
|
|
|
"Faces in certain major modes that spell-fu will not spellcheck.")
|
|
|
|
|
|
|
|
(setq spell-fu-directory (concat doom-etc-dir "spell-fu"))
|
|
|
|
(when (featurep! +everywhere)
|
|
|
|
(add-hook! '(yaml-mode-hook
|
|
|
|
conf-mode-hook
|
|
|
|
prog-mode-hook)
|
|
|
|
#'spell-fu-mode))
|
|
|
|
:config
|
|
|
|
(map! :after spell-fu
|
|
|
|
:map override
|
|
|
|
:n [return]
|
|
|
|
(cmds! (memq 'spell-fu-incorrect-face (face-at-point nil t))
|
|
|
|
#'+spell/correct))
|
|
|
|
|
2021-03-27 22:05:54 -04:00
|
|
|
;; TODO PR this fix upstream!
|
|
|
|
(defadvice! +spell--fix-face-detection-a (orig-fn &rest args)
|
|
|
|
"`spell-fu--faces-at-point' uses face detection that won't penetrary
|
|
|
|
overlays (like `hl-line'). This makes `spell-fu-faces-exclude' demonstrably less
|
|
|
|
useful when it'll still spellcheck excluded faces on any line that `hl-line' is
|
|
|
|
displayed on, even momentarily."
|
|
|
|
:around #'spell-fu--faces-at-point
|
|
|
|
(letf! (defun get-char-property (pos prop &optional obj)
|
|
|
|
(or (plist-get (text-properties-at pos) prop)
|
|
|
|
(funcall get-char-property pos prop obj)))
|
|
|
|
(apply orig-fn args)))
|
|
|
|
|
2020-08-23 18:48:50 -04:00
|
|
|
(defadvice! +spell--create-word-dict-a (_word words-file _action)
|
2021-03-27 22:05:54 -04:00
|
|
|
"Prevent `spell-fu--word-add-or-remove' from throwing non-existant
|
|
|
|
directory errors when writing a personal dictionary file (by creating the
|
|
|
|
directory first)."
|
2020-08-23 18:48:50 -04:00
|
|
|
:before #'spell-fu--word-add-or-remove
|
|
|
|
(unless (file-exists-p words-file)
|
|
|
|
(make-directory (file-name-directory words-file) t)
|
|
|
|
(with-temp-file words-file
|
|
|
|
(insert (format "personal_ws-1.1 %s 0\n" ispell-dictionary)))))
|
|
|
|
|
|
|
|
(add-hook! 'spell-fu-mode-hook
|
|
|
|
(defun +spell-init-excluded-faces-h ()
|
|
|
|
"Set `spell-fu-faces-exclude' according to `+spell-excluded-faces-alist'."
|
2020-12-12 23:22:00 -05:00
|
|
|
(when-let (excluded (cdr (cl-find-if #'derived-mode-p +spell-excluded-faces-alist :key #'car)))
|
2020-08-23 18:48:50 -04:00
|
|
|
(setq-local spell-fu-faces-exclude excluded))))
|
|
|
|
|
|
|
|
;; TODO custom `spell-fu-check-range' function to reduce false positives
|
|
|
|
;; more intelligently, or modify `spell-fu-word-regexp' to include
|
|
|
|
;; non-latin charactersets.
|
|
|
|
)
|
|
|
|
|
|
|
|
(use-package! flyspell ; built-in
|
|
|
|
:defer t
|
|
|
|
:preface
|
|
|
|
;; `flyspell' is loaded at startup. In order to lazy load its config we need
|
|
|
|
;; to pretend it isn't loaded.
|
|
|
|
(defer-feature! flyspell flyspell-mode flyspell-prog-mode)
|
|
|
|
:init
|
|
|
|
(add-hook! '(org-mode-hook
|
|
|
|
markdown-mode-hook
|
|
|
|
TeX-mode-hook
|
|
|
|
rst-mode-hook
|
|
|
|
mu4e-compose-mode-hook
|
|
|
|
message-mode-hook
|
|
|
|
git-commit-mode-hook)
|
|
|
|
#'flyspell-mode)
|
|
|
|
|
|
|
|
(when (featurep! +everywhere)
|
|
|
|
(add-hook! '(yaml-mode-hook
|
|
|
|
conf-mode-hook
|
|
|
|
prog-mode-hook)
|
|
|
|
#'flyspell-prog-mode))
|
|
|
|
|
|
|
|
:config
|
2020-08-31 23:19:31 -04:00
|
|
|
(provide 'ispell) ; forcibly load ispell configs
|
|
|
|
|
2020-08-23 18:48:50 -04:00
|
|
|
(setq flyspell-issue-welcome-flag nil
|
|
|
|
;; Significantly speeds up flyspell, which would otherwise print
|
|
|
|
;; messages for every word when checking the entire buffer
|
|
|
|
flyspell-issue-message-flag nil)
|
|
|
|
|
|
|
|
(add-hook! 'flyspell-mode-hook
|
|
|
|
(defun +spell-inhibit-duplicate-detection-maybe-h ()
|
|
|
|
"Don't mark duplicates when style/grammar linters are present.
|
|
|
|
e.g. proselint and langtool."
|
|
|
|
(and (or (and (bound-and-true-p flycheck-mode)
|
|
|
|
(executable-find "proselint"))
|
|
|
|
(featurep 'langtool))
|
|
|
|
(setq-local flyspell-mark-duplications-flag nil))))
|
|
|
|
|
|
|
|
;; Ensure mode-local predicates declared with `set-flyspell-predicate!' are
|
|
|
|
;; used in their respective major modes.
|
|
|
|
(add-hook 'flyspell-mode-hook #'+spell-init-flyspell-predicate-h)
|
|
|
|
|
|
|
|
(let ((flyspell-correct
|
2020-12-11 17:36:12 -05:00
|
|
|
(cmds! (and (not mark-active)
|
|
|
|
(not (and (bound-and-true-p evil-local-mode)
|
|
|
|
(or (evil-insert-state-p)
|
|
|
|
(evil-emacs-state-p))))
|
2020-08-23 18:48:50 -04:00
|
|
|
(memq 'flyspell-incorrect (face-at-point nil t)))
|
|
|
|
#'flyspell-correct-at-point)))
|
|
|
|
(map! :map flyspell-mouse-map
|
|
|
|
"RET" flyspell-correct
|
|
|
|
[return] flyspell-correct
|
|
|
|
[mouse-1] #'flyspell-correct-at-point)))
|
|
|
|
|
|
|
|
|
|
|
|
(use-package! flyspell-correct
|
|
|
|
:commands flyspell-correct-previous
|
|
|
|
:general ([remap ispell-word] #'flyspell-correct-at-point)
|
|
|
|
:config
|
|
|
|
(cond ((and (featurep! :completion helm)
|
|
|
|
(require 'flyspell-correct-helm nil t)))
|
|
|
|
((and (featurep! :completion ivy)
|
|
|
|
(require 'flyspell-correct-ivy nil t)))
|
2021-07-09 20:16:11 +03:00
|
|
|
((featurep! :completion vertico)) ; vertico doesn't need any extra configuration
|
2021-04-29 12:43:16 +03:00
|
|
|
((require 'flyspell-correct-popup nil t) ; only use popup if no compatible completion UI is enabled
|
2020-08-23 18:48:50 -04:00
|
|
|
(setq flyspell-popup-correct-delay 0.8)
|
|
|
|
(define-key popup-menu-keymap [escape] #'keyboard-quit))))
|
|
|
|
|
|
|
|
|
|
|
|
(use-package! flyspell-lazy
|
|
|
|
:after flyspell
|
|
|
|
:config
|
|
|
|
(setq flyspell-lazy-idle-seconds 1
|
|
|
|
flyspell-lazy-window-idle-seconds 3)
|
|
|
|
(flyspell-lazy-mode +1)))
|