From 3586cecd8b39a26f7f86ac78e9a23761ccb1beae Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Tue, 25 Jan 2022 16:56:48 -0600 Subject: Allow saving ispell-local-words in .dir-locals.el TODO: Automatically move local words to .dir-locals on save --- init.el | 4 +++ lisp/+ispell.el | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 lisp/+ispell.el diff --git a/init.el b/init.el index a7012ea..2a6dab5 100644 --- a/init.el +++ b/init.el @@ -400,6 +400,10 @@ (:bind "c" #'+Info-copy-current-node-name "w" #'+Info-copy-current-node-name))) +(setup ispell + (:also-load +ispell) + (put 'ispell-buffer-session-localwords 'safe-local-variable #'+ispell-safe-local-p)) + (setup kmacro (:also-load +kmacro) (with-eval-after-load '+kmacro diff --git a/lisp/+ispell.el b/lisp/+ispell.el new file mode 100644 index 0000000..e35b2f1 --- /dev/null +++ b/lisp/+ispell.el @@ -0,0 +1,82 @@ +;;; +ispell.el --- Customizations for `ispell' -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(require 'cl) + +;; Utility function TODO: move elsewhere +(defun +ispell-append-removing-duplicates (&rest lists) + "Append LISTS, removing duplicates from the result. +Any keyword arguments to `cl-remove-duplicates' should come +before the LISTS." + (let (cl-remove-duplicates-args) + (while (keywordp (car lists)) + (push (pop lists) cl-remove-duplicates-args) + (push (pop lists) cl-remove-duplicates-args)) + (apply #'cl-remove-duplicates (apply #'append lists) + (nreverse cl-remove-duplicates-args)))) + +;;; Ispell in .dir-locals + +;; Let Emacs know a list of strings is safe +(defun +ispell-safe-local-p (list) + (and (listp list) + (seq-every-p #'stringp list))) + +;; Can I instruct ispell to insert LocalWords in a different file? +;; https://emacs.stackexchange.com/q/31396/2264 + +;; How can I move all my file-local LocalWords to .dir-locals.el? +;; https://emacs.stackexchange.com/q/31419 + +;; Adapted from ispell.el:ispell-buffer-local-words +(defun +ispell-buffer-local-words-list () + (let (words) + (or ispell-buffer-local-name + (setq ispell-buffer-local-name (buffer-name))) + (save-excursion + (goto-char (point-min)) + (while (search-forward ispell-words-keyword nil t) + (let ((end (point-at-eol)) + (ispell-casechars (ispell-get-casechars)) + string) + (while (re-search-forward " *\\([^ ]+\\)" end t) + (setq string (match-string-no-properties 1)) + (if (and (< 1 (length string)) + (equal 0 (string-match ispell-casechars string))) + (push string words)))))) + words)) + +(defun +ispell-move-buffer-words-to-dir-locals () + (interactive) + (unless (buffer-file-name) + (user-error "Buffer not attached to file")) + (hack-dir-local-variables) + (let ((words (+ispell-buffer-local-words-list)) + (dir-local-words (+ispell-append-removing-duplicates + (alist-get 'ispell-buffer-session-localwords + dir-local-variables-alist) + (alist-get 'ispell-buffer-session-localwords + file-local-variables-alist)))) + (save-excursion + (add-dir-local-variable + major-mode + 'ispell-buffer-session-localwords + (setq ispell-buffer-session-localwords + (+ispell-append-removing-duplicates + :test #'string= + dir-local-words ispell-buffer-session-localwords words))) + (when (y-or-n-p "Save .dir-locals.el?") + (save-buffer)) + (bury-buffer)) + (or ispell-buffer-local-name + (setq ispell-buffer-local-name (buffer-name))) + (save-excursion + (goto-char (point-min)) + (while (search-forward ispell-words-keyword nil t) + (delete-region (point-at-bol) (1+ (point-at-eol))))))) + +(provide '+ispell) +;;; +ispell.el ends here -- cgit 1.4.1-21-gabe81