mastodon.el: Collect handles in clipboard (Emacs kill ring)

| mastodon, emacs

I sometimes want to thank a bunch of people for contributing to a Mastodon conversation. The following code lets me collect handles in a single kill ring entry by calling it with my point over a handle or a toot, or with an active region.

(defvar my-mastodon-handle "@sacha@social.sachachua.com")
(defun my-mastodon-copy-handle (&optional start-new beg end)
  "Append Mastodon handles to the kill ring.

Use the handle at point or the author of the toot.  If called with a
region, collect all handles in the region.

Append to the current kill if it starts with @. If not, start a new
kill. Call with \\[universal-argument] to always start a new list.

Omit my own handle, as specified in `my-mastodon-handle'."
  (interactive (list current-prefix-arg
                     (when (region-active-p) (region-beginning))
                     (when (region-active-p) (region-end))))
  (let ((handle
         (if (and beg end)
             ;; collect handles in region
             (save-excursion
               (goto-char beg)
               (let (list)
                 ;; Collect all handles from the specified region
                 (while (< (point) end)
                   (let ((mastodon-handle (get-text-property (point) 'mastodon-handle))
                         (button (get-text-property (point) 'button)))
                     (cond
                      (mastodon-handle
                       (when (and (string-match "@" mastodon-handle)
                                  (or (null my-mastodon-handle)
                                      (not (string= my-mastodon-handle mastodon-handle))))
                         (cl-pushnew
                          (concat (if (string-match "^@" mastodon-handle) ""
                                    "@")
                                  mastodon-handle)
                          list
                          :test #'string=))
                       (goto-char (next-single-property-change (point) 'mastodon-handle nil end)))
                      ((and button (looking-at "@"))
                       (let ((text-start (point))
                             (text-end (or (next-single-property-change (point) 'button nil end) end)))
                         (dolist (h (split-string (buffer-substring-no-properties text-start text-end) ", \n\t"))
                           (unless (and my-mastodon-handle (string= my-mastodon-handle h))
                             (cl-pushnew h list :test #'string=)))
                         (goto-char text-end)))
                      (t
                       ;; collect authors of toots too
                       (when-let*
                           ((toot (mastodon-toot--base-toot-or-item-json))
                            (author (and toot
                                         (concat "@"
                                                 (alist-get
                                                  'acct
                                                  (alist-get 'account (mastodon-toot--base-toot-or-item-json)))))))
                         (unless (and my-mastodon-handle (string= my-mastodon-handle author))
                           (cl-pushnew
                            author
                            list
                            :test #'string=)))
                       (goto-char (next-property-change (point) nil end))))))
                 (setq handle (string-join (seq-uniq list #'string=) " "))))
           (concat "@"
                   (or
                    (get-text-property (point) 'mastodon-handle)
                    (alist-get
                     'acct
                     (alist-get 'account (mastodon-toot--base-toot-or-item-json))))))))
    (if (or start-new (null kill-ring) (not (string-match "^@" (car kill-ring))))
        (kill-new handle)
      (dolist (h (split-string handle " "))
        (unless (member h (split-string " " (car kill-ring)))
          (setf (car kill-ring) (concat (car kill-ring) " " h)))))
    (message "%s" (car kill-ring))))

Another perk of tooting from Emacs using mastodon.el. =)

This is part of my Emacs configuration.
View org source for this post
You can comment on Mastodon, comment with Disqus (JS required), or you can e-mail me at sacha@sachachua.com.