aboutsummaryrefslogtreecommitdiff
path: root/lisp/mastodon-toot.el
diff options
context:
space:
mode:
authormarty hiatt <martianhiatus [a t] riseup [d o t] net>2023-03-23 11:32:48 +0100
committermarty hiatt <martianhiatus [a t] riseup [d o t] net>2023-03-23 11:32:48 +0100
commit756b879634ae6994b52bd4c011bc4b46a0995037 (patch)
tree05c63b4cb37a4b5b0a28f37251e1b3d3226f3122 /lisp/mastodon-toot.el
parent08ed1ae30888086256f343be978cf7eb65cec9eb (diff)
parent19f18b4076efefa212a0e56757ac844eafda9481 (diff)
Merge branch 'develop'
Diffstat (limited to 'lisp/mastodon-toot.el')
-rw-r--r--lisp/mastodon-toot.el533
1 files changed, 277 insertions, 256 deletions
diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el
index b8930b0..82a9482 100644
--- a/lisp/mastodon-toot.el
+++ b/lisp/mastodon-toot.el
@@ -33,11 +33,11 @@
;;; Code:
(eval-when-compile (require 'subr-x))
-(when (require 'emojify nil :noerror)
- (declare-function emojify-insert-emoji "emojify")
- (declare-function emojify-set-emoji-data "emojify")
- (defvar emojify-emojis-dir)
- (defvar emojify-user-emojis))
+(require 'emojify nil :noerror)
+(declare-function emojify-insert-emoji "emojify")
+(declare-function emojify-set-emoji-data "emojify")
+(defvar emojify-emojis-dir)
+(defvar emojify-user-emojis)
(require 'cl-lib)
(require 'persist)
@@ -48,43 +48,45 @@
(defvar mastodon-tl--enable-proportional-fonts)
(defvar mastodon-profile-account-settings)
+(autoload 'iso8601-parse "iso8601")
(autoload 'mastodon-auth--user-acct "mastodon-auth")
(autoload 'mastodon-http--api "mastodon-http")
+(autoload 'mastodon-http--build-array-params-alist "mastodon-http")
(autoload 'mastodon-http--delete "mastodon-http")
(autoload 'mastodon-http--get-json "mastodon-http")
(autoload 'mastodon-http--get-json-async "mastodon-http")
(autoload 'mastodon-http--post "mastodon-http")
(autoload 'mastodon-http--post-media-attachment "mastodon-http")
(autoload 'mastodon-http--process-json "mastodon-http")
+(autoload 'mastodon-http--put "mastodon-http")
(autoload 'mastodon-http--read-file-as-string "mastodon-http")
(autoload 'mastodon-http--triage "mastodon-http")
+(autoload 'mastodon-profile--fetch-server-account-settings "mastodon-profile")
+(autoload 'mastodon-profile--fetch-server-account-settings-maybe "mastodon-profile")
+(autoload 'mastodon-profile--get-source-pref "mastodon-profile")
+(autoload 'mastodon-profile--show-user "mastodon-profile")
+(autoload 'mastodon-profile--update-preference "mastodon-profile")
(autoload 'mastodon-search--search-accounts-query "mastodon-search")
(autoload 'mastodon-search--search-tags-query "mastodon-search")
(autoload 'mastodon-tl--as-string "mastodon-tl")
+(autoload 'mastodon-tl--buffer-type-eq "mastodon-tl")
(autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl")
+(autoload 'mastodon-tl--do-if-toot-strict "mastodon-tl")
(autoload 'mastodon-tl--field "mastodon-tl")
(autoload 'mastodon-tl--find-property-range "mastodon-tl")
(autoload 'mastodon-tl--find-property-range "mastodon-tl")
(autoload 'mastodon-tl--goto-next-toot "mastodon-tl")
+(autoload 'mastodon-tl--map-alist "mastodon-tl")
(autoload 'mastodon-tl--property "mastodon-tl")
(autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl")
-(autoload 'mastodon-tl--toot-id "mastodon-tl")
-(autoload 'mastodon-toot "mastodon")
-(autoload 'mastodon-profile--get-source-pref "mastodon-profile")
-(autoload 'mastodon-profile--update-preference "mastodon-profile")
-(autoload 'mastodon-profile--fetch-server-account-settings "mastodon-profile")
(autoload 'mastodon-tl--render-text "mastodon-tl")
-(autoload 'mastodon-profile--fetch-server-account-settings-maybe "mastodon-profile")
-(autoload 'mastodon-http--build-array-params-alist "mastodon-http")
-(autoload 'mastodon-http--put "mastodon-http")
+(autoload 'mastodon-tl--set-buffer-spec "mastodon-tl")
(autoload 'mastodon-tl--symbol "mastodon-tl")
-(autoload 'mastodon-tl--view-scheduled-toots "mastodon-tl")
-(autoload 'mastodon-tl--cancel-scheduled-toot "mastodon-toot")
+(autoload 'mastodon-tl--toot-id "mastodon-tl")
+(autoload 'mastodon-toot "mastodon")
+(autoload 'mastodon-views--cancel-scheduled-toot "mastodon-views")
+(autoload 'mastodon-views--view-scheduled-toots "mastodon-views")
(autoload 'org-read-date "org")
-(autoload 'iso8601-parse "iso8601")
-(autoload 'mastodon-tl--buffer-type-eq "mastodon-tl")
-(autoload 'mastodon-profile--show-user "mastodon-profile")
-(autoload 'mastodon-tl--set-buffer-spec "mastodon-tl")
;; for mastodon-toot--translate-toot-text
(autoload 'mastodon-tl--content "mastodon-tl")
@@ -98,18 +100,15 @@
(defcustom mastodon-toot--default-media-directory "~/"
"The default directory when prompting for a media file to upload."
- :group 'mastodon-toot
:type 'string)
(defcustom mastodon-toot--attachment-height 80
"Height of the attached images preview in the toot draft buffer."
- :group 'mastodon-toot
:type 'integer)
(defcustom mastodon-toot--enable-completion t
"Whether to enable completion of mentions and hashtags.
Used for completion in toot compose buffer."
- :group 'mastodon-toot
:type 'boolean)
(defcustom mastodon-toot--use-company-for-completion nil
@@ -119,12 +118,10 @@ buffer, and mastodon completion backends are added to
`company-capf'.
You need to install company yourself to use this."
- :group 'mastodon-toot
:type 'boolean)
(defcustom mastodon-toot--completion-style-for-mentions "all"
"The company completion style to use for mentions."
- :group 'mastodon-toot
:type '(choice
(const :tag "off" nil)
(const :tag "following only" "following")
@@ -132,27 +129,23 @@ You need to install company yourself to use this."
(defcustom mastodon-toot-display-orig-in-reply-buffer nil
"Display a copy of the toot replied to in the compose buffer."
- :group 'mastodon-toot
:type 'boolean)
(defcustom mastodon-toot-orig-in-reply-length 160
"Length to crop toot replied to in the compose buffer to."
- :group 'mastodon-toot
:type 'integer)
(defcustom mastodon-toot--default-reply-visibility "public"
"Default visibility settings when replying.
If the original toot visibility is different we use the more restricted one."
- :group 'mastodon-toot
:type '(choice
- (const :tag "public" "public")
- (const :tag "unlisted" "unlisted")
- (const :tag "followers only" "private")
- (const :tag "direct" "direct")))
+ (const :tag "public" "public")
+ (const :tag "unlisted" "unlisted")
+ (const :tag "followers only" "private")
+ (const :tag "direct" "direct")))
(defcustom mastodon-toot--enable-custom-instance-emoji nil
"Whether to enable your instance's custom emoji by default."
- :group 'mastodon-toot
:type 'boolean)
(defvar-local mastodon-toot--content-warning nil
@@ -223,16 +216,16 @@ send.")
(defvar mastodon-toot-handle-regex
(concat
- ;; preceding space or bol [boundary doesn't work with @]
- "\\([\n\t ]\\|^\\)"
+ ;; preceding bracket, space or bol [boundary doesn't work with @]
+ "\\([(\n\t ]\\|^\\)"
"\\(?2:@[1-9a-zA-Z._-]+" ; a handle
"\\(@[^ \n\t]*\\)?\\)" ; with poss domain, * = allow only @
"\\b"))
(defvar mastodon-toot-tag-regex
(concat
- ;; preceding space or bol [boundary doesn't work with #]
- "\\([\n\t ]\\|^\\)"
+ ;; preceding bracket, space or bol [boundary doesn't work with #]
+ "\\([(\n\t ]\\|^\\)"
"\\(?2:#[1-9a-zA-Z_]+\\)" ; tag
"\\b")) ; boundary
@@ -287,14 +280,14 @@ NO-TOOT means we are not calling from a toot buffer."
(mastodon-toot--update-status-fields)))))
(defun mastodon-toot--action-success (marker byline-region remove)
- "Insert/remove the text MARKER with 'success face in byline.
+ "Insert/remove the text MARKER with `success' face in byline.
BYLINE-REGION is a cons of start and end pos of the byline to be
modified.
Remove MARKER if REMOVE is non-nil, otherwise add it."
(let ((inhibit-read-only t)
(bol (car byline-region))
(eol (cdr byline-region))
- (at-byline-p (eq (get-text-property (point) 'byline) t)))
+ (at-byline-p (eq (mastodon-tl--property 'byline :no-move) t)))
(save-excursion
(when remove
(goto-char bol)
@@ -329,59 +322,90 @@ boosting, or bookmarking toots."
(defun mastodon-toot--toggle-boost-or-favourite (type)
"Toggle boost or favourite of toot at `point'.
-TYPE is a symbol, either 'favourite or 'boost."
+TYPE is a symbol, either `favourite' or `boost.'"
(interactive)
- (let* ((boost-p (equal type 'boost))
- (has-id (mastodon-tl--property 'base-toot-id))
- (byline-region (when has-id
- (mastodon-tl--find-property-range 'byline (point))))
- (id (when byline-region
- (mastodon-tl--as-string (mastodon-tl--property 'base-toot-id))))
- (boosted (when byline-region
- (get-text-property (car byline-region) 'boosted-p)))
- (faved (when byline-region
- (get-text-property (car byline-region) 'favourited-p)))
- (action (if boost-p
- (if boosted "unreblog" "reblog")
- (if faved "unfavourite" "favourite")))
- (msg (if boosted "unboosted" "boosted"))
- (action-string (if boost-p "boost" "favourite"))
- (remove (if boost-p (when boosted t) (when faved t)))
- (toot-type (alist-get 'type (mastodon-tl--property 'toot-json)))
- (visibility (mastodon-tl--field 'visibility
- (mastodon-tl--property 'toot-json))))
- (if byline-region
- (cond ;; actually there's nothing wrong with faving/boosting own toots!
- ;;((mastodon-toot--own-toot-p (mastodon-tl--property 'toot-json))
- ;;(error "You can't %s your own toots" action-string))
- ;; & nothing wrong with faving/boosting own toots from notifs:
- ;; this boosts/faves the base toot, not the notif status
- ((and (equal "reblog" toot-type)
- (not (mastodon-tl--buffer-type-eq 'notifications)))
- (error "You can't %s boosts" action-string))
- ((and (equal "favourite" toot-type)
- (not (mastodon-tl--buffer-type-eq 'notifications)))
- (error "You can't %s favourites" action-string))
- ((and (equal "private" visibility)
- (equal type 'boost))
- (error "You can't boost private toots"))
- (t
- (mastodon-toot--action
- action
- (lambda ()
- (let ((inhibit-read-only t))
- (add-text-properties (car byline-region)
- (cdr byline-region)
- (if boost-p
- (list 'boosted-p (not boosted))
- (list 'favourited-p (not faved))))
- (mastodon-toot--action-success
- (if boost-p
- (mastodon-tl--symbol 'boost)
- (mastodon-tl--symbol 'favourite))
- byline-region remove))
- (message (format "%s #%s" (if boost-p msg action) id))))))
- (message (format "Nothing to %s here?!?" action-string)))))
+ (mastodon-tl--do-if-toot-strict
+ (let* ((boost-p (equal type 'boost))
+ (has-id (mastodon-tl--property 'base-toot-id))
+ (byline-region (when has-id
+ (mastodon-tl--find-property-range 'byline (point))))
+ (id (when byline-region
+ (mastodon-tl--as-string (mastodon-tl--property 'base-toot-id))))
+ (boosted (when byline-region
+ (get-text-property (car byline-region) 'boosted-p)))
+ (faved (when byline-region
+ (get-text-property (car byline-region) 'favourited-p)))
+ (action (if boost-p
+ (if boosted "unreblog" "reblog")
+ (if faved "unfavourite" "favourite")))
+ (msg (if boosted "unboosted" "boosted"))
+ (action-string (if boost-p "boost" "favourite"))
+ (remove (if boost-p (when boosted t) (when faved t)))
+ (toot-type (alist-get 'type (mastodon-tl--property 'toot-json)))
+ (visibility (mastodon-tl--field 'visibility
+ (mastodon-tl--property 'toot-json))))
+ (if byline-region
+ (cond ;; actually there's nothing wrong with faving/boosting own toots!
+ ;;((mastodon-toot--own-toot-p (mastodon-tl--property 'toot-json))
+ ;;(error "You can't %s your own toots" action-string))
+ ;; & nothing wrong with faving/boosting own toots from notifs:
+ ;; this boosts/faves the base toot, not the notif status
+ ((and (equal "reblog" toot-type)
+ (not (mastodon-tl--buffer-type-eq 'notifications)))
+ (error "You can't %s boosts" action-string))
+ ((and (equal "favourite" toot-type)
+ (not (mastodon-tl--buffer-type-eq 'notifications)))
+ (error "You can't %s favourites" action-string))
+ ((and (equal "private" visibility)
+ (equal type 'boost))
+ (error "You can't boost private toots"))
+ (t
+ (mastodon-toot--action
+ action
+ (lambda ()
+ (let ((inhibit-read-only t))
+ (add-text-properties (car byline-region)
+ (cdr byline-region)
+ (if boost-p
+ (list 'boosted-p (not boosted))
+ (list 'favourited-p (not faved))))
+ (mastodon-toot--update-stats-on-action type remove)
+ (mastodon-toot--action-success
+ (if boost-p
+ (mastodon-tl--symbol 'boost)
+ (mastodon-tl--symbol 'favourite))
+ byline-region remove))
+ (message (format "%s #%s" (if boost-p msg action) id))))))
+ (message (format "Nothing to %s here?!?" action-string))))))
+
+(defun mastodon-toot--inc-or-dec (count subtract)
+ "If SUBTRACT, decrement COUNT, else increment."
+ (if subtract
+ (1- count)
+ (1+ count)))
+
+(defun mastodon-toot--update-stats-on-action (action &optional subtract)
+ "Increment the toot stats display upon ACTION.
+ACTION is a symbol, either `favourite' or `boost'.
+SUBTRACT means we are un-favouriting or unboosting, so we decrement."
+ (let* ((count-prop (if (eq action 'favourite)
+ 'favourites-count
+ 'boosts-count))
+ (count-prop-range (mastodon-tl--find-property-range count-prop (point)))
+ (count (get-text-property (car count-prop-range) count-prop))
+ (inhibit-read-only 1))
+ ;; TODO another way to implement this would be to async fetch counts again
+ ;; and re-display from count-properties
+ (add-text-properties
+ (car count-prop-range)
+ (cdr count-prop-range)
+ (list 'display ; update the display prop:
+ (number-to-string
+ (mastodon-toot--inc-or-dec count subtract))
+ ;; update the count prop
+ ;; we rely on this for any subsequent actions:
+ count-prop
+ (mastodon-toot--inc-or-dec count subtract)))))
(defun mastodon-toot--toggle-boost ()
"Boost/unboost toot at `point'."
@@ -394,39 +418,40 @@ TYPE is a symbol, either 'favourite or 'boost."
(mastodon-toot--toggle-boost-or-favourite 'favourite))
;; TODO maybe refactor into boost/fave fun
-(defun mastodon-toot--bookmark-toot-toggle ()
+(defun mastodon-toot--toggle-bookmark ()
"Bookmark or unbookmark toot at point."
(interactive)
- (let* ( ;(toot (mastodon-tl--property 'toot-json))
- (id (mastodon-tl--property 'base-toot-id))
- ;; (mastodon-tl--as-string (mastodon-tl--toot-id toot)))
- (bookmarked-p (mastodon-tl--property 'bookmarked-p))
- (prompt (if bookmarked-p
- (format "Toot already bookmarked. Remove? ")
- (format "Bookmark this toot? ")))
- (byline-region
- (when id
- (mastodon-tl--find-property-range 'byline (point))))
- (action (if bookmarked-p "unbookmark" "bookmark"))
- (bookmark-str (mastodon-tl--symbol 'bookmark))
- (message (if bookmarked-p
- "Bookmark removed!"
- "Toot bookmarked!"))
- (remove (when bookmarked-p t)))
- (if byline-region
- (when (y-or-n-p prompt)
- (mastodon-toot--action
- action
- (lambda ()
- (let ((inhibit-read-only t))
- (add-text-properties (car byline-region)
- (cdr byline-region)
- (list 'bookmarked-p (not bookmarked-p))))
- (mastodon-toot--action-success
- bookmark-str
- byline-region remove)
- (message (format "%s #%s" message id)))))
- (message (format "Nothing to %s here?!?" action)))))
+ (mastodon-tl--do-if-toot-strict
+ (let* ( ;(toot (mastodon-tl--property 'toot-json))
+ (id (mastodon-tl--property 'base-toot-id))
+ ;; (mastodon-tl--as-string (mastodon-tl--toot-id toot)))
+ (bookmarked-p (mastodon-tl--property 'bookmarked-p))
+ (prompt (if bookmarked-p
+ (format "Toot already bookmarked. Remove? ")
+ (format "Bookmark this toot? ")))
+ (byline-region
+ (when id
+ (mastodon-tl--find-property-range 'byline (point))))
+ (action (if bookmarked-p "unbookmark" "bookmark"))
+ (bookmark-str (mastodon-tl--symbol 'bookmark))
+ (message (if bookmarked-p
+ "Bookmark removed!"
+ "Toot bookmarked!"))
+ (remove (when bookmarked-p t)))
+ (if byline-region
+ (when (y-or-n-p prompt)
+ (mastodon-toot--action
+ action
+ (lambda ()
+ (let ((inhibit-read-only t))
+ (add-text-properties (car byline-region)
+ (cdr byline-region)
+ (list 'bookmarked-p (not bookmarked-p))))
+ (mastodon-toot--action-success
+ bookmark-str
+ byline-region remove)
+ (message (format "%s #%s" message id)))))
+ (message (format "Nothing to %s here?!?" action))))))
(defun mastodon-toot--list-toot-boosters ()
"List the boosters of toot at point."
@@ -441,26 +466,27 @@ TYPE is a symbol, either 'favourite or 'boost."
(defun mastodon-toot--list-toot-boosters-or-favers (&optional favourite)
"List the favouriters or boosters of toot at point.
With FAVOURITE, list favouriters, else list boosters."
- (let* ((base-toot (mastodon-tl--property 'base-toot-id))
- (endpoint (if favourite "favourited_by" "reblogged_by"))
- (url (mastodon-http--api
- (format "statuses/%s/%s" base-toot endpoint)))
- (params '(("limit" . "80")))
- (json (mastodon-http--get-json url params)))
- (if (eq (caar json) 'error)
- (error "%s (Status does not exist or is private)"
- (alist-get 'error json))
- (let ((handles (mapcar (lambda (x) (alist-get 'acct x)) json))
- (type-string (if favourite "Favouriters" "Boosters")))
- (if (not handles)
- (error "Looks like this toot has no %s" type-string)
- (let ((choice
- (completing-read
- (format "%s (enter to view profile): " type-string)
- handles
- nil
- t)))
- (mastodon-profile--show-user choice)))))))
+ (mastodon-tl--do-if-toot-strict
+ (let* ((base-toot (mastodon-tl--property 'base-toot-id))
+ (endpoint (if favourite "favourited_by" "reblogged_by"))
+ (url (mastodon-http--api
+ (format "statuses/%s/%s" base-toot endpoint)))
+ (params '(("limit" . "80")))
+ (json (mastodon-http--get-json url params)))
+ (if (eq (caar json) 'error)
+ (error "%s (Status does not exist or is private)"
+ (alist-get 'error json))
+ (let ((handles (mastodon-tl--map-alist 'acct json))
+ (type-string (if favourite "Favouriters" "Boosters")))
+ (if (not handles)
+ (error "Looks like this toot has no %s" type-string)
+ (let ((choice
+ (completing-read
+ (format "%s (enter to view profile): " type-string)
+ handles
+ nil
+ t)))
+ (mastodon-profile--show-user choice))))))))
(defun mastodon-toot--copy-toot-url ()
"Copy URL of toot at point.
@@ -520,12 +546,12 @@ Uses `lingva.el'."
(msg-y-or-n (if pinned-p "Unpin" "Pin")))
(if (not pinnable-p)
(message "You can only pin your own toots.")
- (if (y-or-n-p (format "%s this toot? " msg-y-or-n))
- (mastodon-toot--action action
- (lambda ()
- (when mastodon-tl--buffer-spec
- (mastodon-tl--reload-timeline-or-profile))
- (message "Toot %s!" msg)))))))
+ (when (y-or-n-p (format "%s this toot? " msg-y-or-n))
+ (mastodon-toot--action action
+ (lambda ()
+ (when mastodon-tl--buffer-spec
+ (mastodon-tl--reload-timeline-or-profile))
+ (message "Toot %s!" msg)))))))
(defun mastodon-toot--delete-toot ()
"Delete user's toot at point synchronously."
@@ -546,22 +572,22 @@ NO-REDRAFT means delete toot only."
(reply-id (alist-get 'in_reply_to_id toot)))
(if (not (mastodon-toot--own-toot-p toot))
(message "You can only delete (and redraft) your own toots.")
- (if (y-or-n-p (if no-redraft
- (format "Delete this toot? ")
- (format "Delete and redraft this toot? ")))
- (let* ((response (mastodon-http--delete url)))
- (mastodon-http--triage
- response
- (lambda ()
- (if no-redraft
- (progn
- (when mastodon-tl--buffer-spec
- (mastodon-tl--reload-timeline-or-profile))
- (message "Toot deleted!"))
- (mastodon-toot--redraft response
- reply-id
- toot-visibility
- toot-cw)))))))))
+ (when (y-or-n-p (if no-redraft
+ (format "Delete this toot? ")
+ (format "Delete and redraft this toot? ")))
+ (let* ((response (mastodon-http--delete url)))
+ (mastodon-http--triage
+ response
+ (lambda ()
+ (if no-redraft
+ (progn
+ (when mastodon-tl--buffer-spec
+ (mastodon-tl--reload-timeline-or-profile))
+ (message "Toot deleted!"))
+ (mastodon-toot--redraft response
+ reply-id
+ toot-visibility
+ toot-cw)))))))))
(defun mastodon-toot--set-cw (&optional cw)
"Set content warning to CW if it is non-nil."
@@ -727,16 +753,6 @@ to `emojify-user-emojis', and the emoji data is updated."
(point-min))))
(buffer-substring (cdr header-region) (point-max))))
-(defun mastodon-toot--set-visibility (visibility)
- "Set the visiblity of the next toot to VISIBILITY."
- (interactive
- (list (completing-read "Visiblity: " '("public"
- "unlisted"
- "private"
- "direct"))))
- (setq mastodon-toot--visibility visibility)
- (message "Visibility set to %s" visibility))
-
(defun mastodon-toot--build-poll-params ()
"Return an alist of parameters for POSTing a poll status."
(append
@@ -815,7 +831,7 @@ instance to edit a toot."
(message "Toot toot!"))
;; cancel scheduled toot if we were editing it:
(when scheduled-id
- (mastodon-tl--cancel-scheduled-toot
+ (mastodon-views--cancel-scheduled-toot
scheduled-id :no-confirm))
(mastodon-toot--restore-previous-window-config
prev-window-config))))))))
@@ -870,7 +886,7 @@ instance to edit a toot."
(insert (propertize (if (= count 1)
(format "%s [original]:\n" count)
(format "%s:\n" count))
- 'face 'font-lock-comment-face)
+ 'face font-lock-comment-face)
(mastodon-toot--insert-toot-iter x)
"\n")
(cl-incf count))
@@ -903,9 +919,8 @@ Buffer-local variable `mastodon-toot-previous-window-config' holds the config."
"Apply `mastodon-toot--process-local' function to each mention in MENTIONS.
Remove empty string (self) from result and joins the sequence with whitespace."
(mapconcat (lambda (mention) mention)
- (remove "" (mapcar (lambda (x) (mastodon-toot--process-local x))
- mentions))
- " "))
+ (remove "" (mapcar #'mastodon-toot--process-local mentions))
+ " "))
(defun mastodon-toot--process-local (acct)
"Add domain to local ACCT and replace the curent user name with \"\".
@@ -931,8 +946,7 @@ Federated user: `username@host.co`."
(alist-get 'mentions (alist-get 'reblog status))
(alist-get 'mentions status))))
;; reverse does not work on vectors in 24.5
- (mapcar (lambda(x) (alist-get 'acct x))
- (reverse mentions))))
+ (mastodon-tl--map-alist 'acct (reverse mentions))))
(defun mastodon-toot--get-bounds (regex)
"Get bounds of tag or handle before point using REGEX."
@@ -1018,39 +1032,39 @@ If TAGS, we search for tags, else we search for handles."
Customize `mastodon-toot-display-orig-in-reply-buffer' to display
text of the toot being replied to in the compose buffer."
(interactive)
- (let* ((toot (mastodon-tl--property 'toot-json))
- ;; NB: we cannot use mastodon-tl--property for 'base-toot
- ;; because if it doesn't have one, it is fetched from next toot!
- ;; we also cannot use --field because we need to get a different property first
- (base-toot (get-text-property (point) 'base-toot)) ; for new notifs handling
- (id (mastodon-tl--as-string (mastodon-tl--field 'id (or base-toot toot))))
- (account (mastodon-tl--field 'account toot))
- (user (alist-get 'acct account))
- (mentions (mastodon-toot--mentions (or base-toot toot)))
- (boosted (mastodon-tl--field 'reblog (or base-toot toot)))
- (booster (when boosted
- (alist-get 'acct
- (alist-get 'account toot)))))
- (mastodon-toot (when user
- (if booster
- (if (and (not (equal user booster))
- (not (member booster mentions)))
- ;; different booster, user and mentions:
- (mastodon-toot--mentions-to-string (append (list user booster) mentions nil))
- ;; booster is either user or in mentions:
- (if (not (member user mentions))
- ;; user not already in mentions:
- (mastodon-toot--mentions-to-string (append (list user) mentions nil))
- ;; user already in mentions:
- (mastodon-toot--mentions-to-string (copy-sequence mentions))))
- ;; ELSE no booster:
- (if (not (member user mentions))
- ;; user not in mentions:
- (mastodon-toot--mentions-to-string (append (list user) mentions nil))
- ;; user in mentions already:
- (mastodon-toot--mentions-to-string (copy-sequence mentions)))))
- id
- (or base-toot toot))))
+ (mastodon-tl--do-if-toot-strict
+ (let* ((toot (mastodon-tl--property 'toot-json))
+ ;; no-move arg for base toot, because if it doesn't have one, it is
+ ;; fetched from next toot!
+ (base-toot (mastodon-tl--property 'base-toot :no-move)) ; for new notifs handling
+ (id (mastodon-tl--as-string (mastodon-tl--field 'id (or base-toot toot))))
+ (account (mastodon-tl--field 'account toot))
+ (user (alist-get 'acct account))
+ (mentions (mastodon-toot--mentions (or base-toot toot)))
+ (boosted (mastodon-tl--field 'reblog (or base-toot toot)))
+ (booster (when boosted
+ (alist-get 'acct
+ (alist-get 'account toot)))))
+ (mastodon-toot (when user
+ (if booster
+ (if (and (not (equal user booster))
+ (not (member booster mentions)))
+ ;; different booster, user and mentions:
+ (mastodon-toot--mentions-to-string (append (list user booster) mentions nil))
+ ;; booster is either user or in mentions:
+ (if (not (member user mentions))
+ ;; user not already in mentions:
+ (mastodon-toot--mentions-to-string (append (list user) mentions nil))
+ ;; user already in mentions:
+ (mastodon-toot--mentions-to-string (copy-sequence mentions))))
+ ;; ELSE no booster:
+ (if (not (member user mentions))
+ ;; user not in mentions:
+ (mastodon-toot--mentions-to-string (append (list user) mentions nil))
+ ;; user in mentions already:
+ (mastodon-toot--mentions-to-string (copy-sequence mentions)))))
+ id
+ (or base-toot toot)))))
(defun mastodon-toot--toggle-warning ()
"Toggle `mastodon-toot--content-warning'."
@@ -1070,16 +1084,18 @@ text of the toot being replied to in the compose buffer."
(defun mastodon-toot--change-visibility ()
"Change the current visibility to the next valid value."
(interactive)
- (setq mastodon-toot--visibility
- (cond ((string= mastodon-toot--visibility "public")
- "unlisted")
- ((string= mastodon-toot--visibility "unlisted")
- "private")
- ((string= mastodon-toot--visibility "private")
- "direct")
- (t
- "public")))
- (mastodon-toot--update-status-fields))
+ (if (mastodon-tl--buffer-type-eq 'edit-toot)
+ (message "You can't change visibility when editing toots.")
+ (setq mastodon-toot--visibility
+ (cond ((string= mastodon-toot--visibility "public")
+ "unlisted")
+ ((string= mastodon-toot--visibility "unlisted")
+ "private")
+ ((string= mastodon-toot--visibility "private")
+ "direct")
+ (t
+ "public")))
+ (mastodon-toot--update-status-fields)))
(defun mastodon-toot--clear-all-attachments ()
"Remove all attachments from a toot draft."
@@ -1241,34 +1257,40 @@ With RESCHEDULE, reschedule the scheduled toot at point without editing."
;; original idea by christian tietze, thanks!
;; https://codeberg.org/martianh/mastodon.el/issues/285
(interactive)
- (let* ((id (when reschedule (get-text-property (point) 'id)))
- (ts (when reschedule
- (alist-get 'scheduled_at
- (get-text-property (point) 'scheduled-json))))
- (time-value
- (org-read-date t t nil "Schedule toot:"
- ;; default to scheduled timestamp if already set:
- (mastodon-toot--iso-to-org
- ;; we are rescheduling without editing:
- (or ts
- ;; we are maybe editing the scheduled toot:
- mastodon-toot--scheduled-for))))
- (iso8601-str (format-time-string "%FT%T%z" time-value))
- (msg-str (format-time-string "%d-%m-%y at %H:%M[%z]" time-value)))
- (if (not reschedule)
- (progn
- (setq-local mastodon-toot--scheduled-for iso8601-str)
- (message (format "Toot scheduled for %s." msg-str)))
- (let* ((args (when reschedule `(("scheduled_at" . ,iso8601-str))))
- (url (when reschedule (mastodon-http--api
- (format "scheduled_statuses/%s" id))))
- (response (mastodon-http--put url args)))
- (mastodon-http--triage response
- (lambda ()
- ;; reschedule means we are in scheduled toots view:
- (mastodon-tl--view-scheduled-toots)
- (message
- (format "Toot rescheduled for %s." msg-str))))))))
+ (cond ((mastodon-tl--buffer-type-eq 'edit-toot)
+ (message "You can't schedule toots you're editing."))
+ ((not (or (mastodon-tl--buffer-type-eq 'new-toot)
+ (mastodon-tl--buffer-type-eq 'scheduled-statuses)))
+ (message "You can only schedule toots from the compose toot buffer or the scheduled toots view."))
+ (t
+ (let* ((id (when reschedule (mastodon-tl--property 'id :no-move)))
+ (ts (when reschedule
+ (alist-get 'scheduled_at
+ (mastodon-tl--property 'scheduled-json :no-move))))
+ (time-value
+ (org-read-date t t nil "Schedule toot:"
+ ;; default to scheduled timestamp if already set:
+ (mastodon-toot--iso-to-org
+ ;; we are rescheduling without editing:
+ (or ts
+ ;; we are maybe editing the scheduled toot:
+ mastodon-toot--scheduled-for))))
+ (iso8601-str (format-time-string "%FT%T%z" time-value))
+ (msg-str (format-time-string "%d-%m-%y at %H:%M[%z]" time-value)))
+ (if (not reschedule)
+ (progn
+ (setq-local mastodon-toot--scheduled-for iso8601-str)
+ (message (format "Toot scheduled for %s." msg-str)))
+ (let* ((args (when reschedule `(("scheduled_at" . ,iso8601-str))))
+ (url (when reschedule (mastodon-http--api
+ (format "scheduled_statuses/%s" id))))
+ (response (mastodon-http--put url args)))
+ (mastodon-http--triage response
+ (lambda ()
+ ;; reschedule means we are in scheduled toots view:
+ (mastodon-views--view-scheduled-toots)
+ (message
+ (format "Toot rescheduled for %s." msg-str))))))))))
(defun mastodon-toot--iso-to-human (ts)
"Format an ISO8601 timestamp TS to be more human-readable."
@@ -1346,7 +1368,7 @@ LONGEST is the length of the longest binding."
(mastodon-toot--format-kbinds kbinds))))
(concat
" Compose a new toot here. The following keybindings are available:"
- (mapconcat 'identity
+ (mapconcat #'identity
(mastodon-toot--formatted-kbinds-pairs
(mastodon-toot--format-kbinds kbinds)
longest-kbind)
@@ -1387,7 +1409,7 @@ REPLY-TEXT is the text of the toot being replied to."
(propertize "None "
'toot-attachments t)
"\n")
- 'face 'font-lock-comment-face
+ 'face font-lock-comment-face
'read-only "Edit your message below."
'toot-post-header t)
(if reply-text
@@ -1399,7 +1421,7 @@ REPLY-TEXT is the text of the toot being replied to."
(propertize
(concat divider "\n")
'rear-nonsticky t
- 'face 'font-lock-comment-face
+ 'face font-lock-comment-face
'read-only "Edit your message below."
'toot-post-header t))))
@@ -1633,7 +1655,7 @@ EDIT means we are editing an existing toot, not composing a new one."
;; company
(when (and mastodon-toot--use-company-for-completion
(require 'company nil :no-error))
- (declare-function 'company-mode-on "company")
+ (declare-function company-mode-on "company")
(set (make-local-variable 'company-backends)
(add-to-list 'company-backends 'company-capf))
(company-mode-on)))
@@ -1661,7 +1683,6 @@ EDIT means we are editing an existing toot, not composing a new one."
(define-minor-mode mastodon-toot-mode
"Minor mode to capture Mastodon toots."
- :group 'mastodon-toot
:keymap mastodon-toot-mode-map
:global nil)