featurep! will be renamed modulep! in the future, so it's been deprecated. They have identical interfaces, and can be replaced without issue. featurep! was never quite the right name for this macro. It implied that it had some connection to featurep, which it doesn't (only that it was similar in purpose; still, Doom modules are not features). To undo such implications and be consistent with its namespace (and since we're heading into a storm of breaking changes with the v3 release anyway), now was the best opportunity to begin the transition.
116 lines
4.8 KiB
EmacsLisp
116 lines
4.8 KiB
EmacsLisp
;;; checkers/spell/autoload/+spell-fu.el -*- lexical-binding: t; -*-
|
|
;;;###if (not (modulep! +flyspell))
|
|
|
|
(defun +spell--correct (replace poss word orig-pt start end)
|
|
(cond ((eq replace 'ignore)
|
|
(goto-char orig-pt)
|
|
nil)
|
|
((eq replace 'save)
|
|
(goto-char orig-pt)
|
|
(ispell-send-string (concat "*" word "\n"))
|
|
(ispell-send-string "#\n")
|
|
(setq ispell-pdict-modified-p '(t)))
|
|
((or (eq replace 'buffer) (eq replace 'session))
|
|
(ispell-send-string (concat "@" word "\n"))
|
|
(add-to-list 'ispell-buffer-session-localwords word)
|
|
(or ispell-buffer-local-name ; session localwords might conflict
|
|
(setq ispell-buffer-local-name (buffer-name)))
|
|
(if (null ispell-pdict-modified-p)
|
|
(setq ispell-pdict-modified-p
|
|
(list ispell-pdict-modified-p)))
|
|
(goto-char orig-pt)
|
|
(if (eq replace 'buffer)
|
|
(ispell-add-per-file-word-list word)))
|
|
(replace
|
|
(let ((new-word (if (atom replace)
|
|
replace
|
|
(car replace)))
|
|
(orig-pt (+ (- (length word) (- end start))
|
|
orig-pt)))
|
|
(unless (equal new-word (car poss))
|
|
(delete-region start end)
|
|
(goto-char start)
|
|
(insert new-word))))
|
|
((goto-char orig-pt)
|
|
nil)))
|
|
|
|
(defun +spell-correct-ivy-fn (candidates word)
|
|
(ivy-read (format "Corrections for %S: " word) candidates))
|
|
|
|
(defun +spell-correct-helm-fn (candidates word)
|
|
(helm :sources (helm-build-sync-source
|
|
"Ispell"
|
|
:candidates candidates)
|
|
:prompt (format "Corrections for %S: " word)))
|
|
|
|
(defun +spell-correct-generic-fn (candidates word)
|
|
(completing-read (format "Corrections for %S: " word) candidates))
|
|
|
|
;;;###autoload
|
|
(defun +spell/correct ()
|
|
"Correct spelling of word at point."
|
|
(interactive)
|
|
;; spell-fu fails to initialize correctly if it can't find aspell or a similar
|
|
;; program. We want to signal the error, not tell the user that every word is
|
|
;; spelled correctly.
|
|
(unless (;; This is what spell-fu uses to check for the aspell executable
|
|
or (and ispell-really-aspell ispell-program-name)
|
|
(executable-find "aspell"))
|
|
(user-error "Aspell is required for spell checking"))
|
|
|
|
(ispell-set-spellchecker-params)
|
|
(save-current-buffer
|
|
(ispell-accept-buffer-local-defs))
|
|
(if (not (or (modulep! :completion ivy)
|
|
(modulep! :completion helm)
|
|
(modulep! :completion vertico)))
|
|
(call-interactively #'ispell-word)
|
|
(cl-destructuring-bind (start . end)
|
|
(or (bounds-of-thing-at-point 'word)
|
|
(user-error "No word at point"))
|
|
(let ((word (thing-at-point 'word t))
|
|
(orig-pt (point))
|
|
poss ispell-filter)
|
|
(ispell-send-string "%\n")
|
|
(ispell-send-string (concat "^" word "\n"))
|
|
(while (progn (accept-process-output ispell-process)
|
|
(not (string= "" (car ispell-filter)))))
|
|
;; Remove leading empty element
|
|
(setq ispell-filter (cdr ispell-filter))
|
|
;; ispell process should return something after word is sent. Tag word as
|
|
;; valid (i.e., skip) otherwise
|
|
(unless ispell-filter
|
|
(setq ispell-filter '(*)))
|
|
(when (consp ispell-filter)
|
|
(setq poss (ispell-parse-output (car ispell-filter))))
|
|
(cond
|
|
((or (eq poss t) (stringp poss))
|
|
;; don't correct word
|
|
(message "%s is correct" (funcall ispell-format-word-function word))
|
|
t)
|
|
((null poss)
|
|
;; ispell error
|
|
(error "Ispell: error in Ispell process"))
|
|
(t
|
|
;; The word is incorrect, we have to propose a replacement.
|
|
(setq res (funcall +spell-correct-interface (nth 2 poss) word))
|
|
;; Some interfaces actually eat 'C-g' so it's impossible to stop rapid
|
|
;; mode. So when interface returns nil we treat it as a stop.
|
|
(unless res (setq res (cons 'break word)))
|
|
(cond
|
|
((stringp res)
|
|
(+spell--correct res poss word orig-pt start end))
|
|
((let ((cmd (car res))
|
|
(wrd (cdr res)))
|
|
(unless (or (eq cmd 'skip)
|
|
(eq cmd 'break)
|
|
(eq cmd 'stop))
|
|
(+spell--correct cmd poss wrd orig-pt start end)
|
|
(unless (string-equal wrd word)
|
|
(+spell--correct wrd poss word orig-pt start end))))))
|
|
(ispell-pdict-save t)))))))
|
|
|
|
;;;###autoload (defalias '+spell/add-word #'spell-fu-word-add)
|
|
;;;###autoload (defalias '+spell/remove-word #'spell-fu-word-remove)
|
|
;;;###autoload (defalias '+spell/next-error #'spell-fu-goto-next-error)
|
|
;;;###autoload (defalias '+spell/previous-error #'spell-fu-goto-previous-error)
|