about summary refs log tree commit diff stats
path: root/lisp/+ispell.el
blob: c3ee4171e5d71be356fd685b314b34d4977af543 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
;;; +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))

;;;###autoload
(defun +ispell-move-buffer-words-to-dir-locals (&optional arg)
  "Move the current buffer-local words to .dir-locals.el.
This function prompts the user to save .dir-locals.el, unless
prefix ARG is non-nil; then it just saves them."
  (interactive "P")
  (unless (buffer-file-name)
    (user-error "Buffer not attached to file"))
  (hack-dir-local-variables)
  (when-let ((new-words (+ispell-append-removing-duplicates
                              :test #'string=
                              ispell-buffer-session-localwords
                              (alist-get 'ispell-buffer-session-localwords
                                         dir-local-variables-alist)
                              (alist-get 'ispell-buffer-session-localwords
                                         file-local-variables-alist)
                              (+ispell-buffer-local-words-list))))
    (save-excursion
      (add-dir-local-variable
       major-mode
       'ispell-buffer-session-localwords
       (setq ispell-buffer-session-localwords
             new-words))
      (when (or arg
                (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)))))))

;;;###autoload
(defun +ispell-move-buffer-words-to-dir-locals-hook ()
  "Convenience function for binding to a hook."
  (+ispell-move-buffer-words-to-dir-locals t))

(provide '+ispell)
;;; +ispell.el ends here