diff options
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/mastodon-search.el | 4 | ||||
-rw-r--r-- | lisp/mastodon-tl.el | 330 | ||||
-rw-r--r-- | lisp/mastodon-toot.el | 64 | ||||
-rw-r--r-- | lisp/mastodon-views.el | 26 | ||||
-rw-r--r-- | lisp/mastodon.el | 2 |
5 files changed, 269 insertions, 157 deletions
diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 9b3641b..8cfa3cb 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -191,7 +191,9 @@ user's profile note. This is also called by `mastodon-tl--get-follow-suggestions' and `mastodon-profile--insert-follow-requests'." (mapc (lambda (acct) - (insert (mastodon-search--propertize-user acct note))) + (insert (concat (mastodon-search--propertize-user acct note) + mastodon-tl--horiz-bar + "\n\n"))) json)) (defun mastodon-search--propertize-user (acct &optional note) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index e90be9a..b2b7d27 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1090,117 +1090,6 @@ HELP-ECHO, DISPLAY, and FACE are the text properties to add." (concat help-echo "\nC-RET: play " type " with mpv")))) -;;; INSERT TOOTS - -(defun mastodon-tl--content (toot) - "Retrieve text content from TOOT. -Runs `mastodon-tl--render-text' and fetches poll or media." - (let* ((content (mastodon-tl--field 'content toot)) - (reblog (alist-get 'reblog toot)) - (poll-p (if reblog - (alist-get 'poll reblog) - (alist-get 'poll toot)))) - (concat - (mastodon-tl--render-text content toot) - (when poll-p - (mastodon-tl--get-poll toot)) - (mastodon-tl--media toot)))) - -(defun mastodon-tl--insert-status (toot body author-byline action-byline - &optional id base-toot detailed-p) - "Display the content and byline of timeline element TOOT. -BODY will form the section of the toot above the byline. -AUTHOR-BYLINE is an optional function for adding the author -portion of the byline that takes one variable. By default it is -`mastodon-tl--byline-author'. -ACTION-BYLINE is also an optional function for adding an action, -such as boosting favouriting and following to the byline. It also -takes a single function. By default it is -`mastodon-tl--byline-boosted'. -ID is that of the status if it is a notification, which is -attached as a `toot-id' property if provided. If the -status is a favourite or boost notification, BASE-TOOT is the -JSON of the toot responded to. -DETAILED-P means display more detailed info. For now -this just means displaying toot client." - (let ((start-pos (point))) - (insert - (propertize - (concat "\n" - body - " \n" - (mastodon-tl--byline toot author-byline action-byline detailed-p)) - 'toot-id (or id ; notification's own id - (alist-get 'id toot)) ; toot id - 'base-toot-id (mastodon-tl--toot-id - ;; if status is a notif, get id from base-toot - ;; (-tl--toot-id toot) will not work here: - (or base-toot - ;; else normal toot with reblog check: - toot)) - 'toot-json toot - 'base-toot base-toot) - "\n") - (when mastodon-tl--display-media-p - (mastodon-media--inline-images start-pos (point))))) - -;; from mastodon-alt.el: -(defun mastodon-tl--toot-for-stats (&optional toot) - "Return the TOOT on which we want to extract stats. -If no TOOT is given, the one at point is considered." - (let* ((original-toot (or toot (get-text-property (point) 'toot-json))) - (toot (or (alist-get 'status original-toot) - (when (alist-get 'type original-toot) - original-toot) - (alist-get 'reblog original-toot) - original-toot)) - (type (alist-get 'type (or toot)))) - (unless (member type '("follow" "follow_request")) - toot))) - -(defun mastodon-tl--toot-stats (toot) - "Return a right aligned string (using display align-to). -String is filled with TOOT statistics (boosts, favs, replies). -When the TOOT is a reblog (boost), statistics from reblogged -toots are returned. -To disable showing the stats, customize -`mastodon-tl--show-stats'." - (when-let ((toot (mastodon-tl--toot-for-stats toot))) - (let* ((favourites-count (alist-get 'favourites_count toot)) - (favourited (equal 't (alist-get 'favourited toot))) - (faves-prop (propertize (format "%s" favourites-count) - 'favourites-count favourites-count)) - (boosts-count (alist-get 'reblogs_count toot)) - (boosted (equal 't (alist-get 'reblogged toot))) - (boosts-prop (propertize (format "%s" boosts-count) - 'boosts-count boosts-count)) - (replies-count (alist-get 'replies_count toot)) - (favourites (format "%s %s" faves-prop ;favourites-count - (mastodon-tl--symbol 'favourite))) - (boosts (format "%s %s" boosts-prop ;boosts-count - (mastodon-tl--symbol 'boost))) - (replies (format "%s %s" replies-count (mastodon-tl--symbol 'reply))) - (status (concat - (propertize favourites - 'favourited-p favourited - 'favourites-field t - 'face font-lock-comment-face) - (propertize " | " 'face font-lock-comment-face) - (propertize boosts - 'boosted-p boosted - 'boosts-field t - 'face font-lock-comment-face) - (propertize " | " 'face font-lock-comment-face) - (propertize replies - 'replies-field t - 'replies-count replies-count - 'face font-lock-comment-face))) - (status (concat - (propertize " " 'display `(space :align-to (- right ,(+ (length status) 7)))) - status))) - status))) - - ;; POLLS (defun mastodon-tl--get-poll (toot) @@ -1359,7 +1248,115 @@ in which case play first video or gif from current toot." (message "no moving image here?")))) -;; INSERT TOOTS +;;; INSERT TOOTS + +(defun mastodon-tl--content (toot) + "Retrieve text content from TOOT. +Runs `mastodon-tl--render-text' and fetches poll or media." + (let* ((content (mastodon-tl--field 'content toot)) + (reblog (alist-get 'reblog toot)) + (poll-p (if reblog + (alist-get 'poll reblog) + (alist-get 'poll toot)))) + (concat + (mastodon-tl--render-text content toot) + (when poll-p + (mastodon-tl--get-poll toot)) + (mastodon-tl--media toot)))) + +(defun mastodon-tl--insert-status (toot body author-byline action-byline + &optional id base-toot detailed-p) + "Display the content and byline of timeline element TOOT. +BODY will form the section of the toot above the byline. +AUTHOR-BYLINE is an optional function for adding the author +portion of the byline that takes one variable. By default it is +`mastodon-tl--byline-author'. +ACTION-BYLINE is also an optional function for adding an action, +such as boosting favouriting and following to the byline. It also +takes a single function. By default it is +`mastodon-tl--byline-boosted'. +ID is that of the status if it is a notification, which is +attached as a `toot-id' property if provided. If the +status is a favourite or boost notification, BASE-TOOT is the +JSON of the toot responded to. +DETAILED-P means display more detailed info. For now +this just means displaying toot client." + (let ((start-pos (point))) + (insert + (propertize + (concat "\n" + body + " \n" + (mastodon-tl--byline toot author-byline action-byline detailed-p)) + 'toot-id (or id ; notification's own id + (alist-get 'id toot)) ; toot id + 'base-toot-id (mastodon-tl--toot-id + ;; if status is a notif, get id from base-toot + ;; (-tl--toot-id toot) will not work here: + (or base-toot + ;; else normal toot with reblog check: + toot)) + 'toot-json toot + 'base-toot base-toot) + "\n") + (when mastodon-tl--display-media-p + (mastodon-media--inline-images start-pos (point))))) + +;; from mastodon-alt.el: +(defun mastodon-tl--toot-for-stats (&optional toot) + "Return the TOOT on which we want to extract stats. +If no TOOT is given, the one at point is considered." + (let* ((original-toot (or toot (get-text-property (point) 'toot-json))) + (toot (or (alist-get 'status original-toot) + (when (alist-get 'type original-toot) + original-toot) + (alist-get 'reblog original-toot) + original-toot)) + (type (alist-get 'type (or toot)))) + (unless (member type '("follow" "follow_request")) + toot))) + +(defun mastodon-tl--toot-stats (toot) + "Return a right aligned string (using display align-to). +String is filled with TOOT statistics (boosts, favs, replies). +When the TOOT is a reblog (boost), statistics from reblogged +toots are returned. +To disable showing the stats, customize +`mastodon-tl--show-stats'." + (when-let ((toot (mastodon-tl--toot-for-stats toot))) + (let* ((favourites-count (alist-get 'favourites_count toot)) + (favourited (equal 't (alist-get 'favourited toot))) + (faves-prop (propertize (format "%s" favourites-count) + 'favourites-count favourites-count)) + (boosts-count (alist-get 'reblogs_count toot)) + (boosted (equal 't (alist-get 'reblogged toot))) + (boosts-prop (propertize (format "%s" boosts-count) + 'boosts-count boosts-count)) + (replies-count (alist-get 'replies_count toot)) + (favourites (format "%s %s" faves-prop ;favourites-count + (mastodon-tl--symbol 'favourite))) + (boosts (format "%s %s" boosts-prop ;boosts-count + (mastodon-tl--symbol 'boost))) + (replies (format "%s %s" replies-count (mastodon-tl--symbol 'reply))) + (status (concat + (propertize favourites + 'favourited-p favourited + 'favourites-field t + 'face font-lock-comment-face) + (propertize " | " 'face font-lock-comment-face) + (propertize boosts + 'boosted-p boosted + 'boosts-field t + 'face font-lock-comment-face) + (propertize " | " 'face font-lock-comment-face) + (propertize replies + 'replies-field t + 'replies-count replies-count + 'face font-lock-comment-face))) + (status (concat + (propertize " " 'display `(space :align-to (- right ,(+ (length status) 7)))) + status))) + status))) (defun mastodon-tl--is-reply (toot) "Check if the TOOT is a reply to another one (and not boosted)." @@ -1667,6 +1664,10 @@ webapp" (reblog (alist-get 'reblog json))) (if reblog (alist-get 'id reblog) id))) +(defun mastodon-tl--toot-or-base (json) + "Return the base toot or just the toot from toot JSON." + (or (alist-get 'reblog json) json)) + ;;; THREADS @@ -1719,8 +1720,7 @@ view all branches of a thread." (mastodon-http--api (concat "statuses/" id)) nil :silent)) - (context (mastodon-http--get-json url nil :silent)) - (marker (make-marker))) + (context (mastodon-http--get-json url nil :silent))) (if (equal (caar toot) 'error) (message "Error: %s" (cdar toot)) (when (member (alist-get 'type toot) '("reblog" "favourite")) @@ -1731,7 +1731,8 @@ view all branches of a thread." ;; if we have a thread: (progn (with-current-buffer (get-buffer-create buffer) - (let ((inhibit-read-only t)) + (let ((inhibit-read-only t) + (marker (make-marker))) (switch-to-buffer buffer) (erase-buffer) (mastodon-mode) @@ -1743,10 +1744,10 @@ view all branches of a thread." (move-marker marker (point)) ;; print re-fetched toot: (mastodon-tl--toot toot :detailed-p) - (mastodon-tl--timeline (alist-get 'descendants context)))) - ;; put point at the toot: - (goto-char (marker-position marker)) - (mastodon-tl--goto-next-toot)) + (mastodon-tl--timeline (alist-get 'descendants context)) + ;; put point at the toot: + (goto-char (marker-position marker)) + (mastodon-tl--goto-next-toot)))) ;; else just print the lone toot: (mastodon-tl--single-toot id))))))) @@ -2078,7 +2079,7 @@ If TAG is provided, unfollow it." (defun mastodon-tl--list-followed-tags (&optional prefix) "List followed tags. View timeline of tag user choses. -Prefix is sent to `mastodon-tl--get-tag-timeline', which see." +PREFIX is sent to `mastodon-tl--get-tag-timeline', which see." (interactive "p") (let* ((followed-tags-json (mastodon-tl--followed-tags)) (tags (mastodon-tl--map-alist 'name followed-tags-json)) @@ -2089,7 +2090,7 @@ Prefix is sent to `mastodon-tl--get-tag-timeline', which see." (defun mastodon-tl--followed-tags-timeline (&optional prefix) "Open a timeline of all your followed tags. -Prefix is sent to `mastodon-tl--show-tag-timeline', which see." +PREFIX is sent to `mastodon-tl--show-tag-timeline', which see." (interactive "p") (let* ((followed-tags-json (mastodon-tl--followed-tags)) (tags (mastodon-tl--map-alist 'name followed-tags-json))) @@ -2107,6 +2108,93 @@ The suggestions are from followed tags, but any other tags are also allowed." (mastodon-tl--show-tag-timeline prefix selection))) +;;; REPORT TO MODERATORS + +(defun mastodon-tl--instance-rules () + "Return the rules of the user's instance." + (let ((url (mastodon-http--api "instance/rules"))) + (mastodon-http--get-json url nil :silent))) + +(defun mastodon-tl--report-params (account toot) + "Query user and return report params alist. +ACCOUNT and TOOT are the data to use." + (let* ((account-id (mastodon-profile--account-field account 'id)) + (comment (read-string "Add comment [optional]: ")) + (toot-id (when (y-or-n-p "Also report status at point? ") + (mastodon-tl--toot-id toot))) ; base toot if poss + (forward-p (when (y-or-n-p "Forward to remote admin? ") "true")) + (rules (when (y-or-n-p "Cite a rule broken? ") + (mastodon-tl--read-rules-ids))) + (cat (unless rules (if (y-or-n-p "Spam? ") "spam" "other")))) + (mastodon-tl--report-build-params account-id comment toot-id + forward-p cat rules))) + +(defun mastodon-tl--report-build-params + (account-id comment toot-id forward-p cat &optional rules) + "Build the parameters alist based on user responses. +ACCOUNT-ID, COMMENT, TOOT-ID, FORWARD-P, CAT, and RULES are all from +`mastodon-tl--report-params', which see." + (let ((params `(("account_id" . ,account-id) + ,(when comment + `("comment" . ,comment)) + ,(when toot-id + `("status_ids[]" . ,toot-id)) + ,(when forward-p + `("forward" . ,forward-p)) + ,(when cat + `("category" . ,cat))))) + (when rules + (let ((alist + (mastodon-http--build-array-params-alist "rule_ids[]" rules))) + (mapc (lambda (x) + (push x params)) + alist))) + ;; FIXME: the above approach adds nils to your params. + (setq params (delete nil params)) + params)) + +(defun mastodon-tl--report-to-mods () + "Report the author of the toot at point to your instance moderators. +Optionally report the toot at point, add a comment, cite rules +that have been broken, forward the report to the remove admin, +report the account for spam." + (interactive) + (mastodon-tl--do-if-toot + (when (y-or-n-p "Report author of toot at point?") + (let* ((url (mastodon-http--api "reports")) + (toot (mastodon-tl--toot-or-base + (mastodon-tl--property 'toot-json :no-move))) + (account (alist-get 'account toot)) + (handle (alist-get 'acct account)) + (params (mastodon-tl--report-params account toot)) + (response (mastodon-http--post url params))) + ;; (setq masto-report-response response) + (mastodon-http--triage response + (lambda () + (message "User %s reported!" handle))))))) + +(defvar crm-separator) + +(defun mastodon-tl--map-rules-alist (rules) + "Return an alist of the text and id fields of RULES." + (mapcar (lambda (x) + (let-alist x + (cons .text .id))) + rules)) + +(defun mastodon-tl--read-rules-ids () + "Prompt for a list of instance rules and return a list of selected ids." + (let* ((rules (mastodon-tl--instance-rules)) + (alist (mastodon-tl--map-rules-alist rules)) + (crm-separator (replace-regexp-in-string "," "|" crm-separator)) + (choices (completing-read-multiple + "rules [TAB for options, | to separate]: " + alist nil :match))) + (mapcar (lambda (x) + (alist-get x alist nil nil 'equal)) + choices))) + + ;;; UPDATING, etc. (defun mastodon-tl--more-json (endpoint id) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 35e6eab..474337b 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -219,13 +219,20 @@ send.") "\\([(\n\t ]\\|^\\)" "\\(?2:@[0-9a-zA-Z._-]+" ; a handle "\\(@[^ \n\t]*\\)?\\)" ; with poss domain, * = allow only @ - "\\b")) + "\\(\\b\\|'\\)")) ; boundary or ' char (defvar mastodon-toot-tag-regex (concat ;; preceding bracket, space or bol [boundary doesn't work with #] "\\([(\n\t ]\\|^\\)" "\\(?2:#[0-9a-zA-Z_]+\\)" ; tag + "\\(\\b\\|'\\)")) ; boundary or ' char + +(defvar mastodon-toot-url-regex + ;; adapted from ffap-url-regexp + (concat + "\\(?2:\\(news\\(post\\)?:\\|mailto:\\|file:\\|\\(ftp\\|https?\\|telnet\\|gopher\\|www\\|wais\\)://\\)" ; uri prefix + "[^ \n\t]*\\)" ; any old thing that's, i.e. we allow invalid/unwise chars "\\b")) ; boundary (defvar mastodon-toot-mode-map @@ -764,6 +771,13 @@ to `emojify-user-emojis', and the emoji data is updated." `(("poll[multiple]" . ,(symbol-name (plist-get mastodon-toot-poll :multi)))) `(("poll[hide_totals]" . ,(symbol-name (plist-get mastodon-toot-poll :hide)))))) +(defun mastodon-toot--read-cw-string () + "Read a content warning from the minibuffer." + (when (and (not (mastodon-toot--empty-p)) + mastodon-toot--content-warning) + (read-string "Warning: " + mastodon-toot--content-warning-from-reply-or-redraft))) + (defun mastodon-toot--send () "POST contents of new-toot buffer to Mastodon instance and kill buffer. If media items have been attached and uploaded with @@ -781,16 +795,13 @@ instance to edit a toot." (mastodon-http--api (format "statuses/%s" edit-id)) (mastodon-http--api "statuses"))) - (spoiler (when (and (not (mastodon-toot--empty-p)) - mastodon-toot--content-warning) - (read-string "Warning: " - mastodon-toot--content-warning-from-reply-or-redraft))) + (cw (mastodon-toot--read-cw-string)) (args-no-media (append `(("status" . ,toot) ("in_reply_to_id" . ,mastodon-toot--reply-to-id) ("visibility" . ,mastodon-toot--visibility) ("sensitive" . ,(when mastodon-toot--content-nsfw (symbol-name t))) - ("spoiler_text" . ,spoiler) + ("spoiler_text" . ,cw) ("language" . ,mastodon-toot--language)) ;; Pleroma instances can't handle null-valued ;; scheduled_at args, so only add if non-nil @@ -816,8 +827,8 @@ instance to edit a toot." (length mastodon-toot--media-attachment-ids))))) (message "Something is wrong with your uploads. Wait for them to complete or try again.")) ((and mastodon-toot--max-toot-chars - (> (mastodon-toot--count-toot-chars toot) mastodon-toot--max-toot-chars)) - (message "Looks like your toot is longer than that maximum allowed length.")) + (> (mastodon-toot--count-toot-chars toot cw) mastodon-toot--max-toot-chars)) + (message "Looks like your toot (inc. CW) is longer than that maximum allowed length.")) ((mastodon-toot--empty-p) (message "Empty toot. Cowardly refusing to post this.")) (t @@ -944,7 +955,6 @@ eg. \"feduser@fed.social\" -> \"@feduser@fed.social\"." The mentioned users look like this: Local user (including the logged in): `username`. Federated user: `username@host.co`." - (interactive) (let* ((boosted (mastodon-tl--field 'reblog status)) (mentions (if boosted @@ -1235,8 +1245,18 @@ MAX is the maximum number set by their instance." (defun mastodon-toot--read-poll-options (count length) "Read a list of options for poll with COUNT options. LENGTH is the maximum character length allowed for a poll option." - (cl-loop for x from 1 to count - collect (read-string (format "Poll option [%s/%s] [max %s chars]: " x count length)))) + (let* ((choices + (cl-loop for x from 1 to count + collect (read-string + (format "Poll option [%s/%s] [max %s chars]: " + x count length)))) + (longest (cl-reduce #'max (mapcar #'length choices)))) + (if (> longest length) + (progn + (message "looks like you went over the max length. Try again.") + (sleep-for 2) + (mastodon-toot--read-poll-options count length)) + choices))) (defun mastodon-toot--read-poll-expiry () "Prompt for a poll expiry time." @@ -1434,12 +1454,14 @@ REPLY-TEXT is the text of the toot being replied to." 'read-only "Edit your message below." 'toot-post-header t) (if reply-text - (propertize (truncate-string-to-width - (mastodon-tl--render-text reply-text) - mastodon-toot-orig-in-reply-length) - 'read-only "Edit your message below." - 'toot-post-header t - 'face '(variable-pitch :foreground "#7c6f64")) + (concat + (propertize (truncate-string-to-width + (mastodon-tl--render-text reply-text) + mastodon-toot-orig-in-reply-length) + 'read-only "Edit your message below." + 'toot-post-header t + 'face '(variable-pitch :foreground "#7c6f64")) + "\n") "") (propertize (concat divider "\n") @@ -1529,7 +1551,7 @@ REPLY-JSON is the full JSON of the toot being replied to." (list 'invisible (not mastodon-toot--content-warning) 'face 'mastodon-cw-face))))) -(defun mastodon-toot--count-toot-chars (toot-string) +(defun mastodon-toot--count-toot-chars (toot-string &optional cw) "Count the characters in TOOT-STRING. URLs always = 23, and domain names of handles are not counted. This is how mastodon does it." @@ -1547,7 +1569,8 @@ This is how mastodon does it." "\\b") nil t) (replace-match (match-string 2))) ; replace with handle only - (length (buffer-substring (point-min) (point-max))))) + (+ (length cw) + (length (buffer-substring (point-min) (point-max)))))) (defun mastodon-toot--save-toot-text (&rest _args) "Save the current toot text in `mastodon-toot-current-toot-text'. @@ -1615,6 +1638,9 @@ Added to `after-change-functions'." (cdr header-region)) (mastodon-toot--propertize-item mastodon-toot-handle-regex 'mastodon-display-name-face + (cdr header-region)) + (mastodon-toot--propertize-item mastodon-toot-url-regex + 'link (cdr header-region))))) (defun mastodon-toot--propertize-item (regex face start) diff --git a/lisp/mastodon-views.el b/lisp/mastodon-views.el index de498f3..8064282 100644 --- a/lisp/mastodon-views.el +++ b/lisp/mastodon-views.el @@ -893,26 +893,20 @@ IND is the optional indentation level to print at." (defun mastodon-views--print-instance-rules-or-fields (alist) "Print ALIST of instance rules or contact account or emoji fields." - (let ((key (cond ((alist-get 'id alist) - 'id) - ((alist-get 'name alist) - 'name) - ((alist-get 'shortcode alist) - 'shortcode))) - (value (cond ((alist-get 'id alist) - 'text) - ((alist-get 'value alist) - 'value) - ((alist-get 'url alist) - 'url)))) + (let ((key (or (alist-get 'id alist) + (alist-get 'name alist) + (alist-get 'shortcode alist))) + (value (or (alist-get 'text alist) + (alist-get 'value alist) + (alist-get 'url alist)))) (indent-to 4) (insert (format "%-5s: " - (propertize (alist-get key alist) - 'face '(:underline t))) - (mastodon-views--newline-if-long (alist-get value alist)) + (propertize key) + 'face '(:underline t)) + (mastodon-views--newline-if-long value) (format "%s" (mastodon-tl--render-text - (alist-get value alist))) + value)) "\n"))) (defun mastodon-views--newline-if-long (el) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index b384a87..980e31f 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -82,6 +82,7 @@ (autoload 'mastodon-tl--unblock-user "mastodon-tl") (autoload 'mastodon-tl--unfollow-user "mastodon-tl") (autoload 'mastodon-tl--unmute-user "mastodon-tl") +(autoload 'mastodon-tl--report-to-mods "mastodon-tl") (autoload 'mastodon-tl--update "mastodon-tl") (autoload 'mastodon-toot--edit-toot-at-point "mastodon-toot") (when (require 'lingva nil :no-error) @@ -199,6 +200,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-B") #'mastodon-tl--unblock-user) (define-key map (kbd "M") #'mastodon-tl--mute-user) (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) + (define-key map (kbd "Z") #'mastodon-tl--report-to-mods) ;; own profile (define-key map (kbd "O") #'mastodon-profile--my-profile) (define-key map (kbd "U") #'mastodon-profile--update-user-profile-note) |