Using inotify to add Plover Clippy suggestions into Emacs

| emacs

Update 2021-06-19: Changed to a vertical layout, added extra notes.

I don't have a lot of screen space on my laptop, so I don't usually have the Plover suggestion window open as I type. I came up with a Plover plugin to let me flash the last Plover Clippy suggestion as a temporary notification. It went by too quickly, though, so I wrote something that uses inotify to monitor the clippy.txt log and put it an Emacs buffer instead. It results in text like this:

Clippy
KHREUP PEU
added
ATD
Extra notes go here
(defvar my/clippy-recent-suggestions nil "Recent suggestions, limited by `my/clippy-recent-suggestions-limit`.")
(defvar my/clippy-recent-suggestions-limit 3 "Keep this many suggestions.")
(defvar my/clippy-extra-notes nil "Extra notes to add at the end.")
(defun my/clippy-last ()
  (let ((value (string-trim (shell-command-to-string "tail -1 ~/.config/plover/clippy.txt | cut -c 23-"))))
    (when (string-match "^\\(.*?\\)[ \t]+|| .*? -> \\(.+\\)" value)
      (cons (match-string 1 value) (match-string 2 value)))))

(defun my/clippy-show (&rest _)
  (interactive)
  (with-current-buffer (get-buffer-create "*Clippy*")
    (let ((last (my/clippy-last)))
      (unless (member last my/clippy-recent-suggestions)
        (setq my/clippy-recent-suggestions (seq-take (cons last my/clippy-recent-suggestions) my/clippy-recent-suggestions-limit)))
      (erase-buffer)
      (insert (mapconcat (lambda (o) (format "%s\n%s\n" (car o) (cdr o))) my/clippy-recent-suggestions "")
              (or my/clippy-extra-notes "")))))

(defvar my/clippy-monitor nil)
(defun my/clippy-toggle-monitor ()
  (interactive)
  (if (inotify-valid-p my/clippy-monitor)
      (progn
        (message "Turning off")
        (inotify-rm-watch my/clippy-monitor))
    (message "Turning on")
    (setq my/clippy-monitor
          (inotify-add-watch
           (expand-file-name "~/.config/plover/clippy.txt") 'modify
           #'my/clippy-show))))

(defun my/clippy-org-subtree-to-notes ()
  "Copy this subtree's text to `my/clippy-extra-notes'."
  (interactive)
  (save-excursion
    (unless (org-at-heading-p) (org-previous-visible-heading 1))
    (setq my/clippy-extra-notes
          (substring-no-properties
           (org-agenda-get-some-entry-text
            (point-marker)
            most-positive-fixnum)))
    (my/clippy-show)))

(defun my/clippy-add-note (string)
  (interactive "MNote: ")
  (setq my/clippy-extra-notes (concat (string-trim string) "\n" (or my/clippy-extra-notes "")))
  (my/clippy-show))
This is part of my Emacs configuration.
You can comment with Disqus or you can e-mail me at sacha@sachachua.com.