aboutsummaryrefslogtreecommitdiff
path: root/lisp/mastodon-toot.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/mastodon-toot.el')
-rw-r--r--lisp/mastodon-toot.el392
1 files changed, 193 insertions, 199 deletions
diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el
index e77787c..14b9d68 100644
--- a/lisp/mastodon-toot.el
+++ b/lisp/mastodon-toot.el
@@ -225,6 +225,9 @@ For the moment we just put all composed toots in here, as we want
to also capture toots that are 'sent' but that don't successfully
send.")
+
+;;; REGEXES
+
(defvar mastodon-toot-handle-regex
(rx (| (any ?\( "\n" "\t "" ") bol) ; preceding things
(group-n 2 (+ ?@ (* (any ?- ?_ ?. "A-Z" "a-z" "0-9" ))) ; handle
@@ -240,9 +243,12 @@ send.")
;; 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
+ "[^ \n\t]*\\)" ; any old thing, that is, i.e. we allow invalid/unwise chars
"\\b")) ; boundary
+
+;;; MODE MAP
+
(defvar mastodon-toot-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-c") #'mastodon-toot--send)
@@ -281,13 +287,11 @@ NO-TOOT means we are not calling from a toot buffer."
"Set max_toot_chars returned in JSON-RESPONSE and display in new toot buffer.
NO-TOOT means we are not calling from a toot buffer."
(let ((max-chars
- (or
- (alist-get 'max_toot_chars json-response)
- ;; some servers have this instead:
- (alist-get 'max_characters
- (alist-get 'statuses
- (alist-get 'configuration
- json-response))))))
+ (or (alist-get 'max_toot_chars json-response)
+ (alist-get 'max_characters ; some servers have this instead
+ (alist-get 'statuses
+ (alist-get 'configuration
+ json-response))))))
(setq mastodon-toot--max-toot-chars max-chars)
(unless no-toot
(with-current-buffer "*new toot*"
@@ -327,10 +331,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it."
Makes a POST request to the server. Used for favouriting,
boosting, or bookmarking toots."
(let* ((id (mastodon-tl--property 'base-toot-id))
- (url (mastodon-http--api (concat "statuses/"
- (mastodon-tl--as-string id)
- "/"
- action))))
+ (url (mastodon-http--api
+ (concat "statuses/" (mastodon-tl--as-string id) "/" action))))
(let ((response (mastodon-http--post url)))
(mastodon-http--triage response callback))))
@@ -339,9 +341,9 @@ boosting, or bookmarking toots."
TYPE is a symbol, either `favourite' or `boost.'"
(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))))
+ ;; (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
@@ -354,9 +356,9 @@ TYPE is a symbol, either `favourite' or `boost.'"
(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))))
+ (toot-json (mastodon-tl--property 'toot-json))
+ (toot-type (alist-get 'type toot-json))
+ (visibility (mastodon-tl--field 'visibility toot-json)))
(if byline-region
(if (and (or (equal visibility "direct")
(equal visibility "private"))
@@ -387,11 +389,10 @@ TYPE is a symbol, either `favourite' or `boost.'"
(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))
+ (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))))))
@@ -413,16 +414,15 @@ SUBTRACT means we are un-favouriting or unboosting, so we decrement."
(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)))))
+ (add-text-properties (car count-prop-range)
+ (cdr count-prop-range)
+ (list 'display
+ (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'."
@@ -439,16 +439,13 @@ SUBTRACT means we are un-favouriting or unboosting, so we decrement."
"Bookmark or unbookmark toot at point."
(interactive)
(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)))
+ (let* ((id (mastodon-tl--property 'base-toot-id))
(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))))
+ (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
@@ -464,9 +461,8 @@ SUBTRACT means we are un-favouriting or unboosting, so we decrement."
(add-text-properties (car byline-region)
(cdr byline-region)
(list 'bookmarked-p (not bookmarked-p))))
- (mastodon-toot--action-success
- bookmark-str
- byline-region remove)
+ (mastodon-toot--action-success bookmark-str
+ byline-region remove)
(message (format "%s #%s" message id)))))
(message (format "Nothing to %s here?!?" action))))))
@@ -486,23 +482,20 @@ With FAVOURITE, list favouriters, else list boosters."
(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)))
+ (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))
+ (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)))
+ (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 ()
@@ -528,7 +521,6 @@ base toot."
(kill-new (mastodon-tl--content toot))
(message "Toot content copied to the clipboard.")))
-;; (when (require 'lingva nil :no-error)
(defun mastodon-toot--translate-toot-text ()
"Translate text of toot at point.
Uses `lingva.el'."
@@ -536,13 +528,12 @@ Uses `lingva.el'."
(if (not (require 'lingva nil :no-error))
(message "Looks like you need to install lingva.el first.")
(if mastodon-tl--buffer-spec
- (let ((toot (mastodon-tl--property 'toot-json)))
- (if toot
- (lingva-translate nil
- (mastodon-tl--content toot)
- (when mastodon-tl--enable-proportional-fonts
- t))
- (message "No toot to translate?")))
+ (if-let ((toot (mastodon-tl--property 'toot-json)))
+ (lingva-translate nil
+ (mastodon-tl--content toot)
+ (when mastodon-tl--enable-proportional-fonts
+ t))
+ (message "No toot to translate?"))
(message "No mastodon buffer?"))))
(defun mastodon-toot--own-toot-p (toot)
@@ -570,6 +561,9 @@ Uses `lingva.el'."
(mastodon-tl--reload-timeline-or-profile))
(message "Toot %s!" msg)))))))
+
+;;; DELETE, DRAFT, REDRAFT
+
(defun mastodon-toot--delete-toot ()
"Delete user's toot at point synchronously."
(interactive)
@@ -614,6 +608,9 @@ NO-REDRAFT means delete toot only."
(setq mastodon-toot--content-warning t)
(setq mastodon-toot--content-warning-from-reply-or-redraft cw)))
+
+;;; REDRAFT
+
(defun mastodon-toot--redraft (response &optional reply-id toot-visibility toot-cw)
"Opens a new toot compose buffer using values from RESPONSE buffer.
REPLY-ID, TOOT-VISIBILITY, and TOOT-CW of deleted toot are preseved."
@@ -629,9 +626,8 @@ REPLY-ID, TOOT-VISIBILITY, and TOOT-CW of deleted toot are preseved."
;; TODO set new lang/scheduled props here
nil))))
-(defun mastodon-toot--set-toot-properties (reply-id visibility cw lang
- &optional scheduled
- scheduled-id)
+(defun mastodon-toot--set-toot-properties
+ (reply-id visibility cw lang &optional scheduled scheduled-id)
"Set the toot properties for the current redrafted or edited toot.
REPLY-ID, VISIBILITY, CW, SCHEDULED, and LANG are the properties to set."
(when reply-id
@@ -687,22 +683,26 @@ TEXT-ONLY means don't check for attachments or polls."
(string-empty-p (mastodon-tl--clean-tabs-and-nl
(mastodon-toot--remove-docs)))))
+
+;;; EMOJIS
+
(defalias 'mastodon-toot--insert-emoji
'emojify-insert-emoji
"Prompt to insert an emoji.")
+(defun mastodon-toot--emoji-dir ()
+ "Return the file path for the mastodon custom emojis directory."
+ (concat (expand-file-name emojify-emojis-dir)
+ "/mastodon-custom-emojis/"))
+
(defun mastodon-toot--download-custom-emoji ()
"Download `mastodon-instance-url's custom emoji.
Emoji images are stored in a subdir of `emojify-emojis-dir'.
To use the downloaded emoji, run `mastodon-toot--enable-custom-emoji'."
(interactive)
- (let ((custom-emoji (mastodon-http--get-json
- (mastodon-http--api "custom_emojis")))
- (mastodon-custom-emoji-dir (file-name-as-directory
- (concat (file-name-as-directory
- (expand-file-name
- emojify-emojis-dir))
- "mastodon-custom-emojis"))))
+ (let* ((url (mastodon-http--api "custom_emojis"))
+ (custom-emoji (mastodon-http--get-json url))
+ (mastodon-custom-emoji-dir (mastodon-toot--emoji-dir)))
(if (not (file-directory-p emojify-emojis-dir))
(message "Looks like you need to set up emojify first.")
(unless (file-directory-p mastodon-custom-emoji-dir)
@@ -715,11 +715,10 @@ To use the downloaded emoji, run `mastodon-toot--enable-custom-emoji'."
(string-match-p "^[a-zA-Z0-9-_]+$" shortcode)
(string-match-p "^[a-zA-Z]+$" (file-name-extension url)))
(url-copy-file url
- (concat
- mastodon-custom-emoji-dir
- shortcode
- "."
- (file-name-extension url))
+ (concat mastodon-custom-emoji-dir
+ shortcode
+ "."
+ (file-name-extension url))
t))))
custom-emoji)
(message "Custom emoji for %s downloaded to %s"
@@ -729,13 +728,11 @@ To use the downloaded emoji, run `mastodon-toot--enable-custom-emoji'."
(defun mastodon-toot--collect-custom-emoji ()
"Return a list of `mastodon-instance-url's custom emoji.
The list is formatted for `emojify-user-emojis', which see."
- (let* ((mastodon-custom-emojis-dir (concat (expand-file-name
- emojify-emojis-dir)
- "/mastodon-custom-emojis/"))
+ (let* ((mastodon-custom-emojis-dir (mastodon-toot--emoji-dir))
(custom-emoji-files (directory-files mastodon-custom-emojis-dir
nil ; not full path
"^[^.]")) ; no dot files
- (mastodon-emojify-user-emojis))
+ mastodon-emojify-user-emojis)
(mapc (lambda (x)
(push
`(,(concat ":"
@@ -753,9 +750,7 @@ Custom emoji must first be downloaded with
`mastodon-toot--download-custom-emoji'. Custom emoji are appended
to `emojify-user-emojis', and the emoji data is updated."
(interactive)
- (unless (file-exists-p (concat (expand-file-name
- emojify-emojis-dir)
- "/mastodon-custom-emojis/"))
+ (unless (file-exists-p (mastodon-toot--emoji-dir))
(when (y-or-n-p "Looks like you haven't downloaded your
instance's custom emoji yet. Download now? ")
(mastodon-toot--download-custom-emoji)))
@@ -789,6 +784,9 @@ to `emojify-user-emojis', and the emoji data is updated."
(read-string "Warning: "
mastodon-toot--content-warning-from-reply-or-redraft)))
+
+;;; SEND TOOT FUNCTION
+
(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
@@ -800,12 +798,9 @@ instance to edit a toot."
(scheduled mastodon-toot--scheduled-for)
(scheduled-id mastodon-toot--scheduled-id)
(edit-id mastodon-toot--edit-toot-id)
- (endpoint
- (if edit-id
- ;; we are sending an edit:
- (mastodon-http--api (format "statuses/%s"
- edit-id))
- (mastodon-http--api "statuses")))
+ (endpoint (if edit-id ; we are sending an edit:
+ (mastodon-http--api (format "statuses/%s" edit-id))
+ (mastodon-http--api "statuses")))
(cw (mastodon-toot--read-cw-string))
(args-no-media (append `(("status" . ,toot)
("in_reply_to_id" . ,mastodon-toot--reply-to-id)
@@ -843,8 +838,7 @@ instance to edit a toot."
((mastodon-toot--empty-p)
(message "Empty toot. Cowardly refusing to post this."))
(t
- (let ((response (if edit-id
- ;; we are sending an edit:
+ (let ((response (if edit-id ; we are sending an edit:
(mastodon-http--put endpoint args)
(mastodon-http--post endpoint args))))
(mastodon-http--triage
@@ -863,12 +857,13 @@ instance to edit a toot."
(let ((pos (marker-position (cadr prev-window-config))))
(mastodon-tl--reload-timeline-or-profile pos))))))))))
-;; EDITING TOOTS:
+
+;;; EDITING TOOTS:
(defun mastodon-toot--edit-toot-at-point ()
"Edit the user's toot at point."
(interactive)
- (let ((toot (or (mastodon-tl--property 'base-toot); fave/boost notifs
+ (let ((toot (or (mastodon-tl--property 'base-toot) ; fave/boost notifs
(mastodon-tl--property 'toot-json))))
(if (not (mastodon-toot--own-toot-p toot))
(message "You can only edit your own toots.")
@@ -882,7 +877,6 @@ instance to edit a toot."
(when (y-or-n-p "Edit this toot? ")
(mastodon-toot--compose-buffer nil reply-id nil content :edit)
(goto-char (point-max))
- ;; (insert content)
;; adopt reply-to-id, visibility, CW, and language:
(mastodon-toot--set-toot-properties reply-id toot-visibility
source-cw toot-language)
@@ -943,7 +937,7 @@ 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 #'mastodon-toot--process-local mentions))
+ (remove "" (mapcar #'mastodon-toot--process-local mentions))
" "))
(defun mastodon-toot--process-local (acct)
@@ -958,30 +952,31 @@ eg. \"feduser@fed.social\" -> \"@feduser@fed.social\"."
(t (concat "@" acct "@" ; local acct
(cadr (split-string mastodon-instance-url "/" t))))))
+
+;;; COMPLETION (TAGS, MENTIONS)
+
(defun mastodon-toot--mentions (status)
"Extract mentions (not the reply-to author or booster) from STATUS.
The mentioned users look like this:
Local user (including the logged in): `username`.
Federated user: `username@host.co`."
(let* ((boosted (mastodon-tl--field 'reblog status))
- (mentions
- (if boosted
- (alist-get 'mentions (alist-get 'reblog status))
- (alist-get 'mentions status))))
+ (mentions (if boosted
+ (alist-get 'mentions (alist-get 'reblog status))
+ (alist-get 'mentions status))))
;; reverse does not work on vectors in 24.5
(mastodon-tl--map-alist 'acct (reverse mentions))))
(defun mastodon-toot--get-bounds (regex)
"Get bounds of tag or handle before point using REGEX."
- ;; needed because # and @ are not part of any existing thing at point
+ ;; # and @ are not part of any existing thing at point
(save-match-data
(save-excursion
;; match full handle inc. domain, or tag including #
;; (see the regexes for subexp 2)
(when (re-search-backward regex
- (save-excursion
- (forward-whitespace -1)
- (point))
+ (save-excursion (forward-whitespace -1)
+ (point))
:no-error)
(cons (match-beginning 2)
(match-end 2))))))
@@ -1004,51 +999,43 @@ If TAGS, we search for tags, else we search for handles."
(defun mastodon-toot--mentions-capf ()
"Build a mentions completion backend for `completion-at-point-functions'."
- (let* ((bounds
- (mastodon-toot--get-bounds mastodon-toot-handle-regex))
+ (let* ((bounds (mastodon-toot--get-bounds mastodon-toot-handle-regex))
(start (car bounds))
(end (cdr bounds)))
(when bounds
(list start
end
- ;; only search when necessary:
- (completion-table-dynamic
+ (completion-table-dynamic ; only search when necessary
(lambda (_)
- ;; Interruptible candidate computation
- ;; suggestion from minad (d mendler), thanks!
+ ;; Interruptible candidate computation, from minad/d mendler, thanks!
(let ((result
(while-no-input
(mastodon-toot--fetch-completion-candidates start end))))
(and (consp result) result))))
:exclusive 'no
:annotation-function
- (lambda (candidate)
- (concat " "
- (mastodon-toot--mentions-annotation-fun candidate)))))))
+ (lambda (cand)
+ (concat " " (mastodon-toot--mentions-annotation-fun cand)))))))
(defun mastodon-toot--tags-capf ()
"Build a tags completion backend for `completion-at-point-functions'."
- (let* ((bounds
- (mastodon-toot--get-bounds mastodon-toot-tag-regex))
+ (let* ((bounds (mastodon-toot--get-bounds mastodon-toot-tag-regex))
(start (car bounds))
(end (cdr bounds)))
(when bounds
(list start
end
- ;; only search when necessary:
- (completion-table-dynamic
+ (completion-table-dynamic ; only search when necessary:
(lambda (_)
- ;; Interruptible candidate computation
- ;; suggestion from minad (d mendler), thanks!
+ ;; Interruptible candidate computation, from minad/d mendler, thanks!
(let ((result
(while-no-input
(mastodon-toot--fetch-completion-candidates start end :tags))))
(and (consp result) result))))
:exclusive 'no
:annotation-function
- (lambda (candidate)
- (concat " "
- (mastodon-toot--tags-annotation-fun candidate)))))))
+ (lambda (cand)
+ (concat " " (mastodon-toot--tags-annotation-fun cand)))))))
(defun mastodon-toot--mentions-annotation-fun (candidate)
"Given a handle completion CANDIDATE, return its annotation string, a username."
@@ -1056,10 +1043,13 @@ If TAGS, we search for tags, else we search for handles."
(defun mastodon-toot--tags-annotation-fun (candidate)
"Given a tag string CANDIDATE, return an annotation, the tag's URL."
- ;; FIXME check the list returned here? should be cadr
- ;;or make it an alist and use cdr
+ ;; TODO: check the list returned here? should be cadr
+ ;; or make it an alist and use cdr
(cadr (assoc candidate mastodon-toot-completions)))
+
+;;; REPLY
+
(defun mastodon-toot--reply ()
"Reply to toot at `point'.
Customize `mastodon-toot-display-orig-in-reply-buffer' to display
@@ -1067,8 +1057,7 @@ text of the toot being replied to in the compose buffer."
(interactive)
(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!
+ ;; no-move arg for base toot: don't try 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))
@@ -1100,6 +1089,9 @@ text of the toot being replied to in the compose buffer."
id
(or base-toot toot)))))
+
+;;; COMPOSE TOOT SETTINGS
+
(defun mastodon-toot--toggle-warning ()
"Toggle `mastodon-toot--content-warning'."
(interactive)
@@ -1131,6 +1123,20 @@ text of the toot being replied to in the compose buffer."
"public")))
(mastodon-toot--update-status-fields)))
+(defun mastodon-toot--set-toot-language ()
+ "Prompt for a language and set `mastodon-toot--language'.
+Return its two letter ISO 639 1 code."
+ (interactive)
+ (let* ((choice (completing-read "Language for this toot: "
+ mastodon-iso-639-1)))
+ (setq mastodon-toot--language
+ (alist-get choice mastodon-iso-639-1 nil nil 'equal))
+ (message "Language set to %s" choice)
+ (mastodon-toot--update-status-fields)))
+
+
+;;; ATTACHMENTS
+
(defun mastodon-toot--clear-all-attachments ()
"Remove all attachments from a toot draft."
(interactive)
@@ -1163,8 +1169,7 @@ File is actually attached to the toot upon posting."
"Upload a single ATTACHMENT using `mastodon-http--post-media-attachment'.
The item's id is added to `mastodon-toot--media-attachment-ids',
which is used to attach it to a toot when posting."
- (let* ((filename (expand-file-name
- (alist-get :filename attachment)))
+ (let* ((filename (expand-file-name (alist-get :filename attachment)))
(caption (alist-get :description attachment))
(url (concat mastodon-instance-url "/api/v2/media")))
(message "Uploading %s... (please wait before starting further uploads)"
@@ -1203,8 +1208,11 @@ which is used to attach it to a toot when posting."
mastodon-toot--media-attachments))
(list "None")))
+
+;;; POLL
+
(defun mastodon-toot--fetch-max-poll-options (instance)
- "Return the maximum number of poll options from INSTANCE, which is json."
+ "Return the maximum number of poll options from JSON data INSTANCE."
(mastodon-toot--fetch-poll-field 'max_options instance))
(defun mastodon-toot--fetch-max-poll-option-chars (instance)
@@ -1216,7 +1224,7 @@ INSTANCE is JSON."
50))) ; masto default
(defun mastodon-toot--fetch-poll-field (field instance)
- "Return FIELD from the poll settings from INSTANCE, which is json."
+ "Return FIELD from the poll settings from JSON data INSTANCE."
(let* ((polls (if (alist-get 'pleroma instance)
(alist-get 'poll_limits instance)
(alist-get 'polls
@@ -1226,8 +1234,7 @@ INSTANCE is JSON."
(defun mastodon-toot--read-poll-options-count (max)
"Read the user's choice of the number of options the poll should have.
MAX is the maximum number set by their instance."
- (let ((number (read-number
- (format "Number of options [2-%s]: " max) 2)))
+ (let ((number (read-number (format "Number of options [2-%s]: " max) 2)))
(if (> number max)
(error "You need to choose a number between 2 and %s" max)
number)))
@@ -1235,7 +1242,6 @@ MAX is the maximum number set by their instance."
(defun mastodon-toot--create-poll ()
"Prompt for new poll options and return as a list."
(interactive)
- ;; re length, API docs show a poll 9 options.
(let* ((instance (mastodon-http--get-json (mastodon-http--api "instance")))
(max-options (mastodon-toot--fetch-max-poll-options instance))
(count (mastodon-toot--read-poll-options-count max-options))
@@ -1252,11 +1258,10 @@ 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."
- (let* ((choices
- (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
@@ -1277,7 +1282,7 @@ LENGTH is the maximum character length allowed for a poll option."
response))))
(defun mastodon-toot--poll-expiry-options-alist ()
- "Return an alist of seconds options."
+ "Return an alist of expiry options options in seconds."
`(("5 minutes" . ,(number-to-string (* 60 5)))
("30 minutes" . ,(number-to-string (* 60 30)))
("1 hour" . ,(number-to-string (* 60 60)))
@@ -1288,16 +1293,8 @@ LENGTH is the maximum character length allowed for a poll option."
("14 days" . ,(number-to-string (* 60 60 24 14)))
("30 days" . ,(number-to-string (* 60 60 24 30)))))
-(defun mastodon-toot--set-toot-language ()
- "Prompt for a language and set `mastodon-toot--language'.
-Return its two letter ISO 639 1 code."
- (interactive)
- (let* ((choice (completing-read "Language for this toot: "
- mastodon-iso-639-1)))
- (setq mastodon-toot--language
- (alist-get choice mastodon-iso-639-1 nil nil 'equal))
- (message "Language set to %s" choice)
- (mastodon-toot--update-status-fields)))
+
+;;; SCHEDULE
(defun mastodon-toot--schedule-toot (&optional reschedule)
"Read a date (+ time) in the minibuffer and schedule the current toot.
@@ -1309,29 +1306,27 @@ With RESCHEDULE, reschedule the scheduled toot at point without editing."
(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."))
+ (message "You can only schedule toots from the compose buffer or 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))))
+ (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))))
+ (let* ((args `(("scheduled_at" . ,iso8601-str)))
+ (url (mastodon-http--api (format "scheduled_statuses/%s" id)))
(response (mastodon-http--put url args)))
(mastodon-http--triage response
(lambda ()
@@ -1351,13 +1346,15 @@ With RESCHEDULE, reschedule the scheduled toot at point without editing."
(when ts (let* ((decoded (iso8601-parse ts)))
(encode-time decoded))))
-;; we'll need to revisit this if the binds get
-;; more diverse than two-chord bindings
+
+;;; DISPLAY KEYBINDINGS
+
(defun mastodon-toot--get-mode-kbinds ()
"Get a list of the keybindings in the mastodon-toot-mode."
(let* ((binds (copy-tree mastodon-toot-mode-map))
(prefix (car (cadr binds)))
- (bindings (remove nil (mapcar (lambda (i) (if (listp i) i))
+ (bindings (remove nil (mapcar (lambda (i)
+ (when (listp i) i))
(cadr binds)))))
(mapcar (lambda (b)
(setf (car b) (vector prefix (car b)))
@@ -1403,17 +1400,17 @@ LONGEST is the length of the longest binding."
(defun mastodon-toot--formatted-kbinds-longest (kbinds-list)
"Return the length of the longest item in KBINDS-LIST."
- (let ((lengths (mapcar (lambda (x)
- (length x))
- kbinds-list)))
+ (let ((lengths (mapcar #'length kbinds-list)))
(car (sort lengths #'>))))
+
+;;; DISPLAY DOCS
+
(defun mastodon-toot--make-mode-docs ()
"Create formatted documentation text for the mastodon-toot-mode."
(let* ((kbinds (mastodon-toot--get-mode-kbinds))
- (longest-kbind
- (mastodon-toot--formatted-kbinds-longest
- (mastodon-toot--format-kbinds kbinds))))
+ (longest-kbind (mastodon-toot--formatted-kbinds-longest
+ (mastodon-toot--format-kbinds kbinds))))
(concat
" Compose a new toot here. The following keybindings are available:"
(mapconcat #'identity
@@ -1426,15 +1423,12 @@ LONGEST is the length of the longest binding."
"Format a REPLY-TEXT for display in compose buffer docs."
(let* ((rendered (mastodon-tl--render-text reply-text))
(no-props (substring-no-properties rendered))
- ;; FIXME: this regex replaces \n at end of every post
- ;; so we have to trim:
+ ;; FIXME: this replaces \n at end of every post, so we have to trim:
(no-newlines (string-trim
(replace-regexp-in-string "[\n]+" " " no-props)))
(reply-to (concat " Reply to: \"" no-newlines "\""))
- (crop (truncate-string-to-width
- ;; (string-limit
- reply-to
- mastodon-toot-orig-in-reply-length)))
+ (crop (truncate-string-to-width reply-to
+ mastodon-toot-orig-in-reply-length)))
(if (> (length no-newlines)
(length crop)) ; we cropped:
(concat crop "\n")
@@ -1492,17 +1486,16 @@ REPLY-TEXT is the text of the toot being replied to."
The default is given by `mastodon-toot--default-reply-visibility'."
(unless (null reply-visibility)
(let ((less-restrictive (member (intern mastodon-toot--default-reply-visibility)
- mastodon-toot-visibility-list)))
+ mastodon-toot-visibility-list)))
(if (member (intern reply-visibility) less-restrictive)
- mastodon-toot--default-reply-visibility reply-visibility))))
+ mastodon-toot--default-reply-visibility reply-visibility))))
(defun mastodon-toot--setup-as-reply (reply-to-user reply-to-id reply-json)
"If REPLY-TO-USER is provided, inject their handle into the message.
If REPLY-TO-ID is provided, set `mastodon-toot--reply-to-id'.
REPLY-JSON is the full JSON of the toot being replied to."
- (let ((reply-visibility
- (mastodon-toot--most-restrictive-visibility
- (alist-get 'visibility reply-json)))
+ (let ((reply-visibility (mastodon-toot--most-restrictive-visibility
+ (alist-get 'visibility reply-json)))
(reply-cw (alist-get 'spoiler_text reply-json)))
(when reply-to-user
(when (> (length reply-to-user) 0) ; self is "" unforch
@@ -1578,18 +1571,19 @@ CW is the content warning, which contributes to the character count."
(insert toot-string)
(goto-char (point-min))
;; handle URLs
- (while (search-forward-regexp "\\w+://[^ \n]*" nil t) ; URL
+ (while (search-forward-regexp mastodon-toot-url-regex nil t)
+ ; "\\w+://[^ \n]*" old regex
(replace-match "xxxxxxxxxxxxxxxxxxxxxxx")) ; 23 x's
;; handle @handles
(goto-char (point-min))
- (while (search-forward-regexp (concat "\\(?2:@[^ @\n]+\\)" ; a handle only
- "\\(@[^ \n]+\\)?" ; with poss domain
- "\\b")
- nil t)
+ (while (search-forward-regexp mastodon-toot-handle-regex nil t)
(replace-match (match-string 2))) ; replace with handle only
(+ (length cw)
(length (buffer-substring (point-min) (point-max))))))
+
+;;; DRAFTS
+
(defun mastodon-toot--save-toot-text (&rest _args)
"Save the current toot text in `mastodon-toot-current-toot-text'.
Added to `after-change-functions' in new toot buffers."
@@ -1629,8 +1623,7 @@ Added to `after-change-functions' in new toot buffers."
mastodon-toot-draft-toots-list
nil t)))
(setq mastodon-toot-draft-toots-list
- (cl-delete draft mastodon-toot-draft-toots-list
- :test 'equal))
+ (cl-delete draft mastodon-toot-draft-toots-list :test 'equal))
(message "Draft deleted!"))
(message "No drafts to delete.")))
@@ -1640,13 +1633,15 @@ Added to `after-change-functions' in new toot buffers."
(setq mastodon-toot-draft-toots-list nil)
(message "All drafts deleted!"))
+
+;;; PROPERTIZE TAGS AND HANDLES
+
(defun mastodon-toot--propertize-tags-and-handles (&rest _args)
"Propertize tags and handles in toot compose buffer.
Added to `after-change-functions'."
(when (mastodon-toot--compose-buffer-p)
- (let ((header-region
- (mastodon-tl--find-property-range 'toot-post-header
- (point-min)))
+ (let ((header-region (mastodon-tl--find-property-range 'toot-post-header
+ (point-min)))
(face (when mastodon-toot--proportional-fonts-compose
'variable-pitch)))
;; cull any prev props:
@@ -1682,14 +1677,13 @@ Added to `after-change-functions'."
(save-match-data
(let* ((fill-column 67))
(goto-char (point-min))
- ;; while-let shoulndn't be needed here, as we really should only have
- ;; one. if we have more, the bug is elsewhere.
(when-let ((prop (text-property-search-forward 'toot-reply)))
(fill-region (prop-match-beginning prop)
(point)))))))
-;; NB: now that we have toot drafts, to ensure offline composing remains
-;; possible, avoid any direct requests here:
+
+;;; COMPOSE BUFFER FUNCTION
+
(defun mastodon-toot--compose-buffer
(&optional reply-to-user reply-to-id reply-json initial-text edit)
"Create a new buffer to capture text for a new toot.
@@ -1733,10 +1727,9 @@ EDIT means we are editing an existing toot, not composing a new one."
(mastodon-toot--get-max-toot-chars))
;; set up completion:
(when mastodon-toot--enable-completion
- (set ; (setq-local
- (make-local-variable 'completion-at-point-functions)
- (add-to-list 'completion-at-point-functions
- #'mastodon-toot--mentions-capf))
+ (set (make-local-variable 'completion-at-point-functions)
+ (add-to-list 'completion-at-point-functions
+ #'mastodon-toot--mentions-capf))
(add-to-list 'completion-at-point-functions
#'mastodon-toot--tags-capf)
;; company
@@ -1748,10 +1741,10 @@ EDIT means we are editing an existing toot, not composing a new one."
(company-mode-on)))
;; after-change:
(make-local-variable 'after-change-functions)
- (cl-pushnew #'mastodon-toot--update-status-fields after-change-functions)
(cl-pushnew #'mastodon-toot--save-toot-text after-change-functions)
- (cl-pushnew #'mastodon-toot--propertize-tags-and-handles after-change-functions)
+ (cl-pushnew #'mastodon-toot--update-status-fields after-change-functions)
(mastodon-toot--update-status-fields)
+ (cl-pushnew #'mastodon-toot--propertize-tags-and-handles after-change-functions)
(mastodon-toot--propertize-tags-and-handles)
(mastodon-toot--refresh-attachments-display)
;; draft toot text saving:
@@ -1765,6 +1758,7 @@ EDIT means we are editing an existing toot, not composing a new one."
;; flyspell ignore masto toot regexes:
(defvar flyspell-generic-check-word-predicate)
+
(defun mastodon-toot-mode-flyspell-verify ()
"A predicate function for `flyspell'.
Only text that is not one of these faces will be spell-checked."