From c8a9683b61a207bf38fd76e337bf22a814b6cbf2 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Thu, 24 Nov 2022 17:57:51 +0100 Subject: draft remove-from-followers --- lisp/mastodon-profile.el | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index fa9642e..8cea4d7 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -822,5 +822,54 @@ These include the author, author of reblogged entries and any user mentioned." (t (mastodon-profile--search-account-by-handle handle))))) +(defun mastodon-profile--remove-user-from-followers (&optional id) + "Remove a user from your followers. +User may be the current profile page if not your own, or the +account ('toot-json) at point if you are on your own profile page (followers)." + (interactive) + (let* ((account (unless id + (cond ((and ;; we are on a profile page + mastodon-profile--account + ;; that is not our own: + (not (string= (mastodon-auth--user-acct) + (alist-get 'acct mastodon-profile--account)))) + mastodon-profile--account) + ;; we are on our own profile page: + ((and (string= (mastodon-auth--user-acct) + (alist-get 'acct mastodon-profile--account)) + ;; viewing our followers: + (string= endpoint-type "followers")) + ;; try for a follower at point: + ;; (mastodon-tl--field 'toot-json) + (get-text-property (point) 'toot-json)) + (t + ;; FIXME: do some thing else? + (get-text-property (point) 'toot-json))))) + ;; TODO: read account from list of all followers' handles + (id (or (alist-get 'id account))) + (handle (if account + (alist-get 'acct account) + (let ((account + (mastodon-profile--account-from-id id))) + (alist-get 'acct account)))) + (url (mastodon-http--api + (format "accounts/%s/remove_from_followers" id)))) + (when (y-or-n-p "Remove follower %s? " handle) + (let ((response (mastodon-http--post url))) + (mastodon-http--triage (lambda () + (message "Follower %s removed!" handle))))))) + +(defun mastodon-profile--remove-from-followers-toot-at-point () + "Prompt for a user in the toot at point and remove from followers." + (let* ((handles + (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json))) + (handle (completing-read "Handle to unfollow: " + handles)) + (account (mastodon-profile--lookup-account-in-status + handle (mastodon-profile--toot-json))) + (id (alist-get 'id account))) + (mastodon-profile--remove-user-from-followers id))) + (provide 'mastodon-profile) ;;; mastodon-profile.el ends here -- cgit v1.2.3 From fc28851921af66ad56829fc06cd217c4b1335d26 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Fri, 25 Nov 2022 17:41:06 +0100 Subject: actually make remove-from-followers work --- lisp/mastodon-profile.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index d6b2b94..801ebd4 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -849,7 +849,7 @@ account ('toot-json) at point if you are on your own profile page (followers)." ;; FIXME: do some thing else? (get-text-property (point) 'toot-json))))) ;; TODO: read account from list of all followers' handles - (id (or (alist-get 'id account))) + (id (or id (alist-get 'id account))) (handle (if account (alist-get 'acct account) (let ((account @@ -857,17 +857,18 @@ account ('toot-json) at point if you are on your own profile page (followers)." (alist-get 'acct account)))) (url (mastodon-http--api (format "accounts/%s/remove_from_followers" id)))) - (when (y-or-n-p "Remove follower %s? " handle) + (when (y-or-n-p (format "Remove follower %s? " handle)) (let ((response (mastodon-http--post url))) - (mastodon-http--triage (lambda () + (mastodon-http--triage response + (lambda () (message "Follower %s removed!" handle))))))) (defun mastodon-profile--remove-from-followers-toot-at-point () "Prompt for a user in the toot at point and remove from followers." - (let* ((handles - (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json))) - (handle (completing-read "Handle to unfollow: " + (interactive) + (let* ((handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json))) + (handle (completing-read "Remove from followers: " handles)) (account (mastodon-profile--lookup-account-in-status handle (mastodon-profile--toot-json))) -- cgit v1.2.3 From 593ad71b2c331d6aeb24dcfb943d4cc435e36bf3 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Fri, 25 Nov 2022 17:45:53 +0100 Subject: don't require match for handle at point --- lisp/mastodon-profile.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 801ebd4..d9b45c8 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -830,6 +830,7 @@ These include the author, author of reblogged entries and any user mentioned." User may be the current profile page if not your own, or the account ('toot-json) at point if you are on your own profile page (followers)." (interactive) + ;; FIXME: this means you can't choose another account if on a profile page (let* ((account (unless id (cond ((and ;; we are on a profile page mastodon-profile--account @@ -869,7 +870,7 @@ account ('toot-json) at point if you are on your own profile page (followers)." (let* ((handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json))) (handle (completing-read "Remove from followers: " - handles)) + handles nil)) (account (mastodon-profile--lookup-account-in-status handle (mastodon-profile--toot-json))) (id (alist-get 'id account))) -- cgit v1.2.3 From e17e2ecd417864c725fe5f182a25cf3024251263 Mon Sep 17 00:00:00 2001 From: Christian Tietze Date: Sat, 26 Nov 2022 11:07:24 +0000 Subject: add mastodon-toot--scheduled-at buffer-local variable to optionally schedule posts --- lisp/mastodon-toot.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index c99f088..eefceda 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -163,6 +163,10 @@ This is determined by the account setting on the server. To change the setting on the server, see `mastodon-toot--set-default-visibility'.") +(defvar-local mastodon-toot--scheduled-at nil + "An ISO 8601 timestamp that declares when the post should be published. +Should be at least 5 minutes into the future.") + (defvar-local mastodon-toot--media-attachments nil "A list of the media attachments of the toot being composed.") @@ -686,7 +690,8 @@ instance to edit a toot." ("sensitive" . ,(when mastodon-toot--content-nsfw (symbol-name t))) ("spoiler_text" . ,spoiler) - ("language" . ,mastodon-toot--language))) + ("language" . ,mastodon-toot--language) + ("scheduled_at" . ,mastodon-toot--scheduled-at))) (args-media (when mastodon-toot--media-attachments (mastodon-http--build-array-params-alist "media_ids[]" -- cgit v1.2.3 From f08fe8278c368795bc5a8f19d1d44a5142c7350c Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sat, 26 Nov 2022 16:43:21 +0100 Subject: fix search.el test --- test/mastodon-search-tests.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mastodon-search-tests.el b/test/mastodon-search-tests.el index e6d4cdb..8dc597a 100644 --- a/test/mastodon-search-tests.el +++ b/test/mastodon-search-tests.el @@ -119,7 +119,7 @@ (should (equal (mastodon-search--get-user-info-@ mastodon-search--single-account-query) - '(": ( ) { : | : & } ; :" "@mousebot" "https://todon.nl/@mousebot")))) + '("@mousebot" "https://todon.nl/@mousebot" ": ( ) { : | : & } ; :")))) (ert-deftest mastodon-search--get-user-info () "Should build a list from a single account for company completion." -- cgit v1.2.3 From 21bb3bff54c766514b93d8022f149f4179e9d31e Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sat, 26 Nov 2022 18:20:01 +0100 Subject: nil the update-fun in buffer-spec for --thread views --- lisp/mastodon-tl.el | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 7d23b69..a5b5ed7 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1491,10 +1491,9 @@ ID is that of the toot to view." (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (mastodon-mode) - (mastodon-tl--set-buffer-spec - buffer - (format "statuses/%s/context" id) - 'mastodon-tl--thread) + (mastodon-tl--set-buffer-spec buffer + (format "statuses/%s/context" id) + nil) (let ((inhibit-read-only t)) (mastodon-tl--timeline (alist-get 'ancestors context)) (goto-char (point-max)) -- cgit v1.2.3 From e23ef05fabe038396875c118101847d69e5de7f6 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 10:35:07 +0100 Subject: add fun mastodon-tl--dm-user --- lisp/mastodon-tl.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index a5b5ed7..53ab57a 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -2175,6 +2175,16 @@ LANGS is the accumulated array param alist if we re-run recursively." (message "Looks like you have no mutes to unmute!") (mastodon-tl--do-user-action-and-response user-handle "unmute" t))) +(defun mastodon-tl--dm-user (user-handle) + "Query for USER-HANDLE from current status and compose a message to that user." + (interactive + (list + (mastodon-tl--interactive-user-handles-get "message"))) + (mastodon-tl--do-if-toot + (mastodon-toot--compose-buffer (concat "@" user-handle)) + (setq mastodon-toot--visibility "direct") + (mastodon-toot--update-status-fields))) + (defun mastodon-tl--interactive-user-handles-get (action) "Get the list of user-handles for ACTION from the current toot." (mastodon-tl--do-if-toot -- cgit v1.2.3 From 3b3e97c0c142e41be1acb419b5793b8aa62b0920 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 11:33:14 +0100 Subject: extract endpoint to let var in --thread --- lisp/mastodon-tl.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 53ab57a..49c26ea 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1469,7 +1469,8 @@ ID is that of the toot to view." (if (or (string= type "follow_request") (string= type "follow")) ; no can thread these (error "No thread") - (let* ((url (mastodon-http--api (format "statuses/%s/context" id))) + (let* ((endpoint (format "statuses/%s/context" id)) + (url (mastodon-http--api endpoint)) (buffer (format "*mastodon-thread-%s*" id)) (toot ;; refetch current toot in case we just faved/boosted: @@ -1492,7 +1493,7 @@ ID is that of the toot to view." (switch-to-buffer buffer) (mastodon-mode) (mastodon-tl--set-buffer-spec buffer - (format "statuses/%s/context" id) + endpoint nil) (let ((inhibit-read-only t)) (mastodon-tl--timeline (alist-get 'ancestors context)) -- cgit v1.2.3 From accc0c8b451580169300d28974c62650e5e30aac Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 11:34:43 +0100 Subject: add tl--mute-thread --- lisp/mastodon-tl.el | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 49c26ea..fe865d0 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1508,6 +1508,46 @@ ID is that of the toot to view." ;; else just print the lone toot: (mastodon-tl--single-toot id))))))) + +(defun mastodon-tl--mute-thread () + "Mute the thread displayed in the current buffer." + (interactive) + (let ((endpoint (mastodon-tl--get-endpoint))) + (if (string-suffix-p "context" endpoint) ; thread view + (let* ((id + (save-match-data + (let ((str (string-match "statuses/\\(?2:[[:digit:]]+\\)/context" + endpoint))) + (match-string 2 endpoint)))) + (we-posted-p (mastodon-tl--user-in-thread-p id)) + (url (mastodon-http--api (format "statuses/%s/mute" id)))) + (if (not we-posted-p) + (message "You can only mute a thread you have posted in.") + (when (y-or-n-p "Mute this thread? ") + (let ((response (mastodon-http--post url))) + (mastodon-http--triage response + (lambda () + (message "Thread muted!")))))))))) + +(defun mastodon-tl--user-in-thread-p (id) + "Return non-nil if the logged-in user has posted to the current thread. +ID is that of the post the context is currently displayed for." + (let* ((context-json (mastodon-http--get-json + (mastodon-http--api (format "statuses/%s/context" id)) + nil :silent)) + (ancestors (alist-get 'ancestors context-json)) + (descendants (alist-get 'descendants context-json)) + (a-ids (mapcar (lambda (status) + (alist-get 'id + (alist-get 'account status))) + ancestors)) + (d-ids (mapcar (lambda (status) + (alist-get 'id + (alist-get 'account status))) + descendants))) + (or (member (mastodon-auth--get-account-id) a-ids) + (member (mastodon-auth--get-account-id) d-ids)))) + ;;; LISTS (defun mastodon-tl--get-users-lists () -- cgit v1.2.3 From fa82691cc42a4344015a4920ee0582a92897160b Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 11:44:34 +0100 Subject: unmute or mute a thread --- lisp/mastodon-tl.el | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index fe865d0..fbf1b7b 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1510,8 +1510,20 @@ ID is that of the toot to view." (defun mastodon-tl--mute-thread () - "Mute the thread displayed in the current buffer." + "Mute the thread displayed in the current buffer. +Note that you can only (un)mute threads you have posted in." (interactive) + (mastodon-tl--mute-or-unmute-thread)) + +(defun mastodon-tl--unmute-thread () + "Mute the thread displayed in the current buffer. +Note that you can only (un)mute threads you have posted in." + (interactive) + (mastodon-tl--mute-or-unmute-thread :unmute)) + +(defun mastodon-tl--mute-or-unmute-thread (&optional unmute) + "Mute a thread. +If UNMUTE, unmute it." (let ((endpoint (mastodon-tl--get-endpoint))) (if (string-suffix-p "context" endpoint) ; thread view (let* ((id @@ -1520,14 +1532,21 @@ ID is that of the toot to view." endpoint))) (match-string 2 endpoint)))) (we-posted-p (mastodon-tl--user-in-thread-p id)) - (url (mastodon-http--api (format "statuses/%s/mute" id)))) + (url (mastodon-http--api + (if unmute + (format "statuses/%s/unmute" id) + (format "statuses/%s/mute" id))))) (if (not we-posted-p) - (message "You can only mute a thread you have posted in.") - (when (y-or-n-p "Mute this thread? ") + (message "You can only (un)mute a thread you have posted in.") + (when (if unmute + (y-or-n-p "Unute this thread? ") + (y-or-n-p "Mute this thread? ")) (let ((response (mastodon-http--post url))) (mastodon-http--triage response (lambda () - (message "Thread muted!")))))))))) + (if unmute + (message "Thread unmuted!") + (message "Thread muted!"))))))))))) (defun mastodon-tl--user-in-thread-p (id) "Return non-nil if the logged-in user has posted to the current thread. -- cgit v1.2.3 From b9865a58cf7f73c5205390dbf4df32d723ba15af Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 13:19:00 +0100 Subject: autoloads and docstrings --- lisp/mastodon-tl.el | 9 +++++++-- lisp/mastodon-toot.el | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index fbf1b7b..2503516 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -79,6 +79,11 @@ (autoload 'mastodon-http--build-params-string "mastodon-http") (autoload 'mastodon-notifications--filter-types-list "mastodon-notifications") (autoload 'mastodon-toot--get-toot-edits "mastodon-toot") +(autoload 'mastodon-toot--update-status-fields "mastodon-toot") +(autoload 'mastodon-toot--compose-buffer "mastodon-toot") + +(defvar mastodon-toot--visibility) +(defvar mastodon-active-user) (when (require 'mpv nil :no-error) (declare-function mpv-start "mpv")) @@ -1157,7 +1162,7 @@ this just means displaying toot client." (let* ((poll (mastodon-tl--field 'poll toot)) (expiry (mastodon-tl--field 'expires_at poll)) (expired-p (if (eq (mastodon-tl--field 'expired poll) :json-false) nil t)) - (multi (mastodon-tl--field 'multiple poll)) + ;; (multi (mastodon-tl--field 'multiple poll)) (voters-count (mastodon-tl--field 'voters_count poll)) (vote-count (mastodon-tl--field 'votes_count poll)) (options (mastodon-tl--field 'options poll)) @@ -1539,7 +1544,7 @@ If UNMUTE, unmute it." (if (not we-posted-p) (message "You can only (un)mute a thread you have posted in.") (when (if unmute - (y-or-n-p "Unute this thread? ") + (y-or-n-p "Unnute this thread? ") (y-or-n-p "Mute this thread? ")) (let ((response (mastodon-http--post url))) (mastodon-http--triage response diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 099ce10..ae7dae2 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -788,8 +788,8 @@ instance to edit a toot." (defun mastodon-toot--insert-toot-iter (it) "Insert iteration IT of toot." - (let ((content (alist-get 'content it)) - (account (alist-get 'account it))) + (let ((content (alist-get 'content it))) + ;; (account (alist-get 'account it)) ;; TODO: handle polls, media (mastodon-tl--render-text content))) @@ -827,7 +827,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." ""))) (defun mastodon-toot--get-bounds (regex) - "Get bounds of tag or handle before point." + "Get bounds of tag or handle before point using REGEX." ;; needed because # and @ are not part of any existing thing at point (save-match-data (save-excursion -- cgit v1.2.3 From 71152484c86abad4da8e699ed095de8319aa5cad Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 13:21:48 +0100 Subject: try to declare company-mode-on --- lisp/mastodon-toot.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index ae7dae2..40ff0ee 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1434,7 +1434,9 @@ a draft into the buffer." 'completion-at-point-functions #'mastodon-toot--tags-capf) ;; company - (when mastodon-toot--use-company-for-completion + (when (and mastodon-toot--use-company-for-completion + (require 'company nil :no-error)) + (declare-function 'company-mode-on "company") (set (make-local-variable 'company-backends) (add-to-list 'company-backends 'company-capf)) (company-mode-on))) -- cgit v1.2.3 From f1c5b02512287a07899f793d667ce6924cbe88e8 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 13:23:43 +0100 Subject: remove redundant str var --- lisp/mastodon-tl.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 2503516..ff00252 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1533,9 +1533,9 @@ If UNMUTE, unmute it." (if (string-suffix-p "context" endpoint) ; thread view (let* ((id (save-match-data - (let ((str (string-match "statuses/\\(?2:[[:digit:]]+\\)/context" - endpoint))) - (match-string 2 endpoint)))) + (string-match "statuses/\\(?2:[[:digit:]]+\\)/context" + endpoint) + (match-string 2 endpoint))) (we-posted-p (mastodon-tl--user-in-thread-p id)) (url (mastodon-http--api (if unmute -- cgit v1.2.3 From 279aabbbeed7e12f7034d11c83079a7e6fdaeedd Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 13:42:57 +0100 Subject: compose buffer - display language selection only when selected --- lisp/mastodon-toot.el | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 40ff0ee..28733e1 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1211,6 +1211,9 @@ REPLY-TEXT is the text of the toot being replied to." (propertize "Visibility" 'toot-post-visibility t) " ⋅ " + (propertize "Language" + 'toot-post-language t) + " " (propertize "CW" 'toot-post-cw-flag t) " " @@ -1264,6 +1267,8 @@ REPLY-JSON is the full JSON of the toot being replied to." (point-min))) (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag (point-min))) + (lang-region (mastodon-tl--find-property-range 'toot-post-language + (point-min))) (toot-string (buffer-substring-no-properties (cdr header-region) (point-max)))) (add-text-properties (car count-region) (cdr count-region) @@ -1279,10 +1284,16 @@ REPLY-JSON is the full JSON of the toot being replied to." "private") "followers-only" mastodon-toot--visibility)))) + (add-text-properties (car lang-region) (cdr lang-region) + (list 'display + (if mastodon-toot--language + (format "Language: %s" + mastodon-toot--language) + ""))) (add-text-properties (car nsfw-region) (cdr nsfw-region) (list 'display (if mastodon-toot--content-nsfw (if mastodon-toot--media-attachments - "NSFW" "NSFW (no effect until attachments added)") + "NSFW" "NSFW (for attachments only)") "") 'face 'mastodon-cw-face)) (add-text-properties (car cw-region) (cdr cw-region) -- cgit v1.2.3 From 119d0de0ec1e916fc14a083368ac32e488d1263b Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Sun, 27 Nov 2022 17:08:33 +0100 Subject: update copyright/author attribution --- lisp/mastodon-discover.el | 2 ++ lisp/mastodon-http.el | 2 ++ lisp/mastodon-inspect.el | 2 ++ lisp/mastodon-media.el | 2 ++ lisp/mastodon-notifications.el | 2 ++ lisp/mastodon-profile.el | 2 ++ lisp/mastodon-tl.el | 1 + lisp/mastodon-toot.el | 1 + 8 files changed, 14 insertions(+) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 08df46e..1b960e5 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -1,7 +1,9 @@ ;;; mastodon-discover.el --- Use Mastodon.el with discover.el -*- lexical-binding: t -*- ;; Copyright (C) 2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen +;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index d677e57..9ef7aec 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -1,7 +1,9 @@ ;;; mastodon-http.el --- HTTP request/response functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen +;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1") (request "0.3.0")) diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index cbf6a8e..112a753 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -1,7 +1,9 @@ ;;; mastodon-inspect.el --- Client for Mastodon -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen +;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index c783130..4e50dbc 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -1,7 +1,9 @@ ;;; mastodon-media.el --- Functions for inlining Mastodon media -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen +;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index f5ddea3..b7fe038 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -1,7 +1,9 @@ ;;; mastodon-notifications.el --- Notification functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen +;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 1200972..babe308 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -1,7 +1,9 @@ ;;; mastodon-profile.el --- Functions for inspecting Mastodon profiles -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen +;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 1.0.0 ;; Package-Requires: ((emacs "27.1")) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index ff00252..76cca6c 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1,6 +1,7 @@ ;;; mastodon-tl.el --- HTTP request/response functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 28733e1..121a590 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1,6 +1,7 @@ ;;; mastodon-toot.el --- Minor mode for sending Mastodon toots -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2020-2022 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt -- cgit v1.2.3 From c719316e92fa1c2a7986ac682ee54637082ede3f Mon Sep 17 00:00:00 2001 From: "Nicolas P. Rougier" Date: Sun, 27 Nov 2022 20:53:53 +0100 Subject: Modify relative time strings such as all string are <= 12 characters --- lisp/mastodon-tl.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 76cca6c..995360c 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -570,25 +570,25 @@ TIMESTAMP is assumed to be in the past." (relative-result (cond ((< seconds-difference 60) - (cons "less than a minute ago" + (cons "now" 60)) ((< seconds-difference (* 1.5 60)) - (cons "one minute ago" + (cons "1 minute ago" 90)) ;; at 90 secs ((< seconds-difference (* 60 59.5)) (funcall regular-response seconds-difference 60 "minute")) ((< seconds-difference (* 1.5 60 60)) - (cons "one hour ago" + (cons "1 hour ago" (* 60 90))) ;; at 90 minutes ((< seconds-difference (* 60 60 23.5)) (funcall regular-response seconds-difference (* 60 60) "hour")) ((< seconds-difference (* 1.5 60 60 24)) - (cons "one day ago" + (cons "1 day ago" (* 1.5 60 60 24))) ;; at a day and a half ((< seconds-difference (* 60 60 24 6.5)) (funcall regular-response seconds-difference (* 60 60 24) "day")) ((< seconds-difference (* 1.5 60 60 24 7)) - (cons "one week ago" + (cons "1 week ago" (* 1.5 60 60 24 7))) ;; a week and a half ((< seconds-difference (* 60 60 24 7 52)) (if (= 52 (floor (+ 0.5 (/ seconds-difference 60 60 24 7)))) @@ -596,7 +596,7 @@ TIMESTAMP is assumed to be in the past." (* 60 60 24 7 52)) (funcall regular-response seconds-difference (* 60 60 24 7) "week"))) ((< seconds-difference (* 1.5 60 60 24 365)) - (cons "one year ago" + (cons "1 year ago" (* 60 60 24 365 1.5))) ;; a year and a half (t (funcall regular-response seconds-difference (* 60 60 24 365.25) "year"))))) -- cgit v1.2.3 From c3212e28d9d82ea86210beaf58cac79f9386fb94 Mon Sep 17 00:00:00 2001 From: "Nicolas P. Rougier" Date: Mon, 28 Nov 2022 13:56:43 +0100 Subject: Better wording for now --- lisp/mastodon-tl.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 995360c..a8bccb9 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -570,7 +570,7 @@ TIMESTAMP is assumed to be in the past." (relative-result (cond ((< seconds-difference 60) - (cons "now" + (cons "just now" 60)) ((< seconds-difference (* 1.5 60)) (cons "1 minute ago" -- cgit v1.2.3 From b6dd92225bfef4bfdbc229791d1c863335d2f403 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 14:25:54 +0100 Subject: simplify remove from followers --- lisp/mastodon-profile.el | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 36042e7..c2c58f6 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -845,25 +845,7 @@ These include the author, author of reblogged entries and any user mentioned." User may be the current profile page if not your own, or the account ('toot-json) at point if you are on your own profile page (followers)." (interactive) - ;; FIXME: this means you can't choose another account if on a profile page - (let* ((account (unless id - (cond ((and ;; we are on a profile page - mastodon-profile--account - ;; that is not our own: - (not (string= (mastodon-auth--user-acct) - (alist-get 'acct mastodon-profile--account)))) - mastodon-profile--account) - ;; we are on our own profile page: - ((and (string= (mastodon-auth--user-acct) - (alist-get 'acct mastodon-profile--account)) - ;; viewing our followers: - (string= endpoint-type "followers")) - ;; try for a follower at point: - ;; (mastodon-tl--field 'toot-json) - (get-text-property (point) 'toot-json)) - (t - ;; FIXME: do some thing else? - (get-text-property (point) 'toot-json))))) + (let* ((account (unless id (get-text-property (point) 'toot-json))) ;; TODO: read account from list of all followers' handles (id (or id (alist-get 'id account))) (handle (if account -- cgit v1.2.3 From e8797f4769248ab79bab4e30548b4796eefd2520 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 14:39:59 +0100 Subject: add remove-from-followers via list of 100 followers. --- lisp/mastodon-profile.el | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index c2c58f6..d0b7179 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -77,6 +77,7 @@ (autoload 'mastodon-tl--get-link-header-from-response "mastodon-tl") (autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") (autoload 'mastodon-tl--symbol "mastodon-tl") +(autoload 'mastodon-auth--get-account-id "mastodon-auth") (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) @@ -575,14 +576,14 @@ NO-REBLOGS means do not display boosts in statuses. HEADERS means also fetch link headers for pagination." (let* ((id (mastodon-profile--account-field account 'id)) (args (when no-reblogs '(("exclude_reblogs" . "t")))) - (url (mastodon-http--api (format "accounts/%s/%s" id endpoint-type))) + (endpoint (format "accounts/%s/%s" id endpoint-type)) + (url (mastodon-http--api endpoint)) (acct (mastodon-profile--account-field account 'acct)) (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) (response (if headers (mastodon-http--get-response url args) (mastodon-http--get-json url args))) (json (if headers (car response) response)) - (endpoint (format "accounts/%s/%s" id endpoint-type)) (link-header (when headers (mastodon-tl--get-link-header-from-response (cdr response)))) @@ -842,11 +843,9 @@ These include the author, author of reblogged entries and any user mentioned." (defun mastodon-profile--remove-user-from-followers (&optional id) "Remove a user from your followers. -User may be the current profile page if not your own, or the -account ('toot-json) at point if you are on your own profile page (followers)." +Optionally provide the ID of the account to remove." (interactive) (let* ((account (unless id (get-text-property (point) 'toot-json))) - ;; TODO: read account from list of all followers' handles (id (or id (alist-get 'id account))) (handle (if account (alist-get 'acct account) @@ -861,8 +860,8 @@ account ('toot-json) at point if you are on your own profile page (followers)." (lambda () (message "Follower %s removed!" handle))))))) -(defun mastodon-profile--remove-from-followers-toot-at-point () - "Prompt for a user in the toot at point and remove from followers." +(defun mastodon-profile--remove-from-followers-at-point () + "Prompt for a user in the item at point and remove from followers." (interactive) (let* ((handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json))) @@ -873,5 +872,25 @@ account ('toot-json) at point if you are on your own profile page (followers)." (id (alist-get 'id account))) (mastodon-profile--remove-user-from-followers id))) +(defun mastodon-profile--remove-from-followers-list () + "Select a user from your followers and remove from followers. +Currently limited to 100 handles. If not found, try +`mastodon-search--search-query'." + (interactive) + (let* ((endpoint (format "accounts/%s/followers" + (mastodon-auth--get-account-id))) + (url (mastodon-http--api endpoint)) + (response (mastodon-http--get-json url + `(("limit" . "100")))) + (handles (mapcar (lambda (x) + (cons + (alist-get 'acct x) + (alist-get 'id x))) + response)) + (choice (completing-read "Remove from followers: " + handles)) + (id (alist-get choice handles nil nil 'equal))) + (mastodon-profile--remove-user-from-followers id))) + (provide 'mastodon-profile) ;;; mastodon-profile.el ends here -- cgit v1.2.3 From e4a6643e1e9d17ff43ef72b36c80308cdbd2a58f Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 15:29:37 +0100 Subject: live count for update profile note, + confirm cancel --- lisp/mastodon-profile.el | 55 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index d0b7179..eaebadb 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -132,7 +132,7 @@ extra keybindings." (defvar mastodon-profile-update-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-profile--user-profile-send-updated) - (define-key map (kbd "C-c C-k") #'kill-buffer-and-window) + (define-key map (kbd "C-c C-k") #'mastodon-profile--update-profile-note-cancel) map) "Keymap for `mastodon-profile-update-mode'.") @@ -296,26 +296,63 @@ JSON is the data returned by the server." (source (alist-get 'source json)) (note (alist-get 'note source)) (buffer (get-buffer-create "*mastodon-update-profile*")) - (inhibit-read-only t)) + (inhibit-read-only t) + (msg-str "Edit your profile note. C-c C-c to send, C-c C-k to cancel.")) (switch-to-buffer-other-window buffer) (text-mode) (mastodon-tl--set-buffer-spec (buffer-name buffer) endpoint nil) (setq-local header-line-format - (propertize - "Edit your profile note. C-c C-c to send, C-c C-k to cancel." - 'face font-lock-comment-face)) + (propertize msg-str + 'face font-lock-comment-face)) (mastodon-profile-update-mode t) - (insert note) - (goto-char (point-min)) + (insert (propertize (concat (propertize "0" + 'note-counter t + 'display nil) + "/500 characters") + 'read-only t + 'face 'font-lock-comment-face + 'note-header t) + "\n") + (make-local-variable 'after-change-functions) + (push #'mastodon-profile--update-note-count after-change-functions) + (let ((start-point (point))) + (insert note) + (goto-char start-point)) (delete-trailing-whitespace) ; remove all ^M's - (message "Edit your profile note. C-c C-c to send, C-c C-k to cancel."))) + (message msg-str))) + +(defun mastodon-profile--update-note-count (&rest _args) + "Display the character count of the profile note buffer." + (let ((inhibit-read-only t) + (header-region (mastodon-tl--find-property-range 'note-header + (point-min))) + (count-region (mastodon-tl--find-property-range 'note-counter + (point-min)))) + (add-text-properties (car count-region) (cdr count-region) + (list 'display + (number-to-string + (mastodon-toot--count-toot-chars + (buffer-substring-no-properties + (cdr header-region) (point-max)))))))) + +(defun mastodon-profile--update-profile-note-cancel () + "Cancel updating user profile and kill buffer and window." + (interactive) + (when (y-or-n-p "Cancel updating your profile note?") + (kill-buffer-and-window))) + +(defun mastodon-profile--note-remove-header () + "Get the body of a toot from the current compose buffer." + (let ((header-region (mastodon-tl--find-property-range 'note-header + (point-min)))) + (buffer-substring (cdr header-region) (point-max)))) (defun mastodon-profile--user-profile-send-updated () "Send PATCH request with the updated profile note." (interactive) - (let* ((note (buffer-substring-no-properties (point-min) (point-max))) + (let* ((note (mastodon-profile--note-remove-header)) (url (mastodon-http--api "accounts/update_credentials"))) (kill-buffer-and-window) (let ((response (mastodon-http--patch url `(("note" . ,note))))) -- cgit v1.2.3 From 9656426c2ec596d3d97bed833a62ac2039a64e85 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 16:09:00 +0100 Subject: confirm update profile note if > 500 chars mastodon server sets a 500 char max, but forks and other servers may not. --- lisp/mastodon-profile.el | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index eaebadb..7e3262a 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -350,14 +350,23 @@ JSON is the data returned by the server." (buffer-substring (cdr header-region) (point-max)))) (defun mastodon-profile--user-profile-send-updated () - "Send PATCH request with the updated profile note." + "Send PATCH request with the updated profile note. +Ask for confirmation if length > 500 characters." (interactive) (let* ((note (mastodon-profile--note-remove-header)) (url (mastodon-http--api "accounts/update_credentials"))) - (kill-buffer-and-window) - (let ((response (mastodon-http--patch url `(("note" . ,note))))) - (mastodon-http--triage response - (lambda () (message "Profile note updated!")))))) + (if (> (mastodon-toot--count-toot-chars note) 500) + (when (y-or-n-p "Note is over mastodon's max for profile notes (500). Proceed?") + (kill-buffer-and-window) + (mastodon-profile--user-profile-send-updated-do url note)) + (kill-buffer-and-window) + (mastodon-profile--user-profile-send-updated-do url note)))) + +(defun mastodon-profile--user-profile-send-updated-do (url note) + "Send PATCH request with the updated profile note." + (let ((response (mastodon-http--patch url `(("note" . ,note))))) + (mastodon-http--triage response + (lambda () (message "Profile note updated!"))))) (defun mastodon-profile--update-preference (pref val &optional source) "Update account PREF erence to setting VAL. -- cgit v1.2.3 From d2bce7f37a9c1f177f42f491662178a45dbc6858 Mon Sep 17 00:00:00 2001 From: "Nicolas P. Rougier" Date: Mon, 28 Nov 2022 16:46:42 +0100 Subject: Fixed test for new elative strings --- test/mastodon-tl-tests.el | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index 1d9355b..726e21a 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -213,28 +213,28 @@ Strict-Transport-Security: max-age=31536000 (mastodon-tl--relative-time-description timestamp))) (check (seconds expected) (should (string= (format-seconds-since seconds) expected)))) - (check 1 "less than a minute ago") - (check 59 "less than a minute ago") - (check 60 "one minute ago") - (check 89 "one minute ago") ;; rounding down + (check 1 "just now") + (check 59 "just now") + (check 60 "1 minute ago") + (check 89 "1 minute ago") ;; rounding down (check 91 "2 minutes ago") ;; rounding up (check (minutes 3.49) "3 minutes ago") ;; rounding down (check (minutes 3.52) "4 minutes ago") (check (minutes 59) "59 minutes ago") - (check (minutes 60) "one hour ago") - (check (minutes 89) "one hour ago") + (check (minutes 60) "1 hour ago") + (check (minutes 89) "1 hour ago") (check (minutes 91) "2 hours ago") (check (hours 3.49) "3 hours ago") ;; rounding down (check (hours 3.51) "4 hours ago") ;; rounding down (check (hours 23.4) "23 hours ago") - (check (hours 23.6) "one day ago") ;; rounding up - (check (days 1.48) "one day ago") ;; rounding down + (check (hours 23.6) "1 day ago") ;; rounding up + (check (days 1.48) "1 day ago") ;; rounding down (check (days 1.52) "2 days ago") ;; rounding up - (check (days 6.6) "one week ago") ;; rounding up + (check (days 6.6) "1 week ago") ;; rounding up (check (weeks 2.49) "2 weeks ago") ;; rounding down (check (weeks 2.51) "3 weeks ago") ;; rounding down (check (1- (weeks 52)) "52 weeks ago") - (check (weeks 52) "one year ago") + (check (weeks 52) "1 year ago") (check (years 2.49) "2 years ago") ;; rounding down (check (years 2.51) "3 years ago") ;; rounding down )) -- cgit v1.2.3 From d8e93a8089b45bda92d9e408f4f713242f9fad50 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 19:33:17 +0100 Subject: add schedule toot function + binding --- lisp/mastodon-toot.el | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 42cce36..4a10131 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -164,10 +164,6 @@ This is determined by the account setting on the server. To change the setting on the server, see `mastodon-toot--set-default-visibility'.") -(defvar-local mastodon-toot--scheduled-at nil - "An ISO 8601 timestamp that declares when the post should be published. -Should be at least 5 minutes into the future.") - (defvar-local mastodon-toot--media-attachments nil "A list of the media attachments of the toot being composed.") @@ -180,6 +176,10 @@ Should be at least 5 minutes into the future.") (defvar-local mastodon-toot--language nil "The language of the toot being composed, in ISO 639 (two-letter).") +(defvar-local mastodon-toot--scheduled-for nil + "An ISO 8601 timestamp that specifying when the post should be published. +Should be at least 5 minutes into the future.") + (defvar-local mastodon-toot--reply-to-id nil "Buffer-local variable to hold the id of the toot being replied to.") @@ -233,6 +233,7 @@ send.") (define-key map (kbd "C-c !") #'mastodon-toot--clear-all-attachments) (define-key map (kbd "C-c C-p") #'mastodon-toot--create-poll) (define-key map (kbd "C-c C-l") #'mastodon-toot--set-toot-lang) + (define-key map (kbd "C-c C-s") #'mastodon-toot--schedule-toot) map) "Keymap for `mastodon-toot'.") @@ -1127,6 +1128,15 @@ Return its two letter ISO 639 1 code." (alist-get choice mastodon-iso-639-1 nil nil 'equal)) (message "Language set to %s" choice))) +(defun mastodon-toot--schedule-toot () + "Read a date (+ time) in the minibuffer and schedule the current toot." + (interactive) + (let* ((time-value (org-read-date nil t nil "Schedule toot:")) + (iso8601-string (format-time-string "%Y-%m-%dT%H:%M:%S%z" time-value)) + (msg-str (format-time-string "%Y-%m-%d at %H:%M[%z]" time-value))) + (setq-local mastodon-toot--scheduled-at iso8601-string) + (message (format "Toot scheduled for %s." msg-str)))) + ;; we'll need to revisit this if the binds get ;; more diverse than two-chord bindings (defun mastodon-toot--get-mode-kbinds () -- cgit v1.2.3 From f493eb003bfb03205b81073adca1448c72317242 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 20:34:01 +0100 Subject: view, reschedule, cancel scheduled toots --- lisp/mastodon-tl.el | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index a8bccb9..4662fc3 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -257,6 +257,13 @@ types of mastodon links and not just shr.el-generated ones.") (keymap-canonicalize map)) "Keymap for when point is on list name.") +(defvar mastodon-tl--scheduled-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "r") 'mastodon-tl--reschedule-toot) + (define-key map (kbd "c") 'mastodon-tl--cancel-scheduled-toot) + (keymap-canonicalize map)) + "Keymap for when point is on a scheduled toot.") + (defvar mastodon-tl--byline-link-keymap (when (require 'mpv nil :no-error) (let ((map (make-sparse-keymap))) @@ -1836,6 +1843,97 @@ If ID is provided, use that list." (let* ((url (mastodon-http--api (format "lists/%s/accounts" list-id)))) (mastodon-http--get-json url))) +;;; SCHEDULED TOOTS + +(defun mastodon-tl--get-scheduled-toots (&optional id) + "Get the user's currently scheduled toots. +If ID, just return that toot." + (let* ((endpoint (if id + (format "scheduled_statuses/%s" id) + "scheduled_statuses")) + (url (mastodon-http--api endpoint))) + (mastodon-http--get-json url))) + +(defun mastodon-tl--reschedule-toot (&optional id) + "Reschedule the scheduled toot at point." + (interactive) + (let* ((id (get-text-property (point) 'id)) + (time-value (org-read-date nil t nil "Schedule toot:")) + (iso8601-str (format-time-string "%Y-%m-%dT%H:%M:%S%z" time-value)) + (msg-str (format-time-string "%Y-%m-%d at %H:%M[%z]" time-value)) + (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 () + (mastodon-tl--update) + (message + (format "Toot rescheduled for %s." msg-str)))))) + +(defun mastodon-tl--view-scheduled-toots () + "Show the user's scheduled toots in a new buffer." + (interactive) + (mastodon-tl--init-sync "scheduled-toots" + "scheduled_statuses" + 'mastodon-tl--insert-scheduled-toots)) + +(defun mastodon-tl--insert-scheduled-toots (json) + "Insert the user's scheduled toots." + (let ((scheduleds (mastodon-tl--get-scheduled-toots))) + (erase-buffer) + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " YOUR SCHEDULED TOOTS\n" + " ------------\n\n") + 'success) + (mastodon-tl--set-face + "[n/p - prev/next\n r - reschedule\n c - cancel]\n\n" + 'font-lock-comment-face)) + (mapcar (lambda (x) + (mastodon-tl--insert-scheduled-toot x)) + scheduleds) + (goto-char (point-min)) + (when json + (mastodon-tl--goto-next-toot)))) + +(defun mastodon-tl--insert-scheduled-toot (toot) + "Insert scheduled TOOT into the buffer." + (let* ((id (alist-get 'id toot)) + (scheduled (alist-get 'scheduled_at toot)) + (params (alist-get 'params toot)) + (text (alist-get 'text params))) + (insert + (propertize (concat text + " | " + scheduled) + 'byline t ; so we nav here + 'toot-id "0" ; so we nav here + 'face 'font-lock-comment-face + 'keymap mastodon-tl--scheduled-map + 'scheduled-json toot + 'id id) + "\n"))) + +(defun mastodon-tl--copy-scheduled-toot-text () + "Copy the text of the scheduled toot at point." + (interactive) + (let* ((toot (get-text-property (point) 'toot)) + (params (alist-get 'params toot)) + (text (alist-get 'text params))) + (kill-new text))) + +(defun mastodon-tl--cancel-scheduled-toot () + "Cancel the scheduled toot at point." + (interactive) + (let* ((id (get-text-property (point) 'id)) + (url (mastodon-http--api (format "scheduled_statuses/%s" id)))) + (when (y-or-n-p "Cancel scheduled toot?") + (let ((response (mastodon-http--delete url))) + (mastodon-http--triage response + (lambda () + (mastodon-tl--view-scheduled-toots) + (message "Toot cancelled!"))))))) + ;;; FILTERS (defun mastodon-tl--create-filter () -- cgit v1.2.3 From ed6024c273f285c93f2dfdea935eb7cbf94b064e Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Mon, 28 Nov 2022 22:54:57 +0100 Subject: update package commentary --- lisp/mastodon.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 921e3af..a6ee4bc 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -29,8 +29,8 @@ ;;; Commentary: -;; mastodon.el is an Emacs client for Mastodon , -;; the federated microblogging social network. It also works with Pleroma instances. +;; mastodon.el is an Emacs client for Mastodon , +;; the federated microblogging social network. It also works with Pleroma instances and other services that implement the Mastodon API. ;; See the readme file at https://codeberg.org/martianh/mastodon.el for set up and usage details. ;;; Code: -- cgit v1.2.3 From 520b2f86006f2274146ccff4b78f9b765b2280d2 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 10:19:10 +0100 Subject: tl.el section headings --- lisp/mastodon-tl.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index a8bccb9..913c7e7 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1446,6 +1446,8 @@ webapp" (reblog (alist-get 'reblog json))) (if reblog (alist-get 'id reblog) id))) +;;; THREADS + (defun mastodon-tl--single-toot (id) "View toot at point in separate buffer. ID is that of the toot to view." @@ -1961,7 +1963,7 @@ RESPONSE is the JSON returned by the server." (message "Looks like there's no toot or user at point?") ,@body)) -;;;; INSTANCES +;;; INSTANCES (defun mastodon-tl--view-own-instance (&optional brief) "View details of your own instance. -- cgit v1.2.3 From 7d676ccd4a4076c65d7b53dbdd9c7846083ffcd9 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 10:29:21 +0100 Subject: tweak scheduled toot message string date format --- lisp/mastodon-toot.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 4a10131..1ddaca8 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1133,7 +1133,7 @@ Return its two letter ISO 639 1 code." (interactive) (let* ((time-value (org-read-date nil t nil "Schedule toot:")) (iso8601-string (format-time-string "%Y-%m-%dT%H:%M:%S%z" time-value)) - (msg-str (format-time-string "%Y-%m-%d at %H:%M[%z]" time-value))) + (msg-str (format-time-string "%d-%m-%y at %H:%M[%z]" time-value))) (setq-local mastodon-toot--scheduled-at iso8601-string) (message (format "Toot scheduled for %s." msg-str)))) -- cgit v1.2.3 From 9bac6bf378137ee220cfa4ae7e43079ef3ce0295 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 11:40:43 +0100 Subject: abbreviate toot compose properties (visibility, char count etc) --- lisp/mastodon-toot.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 1ddaca8..a1fb014 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1289,12 +1289,12 @@ REPLY-JSON is the full JSON of the toot being replied to." (point-max)))) (add-text-properties (car count-region) (cdr count-region) (list 'display - (format "%s/%s characters" + (format "%s/%s chars" (mastodon-toot--count-toot-chars toot-string) (number-to-string mastodon-toot--max-toot-chars)))) (add-text-properties (car visibility-region) (cdr visibility-region) (list 'display - (format "Visibility: %s" + (format "%s" (if (equal mastodon-toot--visibility "private") @@ -1303,7 +1303,7 @@ REPLY-JSON is the full JSON of the toot being replied to." (add-text-properties (car lang-region) (cdr lang-region) (list 'display (if mastodon-toot--language - (format "Language: %s" + (format "Lang: %s ⋅" mastodon-toot--language) ""))) (add-text-properties (car nsfw-region) (cdr nsfw-region) -- cgit v1.2.3 From 2bbc9f7289e2e249d8b4c27a22446c20c5b21f1b Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 11:42:43 +0100 Subject: work on scheduling toots, editing as new, display scheduled ts --- lisp/mastodon-tl.el | 50 +++++++++++++++++++++++++++++++++++--------------- lisp/mastodon-toot.el | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 4662fc3..6a90949 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1854,21 +1854,9 @@ If ID, just return that toot." (url (mastodon-http--api endpoint))) (mastodon-http--get-json url))) -(defun mastodon-tl--reschedule-toot (&optional id) +(defun mastodon-tl--reschedule-toot () "Reschedule the scheduled toot at point." - (interactive) - (let* ((id (get-text-property (point) 'id)) - (time-value (org-read-date nil t nil "Schedule toot:")) - (iso8601-str (format-time-string "%Y-%m-%dT%H:%M:%S%z" time-value)) - (msg-str (format-time-string "%Y-%m-%d at %H:%M[%z]" time-value)) - (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 () - (mastodon-tl--update) - (message - (format "Toot rescheduled for %s." msg-str)))))) + (mastodon-toot--schedule-toot :reschedule)) (defun mastodon-tl--view-scheduled-toots () "Show the user's scheduled toots in a new buffer." @@ -1905,7 +1893,7 @@ If ID, just return that toot." (insert (propertize (concat text " | " - scheduled) + (mastodon-toot--iso-to-human scheduled)) 'byline t ; so we nav here 'toot-id "0" ; so we nav here 'face 'font-lock-comment-face @@ -1914,6 +1902,12 @@ If ID, just return that toot." 'id id) "\n"))) +(defun mastodon-toot--iso-to-human (ts) + "Format an ISO8601 timestamp TS to be more human-readable." + (let* ((decoded (iso8601-parse ts)) + (encoded (encode-time decoded))) + (format-time-string "%d-%m-%y, %H:%M[%z]" encoded))) + (defun mastodon-tl--copy-scheduled-toot-text () "Copy the text of the scheduled toot at point." (interactive) @@ -1934,6 +1928,32 @@ If ID, just return that toot." (mastodon-tl--view-scheduled-toots) (message "Toot cancelled!"))))))) +(defun mastodon-tl--edit-scheduled-as-new () + "Edit scheduled status as new toot." + (interactive) + (let* ((toot (get-text-property (point) 'scheduled-json)) + (scheduled (alist-get 'scheduled_at toot)) + (params (alist-get 'params toot)) + (text (alist-get 'text params)) + (visibility (alist-get 'visibility params)) + (cw (alist-get 'spoiler_text params)) + (lang (alist-get 'language params)) + (poll (alist-get 'poll params)) + (reply-id (alist-get 'in_reply_to_id params)) + (media (alist-get 'media_attachments toot))) + (mastodon-toot--compose-buffer) + (goto-char (point-max)) + (insert text) + ;; adopt properties from scheduled toot: + (when reply-id + (setq mastodon-toot--reply-to-id reply-id)) + (setq mastodon-toot--visibility visibility) + (setq mastodon-toot--scheduled-for scheduled) + (when (not (equal "" lang)) + (setq mastodon-toot--language lang)) + (mastodon-toot--set-cw cw) + (mastodon-toot--update-status-fields))) + ;;; FILTERS (defun mastodon-tl--create-filter () diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a1fb014..29d3914 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -693,7 +693,7 @@ instance to edit a toot." (symbol-name t))) ("spoiler_text" . ,spoiler) ("language" . ,mastodon-toot--language) - ("scheduled_at" . ,mastodon-toot--scheduled-at))) + ("scheduled_at" . ,mastodon-toot--scheduled-for))) (args-media (when mastodon-toot--media-attachments (mastodon-http--build-array-params-alist "media_ids[]" @@ -1126,16 +1126,35 @@ Return its two letter ISO 639 1 code." mastodon-iso-639-1))) (setq mastodon-toot--language (alist-get choice mastodon-iso-639-1 nil nil 'equal)) - (message "Language set to %s" choice))) + (message "Language set to %s" choice) + (mastodon-toot--update-status-fields))) -(defun mastodon-toot--schedule-toot () - "Read a date (+ time) in the minibuffer and schedule the current toot." +(defun mastodon-toot--schedule-toot (&optional reschedule) + "Read a date (+ time) in the minibuffer and schedule the current toot. +With RESCHEDULE, reschedule the scheduled toot at point." (interactive) - (let* ((time-value (org-read-date nil t nil "Schedule toot:")) - (iso8601-string (format-time-string "%Y-%m-%dT%H:%M:%S%z" time-value)) + (let* ((id (when reschedule (get-text-property (point) 'id))) + (time-value (org-read-date nil t nil "Schedule toot:")) + (iso8601-str (format-time-string "%FT%T%z" time-value)) (msg-str (format-time-string "%d-%m-%y at %H:%M[%z]" time-value))) - (setq-local mastodon-toot--scheduled-at iso8601-string) - (message (format "Toot scheduled for %s." msg-str)))) + (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 () + (mastodon-tl--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." + (let* ((decoded (iso8601-parse ts)) + (encoded (encode-time decoded))) + (format-time-string "%d-%m-%y, %H:%M[%z]" encoded))) ;; we'll need to revisit this if the binds get ;; more diverse than two-chord bindings @@ -1230,6 +1249,9 @@ REPLY-TEXT is the text of the toot being replied to." (propertize "Language" 'toot-post-language t) " " + (propertize "Scheduled" + 'toot-post-scheduled t) + " " (propertize "CW" 'toot-post-cw-flag t) " " @@ -1285,6 +1307,8 @@ REPLY-JSON is the full JSON of the toot being replied to." (point-min))) (lang-region (mastodon-tl--find-property-range 'toot-post-language (point-min))) + (scheduled-region (mastodon-tl--find-property-range 'toot-post-scheduled + (point-min))) (toot-string (buffer-substring-no-properties (cdr header-region) (point-max)))) (add-text-properties (car count-region) (cdr count-region) @@ -1306,6 +1330,13 @@ REPLY-JSON is the full JSON of the toot being replied to." (format "Lang: %s ⋅" mastodon-toot--language) ""))) + (add-text-properties (car scheduled-region) (cdr scheduled-region) + (list 'display + (if mastodon-toot--scheduled-for + (format "Scheduled: %s ⋅" + (mastodon-toot--iso-to-human + mastodon-toot--scheduled-for)) + ""))) (add-text-properties (car nsfw-region) (cdr nsfw-region) (list 'display (if mastodon-toot--content-nsfw (if mastodon-toot--media-attachments -- cgit v1.2.3 From 0fda96c715a059b0d149d41ed416525a737f3789 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 11:43:03 +0100 Subject: set-toot-lang > -language --- lisp/mastodon-toot.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 29d3914..0bed0f9 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -232,7 +232,7 @@ send.") (define-key map (kbd "C-c C-a") #'mastodon-toot--attach-media) (define-key map (kbd "C-c !") #'mastodon-toot--clear-all-attachments) (define-key map (kbd "C-c C-p") #'mastodon-toot--create-poll) - (define-key map (kbd "C-c C-l") #'mastodon-toot--set-toot-lang) + (define-key map (kbd "C-c C-l") #'mastodon-toot--set-toot-language) (define-key map (kbd "C-c C-s") #'mastodon-toot--schedule-toot) map) "Keymap for `mastodon-toot'.") @@ -1118,7 +1118,7 @@ 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-lang () +(defun mastodon-toot--set-toot-language () "Prompt for a language and set `mastodon-toot--language'. Return its two letter ISO 639 1 code." (interactive) -- cgit v1.2.3 From 65102c25d97212387a9699efd6253117366f5181 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 12:06:46 +0100 Subject: refactor set toot properties, autoloads, docstrings, fixes --- lisp/mastodon-tl.el | 41 +++++++++++++++++------------------------ lisp/mastodon-toot.el | 35 ++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 6a90949..70e882e 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -82,6 +82,9 @@ (autoload 'mastodon-toot--get-toot-edits "mastodon-toot") (autoload 'mastodon-toot--update-status-fields "mastodon-toot") (autoload 'mastodon-toot--compose-buffer "mastodon-toot") +(autoload 'mastodon-toot--set-toot-properties "mastodon-toot") +(autoload 'mastodon-toot--schedule-toot "mastodon-toot") +(autoload 'mastodon-toot--iso-to-human "mastodon-toot") (defvar mastodon-toot--visibility) (defvar mastodon-active-user) @@ -1866,7 +1869,7 @@ If ID, just return that toot." 'mastodon-tl--insert-scheduled-toots)) (defun mastodon-tl--insert-scheduled-toots (json) - "Insert the user's scheduled toots." + "Insert the user's scheduled toots, from JSON." (let ((scheduleds (mastodon-tl--get-scheduled-toots))) (erase-buffer) (insert (mastodon-tl--set-face @@ -1877,9 +1880,9 @@ If ID, just return that toot." (mastodon-tl--set-face "[n/p - prev/next\n r - reschedule\n c - cancel]\n\n" 'font-lock-comment-face)) - (mapcar (lambda (x) - (mastodon-tl--insert-scheduled-toot x)) - scheduleds) + (mapc (lambda (x) + (mastodon-tl--insert-scheduled-toot x)) + scheduleds) (goto-char (point-min)) (when json (mastodon-tl--goto-next-toot)))) @@ -1902,12 +1905,6 @@ If ID, just return that toot." 'id id) "\n"))) -(defun mastodon-toot--iso-to-human (ts) - "Format an ISO8601 timestamp TS to be more human-readable." - (let* ((decoded (iso8601-parse ts)) - (encoded (encode-time decoded))) - (format-time-string "%d-%m-%y, %H:%M[%z]" encoded))) - (defun mastodon-tl--copy-scheduled-toot-text () "Copy the text of the scheduled toot at point." (interactive) @@ -1916,12 +1913,14 @@ If ID, just return that toot." (text (alist-get 'text params))) (kill-new text))) -(defun mastodon-tl--cancel-scheduled-toot () - "Cancel the scheduled toot at point." +(defun mastodon-tl--cancel-scheduled-toot (no-confirm) + "Cancel the scheduled toot at point. +NO-CONFIRM means don't ask, just do." (interactive) (let* ((id (get-text-property (point) 'id)) (url (mastodon-http--api (format "scheduled_statuses/%s" id)))) - (when (y-or-n-p "Cancel scheduled toot?") + (when (or no-confirm + (y-or-n-p "Cancel scheduled toot?")) (let ((response (mastodon-http--delete url))) (mastodon-http--triage response (lambda () @@ -1938,21 +1937,15 @@ If ID, just return that toot." (visibility (alist-get 'visibility params)) (cw (alist-get 'spoiler_text params)) (lang (alist-get 'language params)) - (poll (alist-get 'poll params)) - (reply-id (alist-get 'in_reply_to_id params)) - (media (alist-get 'media_attachments toot))) + ;; (poll (alist-get 'poll params)) + (reply-id (alist-get 'in_reply_to_id params))) + ;; (media (alist-get 'media_attachments toot))) (mastodon-toot--compose-buffer) (goto-char (point-max)) (insert text) ;; adopt properties from scheduled toot: - (when reply-id - (setq mastodon-toot--reply-to-id reply-id)) - (setq mastodon-toot--visibility visibility) - (setq mastodon-toot--scheduled-for scheduled) - (when (not (equal "" lang)) - (setq mastodon-toot--language lang)) - (mastodon-toot--set-cw cw) - (mastodon-toot--update-status-fields))) + (mastodon-toot--set-toot-properties reply-id visibility cw + scheduled lang))) ;;; FILTERS diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 0bed0f9..d775727 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -80,6 +80,10 @@ (autoload 'mastodon-tl--get-endpoint "mastodon-tl") (autoload 'mastodon-http--put "mastodon-http") (autoload 'mastodon-tl--symbol "mastodon-tl") +(autoload 'mastodon-tl--view-scheduled-toots "mastodon-tl") + +(autoload 'org-read-date "org") +(autoload 'iso8601-parse "iso8601") ;; for mastodon-toot--translate-toot-text (autoload 'mastodon-tl--content "mastodon-tl") @@ -519,11 +523,23 @@ REPLY-ID, TOOT-VISIBILITY, and TOOT-CW of deleted toot are preseved." (goto-char (point-max)) (insert content) ;; adopt reply-to-id, visibility and CW from deleted toot: - (when reply-id - (setq mastodon-toot--reply-to-id reply-id)) - (setq mastodon-toot--visibility toot-visibility) - (mastodon-toot--set-cw toot-cw) - (mastodon-toot--update-status-fields)))) + (mastodon-toot--set-toot-properties + reply-id toot-visibility toot-cw + ;; TODO set new lang/scheduled props here + nil nil)))) + +(defun mastodon-toot--set-toot-properties (reply-id visibility cw + scheduled lang) + "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 + (setq mastodon-toot--reply-to-id reply-id)) + (setq mastodon-toot--visibility visibility) + (setq mastodon-toot--scheduled-for scheduled) + (when (not (string-empty-p lang)) + (setq mastodon-toot--language lang)) + (mastodon-toot--set-cw cw) + (mastodon-toot--update-status-fields)) (defun mastodon-toot--kill (&optional cancel) "Kill `mastodon-toot-mode' buffer and window. @@ -728,7 +744,8 @@ instance to edit a toot." (lambda () (mastodon-toot--kill) (message "Toot toot!") - (mastodon-toot--restore-previous-window-config prev-window-config)))))))) + (mastodon-toot--restore-previous-window-config + prev-window-config)))))))) ;; EDITING TOOTS: @@ -1141,9 +1158,9 @@ With RESCHEDULE, reschedule the scheduled toot at point." (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))) + (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 () (mastodon-tl--view-scheduled-toots) -- cgit v1.2.3 From 7fd6a014a7b7301c03a13e5561d92f9f7e6ca208 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 15:47:22 +0100 Subject: add var scheduled-id, so we can cancel it if we reschedule --- lisp/mastodon-tl.el | 3 ++- lisp/mastodon-toot.el | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 70e882e..8ce2333 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1931,6 +1931,7 @@ NO-CONFIRM means don't ask, just do." "Edit scheduled status as new toot." (interactive) (let* ((toot (get-text-property (point) 'scheduled-json)) + (id (alist-get 'id toot)) (scheduled (alist-get 'scheduled_at toot)) (params (alist-get 'params toot)) (text (alist-get 'text params)) @@ -1945,7 +1946,7 @@ NO-CONFIRM means don't ask, just do." (insert text) ;; adopt properties from scheduled toot: (mastodon-toot--set-toot-properties reply-id visibility cw - scheduled lang))) + lang scheduled id))) ;;; FILTERS diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d775727..2c5c523 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -184,6 +184,9 @@ change the setting on the server, see "An ISO 8601 timestamp that specifying when the post should be published. Should be at least 5 minutes into the future.") +(defvar-local mastodon-toot--scheduled-id nil + "The id of the scheduled post that we are now editing.") + (defvar-local mastodon-toot--reply-to-id nil "Buffer-local variable to hold the id of the toot being replied to.") @@ -526,16 +529,18 @@ REPLY-ID, TOOT-VISIBILITY, and TOOT-CW of deleted toot are preseved." (mastodon-toot--set-toot-properties reply-id toot-visibility toot-cw ;; TODO set new lang/scheduled props here - nil nil)))) + nil)))) -(defun mastodon-toot--set-toot-properties (reply-id visibility cw - scheduled lang) +(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 (setq mastodon-toot--reply-to-id reply-id)) (setq mastodon-toot--visibility visibility) (setq mastodon-toot--scheduled-for scheduled) + (setq mastodon-toot--scheduled-id scheduled-id) (when (not (string-empty-p lang)) (setq mastodon-toot--language lang)) (mastodon-toot--set-cw cw) -- cgit v1.2.3 From 679e15e955e0d7f4d204ea71aaeadaf26bfa690c Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 15:47:41 +0100 Subject: edit toot: use set-toot-properties --- lisp/mastodon-toot.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 2c5c523..86c192b 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -766,16 +766,15 @@ instance to edit a toot." (content (alist-get 'text source)) (source-cw (alist-get 'spoiler_text source)) (toot-visibility (alist-get 'visibility toot)) + (toot-language (alist-get 'language toot)) (reply-id (alist-get 'in_reply_to_id toot))) (when (y-or-n-p "Edit this toot? ") (mastodon-toot--compose-buffer) (goto-char (point-max)) (insert content) - ;; adopt reply-to-id, visibility and CW: - (when reply-id - (setq mastodon-toot--reply-to-id reply-id)) - (setq mastodon-toot--visibility toot-visibility) - (mastodon-toot--set-cw source-cw) + ;; adopt reply-to-id, visibility, CW, and language: + (mastodon-toot--set-toot-properties reply-id toot-visibility + source-cw toot-language) (mastodon-toot--update-status-fields) (setq mastodon-toot--edit-toot-id id)))))) -- cgit v1.2.3 From 3ded5be6dcf964f35eec22a7efaaf74973d4d385 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 16:00:30 +0100 Subject: cancel original scheduled toot if edited/rescheduled --- lisp/mastodon-tl.el | 9 +++++---- lisp/mastodon-toot.el | 13 +++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 8ce2333..6971673 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1913,11 +1913,11 @@ If ID, just return that toot." (text (alist-get 'text params))) (kill-new text))) -(defun mastodon-tl--cancel-scheduled-toot (no-confirm) +(defun mastodon-tl--cancel-scheduled-toot (&optional id no-confirm) "Cancel the scheduled toot at point. -NO-CONFIRM means don't ask, just do." +NO-CONFIRM means there is no ask or message, there is only do." (interactive) - (let* ((id (get-text-property (point) 'id)) + (let* ((id (or id (get-text-property (point) 'id))) (url (mastodon-http--api (format "scheduled_statuses/%s" id)))) (when (or no-confirm (y-or-n-p "Cancel scheduled toot?")) @@ -1925,7 +1925,8 @@ NO-CONFIRM means don't ask, just do." (mastodon-http--triage response (lambda () (mastodon-tl--view-scheduled-toots) - (message "Toot cancelled!"))))))) + (unless no-confirm + (message "Toot cancelled!")))))))) (defun mastodon-tl--edit-scheduled-as-new () "Edit scheduled status as new toot." diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 86c192b..c058296 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -727,7 +727,9 @@ instance to edit a toot." (if mastodon-toot-poll (append args-no-media args-poll) args-no-media))) - (prev-window-config mastodon-toot-previous-window-config)) + (prev-window-config mastodon-toot-previous-window-config) + (scheduled mastodon-toot--scheduled-for) + (scheduled-id mastodon-toot--scheduled-id)) (cond ((and mastodon-toot--media-attachments ;; make sure we have media args ;; and the same num of ids as attachments @@ -748,7 +750,13 @@ instance to edit a toot." (mastodon-http--triage response (lambda () (mastodon-toot--kill) - (message "Toot toot!") + (if scheduled + (message "Toot scheduled!") + (message "Toot toot!")) + ;; cancel scheduled toot if we were editing it: + (when scheduled-id + (mastodon-tl--cancel-scheduled-toot + scheduled-id :no-confirm)) (mastodon-toot--restore-previous-window-config prev-window-config)))))))) @@ -1155,6 +1163,7 @@ Return its two letter ISO 639 1 code." With RESCHEDULE, reschedule the scheduled toot at point." (interactive) (let* ((id (when reschedule (get-text-property (point) 'id))) + ;; TODO if reschedule, set org-read-date to scheduled time (time-value (org-read-date nil t nil "Schedule toot:")) (iso8601-str (format-time-string "%FT%T%z" time-value)) (msg-str (format-time-string "%d-%m-%y at %H:%M[%z]" time-value))) -- cgit v1.2.3 From 24fec2f262123264c2b84d4f9c902b477b731bbb Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 16:16:47 +0100 Subject: display value of --scheduled-for in org-read-date if set --- lisp/mastodon-toot.el | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index c058296..17b57ed 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -81,7 +81,7 @@ (autoload 'mastodon-http--put "mastodon-http") (autoload 'mastodon-tl--symbol "mastodon-tl") (autoload 'mastodon-tl--view-scheduled-toots "mastodon-tl") - +(autoload 'mastodon-tl--cancel-scheduled-toot "mastodon-toot") (autoload 'org-read-date "org") (autoload 'iso8601-parse "iso8601") @@ -1164,7 +1164,10 @@ With RESCHEDULE, reschedule the scheduled toot at point." (interactive) (let* ((id (when reschedule (get-text-property (point) 'id))) ;; TODO if reschedule, set org-read-date to scheduled time - (time-value (org-read-date nil t nil "Schedule toot:")) + (time-value + (org-read-date t t nil "Schedule toot:" + ;; default to scheduled timestamp if already set: + (mastodon-toot--iso-to-org 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) @@ -1172,10 +1175,12 @@ With RESCHEDULE, reschedule the scheduled toot at point." (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)))) + (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)))))))) @@ -1186,6 +1191,11 @@ With RESCHEDULE, reschedule the scheduled toot at point." (encoded (encode-time decoded))) (format-time-string "%d-%m-%y, %H:%M[%z]" encoded))) +(defun mastodon-toot--iso-to-org (ts) + "Convert ISO8601 timestamp TS to something `org-read-date' can handle." + (let* ((decoded (iso8601-parse ts))) + (encode-time decoded))) + ;; we'll need to revisit this if the binds get ;; more diverse than two-chord bindings (defun mastodon-toot--get-mode-kbinds () -- cgit v1.2.3 From 9f5ebd694be8033b3ea79b6e6f56ec777bbdfb80 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 16:25:08 +0100 Subject: make rescheduling without editing work, also with org-read-date --- lisp/mastodon-tl.el | 1 + lisp/mastodon-toot.el | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 6971673..f28c7c5 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1859,6 +1859,7 @@ If ID, just return that toot." (defun mastodon-tl--reschedule-toot () "Reschedule the scheduled toot at point." + (interactive) (mastodon-toot--schedule-toot :reschedule)) (defun mastodon-tl--view-scheduled-toots () diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 17b57ed..87b1b77 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1160,14 +1160,20 @@ Return its two letter ISO 639 1 code." (defun mastodon-toot--schedule-toot (&optional reschedule) "Read a date (+ time) in the minibuffer and schedule the current toot. -With RESCHEDULE, reschedule the scheduled toot at point." +With RESCHEDULE, reschedule the scheduled toot at point without editing." (interactive) (let* ((id (when reschedule (get-text-property (point) 'id))) - ;; TODO if reschedule, set org-read-date to scheduled time + (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 mastodon-toot--scheduled-for))) + (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) @@ -1193,8 +1199,8 @@ With RESCHEDULE, reschedule the scheduled toot at point." (defun mastodon-toot--iso-to-org (ts) "Convert ISO8601 timestamp TS to something `org-read-date' can handle." - (let* ((decoded (iso8601-parse ts))) - (encode-time decoded))) + (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 -- cgit v1.2.3 From ed41f1ce270a25e80b9e75d9da23cc6a7749b9a7 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Tue, 29 Nov 2022 16:38:36 +0100 Subject: edit scheduled post keybindings --- lisp/mastodon-tl.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index f28c7c5..24887b6 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -264,6 +264,8 @@ types of mastodon links and not just shr.el-generated ones.") (let ((map (make-sparse-keymap))) (define-key map (kbd "r") 'mastodon-tl--reschedule-toot) (define-key map (kbd "c") 'mastodon-tl--cancel-scheduled-toot) + (define-key map (kbd "e") 'mastodon-tl--edit-scheduled-as-new) + (define-key map (kbd "") 'mastodon-tl--edit-scheduled-as-new) (keymap-canonicalize map)) "Keymap for when point is on a scheduled toot.") @@ -1879,7 +1881,7 @@ If ID, just return that toot." " ------------\n\n") 'success) (mastodon-tl--set-face - "[n/p - prev/next\n r - reschedule\n c - cancel]\n\n" + "[n/p - prev/next\n r - reschedule\n e/RET - edit toot\n c - cancel]\n\n" 'font-lock-comment-face)) (mapc (lambda (x) (mastodon-tl--insert-scheduled-toot x)) @@ -1916,6 +1918,7 @@ If ID, just return that toot." (defun mastodon-tl--cancel-scheduled-toot (&optional id no-confirm) "Cancel the scheduled toot at point. +ID is that of the scheduled toot to cancel. NO-CONFIRM means there is no ask or message, there is only do." (interactive) (let* ((id (or id (get-text-property (point) 'id))) -- cgit v1.2.3 From a0df42d70b8e7285234c4a8bb3d65154c7a31c70 Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Wed, 30 Nov 2022 10:56:25 +0100 Subject: schedule-toot - comment to acknowledge ct --- lisp/mastodon-toot.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 87b1b77..7efe682 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -1161,6 +1161,8 @@ Return its two letter ISO 639 1 code." (defun mastodon-toot--schedule-toot (&optional reschedule) "Read a date (+ time) in the minibuffer and schedule the current toot. 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 -- cgit v1.2.3 From 308a9824fa5391fd4228949faedffd05b46579da Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Thu, 1 Dec 2022 09:44:32 +0100 Subject: completion - bound the --get-bounds backward regex search this prevents matching when we have type words after a handle/tag (forward-whitespace -1) places point before the previous space. placing it after doesn't work, it breaks some completion cases. --- lisp/mastodon-toot.el | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 7efe682..9402241 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -869,7 +869,11 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (save-excursion ;; match full handle inc. domain, or tag including # ;; (see the regexes for subexp 2) - (when (re-search-backward regex nil :no-error) + (when (re-search-backward regex + (save-excursion + (forward-whitespace -1) + (point)) + :no-error) (cons (match-beginning 2) (match-end 2)))))) -- cgit v1.2.3 From 7a70e091f64729b03ad55079b5a3a86afd178d0c Mon Sep 17 00:00:00 2001 From: marty hiatt Date: Thu, 1 Dec 2022 10:16:21 +0100 Subject: factor fetch candidates fun, try to improve completion performance --- lisp/mastodon-toot.el | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9402241..8d8bfc2 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -877,6 +877,24 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (cons (match-beginning 2) (match-end 2)))))) +(defun mastodon-toot--fetch-completion-candidates (start end &optional tags) + "Search for a completion prefix from buffer positions START to END. +Return a list of candidates. +If TAGS, we search for tags, else we search for handles." + ;; FIXME: can we save the first two-letter search then only filter the + ;; resulting list? + ;; (or mastodon-toot-completions + ;; would work if we could null that var upon completion success + (setq mastodon-toot-completions + (if tags + (let ((tags-list (mastodon-search--search-tags-query + (buffer-substring-no-properties start end)))) + (cl-loop for tag in tags-list + collect (cons (concat "#" (car tag)) + (cdr tag)))) + (mastodon-search--search-accounts-query + (buffer-substring-no-properties start end))))) + (defun mastodon-toot--mentions-capf () "Build a mentions completion backend for `completion-at-point-functions'." (let* ((bounds @@ -889,11 +907,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." ;; only search when necessary: (completion-table-dynamic (lambda (_) - ;; TODO: do we really need to set a local var here - ;; just for the annotation-function? - (setq mastodon-toot-completions - (mastodon-search--search-accounts-query - (buffer-substring-no-properties start end))))) + (mastodon-toot--fetch-completion-candidates start end))) :exclusive 'no :annotation-function (lambda (candidate) @@ -912,13 +926,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." ;; only search when necessary: (completion-table-dynamic (lambda (_) - (setq mastodon-toot-completions - (let ((tags (mastodon-search--search-tags-query - (buffer-substring-no-properties start end)))) - (mapcar (lambda (x) - (list (concat "#" (car x)) - (cdr x))) - tags))))) + (mastodon-toot--fetch-completion-candidates start end :tags))) :exclusive 'no :annotation-function (lambda (candidate) @@ -933,7 +941,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." "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 - (caadr (assoc candidate mastodon-toot-completions))) + (cadr (assoc candidate mastodon-toot-completions))) (defun mastodon-toot--reply () "Reply to toot at `point'. -- cgit v1.2.3