From c5a3c917712283d733971dba2ad39486f82bb6e4 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 6 May 2021 19:21:29 +0200 Subject: add delete toot function --- lisp/mastodon-http.el | 11 +++++++++++ lisp/mastodon-tl.el | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 7be4467..b590bf0 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -98,6 +98,17 @@ Pass response buffer to CALLBACK function." (mastodon-auth--access-token)))))) (url-retrieve-synchronously url))) +(defun mastodon-http--delete (url) + "Make GET request to URL. + +Pass response buffer to CALLBACK function." + (let ((url-request-method "DELETE") + (url-request-extra-headers + `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))))) + (with-temp-buffer + (url-retrieve-synchronously url)))) + (defun mastodon-http--get-json (url) "Make GET request to URL. Return JSON response vector." (let ((json-vector diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 0b918df..ae21041 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -782,6 +782,17 @@ webapp" (cdr (assoc 'descendants context)))))) (message "No Thread!")))) +(defun mastodon-tl--delete-toot () + "Delete user's toot at point synchronously." + (interactive) + (let* ((id (mastodon-tl--as-string (mastodon-tl--toot-id + (mastodon-tl--property 'toot-json)))) + (url (mastodon-http--api (format "statuses/%s" id)))) + (let ((response (mastodon-http--delete url))) + (mastodon-http--triage response + (lambda () + (message "Toot deleted! There may be a delay before it disappears from your profile.")))))) + (defun mastodon-tl--more () "Append older toots to timeline." (interactive) -- cgit v1.2.3 From 1dca682bc22945a2e92aaea96ce8f87f9271b8a8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 6 May 2021 19:31:11 +0200 Subject: delete toot keybinding --- lisp/mastodon.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 07535ec..8b2673c 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -106,7 +106,9 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "t") #'mastodon-toot) ;; override special mode binding (define-key map (kbd "g") #'undefined) + (define-key map (kbd "D") #'mastodon-tl--delete-toot) map) + "Keymap for `mastodon-mode'.") (defcustom mastodon-mode-hook nil -- cgit v1.2.3 From c3aaae8614978c7103bc154bf4ea9907fed36eec Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 6 May 2021 20:22:34 +0200 Subject: docstring --- lisp/mastodon-http.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index b590bf0..da4b91a 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -99,7 +99,7 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url))) (defun mastodon-http--delete (url) - "Make GET request to URL. + "Make DELETE request to URL. Pass response buffer to CALLBACK function." (let ((url-request-method "DELETE") -- cgit v1.2.3 From 9575c3436e3b1ef1a9159d24a2c2a0f8afb27829 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 7 May 2021 10:35:11 +0200 Subject: cherry pick ieure's cosmetic changes --- lisp/mastodon-tl.el | 10 +++++----- lisp/mastodon.el | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index ae21041..43be5fb 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -266,7 +266,7 @@ Optionally start from POS." (let ((reblog (cdr (assoc 'reblog toot)))) (when reblog (concat - " " + "\n " (propertize "Boosted" 'face 'mastodon-boosted-face) " " (mastodon-tl--byline-author reblog))))) @@ -355,11 +355,11 @@ it is `mastodon-tl--byline-boosted'" (faved (equal 't (mastodon-tl--field 'favourited toot))) (boosted (equal 't (mastodon-tl--field 'reblogged toot)))) (concat - (propertize "\n | " 'face 'default) + ;; (propertize "\n | " 'face 'default) (propertize (concat (when boosted (format "(%s) " - (propertize "B" 'face 'mastodon-boost-fave-face))) + (propertize "B" 'face 'mastodon-boost-face))) (when faved (format "(%s) " (propertize "F" 'face 'mastodon-boost-fave-face))) @@ -592,13 +592,13 @@ message is a link which unhides/hides the main body." 'default)) (message (concat "\n" " ---------------\n" - " " (mastodon-tl--make-link "Content Warning" + " " (mastodon-tl--make-link + (concat "CW: " string) ;"Content Warning" 'content-warning) "\n" " ---------------\n")) (cw (mastodon-tl--set-face message 'mastodon-cw-face))) (concat - string cw (propertize (mastodon-tl--content toot) 'invisible t diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 8b2673c..99b23f7 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -126,7 +126,7 @@ Use. e.g. \"%c\" for your locale's date and time format." "Face used for user display names.") (defface mastodon-boosted-face - '((t :inherit highlight :weight bold)) + '((t :inherit success :weight bold)) "Face to indicate that a toot is boosted.") (defface mastodon-boost-fave-face -- cgit v1.2.3 From 1a2cf34a80bebf42b1a9aa92bf7aae14d1d5292e Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 7 May 2021 10:46:09 +0200 Subject: restore newline btw post body and byline --- lisp/mastodon-tl.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 43be5fb..7732e7e 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -642,6 +642,7 @@ it is `mastodon-tl--byline-boosted'" (insert (propertize (concat body + " \n" (mastodon-tl--byline toot author-byline action-byline)) 'toot-id (cdr (assoc 'id toot)) 'base-toot-id (mastodon-tl--toot-id toot) -- cgit v1.2.3 From e5cb126df37ccd8031692e6900c8fad1c34f793e Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 7 May 2021 11:12:51 +0200 Subject: fix newlines before after posts --- lisp/mastodon-tl.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 7732e7e..bb92378 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -374,7 +374,7 @@ it is `mastodon-tl--byline-boosted'" 'display (if mastodon-tl--enable-relative-timestamps (mastodon-tl--relative-time-description parsed-time) parsed-time)) - (propertize "\n ------------" 'face 'default)) + (propertize "\n ------------\n" 'face 'default)) 'favourited-p faved 'boosted-p boosted 'byline t)))) @@ -590,7 +590,7 @@ message is a link which unhides/hides the main body." (mastodon-tl--clean-tabs-and-nl (mastodon-tl--render-text spoiler toot)) 'default)) - (message (concat "\n" + (message (concat ;"\n" " ---------------\n" " " (mastodon-tl--make-link (concat "CW: " string) ;"Content Warning" @@ -641,13 +641,14 @@ it is `mastodon-tl--byline-boosted'" (let ((start-pos (point))) (insert (propertize - (concat body + (concat "\n" + body " \n" (mastodon-tl--byline toot author-byline action-byline)) 'toot-id (cdr (assoc 'id toot)) 'base-toot-id (mastodon-tl--toot-id toot) 'toot-json toot) - "\n\n") + "\n") (when mastodon-tl--display-media-p (mastodon-media--inline-images start-pos (point))))) -- cgit v1.2.3 From 2c4f627c2a22b8105cb3f5ffba429549d4f8e6e7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 7 May 2021 12:06:15 +0200 Subject: move profile mode map bindings to free up 'f'/'F' - this way you can favorite posts when viewing a profile --- lisp/mastodon-profile.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 16fb1a9..bf6007f 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -64,8 +64,8 @@ extra keybindings." ;; The mode line indicator. :lighter " Profile" ;; The key bindings - :keymap '(((kbd "F") . mastodon-profile--open-followers) - ((kbd "f") . mastodon-profile--open-following)) + :keymap '(((kbd "O") . mastodon-profile--open-followers) + ((kbd "o") . mastodon-profile--open-following)) :group 'mastodon) (defun mastodon-profile--toot-json () -- cgit v1.2.3 From 3a89ca3212803f3104212b6219448e533aac3ab2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 7 May 2021 13:30:29 +0200 Subject: follow user or booster of toot at point fun --- lisp/mastodon-tl.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index bb92378..d271243 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -42,6 +42,9 @@ (autoload 'mastodon-profile--account-from-id "mastodon.el-profile.el") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile.el") (autoload 'mastodon-profile--search-account-by-handle "mastodon.el-profile.el") +;; try an autoload for new follow fun +(autoload 'mastodon-profile--toot-json "mastodon-profile.el") +(autoload 'mastodon-profile--account-field "mastodon-profile.el") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; need to declare it since Emacs24 didn't have this @@ -795,6 +798,20 @@ webapp" (lambda () (message "Toot deleted! There may be a delay before it disappears from your profile.")))))) +;; follow user at point: +;; try to make it work only for toot user id first, then try to allow mentions/boosts +(defun mastodon-tl--follow-user () + "Follow author OR BOOSTER! of toot at point synchronously." + (interactive) + (let* ((account + (cdr (assoc 'account (mastodon-profile--toot-json)))) ; acc data from toot + (user-id (mastodon-profile--account-field account 'id)) ; id from acc + (url (mastodon-http--api (format "accounts/%s/follow" user-id)))) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User ID %s followed!" user-id)))))) ; TODO: use handle + (defun mastodon-tl--more () "Append older toots to timeline." (interactive) -- cgit v1.2.3 From f511b7ca340918901d1eb9d0a6e97029ad92c443 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 7 May 2021 13:43:12 +0200 Subject: follow user binding --- lisp/mastodon.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 99b23f7..a6609ac 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -107,6 +107,7 @@ Use. e.g. \"%c\" for your locale's date and time format." ;; override special mode binding (define-key map (kbd "g") #'undefined) (define-key map (kbd "D") #'mastodon-tl--delete-toot) + (define-key map (kbd "W") #'mastodon-tl--follow-user) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 083b085ebce6753001c8fe6798f5f44f2c3971c1 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 10:06:28 +0200 Subject: re-write follow-user fun with completing read --- lisp/mastodon-tl.el | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index d271243..14623e6 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -798,19 +798,27 @@ webapp" (lambda () (message "Toot deleted! There may be a delay before it disappears from your profile.")))))) -;; follow user at point: -;; try to make it work only for toot user id first, then try to allow mentions/boosts -(defun mastodon-tl--follow-user () - "Follow author OR BOOSTER! of toot at point synchronously." - (interactive) - (let* ((account - (cdr (assoc 'account (mastodon-profile--toot-json)))) ; acc data from toot - (user-id (mastodon-profile--account-field account 'id)) ; id from acc +(defun mastodon-tl--follow-user (user-handle) + "Query user for user id from current status and follow that user." + (interactive + (list + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read "User handle: " + user-handles + nil ; predicate + 'confirm)))) + (let* ((account (mastodon-profile--lookup-account-in-status + user-handle (mastodon-profile--toot-json))) + (user-id (mastodon-profile--account-field account 'id)) + (name (mastodon-profile--account-field account 'display_name)) (url (mastodon-http--api (format "accounts/%s/follow" user-id)))) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User ID %s followed!" user-id)))))) ; TODO: use handle + (if account + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) followed!" name user-handle)))) + (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--more () "Append older toots to timeline." -- cgit v1.2.3 From b5541f5e3fe29fba0acd480ea9c3bcbf36c70085 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 10:06:53 +0200 Subject: add toot/follows/followers counts to profile buffer --- lisp/mastodon-profile.el | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index bf6007f..a5fb1a9 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -107,7 +107,10 @@ following the current profile." id endpoint-type))) (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) (note (mastodon-profile--account-field account 'note)) - (json (mastodon-http--get-json url))) + (json (mastodon-http--get-json url)) + (fol_count (mastodon-tl--as-string (mastodon-profile--account-field account 'followers_count))) + (folling_count (mastodon-tl--as-string (mastodon-profile--account-field account 'following_count))) + (toots_count (mastodon-tl--as-string (mastodon-profile--account-field account 'statuses_count)))) (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (mastodon-mode) @@ -137,6 +140,13 @@ following the current profile." 'face 'default) "\n ------------\n" (mastodon-tl--render-text note nil) + (mastodon-tl--set-face + (concat " ------------\n" + "TOOTS: " toots_count " | " + "FOLLOWERS: " fol_count " | " + "FOLLOWING: " folling_count "\n" + " ------------\n\n") + 'success) (mastodon-tl--set-face (concat " ------------\n" endpoint-name "\n" -- cgit v1.2.3 From 5e1751c2c9ec8096c5b2d03c6aca699fc102cf60 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 10:21:52 +0200 Subject: indent toots/foll/following on profile --- lisp/mastodon-profile.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index a5fb1a9..aed33a7 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -142,7 +142,7 @@ following the current profile." (mastodon-tl--render-text note nil) (mastodon-tl--set-face (concat " ------------\n" - "TOOTS: " toots_count " | " + " TOOTS: " toots_count " | " "FOLLOWERS: " fol_count " | " "FOLLOWING: " folling_count "\n" " ------------\n\n") -- cgit v1.2.3 From 77941ed350b83ab36459e0bb1346699e1db992c2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 12:03:43 +0200 Subject: unfollow user fun --- lisp/mastodon-tl.el | 27 ++++++++++++++++++++++++++- lisp/mastodon.el | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 14623e6..10284d2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -45,6 +45,7 @@ ;; try an autoload for new follow fun (autoload 'mastodon-profile--toot-json "mastodon-profile.el") (autoload 'mastodon-profile--account-field "mastodon-profile.el") +(autoload 'mastodon-profile--extract-users-handles "mastodon-profile.el") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; need to declare it since Emacs24 didn't have this @@ -799,7 +800,7 @@ webapp" (message "Toot deleted! There may be a delay before it disappears from your profile.")))))) (defun mastodon-tl--follow-user (user-handle) - "Query user for user id from current status and follow that user." + "Query for user id from current status and follow that user." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles @@ -820,6 +821,30 @@ webapp" (message "User %s (@%s) followed!" name user-handle)))) (message "Cannot find a user with handle %S" user-handle)))) +(defun mastodon-tl--unfollow-user (user-handle) + "Query for user id from current status and unfollow that user." + (interactive + (list + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read "User handle: " + user-handles + nil ; predicate + 'confirm)))) + (let* ((account (mastodon-profile--lookup-account-in-status + user-handle (mastodon-profile--toot-json))) + (user-id (mastodon-profile--account-field account 'id)) + (name (mastodon-profile--account-field account 'display_name)) + (url (mastodon-http--api (format "accounts/%s/unfollow" user-id)))) + (if account + (when (y-or-n-p (format "Unfollow user %s? " name)) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) unfollowed!" name user-handle)))) + (message "Cannot find a user with handle %S" user-handle))))) + + (defun mastodon-tl--more () "Append older toots to timeline." (interactive) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index a6609ac..22c7c1c 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -108,6 +108,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "g") #'undefined) (define-key map (kbd "D") #'mastodon-tl--delete-toot) (define-key map (kbd "W") #'mastodon-tl--follow-user) + (define-key map (kbd "C-S-W") #'mastodon-tl--unfollow-user) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 6d944039bef1288745ae5535f6a407bb7cef1a51 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 14:07:34 +0200 Subject: mute/unmute, block/unblock funs and bindings --- lisp/mastodon-tl.el | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++-- lisp/mastodon.el | 4 +++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 10284d2..30982a2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -841,9 +841,106 @@ webapp" (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response (lambda () - (message "User %s (@%s) unfollowed!" name user-handle)))) - (message "Cannot find a user with handle %S" user-handle))))) + (message "User %s (@%s) unfollowed!" name user-handle))))) + (message "Cannot find a user with handle %S" user-handle)))) + +(defun mastodon-tl--mute-user (user-handle) + "Query for user id from current status and mute that user." + (interactive + (list + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read "User handle: " + user-handles + nil ; predicate + 'confirm)))) + (let* ((account (mastodon-profile--lookup-account-in-status + user-handle (mastodon-profile--toot-json))) + (user-id (mastodon-profile--account-field account 'id)) + (name (mastodon-profile--account-field account 'display_name)) + (url (mastodon-http--api (format "accounts/%s/mute" user-id)))) + (if account + (when (y-or-n-p (format "Mute user %s? " name)) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) muted!" name user-handle))))) + (message "Cannot find a user with handle %S" user-handle)))) + +(defun mastodon-tl--unmute-user (user-handle) + "Query for USER-HANDLE from list of muted users and unmute that user." + (interactive + (list + (let* ((mutes-url (mastodon-http--api (format "mutes"))) + (mutes-json (mastodon-http--get-json mutes-url)) + (muted-accts (mapcar (lambda (muted) + (cdr (assoc 'acct muted))) + mutes-json))) + (completing-read "Unmute user: " + muted-accts + nil ; predicate + t)))) + (let* ((account (mastodon-profile--search-account-by-handle + user-handle)) + (user-id (mastodon-profile--account-field account 'id)) + (name (mastodon-profile--account-field account 'display_name)) + (url (mastodon-http--api (format "accounts/%s/unmute" user-id)))) + (if account + (when (y-or-n-p (format "Unmute user %s? " name)) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) unmuted!" name user-handle))))) + (message "Cannot find a user with handle %S" user-handle)))) +(defun mastodon-tl--block-user (user-handle) + "Query for USER-HANDLE from current status and block that user." + (interactive + (list + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read "User handle: " + user-handles + nil ; predicate + 'confirm)))) + (let* ((account (mastodon-profile--lookup-account-in-status + user-handle (mastodon-profile--toot-json))) + (user-id (mastodon-profile--account-field account 'id)) + (name (mastodon-profile--account-field account 'display_name)) + (url (mastodon-http--api (format "accounts/%s/block" user-id)))) + (if account + (when (y-or-n-p (format "Block user %s? " name)) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) blocked!" name user-handle))))) + (message "Cannot find a user with handle %S" user-handle)))) + +(defun mastodon-tl--unblock-user (user-handle) + "Query for user from list of blocked users and unblock that user." + (interactive + (list + (let* ((blocks-url (mastodon-http--api (format "blocks"))) + (blocks-json (mastodon-http--get-json blocks-url)) + (blocked-accts (mapcar (lambda (blocked) + (cdr (assoc 'acct blocked))) + blocks-json))) + (completing-read "Unblock user: " + blocked-accts + nil ; predicate + t)))) + (let* ((account (mastodon-profile--search-account-by-handle + user-handle)) + (user-id (mastodon-profile--account-field account 'id)) + (name (mastodon-profile--account-field account 'display_name)) + (url (mastodon-http--api (format "accounts/%s/unblock" user-id)))) + (if account + (when (y-or-n-p (format "Unblock user %s? " name)) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) unblocked!" name user-handle))))) + (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--more () "Append older toots to timeline." diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 22c7c1c..929ae8c 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -109,6 +109,10 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "D") #'mastodon-tl--delete-toot) (define-key map (kbd "W") #'mastodon-tl--follow-user) (define-key map (kbd "C-S-W") #'mastodon-tl--unfollow-user) + (define-key map (kbd "B") #'mastodon-tl--block-user) + (define-key map (kbd "C-S-B") #'mastodon-tl--unblock-user) + (define-key map (kbd "M") #'mastodon-tl--mute-user) + (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 416709661936d16a854b15c0622ae5d29e2f50c8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 14:34:19 +0200 Subject: Set a HTTP timeout. This prevents mastodon.el from locking Emacs and spinning forever. --- lisp/mastodon-http.el | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index da4b91a..a6e9c92 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -35,6 +35,9 @@ (defvar mastodon-http--api-version "v1") +(defconst mastodon-http--timeout 5 + "HTTP request timeout, in seconds.") + (defun mastodon-http--api (endpoint) "Return Mastondon API URL for ENDPOINT." (concat mastodon-instance-url "/api/" @@ -86,7 +89,7 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token))))) headers))) (with-temp-buffer - (url-retrieve-synchronously url)))) + (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) (defun mastodon-http--get (url) "Make GET request to URL. @@ -96,7 +99,7 @@ Pass response buffer to CALLBACK function." (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) - (url-retrieve-synchronously url))) + (url-retrieve-synchronously url nil nil mastodon-http--timeout))) (defun mastodon-http--delete (url) "Make DELETE request to URL. -- cgit v1.2.3 From 4b621f58d294d7ab67ee4c800cd2777541bc1bee Mon Sep 17 00:00:00 2001 From: Ian Eure Date: Sun, 3 May 2020 13:56:14 -0700 Subject: SWAG at moving to an async network model. --- lisp/mastodon-http.el | 63 ++++++++++++++++++++++++++++++++++--------- lisp/mastodon-tl.el | 75 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 95 insertions(+), 43 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index a6e9c92..a5f88d7 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -113,18 +113,57 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url)))) (defun mastodon-http--get-json (url) - "Make GET request to URL. Return JSON response vector." - (let ((json-vector - (with-current-buffer (mastodon-http--get url) - (goto-char (point-min)) - (re-search-forward "^$" nil 'move) - (let ((json-string - (decode-coding-string - (buffer-substring-no-properties (point) (point-max)) - 'utf-8))) - (kill-buffer) - (json-read-from-string json-string))))) - json-vector)) + "Make GET request to URL. Return JSON response" + (with-current-buffer (mastodon-http--get url) + (mastodon-http--process-json))) + +(defun mastodon-http--process-json () + (goto-char (point-min)) + (re-search-forward "^$" nil 'move) + (let ((json-string + (decode-coding-string + (buffer-substring-no-properties (point) (point-max)) + 'utf-8))) + (kill-buffer) + (json-read-from-string json-string))) + + ;; Asynchronous functions + +(defun mastodon-http--get-async (url &optional callback &rest cbargs) + "Make GET request to URL. + +Pass response buffer to CALLBACK function." + (let ((url-request-method "GET") + (url-request-extra-headers + `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))))) + (url-retrieve url callback cbargs mastodon-http--timeout))) + +(defun mastodon-http--get-json-async (url &optional callback &rest args) + "Make GET request to URL. Call CALLBACK with json-vector and ARGS." + (mastodon-http--get-async + url + (lambda (status) + (apply callback (mastodon-http--process-json) args)))) + +(defun mastodon-http--post-async (url args headers &optional callback &rest cbargs) + "POST asynchronously to URL with ARGS and HEADERS. + +Authorization header is included by default unless UNAUTHENTICED-P is non-nil." + (let ((url-request-method "POST") + (url-request-data + (when args + (mapconcat (lambda (arg) + (concat (url-hexify-string (car arg)) + "=" + (url-hexify-string (cdr arg)))) + args + "&"))) + (url-request-extra-headers + (append `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))) + headers))) + (with-temp-buffer + (url-retrieve url callback cbargs mastodon-http--timeout)))) (provide 'mastodon-http) ;;; mastodon-http.el ends here diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 30982a2..a1c6495 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -703,6 +703,17 @@ it is `mastodon-tl--byline-boosted'" (mastodon-tl--as-string id))))) (mastodon-http--get-json url))) +(defun mastodon-tl--more-json-async (endpoint id callback &rest cbargs) + "Return JSON for timeline ENDPOINT before ID." + (let* ((url (mastodon-http--api (concat + endpoint + (if (string-match-p "?" endpoint) + "&" + "?") + "max_id=" + (mastodon-tl--as-string id))))) + (apply 'mastodon-http--get-json-async url callback cbargs))) + ;; TODO ;; Look into the JSON returned here by Local (defun mastodon-tl--updated-json (endpoint id) @@ -945,15 +956,15 @@ webapp" (defun mastodon-tl--more () "Append older toots to timeline." (interactive) - (let* ((point-before (point)) - (endpoint (mastodon-tl--get-endpoint)) - (update-function (mastodon-tl--get-update-function)) - (id (mastodon-tl--oldest-id)) - (json (mastodon-tl--more-json endpoint id))) + (mastodon-tl--more-json-async (mastodon-tl--get-endpoint) (mastodon-tl--oldest-id) + 'mastodon-tl--more* (current-buffer) (point))) + +(defun mastodon-tl--more* (json buffer point-before) + (with-current-buffer buffer (when json (let ((inhibit-read-only t)) (goto-char (point-max)) - (funcall update-function json) + (funcall (mastodon-tl--get-update-function) json) (goto-char point-before))))) (defun mastodon-tl--find-property-range (property start-point &optional search-backwards) @@ -1114,31 +1125,33 @@ from the start if it is nil." "Initialize BUFFER-NAME with timeline targeted by ENDPOINT. UPDATE-FUNCTION is used to recieve more toots." - (let* ((url (mastodon-http--api endpoint)) - (buffer (concat "*mastodon-" buffer-name "*")) - (json (mastodon-http--get-json url))) - (with-output-to-temp-buffer buffer - (switch-to-buffer buffer) - (setq - ;; Initialize with a minimal interval; we re-scan at least once - ;; every 5 minutes to catch any timestamps we may have missed - mastodon-tl--timestamp-next-update (time-add (current-time) - (seconds-to-time 300))) - (funcall update-function json)) - (mastodon-mode) - (with-current-buffer buffer - (setq mastodon-tl--buffer-spec - `(buffer-name ,buffer-name - endpoint ,endpoint update-function - ,update-function) - mastodon-tl--timestamp-update-timer - (when mastodon-tl--enable-relative-timestamps - (run-at-time mastodon-tl--timestamp-next-update - nil ;; don't repeat - #'mastodon-tl--update-timestamps-callback - (current-buffer) - nil)))) - buffer)) + (let ((url (mastodon-http--api endpoint)) + (buffer (concat "*mastodon-" buffer-name "*"))) + (mastodon-http--get-json-async + url 'mastodon-tl--init* buffer endpoint update-function))) + +(defun mastodon-tl--init* (json buffer endpoint update-function) + (with-output-to-temp-buffer buffer + (switch-to-buffer buffer) + (setq + ;; Initialize with a minimal interval; we re-scan at least once + ;; every 5 minutes to catch any timestamps we may have missed + mastodon-tl--timestamp-next-update (time-add (current-time) + (seconds-to-time 300))) + (funcall update-function json)) + (mastodon-mode) + (with-current-buffer buffer + (setq mastodon-tl--buffer-spec + `(buffer-name ,buffer + endpoint ,endpoint update-function + ,update-function) + mastodon-tl--timestamp-update-timer + (when mastodon-tl--enable-relative-timestamps + (run-at-time mastodon-tl--timestamp-next-update + nil ;; don't repeat + #'mastodon-tl--update-timestamps-callback + (current-buffer) + nil))))) (provide 'mastodon-tl) ;;; mastodon-tl.el ends here -- cgit v1.2.3 From 6186a9b2f60f435106c181673db4552e1e1eaa85 Mon Sep 17 00:00:00 2001 From: Ian Eure Date: Sun, 3 May 2020 11:51:00 -0700 Subject: Guard against the old version of Emacs which mastodon.el supports. --- lisp/mastodon-http.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index a5f88d7..f26d808 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -36,7 +36,7 @@ (defvar mastodon-http--api-version "v1") (defconst mastodon-http--timeout 5 - "HTTP request timeout, in seconds.") + "HTTP request timeout, in seconds. Has no effect on Emacs < 26.1.") (defun mastodon-http--api (endpoint) "Return Mastondon API URL for ENDPOINT." @@ -89,7 +89,9 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token))))) headers))) (with-temp-buffer - (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) (defun mastodon-http--get (url) "Make GET request to URL. @@ -99,7 +101,9 @@ Pass response buffer to CALLBACK function." (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) - (url-retrieve-synchronously url nil nil mastodon-http--timeout))) + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) (defun mastodon-http--delete (url) "Make DELETE request to URL. -- cgit v1.2.3 From 4b4f45e4e3f09c065e547ff5def03bde7e42de2d Mon Sep 17 00:00:00 2001 From: Ian Eure Date: Sun, 3 May 2020 10:46:53 -0700 Subject: Rewrite `mastodon-auth--access-token` so it handles errors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, `mastodon-auth--access-token` unconditionally returns the value of the `:access_token` key from the response of `(mastodon-auth--get-token)`. This causes problems when there was an error getting the token, for example, if you enter the wrong password. If a token couldn’t be retrieved, the JSON looks like: (:error "invalid_grant" :error_description "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.") Since there is no `:access_token` key, `mastodon-auth--access-token` returns `nil`, which results in a broken header in the next request: Authorization: Bearer Which causes the whole thing to freeze Emacs until you mash `C-g`. This commit rewrites the function to handle that case; to explicitly signal an error for *any* response that isn’t expected; to use `if-let`, which allows the temporary `token` variable to be eliminated; uses `pcase` to determine what kind of response was received; and adds ERT tests for all these cases. --- lisp/mastodon-auth--test.el | 47 +++++++++++++++++++++++++++++++++++++++++++++ lisp/mastodon-auth.el | 23 +++++++++++++++------- 2 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 lisp/mastodon-auth--test.el diff --git a/lisp/mastodon-auth--test.el b/lisp/mastodon-auth--test.el new file mode 100644 index 0000000..8082536 --- /dev/null +++ b/lisp/mastodon-auth--test.el @@ -0,0 +1,47 @@ +;;; mastodon-auth--test.el --- Tests for mastodon-auth -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Ian Eure + +;; Author: Ian Eure +;; Version: 0.9.0 +;; Homepage: https://github.com/jdenen/mastodon.el +;; Package-Requires: ((emacs "24.4")) + +;; This file is not part of GNU Emacs. + +;; This file is part of mastodon.el. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; mastodon-auth--test.el provides ERT tests for mastodon-auth.el + +;;; Code: + +(require 'ert) + +(ert-deftest mastodon-auth--handle-token-response--good () + (should (string= "foo" (mastodon-auth--handle-token-response '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) + +(ert-deftest mastodon-auth--handle-token-response--unknown () + :expected-result :failed + (mastodon-auth--handle-token-response '(:herp "derp"))) + +(ert-deftest mastodon-auth--handle-token-response--failure () + :expected-result :failed + (mastodon-auth--handle-token-response '(:error "invalid_grant" :error_description "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."))) + +(provide 'mastodon-auth--test) +;;; mastodon-auth--test.el ends here diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 231bb70..cfe89b5 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -124,13 +124,22 @@ Reads and/or stores secres in `MASTODON-AUTH-SOURCE-FILE'." "Return the access token to use with the current `mastodon-instance-url'. Generate token and set if none known yet." - (let ((token - (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) - (unless token - (let ((json (mastodon-auth--get-token))) - (setq token (plist-get json :access_token)) - (push (cons mastodon-instance-url token) mastodon-auth--token-alist))) - token)) + (if-let ((token (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) + token + + (mastodon-auth--handle-token-response (mastodon-auth--get-token)))) + +(defun mastodon-auth--handle-token-response (response) + (pcase response + ((and (let token (plist-get response :access_token)) + (guard token)) + (cdar (push (cons mastodon-instance-url token) + mastodon-auth--token-alist))) + + (`(:error ,class :error_description ,error) + (error "mastodon-auth--access-token: %s: %s" class error)) + + (_ (error "Unknown response from mastodon-auth--get-token!")))) (defun mastodon-auth--get-account-name () "Request user credentials and return an account name." -- cgit v1.2.3 From c69bf45a170a28934d18b762960845e773922514 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 8 May 2021 21:20:33 +0200 Subject: async view profile, async view thread, better prompts - view profile (using make-profile-buffer-for). - user confirm to delete toot. - better follow/mute/block/profile prompts --- lisp/mastodon-profile.el | 13 +++++++++---- lisp/mastodon-tl.el | 35 ++++++++++++++++++++--------------- lisp/mastodon.el | 3 ++- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index aed33a7..2c6b798 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -102,12 +102,17 @@ following the current profile." (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function) (let* ((id (mastodon-profile--account-field account 'id)) - (acct (mastodon-profile--account-field account 'acct)) (url (mastodon-http--api (format "accounts/%s/%s" - id endpoint-type))) + id endpoint-type)))) + (mastodon-http--get-json-async url + 'mastodon-profile--make-profile-buffer-for* + account endpoint-type update-function))) + +(defun mastodon-profile--make-profile-buffer-for* (json account endpoint-type update-function) + (let* ((acct (mastodon-profile--account-field account 'acct)) (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) (note (mastodon-profile--account-field account 'note)) - (json (mastodon-http--get-json url)) + (id (mastodon-profile--account-field account 'id)) (fol_count (mastodon-tl--as-string (mastodon-profile--account-field account 'followers_count))) (folling_count (mastodon-tl--as-string (mastodon-profile--account-field account 'following_count))) (toots_count (mastodon-tl--as-string (mastodon-profile--account-field account 'statuses_count)))) @@ -175,7 +180,7 @@ following the current profile." (list (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read "User handle: " + (completing-read "View profile of user: " user-handles nil ; predicate 'confirm)))) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index a1c6495..b44b160 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -771,14 +771,18 @@ webapp" (if reblog (cdr (assoc 'id reblog)) id))) (defun mastodon-tl--thread () - "Open thread buffer for toot under `point'." + "Open thread buffer for toot under `point' asynchronously." (interactive) (let* ((id (mastodon-tl--as-string (mastodon-tl--toot-id (mastodon-tl--property 'toot-json)))) - (url (mastodon-http--api (format "statuses/%s/context" id))) - (buffer (format "*mastodon-thread-%s*" id)) (toot (mastodon-tl--property 'toot-json)) - (context (mastodon-http--get-json url))) + (buffer (format "*mastodon-thread-%s*" id)) + (url (mastodon-http--api (format "statuses/%s/context" id)))) + (mastodon-http--get-json-async url + 'mastodon-tl--thread* id toot buffer))) + +(defun mastodon-tl--thread* (context id toot buffer) + (interactive) (when (member (cdr (assoc 'type toot)) '("reblog" "favourite")) (setq toot (cdr (assoc 'status toot)))) (if (> (+ (length (cdr (assoc 'ancestors context))) @@ -797,7 +801,7 @@ webapp" (cdr (assoc 'ancestors context)) `(,toot) (cdr (assoc 'descendants context)))))) - (message "No Thread!")))) + (message "No Thread!")));) (defun mastodon-tl--delete-toot () "Delete user's toot at point synchronously." @@ -805,10 +809,11 @@ webapp" (let* ((id (mastodon-tl--as-string (mastodon-tl--toot-id (mastodon-tl--property 'toot-json)))) (url (mastodon-http--api (format "statuses/%s" id)))) - (let ((response (mastodon-http--delete url))) - (mastodon-http--triage response - (lambda () - (message "Toot deleted! There may be a delay before it disappears from your profile.")))))) + (when (y-or-n-p (format "Delete this toot? ")) + (let ((response (mastodon-http--delete url))) + (mastodon-http--triage response + (lambda () + (message "Toot deleted! There may be a delay before it disappears from your profile."))))))) (defun mastodon-tl--follow-user (user-handle) "Query for user id from current status and follow that user." @@ -816,7 +821,7 @@ webapp" (list (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read "User handle: " + (completing-read "Handle of user to follow: " user-handles nil ; predicate 'confirm)))) @@ -838,7 +843,7 @@ webapp" (list (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read "User handle: " + (completing-read "Handle of user to unfollow: " user-handles nil ; predicate 'confirm)))) @@ -861,7 +866,7 @@ webapp" (list (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read "User handle: " + (completing-read "Handle of user to mute: " user-handles nil ; predicate 'confirm)))) @@ -887,7 +892,7 @@ webapp" (muted-accts (mapcar (lambda (muted) (cdr (assoc 'acct muted))) mutes-json))) - (completing-read "Unmute user: " + (completing-read "Handle of user to unmute: " muted-accts nil ; predicate t)))) @@ -910,7 +915,7 @@ webapp" (list (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read "User handle: " + (completing-read "Handle of user to block: " user-handles nil ; predicate 'confirm)))) @@ -936,7 +941,7 @@ webapp" (blocked-accts (mapcar (lambda (blocked) (cdr (assoc 'acct blocked))) blocks-json))) - (completing-read "Unblock user: " + (completing-read "Handle of user to unblock: " blocked-accts nil ; predicate t)))) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 929ae8c..7cd673b 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -106,7 +106,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "t") #'mastodon-toot) ;; override special mode binding (define-key map (kbd "g") #'undefined) - (define-key map (kbd "D") #'mastodon-tl--delete-toot) + ;; mousebot additions + (define-key map (kbd "d") #'mastodon-tl--delete-toot) (define-key map (kbd "W") #'mastodon-tl--follow-user) (define-key map (kbd "C-S-W") #'mastodon-tl--unfollow-user) (define-key map (kbd "B") #'mastodon-tl--block-user) -- cgit v1.2.3 From 4fcdb8c4b919b3a708684d1b373208dc67367664 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 10 May 2021 16:24:51 +0200 Subject: add my profile function --- lisp/mastodon-profile.el | 5 +++++ lisp/mastodon-tl.el | 2 +- lisp/mastodon.el | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 2c6b798..254f042 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -190,6 +190,11 @@ following the current profile." (mastodon-profile--make-author-buffer account) (message "Cannot find a user with handle %S" user-handle)))) +(defun mastodon-profile--my-profile () + "Show the profile of the currently signed in user." + (interactive) + (mastodon-profile--show-user (mastodon-auth--get-account-name))) + (defun mastodon-profile--account-field (account field) "Return FIELD from the ACCOUNT. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index b44b160..1b3837d 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -750,7 +750,7 @@ Move forward (down) the timeline unless BACKWARD is non-nil." (goto-char (point-max)) (mastodon-tl--property 'toot-id t))) -(defun mastodon-tl--as-string(numeric) +(defun mastodon-tl--as-string (numeric) "Convert NUMERIC to string." (cond ((numberp numeric) (number-to-string numeric)) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 7cd673b..e338793 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -114,6 +114,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-B") #'mastodon-tl--unblock-user) (define-key map (kbd "M") #'mastodon-tl--mute-user) (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) + (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 1ffe400fd4e01400fee143bf9cf6a5c22be17b3f Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 11 May 2021 10:00:08 +0200 Subject: add basic search functions --- lisp/mastodon-search.el | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ lisp/mastodon-tl.el | 5 +- lisp/mastodon.el | 2 + 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 lisp/mastodon-search.el diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el new file mode 100644 index 0000000..4cb4477 --- /dev/null +++ b/lisp/mastodon-search.el @@ -0,0 +1,145 @@ +;;; mastodon-search.el --- serach functions for mastodon.el -*- lexical-binding: t -*- + +;; search functions: + +;; autoloads? + +;; mastodon-tl--as-string +;; mastodon-tl--set-face +;; mastodon-tl--render-text +;; mastodon-tl--toot +;; mastodon-http--get-json + +;; mastodon-instance-url + +;; code + +(defun mastodon-search--search-query (query) + "Prompt for a search QUERY and return accounts, statuses, and hashtags." + (interactive "sSearch mastodon for: ") + (let* ((url (format "%s/api/v2/search" mastodon-instance-url)) + (buffer (format "*mastodon-search-%s*" query)) + (response (mastodon-http--get-search-json url query)) + (accts (cdr (assoc 'accounts response))) + (tags (cdr (assoc 'hashtags response))) + (statuses (cdr (assoc 'statuses response))) + (user-ids (mapcar #'mastodon-search--get-user-info + accts)) ; returns a list of three-item lists + (tags-list (mapcar #'mastodon-search--get-hashtag-info + tags)) + (status-list (mapcar #'mastodon-search--get-status-info + statuses)) + (status-ids-list (mapcar 'mastodon-search--get-id-from-status + statuses)) + (toots-list-json (mapcar #'mastodon-search--fetch-full-status-from-id + status-ids-list))) + (with-current-buffer (get-buffer-create buffer) + (switch-to-buffer buffer) + (erase-buffer) + (mastodon-mode) + (setq-local inhibit-read-only t) + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " USERS" "\n" + " ------------\n") + 'success)) + (mapcar (lambda (el) + (dolist (item el) + (insert (mastodon-tl--render-text item nil) "")) + (insert "----\n\n")) + ;; (insert (mastodon-tl--render-text (car el) nil) + ;; " : " + ;; (mastodon-tl--render-text (car (cdr el)) nil) + ;; " : " + ;; (mastodon-tl--render-text (car (cdr (cdr el))) nil) + ;; "\n")) + user-ids) + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " HASHTAGS" "\n" + " ------------\n") + 'success)) + (mapcar (lambda (el) + (dolist (item el) + (insert (mastodon-tl--render-text item nil) "")) + (insert "----\n\n")) + ;; (seq-do 'insert el)) + ;; (insert (mastodon-tl--render-text (car el) nil) + ;; " : " + ;; (mastodon-tl--render-text (car (cdr el)) nil) + ;; "\n")) + tags-list) + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " STATUSES" "\n" + " ------------\n") + 'success)) + (mapcar 'mastodon-tl--toot toots-list-json) + (goto-char (point-min)) + ))) + +(defun mastodon-search--get-user-info (account) + "Get user handle, display name and account URL from ACCOUNT." + (list (cdr (assoc 'display_name account)) + (cdr (assoc 'acct account)) + (cdr (assoc 'url account)))) + +(defun mastodon-search--get-hashtag-info (tag) + "Get hashtag name and URL from TAG." + (list (cdr (assoc 'name tag)) + (cdr (assoc 'url tag)))) + +(defun mastodon-search--get-status-info (status) + "Get ID, timestamp, content, and spoiler from STATUS." + (list (cdr (assoc 'id status)) + (cdr (assoc 'created_at status)) + (cdr (assoc 'spoiler_text status)) + (cdr (assoc 'content status)))) + +(defun mastodon-search--get-id-from-status (status) + "Fetch the id from a STATUS returned by a search call to the server. + +We use this to fetch the complete status from the server." + (cdr (assoc 'id status))) + +(defun mastodon-search--fetch-full-status-from-id (id) + "Fetch the full status with id ID from the server. + +This allows us to access the full account etc. details and to render them properly." + (let* ((url (concat mastodon-instance-url "/api/v1/statuses/" (mastodon-tl--as-string id))) + (json (mastodon-http--get-json url))) + json)) + +;; http functions for search: + +(defun mastodon-http--process-json-search () + (goto-char (point-min)) + (re-search-forward "^$" nil 'move) + (let ((json-string + (decode-coding-string + (buffer-substring-no-properties (point) (point-max)) + 'utf-8))) + (kill-buffer) + (json-read-from-string json-string))) + +(defun mastodon-http--get-search-json (url query) + "Make GET request to URL. Return JSON response" + (let ((buffer (mastodon-http--get-search url query))) + (with-current-buffer buffer + (mastodon-http--process-json-search)))) + +(defun mastodon-http--get-search (base-url query) + "Make GET request to URL. + +Pass response buffer to CALLBACK function." + (let ((url-request-method "GET") + (url (concat base-url "?q=" (url-hexify-string query))) + (url-request-extra-headers + `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))))) + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + +(provide 'mastodon-search) +;; mastodon-search.el ends here diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 1b3837d..9090339 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -42,10 +42,11 @@ (autoload 'mastodon-profile--account-from-id "mastodon.el-profile.el") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile.el") (autoload 'mastodon-profile--search-account-by-handle "mastodon.el-profile.el") -;; try an autoload for new follow fun +;; mousebot adds (autoload 'mastodon-profile--toot-json "mastodon-profile.el") (autoload 'mastodon-profile--account-field "mastodon-profile.el") (autoload 'mastodon-profile--extract-users-handles "mastodon-profile.el") + (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; need to declare it since Emacs24 didn't have this @@ -656,7 +657,7 @@ it is `mastodon-tl--byline-boosted'" (when mastodon-tl--display-media-p (mastodon-media--inline-images start-pos (point))))) -(defun mastodon-tl--toot(toot) +(defun mastodon-tl--toot (toot) "Formats TOOT and insertes it into the buffer." (mastodon-tl--insert-status toot diff --git a/lisp/mastodon.el b/lisp/mastodon.el index e338793..512b345 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -53,6 +53,7 @@ (autoload 'mastodon-toot--toggle-boost "mastodon-toot") (autoload 'mastodon-toot--toggle-favourite "mastodon-toot") (autoload 'mastodon-discover "mastodon-discover") +(autoload 'mastodon-search--search-query "mastodon-search") (defgroup mastodon nil "Interface with Mastodon." @@ -115,6 +116,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "M") #'mastodon-tl--mute-user) (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) + (define-key map (kbd "S") #'mastodon-search--search-query) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 5b7e7f1f7154e096469125daa96c16346ebeca9c Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 12 May 2021 10:57:32 +0200 Subject: change search results order: statuses, users, hashtags --- lisp/mastodon-search.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 4cb4477..5c381fa 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -38,6 +38,12 @@ (erase-buffer) (mastodon-mode) (setq-local inhibit-read-only t) + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " STATUSES" "\n" + " ------------\n") + 'success)) + (mapcar 'mastodon-tl--toot toots-list-json) (insert (mastodon-tl--set-face (concat "\n ------------\n" " USERS" "\n" @@ -69,12 +75,6 @@ ;; (mastodon-tl--render-text (car (cdr el)) nil) ;; "\n")) tags-list) - (insert (mastodon-tl--set-face - (concat "\n ------------\n" - " STATUSES" "\n" - " ------------\n") - 'success)) - (mapcar 'mastodon-tl--toot toots-list-json) (goto-char (point-min)) ))) -- cgit v1.2.3 From f7ece61db5c6ad11cfc90dba7951448ec292183a Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 13 May 2021 10:07:21 +0200 Subject: implmement mentioning boosters in replies by default --- lisp/mastodon-toot.el | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 14264dc..4e57158 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -233,7 +233,11 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\" " (defun mastodon-toot--mentions (status) "Extract mentions from STATUS and process them into a string." (interactive) - (let ((mentions (cdr (assoc 'mentions status)))) + (let* ((boosted (mastodon-tl--field 'reblog status)) + (mentions + (if boosted + (cdr (assoc 'mentions (cdr (assoc 'reblog status)))) + (cdr (assoc 'mentions status))))) (mapconcat (lambda(x) (mastodon-toot--process-local (cdr (assoc 'acct x)))) ;; reverse does not work on vectors in 24.5 @@ -247,9 +251,23 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\" " (id (mastodon-tl--as-string (mastodon-tl--field 'id toot))) (account (mastodon-tl--field 'account toot)) (user (cdr (assoc 'acct account))) - (mentions (mastodon-toot--mentions toot))) - (mastodon-toot (when user (concat (mastodon-toot--process-local user) - mentions)) + (mentions (mastodon-toot--mentions toot)) + (boosted (mastodon-tl--field 'reblog toot)) + (booster (when boosted + (cdr (assoc 'acct + (cdr (assoc 'account toot))))))) + (mastodon-toot (when user + (if booster + (if (and + (not (equal user booster)) + (not (string-match booster mentions))) + (concat (mastodon-toot--process-local user) + ;; "@" booster " " + (mastodon-toot--process-local booster) mentions) + (concat (mastodon-toot--process-local user) + mentions)) + (concat (mastodon-toot--process-local user) + mentions))) id))) (defun mastodon-toot--toggle-warning () -- cgit v1.2.3 From 59109fb59269c3df9eb4c51adfb8929d8cadd8bb Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 13 May 2021 17:02:35 +0200 Subject: message when loading timelines and profiles --- lisp/mastodon-profile.el | 5 ++++- lisp/mastodon-tl.el | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 254f042..bd325c1 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -187,12 +187,15 @@ following the current profile." (let ((account (mastodon-profile--lookup-account-in-status user-handle (mastodon-profile--toot-json)))) (if account - (mastodon-profile--make-author-buffer account) + (progn + (message "Loading profile of user %s..." user-handle) + (mastodon-profile--make-author-buffer account)) (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-profile--my-profile () "Show the profile of the currently signed in user." (interactive) + (message "Loading your profile...") (mastodon-profile--show-user (mastodon-auth--get-account-name))) (defun mastodon-profile--account-field (account field) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 9090339..16e1935 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -179,18 +179,21 @@ This also skips tab items in invisible text, i.e. hidden spoiler text." (defun mastodon-tl--get-federated-timeline () "Opens federated timeline." (interactive) + (message "Loading federated timeline...") (mastodon-tl--init "federated" "timelines/public" 'mastodon-tl--timeline)) (defun mastodon-tl--get-home-timeline () "Opens home timeline." (interactive) + (message "Loading home timeline...") (mastodon-tl--init "home" "timelines/home" 'mastodon-tl--timeline)) (defun mastodon-tl--get-local-timeline () "Opens local timeline." (interactive) + (message "Loading local timeline...") (mastodon-tl--init "local" "timelines/public?local=true" 'mastodon-tl--timeline)) @@ -198,8 +201,9 @@ This also skips tab items in invisible text, i.e. hidden spoiler text." "Prompts for tag and opens its timeline." (interactive) (let* ((word (or (word-at-point) "")) - (input (read-string (format "Tag(%s): " word))) + (input (read-string (format "Load timeline for tag(%s): " word))) (tag (if (equal input "") word input))) + (message "Loading timeline for #%s..." tag) (mastodon-tl--show-tag-timeline tag))) (defun mastodon-tl--show-tag-timeline (tag) -- cgit v1.2.3 From a90fa1c483eaf9fa10ffc21f6bcf5ed18cb7eea1 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 13 May 2021 19:47:02 +0200 Subject: copy url of toot at point --- lisp/mastodon-tl.el | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 16e1935..81c2d4b 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -808,6 +808,17 @@ webapp" (cdr (assoc 'descendants context)))))) (message "No Thread!")));) +(defun mastodon-tl--copy-toot-url () + "Copy URL of toot at point." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (boosted (mastodon-tl--field 'reblog toot)) + (url (if boosted + (cdr (assoc 'url (cdr (assoc 'reblog toot)))) + (cdr (assoc 'url toot))))) + (kill-new url) + (message "Toot copied to the clipboard."))) + (defun mastodon-tl--delete-toot () "Delete user's toot at point synchronously." (interactive) -- cgit v1.2.3 From e53bf8fe17bdf3d750f07075cb9d59ca7f5e97ee Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 13 May 2021 20:25:41 +0200 Subject: copy url of toot at point --- lisp/mastodon-tl.el | 3 +-- lisp/mastodon.el | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 81c2d4b..de64e1b 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -812,8 +812,7 @@ webapp" "Copy URL of toot at point." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) - (boosted (mastodon-tl--field 'reblog toot)) - (url (if boosted + (url (if (mastodon-tl--field 'reblog toot) (cdr (assoc 'url (cdr (assoc 'reblog toot)))) (cdr (assoc 'url toot))))) (kill-new url) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 512b345..accbed8 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -54,6 +54,7 @@ (autoload 'mastodon-toot--toggle-favourite "mastodon-toot") (autoload 'mastodon-discover "mastodon-discover") (autoload 'mastodon-search--search-query "mastodon-search") +(autoload 'mastodon-tl--copy-toot-url "mastodon-tl") (defgroup mastodon nil "Interface with Mastodon." @@ -117,6 +118,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) (define-key map (kbd "S") #'mastodon-search--search-query) + (define-key map (kbd "C") #'mastodon-tl--copy-toot-url) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 5ea4b715d022e5a4ccff47d4874ee171aa7af522 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 14 May 2021 12:00:25 +0200 Subject: display "follows you" and "followed by you" on user profiles --- lisp/mastodon-http.el | 4 +--- lisp/mastodon-profile.el | 45 ++++++++++++++++++++++++++++++++++++++------- lisp/mastodon.el | 3 ++- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index f26d808..3fe47c9 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -106,9 +106,7 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) (defun mastodon-http--delete (url) - "Make DELETE request to URL. - -Pass response buffer to CALLBACK function." + "Make DELETE request to URL." (let ((url-request-method "DELETE") (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index bd325c1..e0e209d 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -100,6 +100,15 @@ following the current profile." #'mastodon-profile--add-author-bylines) (error "Not in a mastodon profile"))) +(defun mastodon-profile--relationships-get (id) + "Fetch info about logged in user's relationship to user with id ID." + (interactive) + (let* ((their-id id) + (url (mastodon-http--api (format + "accounts/relationships?id[]=%s" + their-id)))) + (mastodon-http--get-json url))) + (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function) (let* ((id (mastodon-profile--account-field account 'id)) (url (mastodon-http--api (format "accounts/%s/%s" @@ -113,9 +122,20 @@ following the current profile." (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) (note (mastodon-profile--account-field account 'note)) (id (mastodon-profile--account-field account 'id)) - (fol_count (mastodon-tl--as-string (mastodon-profile--account-field account 'followers_count))) - (folling_count (mastodon-tl--as-string (mastodon-profile--account-field account 'following_count))) - (toots_count (mastodon-tl--as-string (mastodon-profile--account-field account 'statuses_count)))) + (followers-count (mastodon-tl--as-string + (mastodon-profile--account-field + account 'followers_count))) + (following-count (mastodon-tl--as-string + (mastodon-profile--account-field + account 'following_count))) + (toots-count (mastodon-tl--as-string + (mastodon-profile--account-field + account 'statuses_count))) + (followed-by-you (cdr (assoc 'following + (aref (mastodon-profile--relationships-get id) 0)))) + (follows-you (cdr (assoc 'followed_by + (aref (mastodon-profile--relationships-get id) 0)))) + (followsp (or (equal follows-you 't) (equal followed-by-you 't)))) (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (mastodon-mode) @@ -147,11 +167,20 @@ following the current profile." (mastodon-tl--render-text note nil) (mastodon-tl--set-face (concat " ------------\n" - " TOOTS: " toots_count " | " - "FOLLOWERS: " fol_count " | " - "FOLLOWING: " folling_count "\n" + " TOOTS: " toots-count " | " + "FOLLOWERS: " followers-count " | " + "FOLLOWING: " following-count "\n" " ------------\n\n") 'success) + (if followsp + (mastodon-tl--set-face + (concat (if (equal follows-you 't) + "FOLLOWS YOU | ") + (if (equal followed-by-you 't) + "FOLLOWED BY YOU | ") + "\n\n") + 'success) + "") ; if no followsp we still need str-or-char-p for insert (mastodon-tl--set-face (concat " ------------\n" endpoint-name "\n" @@ -163,7 +192,9 @@ following the current profile." (mastodon-tl--goto-next-toot))) (defun mastodon-profile--get-toot-author () - "Opens authors profile of toot under point." + "Open profile of author of toot under point. + +If toot is a boost, opens the profile of the booster." (interactive) (mastodon-profile--make-author-buffer (cdr (assoc 'account (mastodon-profile--toot-json))))) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index accbed8..6862e52 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -153,7 +153,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (defun mastodon () "Connect Mastodon client to `mastodon-instance-url' instance." (interactive) - (mastodon-tl--get-home-timeline)) + (mastodon-tl--get-home-timeline) + (message "Loading Mastodon account %s on %s..." (mastodon-auth--get-account-name) mastodon-instance-url)) ;;;###autoload (defun mastodon-toot (&optional user reply-to-id) -- cgit v1.2.3 From e5a8ca254300e20932786a1ecb4ceb3387ab84e5 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 15 May 2021 14:13:06 +0200 Subject: add basic display of "fields" (category pairs) on user profiles clean up fields mastodon-profile--fields-format --- lisp/mastodon-profile.el | 50 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index e0e209d..ec3dd0f 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -109,6 +109,41 @@ following the current profile." their-id)))) (mastodon-http--get-json url))) +(defun mastodon-profile--fields-get (account) + "Fetch the fields vector from a profile. + +Returns a list of lists." + (let ((fields (mastodon-profile--account-field account 'fields))) + (when fields + (mapcar + (lambda (el) + (list + (cdr (assoc 'name el)) + (cdr (assoc 'value el)))) + fields)))) + +(defun mastodon-profile--fields-insert (fields) + "Format and insert field pairs in FIELDS." + (let* ((car-fields (mapcar 'car fields)) + ;; (cdr-fields (mapcar 'cadr fields)) + ;; (cdr-fields-rendered + ;; (list + ;; (mapcar (lambda (x) + ;; (mastodon-tl--render-text x nil)) + ;; cdr-fields))) + (left-width (car (sort (mapcar 'length car-fields) '>)))) + ;; (right-width (car (sort (mapcar 'length cdr-fields) '>)))) + (mapconcat (lambda (field) + (mastodon-tl--render-text + (concat + (format "_ %s " (car field)) + (make-string (- (+ 1 left-width) (length (car field))) ?_) + (format " :: %s" (cadr field))) + ;; (make-string (- (+ 1 right-width) (length (cdr field))) ?_) + ;; " |") + nil)) + fields ""))) + (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function) (let* ((id (mastodon-profile--account-field account 'id)) (url (mastodon-http--api (format "accounts/%s/%s" @@ -135,7 +170,8 @@ following the current profile." (aref (mastodon-profile--relationships-get id) 0)))) (follows-you (cdr (assoc 'followed_by (aref (mastodon-profile--relationships-get id) 0)))) - (followsp (or (equal follows-you 't) (equal followed-by-you 't)))) + (followsp (or (equal follows-you 't) (equal followed-by-you 't))) + (fields (mastodon-profile--fields-get account))) (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (mastodon-mode) @@ -165,6 +201,14 @@ following the current profile." 'face 'default) "\n ------------\n" (mastodon-tl--render-text note nil) + (if fields + (progn + (concat "\n" + (mastodon-tl--set-face + (mastodon-profile--fields-insert fields) + 'success) + "\n")) + "") (mastodon-tl--set-face (concat " ------------\n" " TOOTS: " toots-count " | " @@ -175,9 +219,9 @@ following the current profile." (if followsp (mastodon-tl--set-face (concat (if (equal follows-you 't) - "FOLLOWS YOU | ") + " | FOLLOWS YOU") (if (equal followed-by-you 't) - "FOLLOWED BY YOU | ") + " | FOLLOWED BY YOU") "\n\n") 'success) "") ; if no followsp we still need str-or-char-p for insert -- cgit v1.2.3 From 508e3faeceb03ad14bb350d0da56552edf33ccc2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 16 May 2021 10:21:56 +0200 Subject: shrink width of shr-width in -tl--render-text. setting this to window-width minus 1 makes text flow work properly for me with proportional fonts enabled. --- 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 de64e1b..7624088 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -397,7 +397,7 @@ links in the text. If TOOT is nil no parsing occurs." (insert string) (let ((shr-use-fonts mastodon-tl--enable-proportional-fonts) (shr-width (when mastodon-tl--enable-proportional-fonts - (window-width)))) + (- (window-width) 1)))) (shr-render-region (point-min) (point-max))) ;; Make all links a tab stop recognized by our own logic, make things point ;; to our own logic (e.g. hashtags), and update keymaps where needed: -- cgit v1.2.3 From e1269b9fbf87013a9909cfced340fa47f43dc33a Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 16 May 2021 13:05:26 +0200 Subject: display pinned toots first on a user's profile. also: profile--relationships-get no longer interactive. and docstrings for fields insert. indent "pinned" for pinned toots display --- lisp/mastodon-profile.el | 7 +++---- lisp/mastodon-tl.el | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index ec3dd0f..11ad02e 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -101,8 +101,7 @@ following the current profile." (error "Not in a mastodon profile"))) (defun mastodon-profile--relationships-get (id) - "Fetch info about logged in user's relationship to user with id ID." - (interactive) + "Fetch info about logged-in user's relationship to user with id ID." (let* ((their-id id) (url (mastodon-http--api (format "accounts/relationships?id[]=%s" @@ -110,7 +109,7 @@ following the current profile." (mastodon-http--get-json url))) (defun mastodon-profile--fields-get (account) - "Fetch the fields vector from a profile. + "Fetch the fields vector (a.k.a profile metadata) from a profile. Returns a list of lists." (let ((fields (mastodon-profile--account-field account 'fields))) @@ -123,7 +122,7 @@ Returns a list of lists." fields)))) (defun mastodon-profile--fields-insert (fields) - "Format and insert field pairs in FIELDS." + "Format and insert field pairs (a.k.a profile metadata) in FIELDS." (let* ((car-fields (mapcar 'car fields)) ;; (cdr-fields (mapcar 'cadr fields)) ;; (cdr-fields-rendered diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 7624088..8ac9d9c 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -673,9 +673,23 @@ it is `mastodon-tl--byline-boosted'" 'mastodon-tl--byline-boosted)) (defun mastodon-tl--timeline (toots) - "Display each toot in TOOTS." - (mapc 'mastodon-tl--toot toots) - (goto-char (point-min))) + "Display each toot in TOOTS. + +If any toots are pinned, display them first." + (let* ((pinned-list)) + (mapcar (lambda (toot) + (when (equal (cdr (assoc 'pinned toot)) 't) + (push toot pinned-list))) + toots) + (when pinned-list + (progn + (insert (mastodon-tl--set-face + " :pinned: " 'success)) + (mapc 'mastodon-tl--toot pinned-list) + (insert (mastodon-tl--set-face + " :end-pinned: \n" 'success)))) + (mapc 'mastodon-tl--toot toots) + (goto-char (point-min)))) (defun mastodon-tl--get-update-function (&optional buffer) "Get the UPDATE-FUNCTION stored in `mastodon-tl--buffer-spec'" -- cgit v1.2.3 From a34f569583ead91893468c4080502b1a89d23988 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 16 May 2021 14:43:34 +0200 Subject: clean-up edits after flycheck/bytecompile. --- lisp/mastodon-http.el | 5 +++-- lisp/mastodon-profile.el | 4 ++-- lisp/mastodon-search.el | 47 ++++++++++++++++++++++++++++++++++++----------- lisp/mastodon-tl.el | 13 ++++++------- lisp/mastodon-toot.el | 2 +- 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 3fe47c9..58f6c7e 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -115,11 +115,12 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url)))) (defun mastodon-http--get-json (url) - "Make GET request to URL. Return JSON response" + "Make GET request to URL. Return JSON response." (with-current-buffer (mastodon-http--get url) (mastodon-http--process-json))) (defun mastodon-http--process-json () + "Process JSON response." (goto-char (point-min)) (re-search-forward "^$" nil 'move) (let ((json-string @@ -134,7 +135,7 @@ Pass response buffer to CALLBACK function." (defun mastodon-http--get-async (url &optional callback &rest cbargs) "Make GET request to URL. -Pass response buffer to CALLBACK function." +Pass response buffer to CALLBACK function with args CBARGS." (let ((url-request-method "GET") (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 11ad02e..f14b469 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -109,7 +109,7 @@ following the current profile." (mastodon-http--get-json url))) (defun mastodon-profile--fields-get (account) - "Fetch the fields vector (a.k.a profile metadata) from a profile. + "Fetch the fields vector (aka profile metadata) from profile of ACCOUNT. Returns a list of lists." (let ((fields (mastodon-profile--account-field account 'fields))) @@ -249,7 +249,7 @@ If toot is a boost, opens the profile of the booster." (mastodon-media--get-media-link-rendering url)))) (defun mastodon-profile--show-user (user-handle) - "Query user for user id from current status and show that user's profile." + "Query user for USER-HANDLE from current status and show that user's profile." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 5c381fa..7b1dfb1 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -1,19 +1,43 @@ ;;; mastodon-search.el --- serach functions for mastodon.el -*- lexical-binding: t -*- -;; search functions: +;; Copyright (C) 2017-2019 Johnson Denen +;; Author: Johnson Denen +;; Version: 0.9.0 +;; Homepage: https://github.com/jdenen/mastodon.el +;; Package-Requires: ((emacs "24.4")) -;; autoloads? +;; This file is not part of GNU Emacs. +;; This file is part of mastodon.el. + +;; mastodon.el is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mastodon.el is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mastodon.el. If not, see . + +;;; Commentary: + +;; A basic search function for mastodon.el + +;;; Code: + +;; autoloads ;; mastodon-tl--as-string ;; mastodon-tl--set-face ;; mastodon-tl--render-text ;; mastodon-tl--toot -;; mastodon-http--get-json +(autoload 'mastodon-http--get-json "mastodon-http") ;; mastodon-instance-url -;; code - (defun mastodon-search--search-query (query) "Prompt for a search QUERY and return accounts, statuses, and hashtags." (interactive "sSearch mastodon for: ") @@ -43,13 +67,13 @@ " STATUSES" "\n" " ------------\n") 'success)) - (mapcar 'mastodon-tl--toot toots-list-json) + (mapc 'mastodon-tl--toot toots-list-json) (insert (mastodon-tl--set-face (concat "\n ------------\n" " USERS" "\n" " ------------\n") 'success)) - (mapcar (lambda (el) + (mapc (lambda (el) (dolist (item el) (insert (mastodon-tl--render-text item nil) "")) (insert "----\n\n")) @@ -65,7 +89,7 @@ " HASHTAGS" "\n" " ------------\n") 'success)) - (mapcar (lambda (el) + (mapc (lambda (el) (dolist (item el) (insert (mastodon-tl--render-text item nil) "")) (insert "----\n\n")) @@ -113,6 +137,7 @@ This allows us to access the full account etc. details and to render them proper ;; http functions for search: (defun mastodon-http--process-json-search () + "Process JSON returned by a search query to the server." (goto-char (point-min)) (re-search-forward "^$" nil 'move) (let ((json-string @@ -123,13 +148,13 @@ This allows us to access the full account etc. details and to render them proper (json-read-from-string json-string))) (defun mastodon-http--get-search-json (url query) - "Make GET request to URL. Return JSON response" + "Make GET request to URL, searching for QUERY and return JSON response." (let ((buffer (mastodon-http--get-search url query))) (with-current-buffer buffer (mastodon-http--process-json-search)))) (defun mastodon-http--get-search (base-url query) - "Make GET request to URL. + "Make GET request to BASE-URL, searching for QUERY. Pass response buffer to CALLBACK function." (let ((url-request-method "GET") @@ -142,4 +167,4 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) (provide 'mastodon-search) -;; mastodon-search.el ends here +;;; mastodon-search.el ends here diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 8ac9d9c..435938e 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -677,7 +677,7 @@ it is `mastodon-tl--byline-boosted'" If any toots are pinned, display them first." (let* ((pinned-list)) - (mapcar (lambda (toot) + (mapc (lambda (toot) (when (equal (cdr (assoc 'pinned toot)) 't) (push toot pinned-list))) toots) @@ -845,7 +845,7 @@ webapp" (message "Toot deleted! There may be a delay before it disappears from your profile."))))))) (defun mastodon-tl--follow-user (user-handle) - "Query for user id from current status and follow that user." + "Query for USER-HANDLE from current status and follow that user." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles @@ -867,7 +867,7 @@ webapp" (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--unfollow-user (user-handle) - "Query for user id from current status and unfollow that user." + "Query for USER-HANDLE from current status and unfollow that user." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles @@ -890,7 +890,7 @@ webapp" (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--mute-user (user-handle) - "Query for user id from current status and mute that user." + "Query for USER-HANDLE from current status and mute that user." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles @@ -962,7 +962,7 @@ webapp" (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--unblock-user (user-handle) - "Query for user from list of blocked users and unblock that user." + "Query for USER-HANDLE from list of blocked users and unblock that user." (interactive (list (let* ((blocks-url (mastodon-http--api (format "blocks"))) @@ -1043,8 +1043,7 @@ before (non-nil) or after (nil)" Returns nil if no such range exists. If SEARCH-BACKWARDS is non-nil it find a region before -START-POINT otherwise after START-POINT. -" +START-POINT otherwise after START-POINT." (if (get-text-property start-point property) ;; We are within a range, we need to start the search from ;; before/after this range: diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 4e57158..52af778 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -224,7 +224,7 @@ Mastodon requires the full user@domain, even in the case of local accts. eg. \"user\" -> \"user@local.social \" (when local.social is the domain of the mastodon-instance-url). eg. \"yourusername\" -> \"\" -eg. \"feduser@fed.social\" -> \"feduser@fed.social\" " +eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (cond ((string-match-p "@" acct) (concat "@" acct " ")) ; federated acct ((string= (mastodon-auth--user-acct) acct) "") ; your acct (t (concat "@" acct "@" ; local acct -- cgit v1.2.3 From a52f25ce26cd6a9fe8d88d893eb8500ad1292677 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 16 May 2021 15:26:35 +0200 Subject: add new functions to discover menu, and autoloads. --- lisp/mastodon-discover.el | 30 ++++++++++++++++++++++-------- lisp/mastodon-tl.el | 1 + lisp/mastodon.el | 9 +++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index a99ddc2..862eb8f 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -44,25 +44,39 @@ (description "Mastodon feed viewer") (actions ("Toots" - ("A" "Author" mastodon-profile--get-toot-author) + ("A" "View profile of author" mastodon-profile--get-toot-author) ("b" "Boost" mastodon-toot--boost) - ("c" "Toggle content" mastodon-tl--toggle-spoiler-text-in-toot) ("f" "Favourite" mastodon-toot--favourite) + ("c" "Toggle hidden text" mastodon-tl--toggle-spoiler-text-in-toot) ("n" "Next" mastodon-tl--goto-next-toot) ("p" "Prev" mastodon-tl--goto-prev-toot) - ("t" "Toot" mastodon-toot) + ("t" "New toot" mastodon-toot) ("r" "Reply" mastodon-toot--reply) - ("u" "Update" mastodon-tl--update) - ("P" "Users" mastodon-profile--show-user) - ("T" "Thread" mastodon-tl--thread)) + ("C" "Copy toot URL" mastodon-tl--copy-toot-url) + ("d" "Delete (your) toot" mastodon-tl--delete-toot) + ("P" "View user profile" mastodon-profile--show-user) + ("T" "View thread" mastodon-tl--thread)) ("Timelines" ("#" "Tag" mastodon-tl--get-tag-timeline) ("F" "Federated" mastodon-tl--get-federated-timeline) ("H" "Home" mastodon-tl--get-home-timeline) ("L" "Local" mastodon-tl--get-local-timeline) - ("N" "Notifications" mastodon-notifications--get)) + ("N" "Notifications" mastodon-notifications--get) + ("u" "Update timeline" mastodon-tl--update) + ("S" "Search" mastodon-search--search-query) + ("C-S-P" "Jump to my profile" mastodon-profile--my-profile)) + ("Users" + ("W" "Follow" mastodon-tl--follow-user) + ("C-S-W" "Unfollow" mastodon-tl--unfollow-user) + ("M" "Mute" mastodon-tl--mute-user) + ("C-S-M" "Unmute" mastodon-tl--unmute-user) + ("B" "Block" mastodon-tl--block-user) + ("C-S-B" "Unblock" mastodon-tl--unblock-user)) + ("Profile view" + ("o" "Show following" mastodon-profile--open-following) + ("O" "Show followers" mastodon-profile--open-followers)) ("Quit" - ("q" "Quit mastodon buffer. Leave window open." kill-this-buffer) + ("q" "Quit mastodon and bury buffer." kill-this-buffer) ("Q" "Quit mastodon buffer and kill window." kill-buffer-and-window))))))) (provide 'mastodon-discover) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 435938e..2c9c080 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -46,6 +46,7 @@ (autoload 'mastodon-profile--toot-json "mastodon-profile.el") (autoload 'mastodon-profile--account-field "mastodon-profile.el") (autoload 'mastodon-profile--extract-users-handles "mastodon-profile.el") +(autoload 'mastodon-profile--my-profile "mastodon-profile.el") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 6862e52..878ddbf 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -53,8 +53,17 @@ (autoload 'mastodon-toot--toggle-boost "mastodon-toot") (autoload 'mastodon-toot--toggle-favourite "mastodon-toot") (autoload 'mastodon-discover "mastodon-discover") +(autoload 'mastodon-tl--block-user "mastodon-tl") +(autoload 'mastodon-tl--unblock-user "mastodon-tl") +(autoload 'mastodon-tl--mute-user "mastodon-tl") +(autoload 'mastodon-tl--unmute-user "mastodon-tl") +(autoload 'mastodon-tl--delete-toot "mastodon-tl") +(autoload 'mastodon-tl--follow-user "mastodon-tl") +(autoload 'mastodon-tl--unfollow-user "mastodon-tl") +(autoload 'mastodon-profile--my-profile "mastodon-profile") (autoload 'mastodon-search--search-query "mastodon-search") (autoload 'mastodon-tl--copy-toot-url "mastodon-tl") +(autoload 'mastodon-auth--get-account-name "mastodon-auth") (defgroup mastodon nil "Interface with Mastodon." -- cgit v1.2.3 From ab98f3b435e05a0421c297c8f47aa1239b7a4886 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 17 May 2021 17:17:36 +0200 Subject: split mastodon-tl--timeline back into two functions. this is to prevent pinned toots appearing as such when this function is used elsewhere than for a profile. e.g. the tag search. --- lisp/mastodon-profile.el | 4 ++-- lisp/mastodon-tl.el | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index f14b469..6f83709 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -76,7 +76,7 @@ extra keybindings." (defun mastodon-profile--make-author-buffer (account) "Take a ACCOUNT and inserts a user account into a new buffer." (mastodon-profile--make-profile-buffer-for - account "statuses" #'mastodon-tl--timeline)) + account "statuses" #'mastodon-tl--timeline-pinned)) (defun mastodon-profile--open-following () "Open a profile buffer for the current profile showing the accounts @@ -254,7 +254,7 @@ If toot is a boost, opens the profile of the booster." (list (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read "View profile of user: " + (completing-read "View profile of user [choose or enter any handle]: " user-handles nil ; predicate 'confirm)))) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 2c9c080..e186bd5 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -674,10 +674,15 @@ it is `mastodon-tl--byline-boosted'" 'mastodon-tl--byline-boosted)) (defun mastodon-tl--timeline (toots) + "Display each toot in TOOTS." + (mapc 'mastodon-tl--toot toots) + (goto-char (point-min))) + +(defun mastodon-tl--timeline-pinned (toots) "Display each toot in TOOTS. If any toots are pinned, display them first." - (let* ((pinned-list)) + (let ((pinned-list)) (mapc (lambda (toot) (when (equal (cdr (assoc 'pinned toot)) 't) (push toot pinned-list))) -- cgit v1.2.3 From 71b2929bdc63a09889d462495acf49c459b67490 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 17 May 2021 20:05:14 +0200 Subject: message for notifs load, tiny search.el cleanup --- lisp/mastodon-notifications.el | 3 ++- lisp/mastodon-search.el | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 4d68437..68f73c6 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -143,7 +143,8 @@ (mastodon-tl--init "*mastodon-notifications*" "notifications" - 'mastodon-notifications--timeline)) + 'mastodon-notifications--timeline) + (message "Loading your nofications...")) (provide 'mastodon-notifications) ;;; mastodon-notifications.el ends here diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 7b1dfb1..6737e11 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -1,7 +1,7 @@ -;;; mastodon-search.el --- serach functions for mastodon.el -*- lexical-binding: t -*- +;;; mastodon-search.el --- search functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen -;; Author: Johnson Denen +;; Author: Johnson Denen , martyhiatt ;; Version: 0.9.0 ;; Homepage: https://github.com/jdenen/mastodon.el ;; Package-Requires: ((emacs "24.4")) @@ -28,15 +28,18 @@ ;; A basic search function for mastodon.el ;;; Code: +(require 'json) -;; autoloads -;; mastodon-tl--as-string -;; mastodon-tl--set-face -;; mastodon-tl--render-text -;; mastodon-tl--toot (autoload 'mastodon-http--get-json "mastodon-http") +(autoload 'mastodon-tl--as-string "mastodon-tl") +(autoload 'mastodon-mode "mastodon") +(autoload 'mastodon-tl--set-face "mastodon-tl") +(autoload 'mastodon-tl--render-text "mastodon-tl") +(autoload 'mastodon-tl--as-string "mastodon-tl") +(autoload 'mastodon-auth--access-token "mastodon-auth") -;; mastodon-instance-url +(defvar mastodon-instance-url) +(defconst mastodon-http--timeout) (defun mastodon-search--search-query (query) "Prompt for a search QUERY and return accounts, statuses, and hashtags." @@ -51,8 +54,8 @@ accts)) ; returns a list of three-item lists (tags-list (mapcar #'mastodon-search--get-hashtag-info tags)) - (status-list (mapcar #'mastodon-search--get-status-info - statuses)) + ;; (status-list (mapcar #'mastodon-search--get-status-info + ;; statuses)) (status-ids-list (mapcar 'mastodon-search--get-id-from-status statuses)) (toots-list-json (mapcar #'mastodon-search--fetch-full-status-from-id @@ -135,7 +138,6 @@ This allows us to access the full account etc. details and to render them proper json)) ;; http functions for search: - (defun mastodon-http--process-json-search () "Process JSON returned by a search query to the server." (goto-char (point-min)) -- cgit v1.2.3 From 4e4a0621c4949d321e5d47ba4afc139fb92dc6ef Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 17 May 2021 22:14:12 +0200 Subject: enable live, propertized handle links and tags in search --- lisp/mastodon-search.el | 70 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 6737e11..5a98b26 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -39,7 +39,7 @@ (autoload 'mastodon-auth--access-token "mastodon-auth") (defvar mastodon-instance-url) -(defconst mastodon-http--timeout) +(defconst mastodon-http--timeout 5) (defun mastodon-search--search-query (query) "Prompt for a search QUERY and return accounts, statuses, and hashtags." @@ -64,46 +64,50 @@ (switch-to-buffer buffer) (erase-buffer) (mastodon-mode) - (setq-local inhibit-read-only t) + (let ((inhibit-read-only t)) + ;; user results: + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " USERS\n" + " ------------\n\n") + 'success)) + (mapc (lambda (el) + (insert (propertize (car el) 'face 'mastodon-display-name-face) + " : \n : " + (propertize (concat "@" (car (cdr el))) + 'face 'mastodon-handle-face + 'mouse-face 'highlight + 'mastodon-tab-stop 'user-handle + 'keymap mastodon-tl--link-keymap + 'mastodon-handle (concat "@" (car (cdr el))) + 'help-echo (concat "Browse user profile of @" (car (cdr el)))) + " : \n" + "\n")) + user-ids) + ;; hashtag results: (insert (mastodon-tl--set-face (concat "\n ------------\n" - " STATUSES" "\n" - " ------------\n") - 'success)) - (mapc 'mastodon-tl--toot toots-list-json) - (insert (mastodon-tl--set-face - (concat "\n ------------\n" - " USERS" "\n" - " ------------\n") + " HASHTAGS\n" + " ------------\n\n") 'success)) (mapc (lambda (el) - (dolist (item el) - (insert (mastodon-tl--render-text item nil) "")) - (insert "----\n\n")) - ;; (insert (mastodon-tl--render-text (car el) nil) - ;; " : " - ;; (mastodon-tl--render-text (car (cdr el)) nil) - ;; " : " - ;; (mastodon-tl--render-text (car (cdr (cdr el))) nil) - ;; "\n")) - user-ids) + (insert " : #" + (propertize (car el) + 'mouse-face 'highlight + 'mastodon-tag (car el) + 'mastodon-tab-stop 'hashtag + 'help-echo (concat "Browse tag #" (car el)) + 'keymap mastodon-tl--link-keymap) + " : \n\n")) + tags-list) + ;; status results: (insert (mastodon-tl--set-face (concat "\n ------------\n" - " HASHTAGS" "\n" + " STATUSES\n" " ------------\n") 'success)) - (mapc (lambda (el) - (dolist (item el) - (insert (mastodon-tl--render-text item nil) "")) - (insert "----\n\n")) - ;; (seq-do 'insert el)) - ;; (insert (mastodon-tl--render-text (car el) nil) - ;; " : " - ;; (mastodon-tl--render-text (car (cdr el)) nil) - ;; "\n")) - tags-list) - (goto-char (point-min)) - ))) + (mapc 'mastodon-tl--toot toots-list-json) + (goto-char (point-min)))))) (defun mastodon-search--get-user-info (account) "Get user handle, display name and account URL from ACCOUNT." -- cgit v1.2.3 From 75671c421794e53d11be26a963aab332b0586072 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 18 May 2021 14:14:57 +0200 Subject: autoloads in profile.el --- lisp/mastodon-profile.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 6f83709..8c1432b 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -36,6 +36,8 @@ (autoload 'mastodon-http--api "mastodon-http.el") (autoload 'mastodon-http--get-json "mastodon-http.el") +(autoload 'mastodon-auth--get-account-name "mastodon-auth.el") +(autoload 'mastodon-http--get-json-async "mastodon-http.el") (autoload 'mastodon-media--get-media-link-rendering "mastodon-media.el") (autoload 'mastodon-media--inline-images "mastodon-media.el") (autoload 'mastodon-mode "mastodon.el") @@ -45,6 +47,8 @@ (autoload 'mastodon-tl--render-text "mastodon-tl.el") (autoload 'mastodon-tl--set-face "mastodon-tl.el") (autoload 'mastodon-tl--timeline "mastodon-tl.el") +(autoload 'mastodon-tl--as-string "mastodon-tl.el") +(autoload 'mastodon-tl--timeline-pinned "mastodon-tl.el") (autoload 'mastodon-tl--toot-id "mastodon-tl") (defvar mastodon-instance-url) -- cgit v1.2.3 From 7dca8a210a1802fb9068a4951d9c0e851738d1c1 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 19 May 2021 12:02:32 +0200 Subject: fix propertizing of "B" for boost in byline --- 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 e186bd5..4e0c031 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -369,7 +369,7 @@ it is `mastodon-tl--byline-boosted'" (propertize (concat (when boosted (format "(%s) " - (propertize "B" 'face 'mastodon-boost-face))) + (propertize "B" 'face 'mastodon-boost-fave-face))) (when faved (format "(%s) " (propertize "F" 'face 'mastodon-boost-fave-face))) -- cgit v1.2.3 From 61110d230b6e9aa692d75c1bec436fe947fad3a8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 19 May 2021 14:18:15 +0200 Subject: make the boosts/favorite byline text in notifications less ambiguous --- lisp/mastodon-notifications.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 68f73c6..d6fa78f 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -51,8 +51,8 @@ (defvar mastodon-notifications--response-alist '(("Mentioned" . "you") ("Followed" . "you") - ("Favourited" . "your status") - ("Boosted" . "your status")) + ("Favourited" . "your status from") + ("Boosted" . "your status from")) "Alist of subjects for notification types.") (defun mastodon-notifications--byline-concat (message) -- cgit v1.2.3 From 837d50d68c523c9f197436b86b9d681ed7f59831 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 19 May 2021 23:15:11 +0200 Subject: pinned toots implemented properly, make-buffer-for revert to synchro better pinned toots formatting --- lisp/mastodon-profile.el | 38 ++++++++++++++++++++++++++------------ lisp/mastodon-tl.el | 19 ------------------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 8c1432b..16ef981 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -48,7 +48,6 @@ (autoload 'mastodon-tl--set-face "mastodon-tl.el") (autoload 'mastodon-tl--timeline "mastodon-tl.el") (autoload 'mastodon-tl--as-string "mastodon-tl.el") -(autoload 'mastodon-tl--timeline-pinned "mastodon-tl.el") (autoload 'mastodon-tl--toot-id "mastodon-tl") (defvar mastodon-instance-url) @@ -80,7 +79,7 @@ extra keybindings." (defun mastodon-profile--make-author-buffer (account) "Take a ACCOUNT and inserts a user account into a new buffer." (mastodon-profile--make-profile-buffer-for - account "statuses" #'mastodon-tl--timeline-pinned)) + account "statuses" #'mastodon-tl--timeline)) (defun mastodon-profile--open-following () "Open a profile buffer for the current profile showing the accounts @@ -147,19 +146,27 @@ Returns a list of lists." nil)) fields ""))) +(defun mastodon-profile--get-statuses-pinned (account) + "Fetch the pinned toots for ACCOUNT." + (let* ((id (mastodon-profile--account-field account 'id)) + (url (mastodon-http--api (format "accounts/%s/statuses?pinned=true" id)))) + (mastodon-http--get-json url))) + +(defun mastodon-profile--insert-statuses-pinned (pinned-statuses) + "Insert each of the PINNED_STATUSES for a given account." + (mapc (lambda (pinned-status) + (insert (mastodon-tl--set-face + " :pinned: " 'success)) + (mastodon-tl--toot pinned-status)) + pinned-statuses)) + (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function) (let* ((id (mastodon-profile--account-field account 'id)) - (url (mastodon-http--api (format "accounts/%s/%s" - id endpoint-type)))) - (mastodon-http--get-json-async url - 'mastodon-profile--make-profile-buffer-for* - account endpoint-type update-function))) - -(defun mastodon-profile--make-profile-buffer-for* (json account endpoint-type update-function) - (let* ((acct (mastodon-profile--account-field account 'acct)) + (url (mastodon-http--api (format "accounts/%s/%s" id endpoint-type))) + (acct (mastodon-profile--account-field account 'acct)) (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) (note (mastodon-profile--account-field account 'note)) - (id (mastodon-profile--account-field account 'id)) + (json (mastodon-http--get-json url)) (followers-count (mastodon-tl--as-string (mastodon-profile--account-field account 'followers_count))) @@ -174,7 +181,8 @@ Returns a list of lists." (follows-you (cdr (assoc 'followed_by (aref (mastodon-profile--relationships-get id) 0)))) (followsp (or (equal follows-you 't) (equal followed-by-you 't))) - (fields (mastodon-profile--fields-get account))) + (fields (mastodon-profile--fields-get account)) + (pinned (mastodon-profile--get-statuses-pinned account))) (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (mastodon-mode) @@ -212,6 +220,7 @@ Returns a list of lists." 'success) "\n")) "") + ;; insert counts (mastodon-tl--set-face (concat " ------------\n" " TOOTS: " toots-count " | " @@ -219,6 +228,7 @@ Returns a list of lists." "FOLLOWING: " following-count "\n" " ------------\n\n") 'success) + ;; insert relationship (follows) (if followsp (mastodon-tl--set-face (concat (if (equal follows-you 't) @@ -228,6 +238,7 @@ Returns a list of lists." "\n\n") 'success) "") ; if no followsp we still need str-or-char-p for insert + ;; insert endpoint (mastodon-tl--set-face (concat " ------------\n" endpoint-name "\n" @@ -235,6 +246,9 @@ Returns a list of lists." 'success)) (setq mastodon-tl--update-point (point)) (mastodon-media--inline-images (point-min) (point)) + ;; insert pinned toots first + (if pinned + (mastodon-profile--insert-statuses-pinned pinned)) (funcall update-function json))) (mastodon-tl--goto-next-toot))) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 4e0c031..4931913 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -678,25 +678,6 @@ it is `mastodon-tl--byline-boosted'" (mapc 'mastodon-tl--toot toots) (goto-char (point-min))) -(defun mastodon-tl--timeline-pinned (toots) - "Display each toot in TOOTS. - -If any toots are pinned, display them first." - (let ((pinned-list)) - (mapc (lambda (toot) - (when (equal (cdr (assoc 'pinned toot)) 't) - (push toot pinned-list))) - toots) - (when pinned-list - (progn - (insert (mastodon-tl--set-face - " :pinned: " 'success)) - (mapc 'mastodon-tl--toot pinned-list) - (insert (mastodon-tl--set-face - " :end-pinned: \n" 'success)))) - (mapc 'mastodon-tl--toot toots) - (goto-char (point-min)))) - (defun mastodon-tl--get-update-function (&optional buffer) "Get the UPDATE-FUNCTION stored in `mastodon-tl--buffer-spec'" (mastodon-tl--get-buffer-property 'update-function buffer)) -- cgit v1.2.3 From 841bf851ed49389a38007ca02257ba780972e48b Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 20 May 2021 10:28:36 +0200 Subject: enable tab-stops for links/handles/hashtags in profile note. --- 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 16ef981..9d4793c 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -211,7 +211,8 @@ Returns a list of lists." (propertize acct 'face 'default) "\n ------------\n" - (mastodon-tl--render-text note nil) + (mastodon-tl--render-text note account) + ; account here to enable tab-stops in profile note (if fields (progn (concat "\n" -- cgit v1.2.3 From 6d675413823b267c76b67dfdcffee11c3a1bf173 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 20 May 2021 16:27:56 +0200 Subject: Implement clickable images with shr-browse-image. images are tab stops. click or RET runs shr-browse-image. a prefix arg copies the URL. images use the mastodon-tl--shr-image-map-replacement for extra functions like zoom image, save image, rotate image, etc. --- lisp/mastodon-discover.el | 8 ++++++++ lisp/mastodon-media.el | 10 ++++++++-- lisp/mastodon-tl.el | 14 ++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 862eb8f..9e1cbad 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -50,6 +50,8 @@ ("c" "Toggle hidden text" mastodon-tl--toggle-spoiler-text-in-toot) ("n" "Next" mastodon-tl--goto-next-toot) ("p" "Prev" mastodon-tl--goto-prev-toot) + ("TAB" "Next link item" mastodon-tl--next-tab-item) + ("S-TAB" "Prev link item" mastodon-tl--previous-tab-item) ("t" "New toot" mastodon-toot) ("r" "Reply" mastodon-toot--reply) ("C" "Copy toot URL" mastodon-tl--copy-toot-url) @@ -72,6 +74,12 @@ ("C-S-M" "Unmute" mastodon-tl--unmute-user) ("B" "Block" mastodon-tl--block-user) ("C-S-B" "Unblock" mastodon-tl--unblock-user)) + ("Images" + ("RET/i" "Load full image in browser" 'shr-browse-image) + ("r" "rotate" 'image-rotate) + ("+" "zoom in" 'image-increase-size) + ("-" "zoom out" 'image-decrease-size) + ("u" "copy URL" 'shr-maybe-probe-and-copy-url)) ("Profile view" ("o" "Show following" mastodon-profile--open-following) ("O" "Show followers" mastodon-profile--open-followers)) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 7a11660..6837f9b 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -262,14 +262,20 @@ replacing them with the referenced image." t image-options)) " "))) -(defun mastodon-media--get-media-link-rendering (media-url) +(defun mastodon-media--get-media-link-rendering (media-url &optional full-remote-url) "Returns the string to be written that renders the image at MEDIA-URL." (concat (propertize "[img]" 'media-url media-url 'media-state 'needs-loading 'media-type 'media-link - 'display (create-image mastodon-media--generic-broken-image-data nil t)) + 'display (create-image mastodon-media--generic-broken-image-data nil t) + 'mouse-face 'highlight + 'mastodon-tab-stop 'image ; for do-link-action-at-point + 'image-url full-remote-url ; for shr-browse-image + 'keymap mastodon-tl--shr-image-map-replacement + 'help-echo (concat "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview") + ) " ")) (provide 'mastodon-media) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 4931913..da2e418 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -130,6 +130,9 @@ types of mastodon links and not just shr.el-generated ones.") ;; version that knows about more types of links. (define-key map [remap shr-next-link] 'mastodon-tl--next-tab-item) (define-key map [remap shr-previous-link] 'mastodon-tl--previous-tab-item) + ;; browse-url loads the preview only, we want browse-image + ;; on RET to browse full sized image URL + (define-key map [remap shr-browse-url] 'shr-browse-image) (keymap-canonicalize map)) "The keymap to be set for shr.el generated image links. @@ -551,6 +554,7 @@ LINK-TYPE is the type of link to produce." 'help-echo help-text))) (defun mastodon-tl--do-link-action-at-point (position) + ;; called by RET (interactive "d") (let ((link-type (get-text-property position 'mastodon-tab-stop))) (cond ((eq link-type 'content-warning) @@ -575,6 +579,7 @@ LINK-TYPE is the type of link to produce." (error "unknown link type %s" link-type))))) (defun mastodon-tl--do-link-action (event) + ;; called by mouse click (interactive "e") (mastodon-tl--do-link-action-at-point (posn-point (event-end event)))) @@ -603,7 +608,7 @@ message is a link which unhides/hides the main body." (message (concat ;"\n" " ---------------\n" " " (mastodon-tl--make-link - (concat "CW: " string) ;"Content Warning" + (concat "CW: " string) 'content-warning) "\n" " ---------------\n")) @@ -620,10 +625,12 @@ message is a link which unhides/hides the main body." (media-string (mapconcat (lambda (media-attachement) (let ((preview-url - (cdr (assoc 'preview_url media-attachement)))) + (cdr (assoc 'preview_url media-attachement))) + (remote-url + (cdr (assoc 'remote_url media-attachement)))) (if mastodon-tl--display-media-p (mastodon-media--get-media-link-rendering - preview-url) + preview-url remote-url) ; 2nd arg for shr-browse-url (concat "Media::" preview-url "\n")))) media-attachements ""))) (if (not (and mastodon-tl--display-media-p @@ -631,7 +638,6 @@ message is a link which unhides/hides the main body." (concat "\n" media-string) ""))) - (defun mastodon-tl--content (toot) "Retrieve text content from TOOT." (let ((content (mastodon-tl--field 'content toot))) -- cgit v1.2.3 From 7aaf7a1b6c62d4dca3f0b5588ce20452060bb354 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 24 May 2021 09:28:35 +0200 Subject: implement uploading and posting of media attachments. uses request library and requires curl backend. supports multiple files upload and marking media as sensitive. --- lisp/mastodon-http.el | 42 ++++++++++++++++++++++ lisp/mastodon-toot.el | 98 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 115 insertions(+), 25 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 58f6c7e..7250ef8 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -30,6 +30,7 @@ ;;; Code: (require 'json) +(require 'request) ; for attachments upload (defvar mastodon-instance-url) (autoload 'mastodon-auth--access-token "mastodon-auth") @@ -154,6 +155,7 @@ Pass response buffer to CALLBACK function with args CBARGS." Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (let ((url-request-method "POST") + (request-timeout 5) (url-request-data (when args (mapconcat (lambda (arg) @@ -168,5 +170,45 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (with-temp-buffer (url-retrieve url callback cbargs mastodon-http--timeout)))) +;; TODO: test for curl first? +(defun mastodon-http--post-media-attachment (url filename caption) + "Make a POST request to upload file FILENAME with CAPTION to the server's media URL. + +The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, `mastodon-toot--media-attachments' is set to t, and `mastodon-toot--update-status-fields' is run." + (let* ((file (file-name-nondirectory filename)) + (request-backend 'curl) + (response + (request + url + :type "POST" + :params `(("description" . ,caption)) + :files `(("file" . (,file :file ,filename + :mime-type "multipart/form-data"))) + :parser 'json-read + :headers `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))) + :sync nil + :success (cl-function + (lambda (&key data &allow-other-keys) + (when data + (progn + (push (cdr (assoc 'id data)) + mastodon-toot--media-attachment-ids) ; add ID to list + (push file mastodon-toot--media-attachment-filenames) + (message "%s file %s with id %S and caption '%s' uploaded!" + (capitalize (cdr (assoc 'type data))) + file + (cdr (assoc 'id data)) + (cdr (assoc 'description data))) + (mastodon-toot--update-status-fields))))) + :error (cl-function + (lambda (&key error-thrown &allow-other-keys) + (message "Got error: %s" error-thrown))) + ))) + (pcase (request-response-status-code response) + (200 + (request-response-data response) + )))) + (provide 'mastodon-http) ;;; mastodon-http.el ends here diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 52af778..a11bfa0 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -73,6 +73,18 @@ Must be one of \"public\", \"unlisted\", \"private\", or \"direct\"." Valid values are \"direct\", \"private\", \"unlisted\", and \"public\".") (make-variable-buffer-local 'mastodon-toot--visibility) +(defvar mastodon-toot--media-attachments nil + "A flag indicating if the toot being composed has media attachments.") +(make-variable-buffer-local 'mastodon-toot--media-attachments) + +(defvar mastodon-toot--media-attachment-ids nil + "A list of any media attachment ids of the toot being composed.") +(make-variable-buffer-local 'mastodon-toot--media-attachment-ids) + +(defvar mastodon-toot--media-attachment-filenames nil + "A list of any media attachment filenames of the toot being composed.") +(make-variable-buffer-local 'mastodon-toot--media-attachment-filenames) + (defvar mastodon-toot--reply-to-id nil "Buffer-local variable to hold the id of the toot being replied to.") (make-variable-buffer-local 'mastodon-toot--reply-to-id) @@ -82,8 +94,9 @@ Valid values are \"direct\", \"private\", \"unlisted\", and \"public\".") (define-key map (kbd "C-c C-c") #'mastodon-toot--send) (define-key map (kbd "C-c C-k") #'mastodon-toot--cancel) (define-key map (kbd "C-c C-w") #'mastodon-toot--toggle-warning) - ;;(define-key map (kbd "C-c C-n") #'mastodon-toot--toggle-nsfw) + (define-key map (kbd "C-c C-n") #'mastodon-toot--toggle-nsfw) (define-key map (kbd "C-c C-v") #'mastodon-toot--change-visibility) + (define-key map (kbd "C-c C-a") #'mastodon-toot--add-media-attachment) map) "Keymap for `mastodon-toot'.") @@ -194,28 +207,52 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (setq mastodon-toot--visibility visibility) (message "Visibility set to %s" visibility)) +(defun mastodon-toot--add-media-attachment () + "Prompt the user for a file and POST it to the media endpoint on the server. + +Set `mastodon-toot--media-attachment-ids' to the item's id so it can be attached to the toot." + (interactive) + (let* ((filename (read-file-name "Choose file to attach to this toot: ")) + (caption (read-string "Enter a caption: ")) + (url (concat mastodon-instance-url "/api/v1/media"))) + (message "Uploading %s..." (file-name-nondirectory filename)) + (mastodon-http--post-media-attachment url filename caption) + (setq mastodon-toot--media-attachments t))) + (defun mastodon-toot--send () - "Kill new-toot buffer/window and POST contents to the Mastodon instance." + "Kill new-toot buffer/window and POST contents to the Mastodon instance. + +If media items have been uploaded with `mastodon-toot--add-media-attachment', attach them to the toot." (interactive) (let* ((toot (mastodon-toot--remove-docs)) - (empty-toot-p (string= "" (mastodon-tl--clean-tabs-and-nl toot))) + (empty-toot-p (and (not mastodon-toot--media-attachments) + (string= "" (mastodon-tl--clean-tabs-and-nl toot)))) (endpoint (mastodon-http--api "statuses")) (spoiler (when (and (not empty-toot-p) mastodon-toot--content-warning) (read-string "Warning: "))) - (args `(("status" . ,toot) - ("in_reply_to_id" . ,mastodon-toot--reply-to-id) - ("visibility" . ,mastodon-toot--visibility) - ("sensitive" . ,(when mastodon-toot--content-nsfw - (symbol-name t))) - ("visibility" . ,mastodon-toot--visibility) - ("spoiler_text" . ,spoiler)))) - (if empty-toot-p - (message "Empty toot. Cowardly refusing to post this.") - (mastodon-toot--kill) - (let ((response (mastodon-http--post endpoint args nil))) - (mastodon-http--triage response - (lambda () (message "Toot toot!"))))))) + (args-no-media `(("status" . ,toot) + ("in_reply_to_id" . ,mastodon-toot--reply-to-id) + ("visibility" . ,mastodon-toot--visibility) + ("sensitive" . ,(when mastodon-toot--content-nsfw + (symbol-name t))) + ("spoiler_text" . ,spoiler))) + (args-media + (when mastodon-toot--media-attachments + (mapcar + (lambda (id) + (cons "media_ids[]" id)) + mastodon-toot--media-attachment-ids))) + (args (append args-no-media args-media))) + (if (and mastodon-toot--media-attachments + (equal mastodon-toot--media-attachment-ids nil)) + (message "Looks like your uploads are not yet ready...") + (if empty-toot-p + (message "Empty toot. Cowardly refusing to post this.") + (mastodon-toot--kill) + (let ((response (mastodon-http--post endpoint args nil))) + (mastodon-http--triage response + (lambda () (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) "Adds domain to local ACCT and replaces the curent user name with \"\". @@ -359,11 +396,14 @@ warning flags etc." (propertize "Visibility" 'toot-post-visibility t) " ⋅ " + (propertize "Attachment" + 'toot-attachment t) + " ⋅ " (propertize "CW" 'toot-post-cw-flag t) - ;; " " - ;; (propertize "NSFW" - ;; 'toot-post-nsfw-flag t) + " " + (propertize "NSFW" + 'toot-post-nsfw-flag t) "\n" divider (propertize "\n" @@ -388,22 +428,30 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (point-min))) (visibility-region (mastodon-tl--find-property-range 'toot-post-visibility (point-min))) - ;; (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag - ;; (point-min))) + (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag + (point-min))) (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag (point-min))) + (attachment-region (mastodon-tl--find-property-range + 'toot-attachment (point-min))) ) (add-text-properties (car count-region) (cdr count-region) (list 'display - (format "%s characters in message" + (format "%s characters" (- (point-max) (cdr header-region))))) (add-text-properties (car visibility-region) (cdr visibility-region) (list 'display (format "Visibility: %s" mastodon-toot--visibility))) - ;; (add-text-properties (car nsfw-region) (cdr nsfw-region) - ;; (list 'invisible (not mastodon-toot--content-nsfw) - ;; 'face 'mastodon-cw-face)) + (add-text-properties (car attachment-region) (cdr attachment-region) + (list 'display + (format "Attached: %s" + (mapconcat 'identity + mastodon-toot--media-attachment-filenames + ", ")))) + (add-text-properties (car nsfw-region) (cdr nsfw-region) + (list 'invisible (not mastodon-toot--content-nsfw) + 'face 'mastodon-cw-face)) (add-text-properties (car cw-region) (cdr cw-region) (list 'invisible (not mastodon-toot--content-warning) 'face 'mastodon-cw-face)))) -- cgit v1.2.3 From 3ae6b112e330110de8418cb2bfad1e7cdf7fbf2f Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 24 May 2021 09:41:35 +0200 Subject: typos in -tl, thread* no longer interactive. --- lisp/mastodon-tl.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index da2e418..adb834a 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -347,7 +347,7 @@ TIMESTAMP is assumed to be in the past." (time-add timestamp (seconds-to-time (cdr relative-result)))))) (defun mastodon-tl--relative-time-description (timestamp &optional current-time) - "Returns a string with a human readable description of TIMESTMAP relative to the current time. + "Returns a string with a human readable description of TIMESTAMP relative to the current time. Use the optional CURRENT-TIME as the current time (only used for reliable testing). @@ -646,7 +646,7 @@ message is a link which unhides/hides the main body." (mastodon-tl--media toot)))) (defun mastodon-tl--insert-status (toot body author-byline action-byline) - "Display the content and byline of a timeline element. + "Display the content and byline of timeline element TOOT. BODY will form the section of the toot above the byline. AUTHOR-BYLINE is an optional function for adding the author portion of @@ -794,7 +794,7 @@ webapp" 'mastodon-tl--thread* id toot buffer))) (defun mastodon-tl--thread* (context id toot buffer) - (interactive) + ;; (interactive) (when (member (cdr (assoc 'type toot)) '("reblog" "favourite")) (setq toot (cdr (assoc 'status toot)))) (if (> (+ (length (cdr (assoc 'ancestors context))) @@ -823,7 +823,7 @@ webapp" (cdr (assoc 'url (cdr (assoc 'reblog toot)))) (cdr (assoc 'url toot))))) (kill-new url) - (message "Toot copied to the clipboard."))) + (message "Toot URL copied to the clipboard."))) (defun mastodon-tl--delete-toot () "Delete user's toot at point synchronously." @@ -995,7 +995,7 @@ webapp" (goto-char point-before))))) (defun mastodon-tl--find-property-range (property start-point &optional search-backwards) - " Returns `nil` if no such range is found. + "Returns `nil` if no such range is found. If PROPERTY is set at START-POINT returns a range around START-POINT otherwise before/after START-POINT. -- cgit v1.2.3 From 7b23d4d03aee72e54484034bc91bd51e909ead32 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 24 May 2021 11:04:47 +0200 Subject: pin/unpin toot funs, delete toot now tests if toot is own. --- lisp/mastodon-tl.el | 59 +++++++++++++++++++++++++++++++++++++++++++++-------- lisp/mastodon.el | 2 ++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index adb834a..85f5641 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -794,7 +794,6 @@ webapp" 'mastodon-tl--thread* id toot buffer))) (defun mastodon-tl--thread* (context id toot buffer) - ;; (interactive) (when (member (cdr (assoc 'type toot)) '("reblog" "favourite")) (setq toot (cdr (assoc 'status toot)))) (if (> (+ (length (cdr (assoc 'ancestors context))) @@ -825,17 +824,61 @@ webapp" (kill-new url) (message "Toot URL copied to the clipboard."))) +;; TODO redraw buffer on success? (defun mastodon-tl--delete-toot () "Delete user's toot at point synchronously." (interactive) - (let* ((id (mastodon-tl--as-string (mastodon-tl--toot-id - (mastodon-tl--property 'toot-json)))) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) (url (mastodon-http--api (format "statuses/%s" id)))) - (when (y-or-n-p (format "Delete this toot? ")) - (let ((response (mastodon-http--delete url))) - (mastodon-http--triage response - (lambda () - (message "Toot deleted! There may be a delay before it disappears from your profile."))))))) + (if (or (cdr (assoc 'reblog toot)) + (not (equal (cdr (assoc 'acct + (cdr (assoc 'account toot)))) + (mastodon-auth--user-acct)))) + (message "You can only delete your own toots.") + (if (y-or-n-p (format "Delete this toot? ")) + (let ((response (mastodon-http--delete url))) + (mastodon-http--triage response + (lambda () + (message "Toot deleted!")))))))) + +;; TODO: rewrite pin/unpin as toggle functions +(defun mastodon-tl--pin-toot () + "Pin user's toot at point synchronously." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s/pin" id))) + (pinnable-p (and + (not (cdr (assoc 'reblog toot))) + (equal (cdr (assoc 'acct + (cdr (assoc 'account toot)))) + (mastodon-auth--user-acct)))) + (pinned-p (equal (cdr (assoc 'pinned toot)) t))) + (if (not pinnable-p) + (message "You can only pin your own toots.") + (if pinned-p + (message "Looks like toot is already pinned.") + (if (y-or-n-p (format "Pin this toot to your profile? ")) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "Toot pinned!"))))))))) + +(defun mastodon-tl--unpin-toot () + "Unpin user's toot at point synchronously." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s/unpin" id))) + (pinned-p (equal (cdr (assoc 'pinned toot)) t))) + (if (not pinned-p) + (message "No pinned toot to unpin here.") + (if (y-or-n-p (format "Unpin this toot? ")) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "Toot unpinned!")))))))) (defun mastodon-tl--follow-user (user-handle) "Query for USER-HANDLE from current status and follow that user." diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 878ddbf..2d51120 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -128,6 +128,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) (define-key map (kbd "S") #'mastodon-search--search-query) (define-key map (kbd "C") #'mastodon-tl--copy-toot-url) + (define-key map (kbd "i") #'mastodon-tl--pin-toot) + (define-key map (kbd "I") #'mastodon-tl--unpin-toot) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From d8121e7447bf30767cd91523e12429a7a934a2c9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 25 May 2021 11:22:26 +0200 Subject: pin/unpin now toggle fun, and moved copy/delete to mastodon-toot. --- lisp/mastodon-discover.el | 5 ++-- lisp/mastodon-tl.el | 66 ----------------------------------------------- lisp/mastodon-toot.el | 51 ++++++++++++++++++++++++++++++++++++ lisp/mastodon.el | 12 ++++----- 4 files changed, 60 insertions(+), 74 deletions(-) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 9e1cbad..55623f7 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -54,8 +54,9 @@ ("S-TAB" "Prev link item" mastodon-tl--previous-tab-item) ("t" "New toot" mastodon-toot) ("r" "Reply" mastodon-toot--reply) - ("C" "Copy toot URL" mastodon-tl--copy-toot-url) - ("d" "Delete (your) toot" mastodon-tl--delete-toot) + ("C" "Copy toot URL" mastodon-toot--copy-toot-url) + ("d" "Delete (your) toot" mastodon-toot--delete-toot) + ("i" "Pin/Unpin (your) toot" mastodon-toot--pin-toot-toggle) ("P" "View user profile" mastodon-profile--show-user) ("T" "View thread" mastodon-tl--thread)) ("Timelines" diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 85f5641..5bc07e0 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -814,72 +814,6 @@ webapp" (cdr (assoc 'descendants context)))))) (message "No Thread!")));) -(defun mastodon-tl--copy-toot-url () - "Copy URL of toot at point." - (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (url (if (mastodon-tl--field 'reblog toot) - (cdr (assoc 'url (cdr (assoc 'reblog toot)))) - (cdr (assoc 'url toot))))) - (kill-new url) - (message "Toot URL copied to the clipboard."))) - -;; TODO redraw buffer on success? -(defun mastodon-tl--delete-toot () - "Delete user's toot at point synchronously." - (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s" id)))) - (if (or (cdr (assoc 'reblog toot)) - (not (equal (cdr (assoc 'acct - (cdr (assoc 'account toot)))) - (mastodon-auth--user-acct)))) - (message "You can only delete your own toots.") - (if (y-or-n-p (format "Delete this toot? ")) - (let ((response (mastodon-http--delete url))) - (mastodon-http--triage response - (lambda () - (message "Toot deleted!")))))))) - -;; TODO: rewrite pin/unpin as toggle functions -(defun mastodon-tl--pin-toot () - "Pin user's toot at point synchronously." - (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s/pin" id))) - (pinnable-p (and - (not (cdr (assoc 'reblog toot))) - (equal (cdr (assoc 'acct - (cdr (assoc 'account toot)))) - (mastodon-auth--user-acct)))) - (pinned-p (equal (cdr (assoc 'pinned toot)) t))) - (if (not pinnable-p) - (message "You can only pin your own toots.") - (if pinned-p - (message "Looks like toot is already pinned.") - (if (y-or-n-p (format "Pin this toot to your profile? ")) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "Toot pinned!"))))))))) - -(defun mastodon-tl--unpin-toot () - "Unpin user's toot at point synchronously." - (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s/unpin" id))) - (pinned-p (equal (cdr (assoc 'pinned toot)) t))) - (if (not pinned-p) - (message "No pinned toot to unpin here.") - (if (y-or-n-p (format "Unpin this toot? ")) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "Toot unpinned!")))))))) - (defun mastodon-tl--follow-user (user-handle) "Query for USER-HANDLE from current status and follow that user." (interactive diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a11bfa0..6f82ded 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -35,6 +35,7 @@ (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") +(autoload 'mastodon-http--delete "mastodon-http") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") @@ -182,6 +183,56 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (message (format "%s #%s" action id)))) (message "Nothing to favorite here?!?")))) +(defun mastodon-toot--pin-toot-toggle () + "Pin or unpin user's toot at point." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s/pin" id))) + (pinnable-p (and + (not (cdr (assoc 'reblog toot))) + (equal (cdr (assoc 'acct + (cdr (assoc 'account toot)))) + (mastodon-auth--user-acct)))) + (pinned-p (equal (cdr (assoc 'pinned toot)) t)) + (action (if pinned-p "unpin" "pin")) + (msg (if pinned-p "unpinned" "pinned")) + (msg-y-or-n (if pinned-p "Unpin" "Pin"))) + (if (not pinnable-p) + (message "You can only pin your own toots.") + (if (y-or-n-p (format "%s this toot? " msg-y-or-n)) + (mastodon-toot--action action + (lambda () + (message "Toot %s!" msg))))))) + +(defun mastodon-toot--copy-toot-url () + "Copy URL of toot at point." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (url (if (mastodon-tl--field 'reblog toot) + (cdr (assoc 'url (cdr (assoc 'reblog toot)))) + (cdr (assoc 'url toot))))) + (kill-new url) + (message "Toot URL copied to the clipboard."))) + +;; TODO redraw buffer on success? +(defun mastodon-toot--delete-toot () + "Delete user's toot at point synchronously." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s" id)))) + (if (or (cdr (assoc 'reblog toot)) + (not (equal (cdr (assoc 'acct + (cdr (assoc 'account toot)))) + (mastodon-auth--user-acct)))) + (message "You can only delete your own toots.") + (if (y-or-n-p (format "Delete this toot? ")) + (let ((response (mastodon-http--delete url))) + (mastodon-http--triage response + (lambda () + (message "Toot deleted!")))))))) + (defun mastodon-toot--kill () "Kill `mastodon-toot-mode' buffer and window." (kill-buffer-and-window)) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 2d51120..f6635c0 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -57,12 +57,13 @@ (autoload 'mastodon-tl--unblock-user "mastodon-tl") (autoload 'mastodon-tl--mute-user "mastodon-tl") (autoload 'mastodon-tl--unmute-user "mastodon-tl") -(autoload 'mastodon-tl--delete-toot "mastodon-tl") (autoload 'mastodon-tl--follow-user "mastodon-tl") (autoload 'mastodon-tl--unfollow-user "mastodon-tl") (autoload 'mastodon-profile--my-profile "mastodon-profile") (autoload 'mastodon-search--search-query "mastodon-search") -(autoload 'mastodon-tl--copy-toot-url "mastodon-tl") +(autoload 'mastodon-toot--delete-toot "mastodon-toot") +(autoload 'mastodon-toot--copy-toot-url "mastodon-toot") +(autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") (autoload 'mastodon-auth--get-account-name "mastodon-auth") (defgroup mastodon nil @@ -118,7 +119,6 @@ Use. e.g. \"%c\" for your locale's date and time format." ;; override special mode binding (define-key map (kbd "g") #'undefined) ;; mousebot additions - (define-key map (kbd "d") #'mastodon-tl--delete-toot) (define-key map (kbd "W") #'mastodon-tl--follow-user) (define-key map (kbd "C-S-W") #'mastodon-tl--unfollow-user) (define-key map (kbd "B") #'mastodon-tl--block-user) @@ -127,9 +127,9 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) (define-key map (kbd "S") #'mastodon-search--search-query) - (define-key map (kbd "C") #'mastodon-tl--copy-toot-url) - (define-key map (kbd "i") #'mastodon-tl--pin-toot) - (define-key map (kbd "I") #'mastodon-tl--unpin-toot) + (define-key map (kbd "d") #'mastodon-toot--delete-toot) + (define-key map (kbd "C") #'mastodon-toot--copy-toot-url) + (define-key map (kbd "i") #'mastodon-toot--pin-toot-toggle) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 16db675587e2e33ac512e2ea43171c2f4fffed9f Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 25 May 2021 17:22:13 +0200 Subject: Support basic displaying of polls. --- lisp/mastodon-tl.el | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 5bc07e0..298964d 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -47,6 +47,7 @@ (autoload 'mastodon-profile--account-field "mastodon-profile.el") (autoload 'mastodon-profile--extract-users-handles "mastodon-profile.el") (autoload 'mastodon-profile--my-profile "mastodon-profile.el") +(autoload 'mastodon-toot--delete-toot "mastodon-toot") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) @@ -640,8 +641,11 @@ message is a link which unhides/hides the main body." (defun mastodon-tl--content (toot) "Retrieve text content from TOOT." - (let ((content (mastodon-tl--field 'content toot))) + (let ((content (mastodon-tl--field 'content toot)) + (poll-p (cdr (assoc 'poll toot)))) (concat + (when poll-p + (mastodon-tl--get-poll toot)) (mastodon-tl--render-text content toot) (mastodon-tl--media toot)))) @@ -668,6 +672,18 @@ it is `mastodon-tl--byline-boosted'" (when mastodon-tl--display-media-p (mastodon-media--inline-images start-pos (point))))) +(defun mastodon-tl--get-poll (toot) + "If post TOOT is a poll, return a formatted string of poll." + (let* ((poll (mastodon-tl--field 'poll toot)) + (options (mastodon-tl--field 'options poll))) + (concat "Poll: \n\n" + (mapconcat (lambda (option) + (format "Option: %s, %s votes.\n" + (cdr (assoc 'title option)) + (cdr (assoc 'votes_count option)))) + options + "\n") "\n"))) + (defun mastodon-tl--toot (toot) "Formats TOOT and insertes it into the buffer." (mastodon-tl--insert-status -- cgit v1.2.3 From 7d143880a05b5ef79269838bcb3bbee9df855561 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 26 May 2021 16:52:16 +0200 Subject: disable emacs 24.5 in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5f5796c..85353b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ before_install: - evm install $EVM_EMACS --use --skip - cask install env: - - EVM_EMACS=emacs-24.5-travis + # - EVM_EMACS=emacs-24.5-travis - EVM_EMACS=emacs-25.1-travis script: - emacs --version -- cgit v1.2.3 From 8309eee64bda0b2a5be7f6eb1d1b26a692117579 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 26 May 2021 17:20:53 +0200 Subject: test change travis.yml --- .travis.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85353b8..8d225d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,26 @@ -language: emacs-lisp -sudo: false +language: emacs-elisp +root: false before_install: - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh - evm install $EVM_EMACS --use --skip - cask install + env: - # - EVM_EMACS=emacs-24.5-travis - - EVM_EMACS=emacs-25.1-travis + global: + - CURL="curl -fsSkL --retry 9 --retry-delay 9" + matrix: + - EMACS_VERSION=25.3 + - EMACS_VERSION=26.1 + - EMACS_VERSION=27.1 + - EMACS_VERSION=master + script: - emacs --version - cask build - cask clean-elc - cask exec ert-runner -l test/ert-helper.el test/*-tests.el - cask emacs --batch -Q -l package-lint.el -f package-lint-batch-and-exit lisp/*.el + notifications: webhooks: urls: -- cgit v1.2.3 From be66260bb4cb4adfff3a350fc6e23f41a3da4ff0 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 26 May 2021 17:23:13 +0200 Subject: typos in tl and http error responses in http.el for attachments --- lisp/mastodon-http.el | 8 ++++++-- lisp/mastodon-toot.el | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 7250ef8..61ae840 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -207,8 +207,12 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' ))) (pcase (request-response-status-code response) (200 - (request-response-data response) - )))) + (request-response-data response)) + (401 + (error "Unauthorized: The access token is invalid.")) + (422 + (error "Unprocessable entity: file or file type is unsupported or invalid.")) + (_ (error "Shit went south."))) (provide 'mastodon-http) ;;; mastodon-http.el ends here diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 6f82ded..cc65597 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -367,7 +367,6 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (defun mastodon-toot--toggle-nsfw () "Toggle `mastodon-toot--content-nsfw'." - ;; This only makes sense once we have attachments. (interactive) (setq mastodon-toot--content-nsfw (not mastodon-toot--content-nsfw)) @@ -417,7 +416,7 @@ e.g. mastodon-toot--send -> Send." (format "\t%s - %s" key command))) (defun mastodon-toot--format-kbinds (kbinds) - "Format a list keybindings, KBINDS, for display in documentation." + "Format a list of keybindings, KBINDS, for display in documentation." (mapconcat 'identity (cons "" (mapcar #'mastodon-toot--format-kbind kbinds)) "\n")) -- cgit v1.2.3 From efdb7f8aa40cd59bc991e57c20f3ef101974f800 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 26 May 2021 17:49:05 +0200 Subject: restore old travis.yml --- .travis.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d225d8..5f5796c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,18 @@ -language: emacs-elisp -root: false +language: emacs-lisp +sudo: false before_install: - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh - evm install $EVM_EMACS --use --skip - cask install - env: - global: - - CURL="curl -fsSkL --retry 9 --retry-delay 9" - matrix: - - EMACS_VERSION=25.3 - - EMACS_VERSION=26.1 - - EMACS_VERSION=27.1 - - EMACS_VERSION=master - + - EVM_EMACS=emacs-24.5-travis + - EVM_EMACS=emacs-25.1-travis script: - emacs --version - cask build - cask clean-elc - cask exec ert-runner -l test/ert-helper.el test/*-tests.el - cask emacs --batch -Q -l package-lint.el -f package-lint-batch-and-exit lisp/*.el - notifications: webhooks: urls: -- cgit v1.2.3 From e86aaaefe20e5ff3036751b91f4f8fec4aaf5394 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 26 May 2021 20:15:54 +0200 Subject: clean up media upload in http.el --- lisp/mastodon-http.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 61ae840..8298cec 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -212,7 +212,7 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' (error "Unauthorized: The access token is invalid.")) (422 (error "Unprocessable entity: file or file type is unsupported or invalid.")) - (_ (error "Shit went south."))) + (_ (error "Shit went south."))))) (provide 'mastodon-http) ;;; mastodon-http.el ends here -- cgit v1.2.3 From 225c0b4acf12cae8593035a1e1662586ec8c74a8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 26 May 2021 21:15:38 +0200 Subject: flychecks and autoloads --- lisp/mastodon-http.el | 7 ++++--- lisp/mastodon-search.el | 2 ++ lisp/mastodon-tl.el | 4 ++++ lisp/mastodon-toot.el | 6 +++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 8298cec..8a7499f 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -31,6 +31,7 @@ (require 'json) (require 'request) ; for attachments upload + (defvar mastodon-instance-url) (autoload 'mastodon-auth--access-token "mastodon-auth") @@ -209,10 +210,10 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' (200 (request-response-data response)) (401 - (error "Unauthorized: The access token is invalid.")) + (error "Unauthorized: The access token is invalid")) (422 - (error "Unprocessable entity: file or file type is unsupported or invalid.")) - (_ (error "Shit went south."))))) + (error "Unprocessable entity: file or file type is unsupported or invalid")) + (_ (error "Shit went south"))))) (provide 'mastodon-http) ;;; mastodon-http.el ends here diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 5a98b26..408b887 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -39,6 +39,8 @@ (autoload 'mastodon-auth--access-token "mastodon-auth") (defvar mastodon-instance-url) +(defvar mastodon-tl--link-keymap) + (defconst mastodon-http--timeout 5) (defun mastodon-search--search-query (query) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 298964d..dac3e66 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -48,6 +48,10 @@ (autoload 'mastodon-profile--extract-users-handles "mastodon-profile.el") (autoload 'mastodon-profile--my-profile "mastodon-profile.el") (autoload 'mastodon-toot--delete-toot "mastodon-toot") +(autoload 'mastodon-http--post "mastodon-http") +(autoload 'mastodon-http--triage "mastodon-http") +(autoload 'mastodon-http--get-json-async "mastodon-http") +(autoload 'mastodon-profile--lookup-account-in-status "mastodon-profile") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index cc65597..c507384 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -44,6 +44,8 @@ (autoload 'mastodon-tl--property "mastodon-tl") (autoload 'mastodon-tl--find-property-range "mastodon-tl") (autoload 'mastodon-toot "mastodon") +(autoload 'mastodon-http--post-media-attachment "mastodon-http") +(autoload 'mastodon-tl--toot-id "mastodon-tl") (defgroup mastodon-toot nil "Tooting in Mastodon." @@ -187,8 +189,6 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." "Pin or unpin user's toot at point." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s/pin" id))) (pinnable-p (and (not (cdr (assoc 'reblog toot))) (equal (cdr (assoc 'acct @@ -249,7 +249,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (buffer-substring (cdr header-region) (point-max)))) (defun mastodon-toot--set-visibility (visibility) - "Sets the visiblity of the next toot" + "Sets the visiblity of the next toot to VISIBILITY." (interactive (list (completing-read "Visiblity: " '("public" "unlisted" -- cgit v1.2.3 From cc1570df86c7a4f43684fd7caf14cf298301c655 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 27 May 2021 12:43:21 +0200 Subject: add request and seq as dependencies, flycheck cleanups, and move http search funs into http.el --- Cask | 2 ++ lisp/mastodon-http.el | 43 +++++++++++++++++++++++++++++++++++++++---- lisp/mastodon-profile.el | 3 ++- lisp/mastodon-search.el | 34 ++-------------------------------- lisp/mastodon.el | 3 ++- 5 files changed, 47 insertions(+), 38 deletions(-) diff --git a/Cask b/Cask index 599efa2..ebb7669 100644 --- a/Cask +++ b/Cask @@ -4,6 +4,8 @@ (package-file "lisp/mastodon.el") (files "lisp/*.el") +(depends-on "seq") + (development (depends-on "ert-runner") (depends-on "el-mock") diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 8a7499f..3b31668 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.0 -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "24.4") (request "0.2.0")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. @@ -33,7 +33,12 @@ (require 'request) ; for attachments upload (defvar mastodon-instance-url) +(defvar mastodon-toot--media-attachment-ids) +(defvar mastodon-toot--media-attachment-filenames) + (autoload 'mastodon-auth--access-token "mastodon-auth") +(autoload 'mastodon-toot--update-status-fields "mastodon-toot") + (defvar mastodon-http--api-version "v1") @@ -132,6 +137,37 @@ Pass response buffer to CALLBACK function." (kill-buffer) (json-read-from-string json-string))) +;; http functions for search: +(defun mastodon-http--process-json-search () + "Process JSON returned by a search query to the server." + (goto-char (point-min)) + (re-search-forward "^$" nil 'move) + (let ((json-string + (decode-coding-string + (buffer-substring-no-properties (point) (point-max)) + 'utf-8))) + (kill-buffer) + (json-read-from-string json-string))) + +(defun mastodon-http--get-search-json (url query) + "Make GET request to URL, searching for QUERY and return JSON response." + (let ((buffer (mastodon-http--get-search url query))) + (with-current-buffer buffer + (mastodon-http--process-json-search)))) + +(defun mastodon-http--get-search (base-url query) + "Make GET request to BASE-URL, searching for QUERY. + +Pass response buffer to CALLBACK function." + (let ((url-request-method "GET") + (url (concat base-url "?q=" (url-hexify-string query))) + (url-request-extra-headers + `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))))) + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + ;; Asynchronous functions (defun mastodon-http--get-async (url &optional callback &rest cbargs) @@ -173,7 +209,7 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." ;; TODO: test for curl first? (defun mastodon-http--post-media-attachment (url filename caption) - "Make a POST request to upload file FILENAME with CAPTION to the server's media URL. + "Make POST request to upload FILENAME with CAPTION to the server's media URL. The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, `mastodon-toot--media-attachments' is set to t, and `mastodon-toot--update-status-fields' is run." (let* ((file (file-name-nondirectory filename)) @@ -204,8 +240,7 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' (mastodon-toot--update-status-fields))))) :error (cl-function (lambda (&key error-thrown &allow-other-keys) - (message "Got error: %s" error-thrown))) - ))) + (message "Got error: %s" error-thrown)))))) (pcase (request-response-status-code response) (200 (request-response-data response)) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 9d4793c..e007343 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.7.2 -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "24.4") (seq "1.8")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. @@ -49,6 +49,7 @@ (autoload 'mastodon-tl--timeline "mastodon-tl.el") (autoload 'mastodon-tl--as-string "mastodon-tl.el") (autoload 'mastodon-tl--toot-id "mastodon-tl") +(autoload 'mastodon-tl--toot "mastodon-tl") (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 408b887..90158a1 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -1,4 +1,4 @@ -;;; mastodon-search.el --- search functions for mastodon.el -*- lexical-binding: t -*- +;;; mastodon-search.el --- Search functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen , martyhiatt @@ -37,6 +37,7 @@ (autoload 'mastodon-tl--render-text "mastodon-tl") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-auth--access-token "mastodon-auth") +(autoload 'mastodon-http--get-search-json "mastodon-http") (defvar mastodon-instance-url) (defvar mastodon-tl--link-keymap) @@ -143,36 +144,5 @@ This allows us to access the full account etc. details and to render them proper (json (mastodon-http--get-json url))) json)) -;; http functions for search: -(defun mastodon-http--process-json-search () - "Process JSON returned by a search query to the server." - (goto-char (point-min)) - (re-search-forward "^$" nil 'move) - (let ((json-string - (decode-coding-string - (buffer-substring-no-properties (point) (point-max)) - 'utf-8))) - (kill-buffer) - (json-read-from-string json-string))) - -(defun mastodon-http--get-search-json (url query) - "Make GET request to URL, searching for QUERY and return JSON response." - (let ((buffer (mastodon-http--get-search url query))) - (with-current-buffer buffer - (mastodon-http--process-json-search)))) - -(defun mastodon-http--get-search (base-url query) - "Make GET request to BASE-URL, searching for QUERY. - -Pass response buffer to CALLBACK function." - (let ((url-request-method "GET") - (url (concat base-url "?q=" (url-hexify-string query))) - (url-request-extra-headers - `(("Authorization" . ,(concat "Bearer " - (mastodon-auth--access-token)))))) - (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) - (url-retrieve-synchronously url) - (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) - (provide 'mastodon-search) ;;; mastodon-search.el ends here diff --git a/lisp/mastodon.el b/lisp/mastodon.el index f6635c0..37876f6 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.0 -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "24.4") (request "0.2.0") (seq "1.8")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. @@ -32,6 +32,7 @@ ;;; Code: (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") +(declare-function request "request") (autoload 'special-mode "simple") (autoload 'mastodon-tl--get-federated-timeline "mastodon-tl") (autoload 'mastodon-tl--get-home-timeline "mastodon-tl") -- cgit v1.2.3 From d6d114189eaf90f6ae4a0257b92555b257c056f2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 30 May 2021 13:32:55 +0200 Subject: http: docstrings and move delete fun --- lisp/mastodon-http.el | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 3b31668..462b5c6 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -101,7 +101,7 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) (defun mastodon-http--get (url) - "Make GET request to URL. + "Make synchronous GET request to URL. Pass response buffer to CALLBACK function." (let ((url-request-method "GET") @@ -112,17 +112,8 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url) (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) -(defun mastodon-http--delete (url) - "Make DELETE request to URL." - (let ((url-request-method "DELETE") - (url-request-extra-headers - `(("Authorization" . ,(concat "Bearer " - (mastodon-auth--access-token)))))) - (with-temp-buffer - (url-retrieve-synchronously url)))) - (defun mastodon-http--get-json (url) - "Make GET request to URL. Return JSON response." + "Make synchronous GET request to URL. Return JSON response." (with-current-buffer (mastodon-http--get url) (mastodon-http--process-json))) @@ -137,6 +128,15 @@ Pass response buffer to CALLBACK function." (kill-buffer) (json-read-from-string json-string))) +(defun mastodon-http--delete (url) + "Make DELETE request to URL." + (let ((url-request-method "DELETE") + (url-request-extra-headers + `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))))) + (with-temp-buffer + (url-retrieve-synchronously url)))) + ;; http functions for search: (defun mastodon-http--process-json-search () "Process JSON returned by a search query to the server." -- cgit v1.2.3 From a9ea433fdee9df9c04705ca41ad517308b6b444e Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 30 May 2021 13:33:43 +0200 Subject: only show pinned statuses for "statuses" profile buffer --- lisp/mastodon-profile.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index e007343..f117f23 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -249,8 +249,8 @@ Returns a list of lists." (setq mastodon-tl--update-point (point)) (mastodon-media--inline-images (point-min) (point)) ;; insert pinned toots first - (if pinned - (mastodon-profile--insert-statuses-pinned pinned)) + (if (and pinned (equal endpoint-type "statuses")) + (mastodon-profile--insert-statuses-pinned pinned)) (funcall update-function json))) (mastodon-tl--goto-next-toot))) -- cgit v1.2.3 From 9c2ab0ac9965d5bb90984d179fb17abcb2cd8ab8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 30 May 2021 13:34:37 +0200 Subject: view favourites fun, and view/accept/reject follow requests funs. and bindings. view-follow-requests makes mastodon-tl--init run in mastodon-profile-mode just so that its bindings can be restricted to that minor mode. --- lisp/mastodon-discover.el | 6 ++++- lisp/mastodon-profile.el | 64 +++++++++++++++++++++++++++++++++++++++++++++-- lisp/mastodon-tl.el | 2 ++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 55623f7..1f063b3 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -83,7 +83,11 @@ ("u" "copy URL" 'shr-maybe-probe-and-copy-url)) ("Profile view" ("o" "Show following" mastodon-profile--open-following) - ("O" "Show followers" mastodon-profile--open-followers)) + ("O" "Show followers" mastodon-profile--open-followers) + ("v" "View favourites" mastodon-profile--view-favourites) + ("R" "View follow requests" mastodon-profile--view-follow-requests) + ("a" "Accept follow request" mastodon-profile--follow-request-accept) + ("r" "Reject follow request" mastodon-profile--follow-request-reject)) ("Quit" ("q" "Quit mastodon and bury buffer." kill-this-buffer) ("Q" "Quit mastodon buffer and kill window." kill-buffer-and-window))))))) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index f117f23..17b480d 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -69,8 +69,12 @@ extra keybindings." :lighter " Profile" ;; The key bindings :keymap '(((kbd "O") . mastodon-profile--open-followers) - ((kbd "o") . mastodon-profile--open-following)) - :group 'mastodon) + ((kbd "o") . mastodon-profile--open-following) + ((kbd "v") . mastodon-profile--view-favourites) + ((kbd "R") . mastodon-profile--view-follow-requests) + ((kbd "a") . mastodon-profile--follow-request-accept) + ((kbd "r") . mastodon-profile--follow-request-reject)) +:group 'mastodon) (defun mastodon-profile--toot-json () "Get the next toot-json." @@ -104,6 +108,62 @@ following the current profile." #'mastodon-profile--add-author-bylines) (error "Not in a mastodon profile"))) +(defun mastodon-profile--view-favourites () + "Open a new buffer displaying the user's favourites." + (interactive) + (mastodon-tl--init "favourites" + "favourites" + 'mastodon-tl--timeline)) + +(defun mastodon-profile--view-follow-requests () + "Open a new buffer displaying the user's follow requests." + (interactive) + (mastodon-profile-mode) + (mastodon-tl--init "follow-requests" + "follow_requests" + 'mastodon-profile--add-author-bylines)) + +(defun mastodon-profile--follow-request-accept () + "Accept the follow request of user at point." + (interactive) + (let* ((acct-json (mastodon-profile--toot-json)) + (id (cdr (assoc 'id acct-json))) + (handle (cdr (assoc 'acct acct-json))) + (name (cdr (assoc 'username acct-json)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/authorize" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (message "Follow request of %s (@%s) accepted!" + name handle)))) + (message "No account result at point?")))) + +(defun mastodon-profile--follow-request-reject () + "Reject the follow request of user at point." + (interactive) + (let* ((acct-json (mastodon-profile--toot-json)) + (id (cdr (assoc 'id acct-json))) + (handle (cdr (assoc 'acct acct-json))) + (name (cdr (assoc 'username acct-json)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/reject" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (message "Follow request of %s (@%s) rejected!" + name handle)))) + (message "No account result at point?")))) + + (defun mastodon-profile--relationships-get (id) "Fetch info about logged-in user's relationship to user with id ID." (let* ((their-id id) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index dac3e66..7b0afeb 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1163,6 +1163,8 @@ UPDATE-FUNCTION is used to recieve more toots." (seconds-to-time 300))) (funcall update-function json)) (mastodon-mode) + (when (equal endpoint "follow_requests") + (mastodon-profile-mode)) (with-current-buffer buffer (setq mastodon-tl--buffer-spec `(buffer-name ,buffer -- cgit v1.2.3 From 00ec168eafb1233b0164611e622f018a3c362ea3 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 30 May 2021 14:08:17 +0200 Subject: update readme --- README.org | 70 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/README.org b/README.org index baa627e..214d3d0 100644 --- a/README.org +++ b/README.org @@ -1,15 +1,37 @@ -* mastodon.el +* mastodon.el fork -[[https://melpa.org/#/mastodon][file:https://melpa.org/packages/mastodon-badge.svg]] +This is a fork of of the great but seemingly dormant https://github.com/jdenen/mastodon.el. -[[https://travis-ci.org/jdenen/mastodon.el][https://travis-ci.org/jdenen/mastodon.el.svg?branch=master]] -[[http://waffle.io/jdenen/mastodon.el][https://badge.waffle.io/jdenen/mastodon.el.png?label=in%20progress&title=In%20Progress]] +It adds the following features: -Emacs client for [[https://github.com/tootsuite/mastodon][Mastodon]] +| | display profile metadata fields | +| =i= | (un)pin toots, display pinned toots on profiles, | +| | display relationship (follows you/followed by you) on profiles | +| | links and tags in profiles are tab stops like in posts | +| =S= | search (posts, users, tags) (improved!) | +| =C-c C-a= (=C-c C-n=) | media uploads (including sensitive/nsfw flag) | +| =RET= | images are links to the full-sized image, can be zoomed | +| | mention booster in replies by default | +| =W=, =M=, =B= | (un)follow, (un)mute, (un)block users | +| =R=, =a=, =r= | view/accept/reject follow requests | +| =v= | view your favorited toots | +| =S-M-P= | jump to your profile | +| =C= | copy toot url | +| =d= | delete your toot | -[[http://spacemacs.org][https://cdn.rawgit.com/syl20bnr/spacemacs/442d025779da2f62fc86c2082703697714db6514/assets/spacemacs-badge.svg]] +It also makes some small cosmetic changes to make timelines easier to read, and makes some functions asynchronous, based on https://github.com/ieure/mastodon.el. -** Installation +This updated version is not on MELPA, to use it you need to clone and require it as per the installation instructions below. + +I did this for my own use and to learn more Elisp. If the code is terrible, feel free to improve or replace it. + +** bugs + +As it stands the client still has some bugs. In particular, when composing a toot, you may have to hit =C-g= before sending your toot. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. + +** Original README + +*** Installation Clone this repository and add the lisp directory to your load path. Then, require it and go. @@ -26,7 +48,7 @@ Or, with =use-package=: :ensure t) #+END_SRC -*** MELPA +**** MELPA Add =MELPA= to your archives: @@ -42,12 +64,12 @@ Update and install: =M-x package-install RET mastodon RET= -*** Emoji +**** Emoji =mastodon-mode= will enable [[https://github.com/iqbalansari/emacs-emojify][Emojify]] if it is loaded in your Emacs environment, so there's no need to write your own hook anymore. =emojify-mode= is not required. -*** Discover +**** Discover =mastodon-mode= can provide a context menu for its keybindings if [[https://github.com/mickeynp/discover.el][Discover]] is installed. It is not required. @@ -68,12 +90,12 @@ Or, with =use-package=: (mastodon-discover)) #+END_SRC -** Usage -*** 2 Factor Auth +*** Usage +**** 2 Factor Auth 2FA is not supported yet. It is in the [[https://github.com/jdenen/mastodon.el/milestone/2][plans]] for the =1.0.0= release. If you have 2FA enabled and try to use mastodon.el, your Emacs client will hang until you `C-g` your way out. -*** Instance +**** Instance Set =mastodon-instance-url= in your =.emacs= or =customize=. Defaults to the [[https://mastodon.social][flagship]]. @@ -85,13 +107,13 @@ There is an option to have your user credentials (email address and password) sa The default is not to do this because if not properly configured it would save these unencrypted which is not a good default to have. Customize the variable =mastodon-auth-source-file= if you want to enable this feature. -*** Timelines +**** Timelines =M-x mastodon= Opens a =*mastodon-home*= buffer in the major mode so you can see toots. You will be prompted for email and password. The app registration process will take place if your =mastodon-token-file= does not contain =:client_id= and =:client_secret=. -**** Keybindings +***** Keybindings |-----------------+---------------------------------------------------------| | Key | Action | @@ -124,7 +146,7 @@ Opens a =*mastodon-home*= buffer in the major mode so you can see toots. You wil | =Q= | Quit mastodon buffer and kill window | |-----------------+---------------------------------------------------------| -**** Legend +***** Legend |--------+-------------------------| | Marker | Meaning | @@ -133,7 +155,7 @@ Opens a =*mastodon-home*= buffer in the major mode so you can see toots. You wil | =(F)= | I favourited this toot. | |--------+-------------------------| -*** Toot toot +**** Toot toot =M-x mastodon-toot= @@ -148,12 +170,12 @@ Authentication stores your access token in the =mastodon-auth--token= variable. It is not stored on your filesystem, so you will have to re-authenticate when you close/reopen Emacs. -**** Customization +***** Customization The default toot visibility can be changed by setting or customizing the =mastodon-toot--default-visibility= variable. Valid values are ="public"=, ="unlisted"=, ="private"=, or =direct=. Toot visibility can also be changed on a per-toot basis from the new toot buffer. -**** Keybindings +***** Keybindings |-----------+------------------------| | Key | Action | @@ -164,28 +186,28 @@ Toot visibility can also be changed on a per-toot basis from the new toot buffer | =C-c C-v= | Change toot visibility | |-----------+------------------------| -** Roadmap +*** Roadmap [[https://github.com/jdenen/mastodon.el/milestone/1][Here]] are the features I plan to implement before putting mastodon.el on MELPA. [[https://github.com/jdenen/mastodon.el/milestone/2][Here]] are the plans I have for the =1.0.0= release. -** Contributing +*** Contributing PRs, issues, and feature requests are very welcome! -*** Features +**** Features 1. Create an [[https://github.com/jdenen/mastodon.el/issues][issue]] detailing the feature you'd like to add. 2. Fork the repository and create a branch off of =develop=. 3. Create a pull request referencing the issue created in step 1. -*** Fixes +**** Fixes 1. In an [[https://github.com/jdenen/mastodon.el/issues][issue]], let me know that you're working to fix it. 2. Fork the repository and create a branch off of =develop=. 3. Create a pull request referencing the issue from step 1. -** Connect +*** Connect If you want to get in touch with me, give me a [[https://mastodon.social/@johnson][toot]] or leave an [[https://github.com/jdenen/mastodon.el/issues][issue]]. -- cgit v1.2.3 From 2f14752767a03f6e9979dd5d3897425cd7aa2e37 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 31 May 2021 08:37:54 +0200 Subject: travis.yml, move to new cask install method --- .travis.yml | 9 +++++++-- lisp/mastodon-media.el | 3 +-- lisp/mastodon-toot.el | 3 +-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5f5796c..6311b0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,12 @@ language: emacs-lisp sudo: false before_install: - - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh + - git clone https://github.com/cask/cask ~/.cask + - PATH=$HOME/.cask/bin:$PATH + - export PATH="/home/travis/.evm/bin:$PATH" + # - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh + - git clone https://github.com/rejeep/evm.git /home/travis/.evm + - evm config path /tmp - evm install $EVM_EMACS --use --skip - cask install env: @@ -11,7 +16,7 @@ script: - emacs --version - cask build - cask clean-elc - - cask exec ert-runner -l test/ert-helper.el test/*-tests.el + # - cask exec ert-runner -l test/ert-helper.el test/*-tests.el - cask emacs --batch -Q -l package-lint.el -f package-lint-batch-and-exit lisp/*.el notifications: webhooks: diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 6837f9b..da99007 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -274,8 +274,7 @@ replacing them with the referenced image." 'mastodon-tab-stop 'image ; for do-link-action-at-point 'image-url full-remote-url ; for shr-browse-image 'keymap mastodon-tl--shr-image-map-replacement - 'help-echo (concat "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview") - ) + 'help-echo (concat "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview")) " ")) (provide 'mastodon-media) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index c507384..8328bb9 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -483,8 +483,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag (point-min))) (attachment-region (mastodon-tl--find-property-range - 'toot-attachment (point-min))) - ) + 'toot-attachment (point-min)))) (add-text-properties (car count-region) (cdr count-region) (list 'display (format "%s characters" -- cgit v1.2.3 From 1ff6d8ef35f83ada24fafd3656dde0a1da57922a Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 31 May 2021 09:58:01 +0200 Subject: bump masto version, bump emacs version to 25.1, dependency in readme --- README.org | 3 +++ lisp/mastodon-auth--test.el | 4 ++-- lisp/mastodon-auth.el | 4 ++-- lisp/mastodon-client.el | 4 ++-- lisp/mastodon-discover.el | 4 ++-- lisp/mastodon-http.el | 4 ++-- lisp/mastodon-inspect.el | 4 ++-- lisp/mastodon-media.el | 4 ++-- lisp/mastodon-notifications.el | 4 ++-- lisp/mastodon-profile.el | 4 ++-- lisp/mastodon-search.el | 4 ++-- lisp/mastodon-tl.el | 4 ++-- lisp/mastodon-toot.el | 4 ++-- lisp/mastodon.el | 4 ++-- 14 files changed, 29 insertions(+), 26 deletions(-) diff --git a/README.org b/README.org index 214d3d0..d06c93a 100644 --- a/README.org +++ b/README.org @@ -25,6 +25,9 @@ This updated version is not on MELPA, to use it you need to clone and require it I did this for my own use and to learn more Elisp. If the code is terrible, feel free to improve or replace it. +** dependency: +This version depends on the library =request= (for uploading attachments). You can install it from melpa. + ** bugs As it stands the client still has some bugs. In particular, when composing a toot, you may have to hit =C-g= before sending your toot. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. diff --git a/lisp/mastodon-auth--test.el b/lisp/mastodon-auth--test.el index 8082536..b8705f5 100644 --- a/lisp/mastodon-auth--test.el +++ b/lisp/mastodon-auth--test.el @@ -3,9 +3,9 @@ ;; Copyright (C) 2020 Ian Eure ;; Author: Ian Eure -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index cfe89b5..3c61848 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index da70dea..90f1375 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 1f063b3..2387feb 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -2,8 +2,8 @@ ;; Copyright (C) 2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 -;; Package-Requires: ((emacs "24.4")) +;; Version: 0.9.1 +;; Package-Requires: ((emacs "25.1")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 462b5c6..e85429f 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -2,8 +2,8 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 -;; Package-Requires: ((emacs "24.4") (request "0.2.0")) +;; Version: 0.9.1 +;; Package-Requires: ((emacs "25.1") (request "0.2.0")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 44b9344..c5a8d5d 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -2,8 +2,8 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 -;; Package-Requires: ((emacs "24.4")) +;; Version: 0.9.1 +;; Package-Requires: ((emacs "25.1")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index da99007..6c17ae0 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index d6fa78f..d40815a 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.7.2 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 17b480d..bf1a3a9 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -2,8 +2,8 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.7.2 -;; Package-Requires: ((emacs "24.4") (seq "1.8")) +;; Version: 0.9.1 +;; Package-Requires: ((emacs "25.1") (seq "1.8")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 90158a1..5e8253f 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen , martyhiatt -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 7b0afeb..ecaeff4 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 8328bb9..a0f886c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 +;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "24.4")) +;; Package-Requires: ((emacs "25.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 37876f6..b703b30 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -2,8 +2,8 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.0 -;; Package-Requires: ((emacs "24.4") (request "0.2.0") (seq "1.8")) +;; Version: 0.9.1 +;; Package-Requires: ((emacs "25.1") (request "0.2.0") (seq "1.8")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. -- cgit v1.2.3 From 35d7133bfc5060e76dfe91526da399ddb8559600 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 31 May 2021 11:51:23 +0200 Subject: foll reqs/faves bindings global, autoloads and declarations, readme --- README.org | 62 +++++++++++++++++++++++++++++++++--------------- lisp/mastodon-auth.el | 1 + lisp/mastodon-media.el | 7 +++--- lisp/mastodon-profile.el | 10 ++++---- lisp/mastodon-tl.el | 16 ++++++------- lisp/mastodon.el | 2 ++ 6 files changed, 64 insertions(+), 34 deletions(-) diff --git a/README.org b/README.org index d06c93a..af2c46c 100644 --- a/README.org +++ b/README.org @@ -4,33 +4,57 @@ This is a fork of of the great but seemingly dormant https://github.com/jdenen/m It adds the following features: -| | display profile metadata fields | -| =i= | (un)pin toots, display pinned toots on profiles, | -| | display relationship (follows you/followed by you) on profiles | -| | links and tags in profiles are tab stops like in posts | -| =S= | search (posts, users, tags) (improved!) | -| =C-c C-a= (=C-c C-n=) | media uploads (including sensitive/nsfw flag) | -| =RET= | images are links to the full-sized image, can be zoomed | -| | mention booster in replies by default | -| =W=, =M=, =B= | (un)follow, (un)mute, (un)block users | -| =R=, =a=, =r= | view/accept/reject follow requests | -| =v= | view your favorited toots | -| =S-M-P= | jump to your profile | -| =C= | copy toot url | -| =d= | delete your toot | +| Profiles: | | +| | display profile metadata fields | +| | display relationship (follows you/followed by you) on profiles | +| | display toots/follows/followers counts on profiles | +| | links and tags in profiles are tab stops like in posts | +| =R=, =a=, =r= | view/accept/reject follow requests | +| =v= | view your favorited toots | +| =i= | (un)pin toots, display pinned toots on profiles | +| =S-C-P= | jump to your profile | +| Timelines: | | +| =W=, =M=, =B= | (un)follow, (un)mute, (un)block users | +| | images are links to the full image, can be zoomed/rotated/saved (see their keymap) | +| =C= | copy url of toot at point | +| =d= | delete your toot at point | +| | display polls (very basic for now) | +| Toots: | | +| =C-c C-a= (=C-c C-n=) | media uploads (and sensitive/nsfw flag) | +| | mention booster in replies by default | +| Search: | | +| =S= | search (posts, users, tags) (improved! but still pretty basic!) | It also makes some small cosmetic changes to make timelines easier to read, and makes some functions asynchronous, based on https://github.com/ieure/mastodon.el. This updated version is not on MELPA, to use it you need to clone and require it as per the installation instructions below. -I did this for my own use and to learn more Elisp. If the code is terrible, feel free to improve or replace it. +The minimum Emacs version is now 25.1. But if you are running an older version it shouldn't be very hard to get it working. -** dependency: -This version depends on the library =request= (for uploading attachments). You can install it from melpa. +I did this for my own use and to learn more Elisp. If the code is terrible, feel free to improve or replace it. It surely still contains errors, I'm only weeding them out as I find them. -** bugs +** NB: dependency: -As it stands the client still has some bugs. In particular, when composing a toot, you may have to hit =C-g= before sending your toot. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. +This version depends on the library =request= (for uploading attachments). You can install it from MELPA, or https://github.com/tkf/emacs-request. + +** NB: bugs + +As it stands the client still has some bugs. In particular, when composing a toot, hit =C-g= before sending your toot. If you don't, your draft may disappear. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. + +Some people have also had niggling troubles with initial auth and set-up, but I couldn't reproduce. + +** roadmap-ish + +I might add a few more features if the ones I added turn out to work ok. Possible additions/amendments: + +- voting on polls +- better display of polls +- mention all thread participants in replies +- handle newlines in toots better, for poetry, etc. +- improve async. +- perhaps integrate live timeline updates from https://github.com/alexjgriffith/mastodon-future.el, and add live updates for notifcations and home timeline. + +It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. ** Original README diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 3c61848..4bd1cce 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -32,6 +32,7 @@ (require 'plstore) (require 'auth-source) (require 'json) +(eval-when-compile (require 'subr-x)) ; for if-let (autoload 'mastodon-client "mastodon-client") (autoload 'mastodon-http--api "mastodon-http") diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 6c17ae0..381d994 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -34,6 +34,8 @@ ;;; Code: (defvar url-show-status) +(defvar mastodon-tl--shr-image-map-replacement) + (defgroup mastodon-media nil "Inline Mastadon media." :prefix "mastodon-media-" @@ -125,7 +127,7 @@ CAQgEIBAAAIBFiNOFMaY6V1tnFhkDQIQCEAgAIEABAKAQAACAQgEIBCAQAACAQgEIBCAQABIXO4e c1y+zhoEIBCAQAAQCEAgAIEABAIQCEAgAIEABAIQCEAgAAgEIBCAQAACAQgEIBCAQAACAQgEAIEA BAIQCEAgAIEABAIsJVH58WqHw8FIgjUIQCAACAQgEIBAAAIBCAQgEIBAAAIBCAQgEAAEAhAIQCBA fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") - "The PNG data for a generic 200x200 'broken image' view") + "The PNG data for a generic 200x200 'broken image' view.") (defun mastodon-media--process-image-response (status-plist marker image-options region-length) @@ -134,8 +136,7 @@ fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") STATUS-PLIST is the usual plist of status events as per `url-retrieve'. IMAGE-OPTIONS are the precomputed options to apply to the image. MARKER is the marker to where the response should be visible. -REGION-LENGTH is the length of the region that should be replaced with the image. -" +REGION-LENGTH is the length of the region that should be replaced with the image." (when (marker-buffer marker) ; only if the buffer hasn't been kill in the meantime (let ((url-buffer (current-buffer)) (is-error-response-p (eq :error (car status-plist)))) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index bf1a3a9..84664c0 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -36,6 +36,8 @@ (autoload 'mastodon-http--api "mastodon-http.el") (autoload 'mastodon-http--get-json "mastodon-http.el") +(autoload 'mastodon-http--post "mastodon-http.el") +(autoload 'mastodon-http--triage "mastodon-http.el") (autoload 'mastodon-auth--get-account-name "mastodon-auth.el") (autoload 'mastodon-http--get-json-async "mastodon-http.el") (autoload 'mastodon-media--get-media-link-rendering "mastodon-media.el") @@ -50,6 +52,7 @@ (autoload 'mastodon-tl--as-string "mastodon-tl.el") (autoload 'mastodon-tl--toot-id "mastodon-tl") (autoload 'mastodon-tl--toot "mastodon-tl") +(autoload 'mastodon-tl--init "mastodon-tl.el") (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) @@ -70,11 +73,9 @@ extra keybindings." ;; The key bindings :keymap '(((kbd "O") . mastodon-profile--open-followers) ((kbd "o") . mastodon-profile--open-following) - ((kbd "v") . mastodon-profile--view-favourites) - ((kbd "R") . mastodon-profile--view-follow-requests) ((kbd "a") . mastodon-profile--follow-request-accept) ((kbd "r") . mastodon-profile--follow-request-reject)) -:group 'mastodon) + :group 'mastodon) (defun mastodon-profile--toot-json () "Get the next toot-json." @@ -214,7 +215,7 @@ Returns a list of lists." (mastodon-http--get-json url))) (defun mastodon-profile--insert-statuses-pinned (pinned-statuses) - "Insert each of the PINNED_STATUSES for a given account." + "Insert each of the PINNED-STATUSES for a given account." (mapc (lambda (pinned-status) (insert (mastodon-tl--set-face " :pinned: " 'success)) @@ -222,6 +223,7 @@ Returns a list of lists." pinned-statuses)) (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function) + "Display profile of ACCOUNT, using ENDPOINT-TYPE and UPDATE-FUNCTION." (let* ((id (mastodon-profile--account-field account 'id)) (url (mastodon-http--api (format "accounts/%s/%s" id endpoint-type))) (acct (mastodon-profile--account-field account 'acct)) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index ecaeff4..d90a759 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -39,14 +39,14 @@ (autoload 'mastodon-media--get-media-link-rendering "mastodon-media") (autoload 'mastodon-media--inline-images "mastodon-media") (autoload 'mastodon-mode "mastodon") -(autoload 'mastodon-profile--account-from-id "mastodon.el-profile.el") -(autoload 'mastodon-profile--make-author-buffer "mastodon-profile.el") -(autoload 'mastodon-profile--search-account-by-handle "mastodon.el-profile.el") +(autoload 'mastodon-profile--account-from-id "mastodon-profile") +(autoload 'mastodon-profile--make-author-buffer "mastodon-profile") +(autoload 'mastodon-profile--search-account-by-handle "mastodon-profile") ;; mousebot adds -(autoload 'mastodon-profile--toot-json "mastodon-profile.el") -(autoload 'mastodon-profile--account-field "mastodon-profile.el") -(autoload 'mastodon-profile--extract-users-handles "mastodon-profile.el") -(autoload 'mastodon-profile--my-profile "mastodon-profile.el") +(autoload 'mastodon-profile--toot-json "mastodon-profile") +(autoload 'mastodon-profile--account-field "mastodon-profile") +(autoload 'mastodon-profile--extract-users-handles "mastodon-profile") +(autoload 'mastodon-profile--my-profile "mastodon-profile") (autoload 'mastodon-toot--delete-toot "mastodon-toot") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") @@ -55,7 +55,7 @@ (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) -(defvar shr-use-fonts) ;; need to declare it since Emacs24 didn't have this +(defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this (defgroup mastodon-tl nil "Timelines in Mastodon." diff --git a/lisp/mastodon.el b/lisp/mastodon.el index b703b30..d3477cb 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -131,6 +131,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "d") #'mastodon-toot--delete-toot) (define-key map (kbd "C") #'mastodon-toot--copy-toot-url) (define-key map (kbd "i") #'mastodon-toot--pin-toot-toggle) + (define-key map (kbd "v") #'mastodon-profile--view-favourites) + (define-key map (kbd "R") #'mastodon-profile--view-follow-requests) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From db26f1b4bc8a62e472ed7c7191a67ddbc2c65c69 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 1 Jun 2021 14:20:28 +0200 Subject: add basic live updates of home/local/federated timelines. the code, mastodon-async.el is taken from https://github.com/alexjgriffith/mastodon-future.el and only slightly modified to make the home stream work. --- README.org | 1 + lisp/mastodon-async.el | 332 +++++++++++++++++++++++++++++++++++++++++++++++++ lisp/mastodon.el | 6 + 3 files changed, 339 insertions(+) create mode 100644 lisp/mastodon-async.el diff --git a/README.org b/README.org index af2c46c..b51644b 100644 --- a/README.org +++ b/README.org @@ -47,6 +47,7 @@ Some people have also had niggling troubles with initial auth and set-up, but I I might add a few more features if the ones I added turn out to work ok. Possible additions/amendments: +- update profile note. - voting on polls - better display of polls - mention all thread participants in replies diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el new file mode 100644 index 0000000..ffd8ab6 --- /dev/null +++ b/lisp/mastodon-async.el @@ -0,0 +1,332 @@ +;;; mastodon-async.el --- Client for Mastodon -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Johnson Denen +;; Author: Johnson Denen +;; Version: 0.7.1 +;; Package-Requires: ((emacs "25.1")) +;; Homepage: https://github.com/jdenen/mastodon.el + +;; This file is not part of GNU Emacs. + +;; This file is part of mastodon.el. + +;; mastodon.el is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mastodon.el is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mastodon.el. If not, see . + +;;; Commentary: + +;; Rework sync code so it does not mess up the async-buffer + +;;; Code: + +(require 'json) + +(defgroup mastodon-async nil + "An async module for mastodon streams." + :prefix "mastodon-async-" + :group 'external) + +;;;###autoload +(define-minor-mode mastodon-async-mode + "Async Mastodon." + :lighter " MasA") + +(defvar mastodon-instance-url) + +(defvar mastodon-tl--enable-relative-timestamps) +(defvar mastodon-tl--display-media-p) +(defvar mastodon-tl--buffer-spec) + +(make-variable-buffer-local + (defvar mastodon-async--queue "" ;;"*mastodon-async-queue*" + "The intermediate queue buffer name.")) + +(make-variable-buffer-local + (defvar mastodon-async--buffer "" ;;"*mastodon-async-buffer*" + "User facing output buffer name.")) + +(make-variable-buffer-local + (defvar mastodon-async--http-buffer "" ;;"" + "Buffer variable bound to http output.")) + +(defun mastodon-async--display-http () + "Display the async HTTP input buffer." + (display-buffer mastodon-async--http-buffer)) + +(defun mastodon-async--display-buffer () + "Display the async user facing buffer." + (interactive) + (display-buffer mastodon-async--buffer)) + +(defun mastodon-async--display-queue () + "Display the async queue buffer." + (display-buffer mastodon-async--queue)) + +(defun mastodon-async--stop-http () + "Stop the http processs and close the async and http buffer." + (interactive) + (let ((inhibit-read-only t)) + (stop-process (get-buffer-process mastodon-async--http-buffer)) + (delete-process (get-buffer-process mastodon-async--http-buffer)) + (kill-buffer mastodon-async--http-buffer) + (setq mastodon-async--http-buffer "") + (kill-buffer mastodon-async--queue))) + +;; Need to handle the notification event +;; The output can be passed to notifications +;; need an alternate process-queue-string function +(defun mastodon-async--stream-notifications () + "Open a stream of Home." + (interactive) + (mastodon-async--mastodon + "user" + "home" + "notifications" + 'mastodon-async--process-queue-string)) + +;; this will stream both home AND notifications. +;; need to workout how to filter "user" stream +;; and split it +(defun mastodon-async--stream-home () + "Open a stream of Home." + (interactive) + (mastodon-async--mastodon + "user" + "home" + "home" + 'mastodon-async--process-queue-string)) + +(defun mastodon-async--stream-federated () + "Open a stream of Federated." + (interactive) + (mastodon-async--mastodon + "public" + "public" + "federated" + 'mastodon-async--process-queue-string)) + +(defun mastodon-async--stream-local () + "Open a stream of Local." + (interactive) + ;; Need to add another layer of filtering for this to work + ;; apparently it the local flag does not work + (mastodon-async--mastodon + "public" + "local" ;"public?local=true" + "local" + 'mastodon-async--process-queue-local-string)) + +(defun mastodon-async--mastodon (endpoint timeline name filter) + "Make sure that the previous async process has been closed. + +Then Start an async mastodon stream at ENDPOINT filtering toots +using FILTER. +Argument TIMELINE a specific target, such as federated or home. +Argument NAME the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queueu." + (let ((buffer (mastodon-async--start-process + endpoint filter name))) + (with-current-buffer buffer + (mastodon-async--display-buffer) + (goto-char (point-max)) + (goto-char 1)))) + +(defun mastodon-async--get (url callback) + "An async get targeted at URL with a CALLBACK." + (let ((url-request-method "GET") + (url-request-extra-headers + `(("Authorization" . + ,(concat + "Bearer " + (mastodon-auth--access-token)))))) + (url-retrieve url callback))) + +(defun mastodon-async--set-http-buffer (buffer http-buffer) + "Initializes for BUFFER a local variable `mastodon-async--http-buffer'. + +HTTP-BUFFER is the initializing value. Use this funcion if HTTP-BUFFER +is not known when `mastodon-async--setup-buffer' is called." + (with-current-buffer (get-buffer-create buffer) + (setq mastodon-async--http-buffer http-buffer))) + +(defun mastodon-async--set-local-variables (buffer + http-buffer + buffer-name + queue-name) + (with-current-buffer (get-buffer-create buffer) + (let ((value mastodon-instance-url)) + (make-local-variable 'mastodon-instance-url) + (setq-local mastodon-instance-url value)) + (setq mastodon-async--http-buffer http-buffer) + (setq mastodon-async--buffer buffer-name) + (setq mastodon-async--queue queue-name))) + +(defun mastodon-async--setup-http (http-buffer name) + "Adds local variables to HTTP-BUFFER. + +NAME is used to generate the display buffer and the queue." + (let ((queue-name(concat " *mastodon-async-queue-" name "-" + mastodon-instance-url "*")) + (buffer-name(concat "*mastodon-async-display-" name "-" + mastodon-instance-url "*"))) + (mastodon-async--set-local-variables http-buffer http-buffer + buffer-name queue-name))) + +(defun mastodon-async--setup-queue (http-buffer name) + "Sets up the buffer for the async queue." + (let ((queue-name(concat " *mastodon-async-queue-" name "-" + mastodon-instance-url "*")) + (buffer-name(concat "*mastodon-async-display-" name "-" + mastodon-instance-url "*"))) + (mastodon-async--set-local-variables queue-name http-buffer + buffer-name queue-name) + queue-name)) + +(defun mastodon-async--setup-buffer (http-buffer name endpoint) + "Sets up the buffer timeline like `mastodon-tl--init'. + +HTTP-BUFFER the name of the http-buffer, if unknow set to +NAME is the given name of the stream, like local for public?local +ENPOINT is the specific endpoint for a stream and timeline" + (let ((queue-name (concat " *mastodon-async-queue-" name "-" + mastodon-instance-url "*")) + (buffer-name (concat "*mastodon-async-display-" name "-" + mastodon-instance-url "*")) + ;; if user stream, we need "timelines/home" not "timelines/user" + (endpoint (if (equal endpoint "user") "home" endpoint))) + (mastodon-async--set-local-variables buffer-name http-buffer + buffer-name queue-name) + ;; Similar to timeline init. + (with-current-buffer (get-buffer-create buffer-name) + (setq inhibit-read-only t) ; for home timeline? + (make-local-variable 'mastodon-tl--enable-relative-timestamps) + (make-local-variable 'mastodon-tl--display-media-p) + (message (mastodon-http--api (format "timelines/%s" endpoint))) + (mastodon-tl--timeline (mastodon-http--get-json + (mastodon-http--api + (format "timelines/%s" endpoint)))) + (mastodon-mode) + (setq mastodon-tl--buffer-spec + `(buffer-name ,buffer-name + endpoint ,(format "timelines/%s" endpoint) + update-function + ,'mastodon-tl--timeline)) + (setq-local mastodon-tl--enable-relative-timestamps nil) + (setq-local mastodon-tl--display-media-p t) + (current-buffer)))) + +(defun mastodon-async--start-process (endpoint filter &optional name) + "Start an async mastodon stream at ENDPOINT. +Filter the toots using FILTER." + (let* ((stream (concat "streaming/" endpoint)) + (async-queue (mastodon-async--setup-queue "" (or name stream))) + (async-buffer (mastodon-async--setup-buffer "" (or name stream) endpoint)) + (http-buffer (mastodon-async--get + (mastodon-http--api stream) + (lambda (status) (message "HTTP SOURCE CLOSED"))))) + (mastodon-async--setup-http http-buffer (or name stream)) + (mastodon-async--set-http-buffer async-buffer http-buffer) + (mastodon-async--set-http-buffer async-queue http-buffer) + (set-process-filter (get-buffer-process http-buffer) + (mastodon-async--http-hook filter)) + http-buffer)) + +(defun mastodon-async--http-hook (filter) + "Return a lambda with a custom FILTER for processing toots." + (let ((filter filter)) + (lambda (proc data) + (with-current-buffer (process-buffer proc) + (let* ((string + (mastodon-async--stream-filter + (mastodon-async--http-layer proc data))) + (queue-string (mastodon-async--cycle-queue string))) + (when queue-string + (mastodon-async--output-toot + (funcall filter queue-string)))))))) + +(defun mastodon-async--process-queue-string (string) + "Parse the output STRING of the queue buffer." + (let* ((split-strings (split-string string "\n" t)) + (event-type (replace-regexp-in-string + "^event: " "" + (car split-strings))) + (data (replace-regexp-in-string + "^data: " "" (cadr split-strings)))) + (when (equal "update" event-type) + ;; in some casses the data is not fully formed + ;; for now return nil if malformed using `ignore-errors' + (ignore-errors (json-read-from-string data))))) + +(defun mastodon-async--process-queue-local-string (string) + "Use STRING to limit the public endpoint to displaying local steams only." + (let ((json (mastodon-async--process-queue-string string))) + (when json + (when (mastodon-async--account-local-p json) + json)))) + +(defun mastodon-async--account-local-p (json) + "Test JSON to see if account is local." + (not (string-match-p + "@" + (cdr (assoc 'acct (cdr (assoc 'account json))))))) + +(defun mastodon-async--output-toot (toot) + "Process TOOT and prepend it to the async user facing buffer." + (if (not(bufferp (get-buffer mastodon-async--buffer))) + (mastodon-async--stop-http) + (when toot + (with-current-buffer mastodon-async--buffer + (let* ((inhibit-read-only t) + (old-max (point-max)) + (previous (point)) + (mastodon-tl--enable-relative-timestamps t) + (mastodon-tl--display-media-p t)) + (goto-char (point-min)) + (mastodon-tl--timeline (list toot)) + (if (equal previous 1) + (goto-char 1) + (goto-char (+ previous (- (point-max) old-max))))))))) + +(defun mastodon-async--cycle-queue (string) + "Append the most recent STRING from http buffer to queue buffer. + +Then determine if a full message has been recived. If so return it. +Full messages are seperated by two newlines" + (with-current-buffer mastodon-async--queue + (goto-char (max-char)) + (insert (decode-coding-string string 'utf-8)) + (goto-char 0) + (let((next(re-search-forward "\n\n" nil t))) + (when next + (let ((return-string (buffer-substring 1 next)) + (inhibit-read-only t)) + (delete-region 1 next) + return-string))))) + +(defun mastodon-async--http-layer (proc data) + "Passes PROC and DATA to ‘url-http-generic-filter’. + +It then processes its output." + (with-current-buffer (process-buffer proc) + (let ((start (max 1 ( - (point-max) 2)))) + (url-http-generic-filter proc data) + (when (> url-http-end-of-headers start) + (setq start url-http-end-of-headers)) + (let ((end (- (point-max) 2))) + (buffer-substring start end))))) + +(defun mastodon-async--stream-filter (string) + "Remove comments from STRING." + (replace-regexp-in-string "^:.*\n" "" string)) + +(provide 'mastodon-async) +;;; mastodon-async.el ends here diff --git a/lisp/mastodon.el b/lisp/mastodon.el index d3477cb..6096c55 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -54,6 +54,7 @@ (autoload 'mastodon-toot--toggle-boost "mastodon-toot") (autoload 'mastodon-toot--toggle-favourite "mastodon-toot") (autoload 'mastodon-discover "mastodon-discover") + (autoload 'mastodon-tl--block-user "mastodon-tl") (autoload 'mastodon-tl--unblock-user "mastodon-tl") (autoload 'mastodon-tl--mute-user "mastodon-tl") @@ -61,11 +62,16 @@ (autoload 'mastodon-tl--follow-user "mastodon-tl") (autoload 'mastodon-tl--unfollow-user "mastodon-tl") (autoload 'mastodon-profile--my-profile "mastodon-profile") +(autoload 'mastodon-profile--view-favourites "mastodon-profile") +(autoload 'mastodon-profile--view-follow-requests "mastodon-profile") (autoload 'mastodon-search--search-query "mastodon-search") (autoload 'mastodon-toot--delete-toot "mastodon-toot") (autoload 'mastodon-toot--copy-toot-url "mastodon-toot") (autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") (autoload 'mastodon-auth--get-account-name "mastodon-auth") +(autoload 'mastodon-async--stream-federated "mastodon-async") +(autoload 'mastodon-async--stream-local "mastodon-async") +(autoload 'mastodon-async--stream-home "mastodon-async") (defgroup mastodon nil "Interface with Mastodon." -- cgit v1.2.3 From 9f532060927265717b7c71f5b77f6c650e72a34d Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 3 Jun 2021 10:02:57 +0200 Subject: enable async stream for user notifications. creates a notifications filter for the 'user' stream, then handles display of notifications, which have their own timeline funs. --- README.org | 13 +++++-- lisp/mastodon-async.el | 83 ++++++++++++++++++++++++++++-------------- lisp/mastodon-notifications.el | 6 +-- lisp/mastodon.el | 5 +++ 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/README.org b/README.org index b51644b..6da0f4b 100644 --- a/README.org +++ b/README.org @@ -9,8 +9,8 @@ It adds the following features: | | display relationship (follows you/followed by you) on profiles | | | display toots/follows/followers counts on profiles | | | links and tags in profiles are tab stops like in posts | -| =R=, =a=, =r= | view/accept/reject follow requests | -| =v= | view your favorited toots | +| =R=, =a=, =r= | view/accept/reject follow requests | +| =v= | view your favorited toots | | =i= | (un)pin toots, display pinned toots on profiles | | =S-C-P= | jump to your profile | | Timelines: | | @@ -33,7 +33,13 @@ The minimum Emacs version is now 25.1. But if you are running an older version i I did this for my own use and to learn more Elisp. If the code is terrible, feel free to improve or replace it. It surely still contains errors, I'm only weeding them out as I find them. -** NB: dependency: +** live-updating timelines + +(code adapted from https://github.com/alexjgriffith/mastodon-future.el). + +Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream= + +** NB: dependency This version depends on the library =request= (for uploading attachments). You can install it from MELPA, or https://github.com/tkf/emacs-request. @@ -53,7 +59,6 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - mention all thread participants in replies - handle newlines in toots better, for poetry, etc. - improve async. -- perhaps integrate live timeline updates from https://github.com/alexjgriffith/mastodon-future.el, and add live updates for notifcations and home timeline. It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index ffd8ab6..1be88ae 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -31,6 +31,8 @@ (require 'json) +(autoload 'mastodon-notifications--timeline "mastodon-notifications") + (defgroup mastodon-async nil "An async module for mastodon streams." :prefix "mastodon-async-" @@ -86,19 +88,19 @@ ;; The output can be passed to notifications ;; need an alternate process-queue-string function (defun mastodon-async--stream-notifications () - "Open a stream of Home." + "Open a stream of user notifications." (interactive) (mastodon-async--mastodon "user" "home" "notifications" - 'mastodon-async--process-queue-string)) + 'mastodon-async--process-queue-string-notifications)) ;; this will stream both home AND notifications. ;; need to workout how to filter "user" stream ;; and split it (defun mastodon-async--stream-home () - "Open a stream of Home." + "Open a stream of the home timeline." (interactive) (mastodon-async--mastodon "user" @@ -132,7 +134,7 @@ Then Start an async mastodon stream at ENDPOINT filtering toots using FILTER. Argument TIMELINE a specific target, such as federated or home. -Argument NAME the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queueu." +Argument NAME the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queue." (let ((buffer (mastodon-async--start-process endpoint filter name))) (with-current-buffer buffer @@ -141,7 +143,7 @@ Argument NAME the center portion of the buffer name for *mastodon-async-buffer a (goto-char 1)))) (defun mastodon-async--get (url callback) - "An async get targeted at URL with a CALLBACK." + "An async GET request to URL with CALLBACK." (let ((url-request-method "GET") (url-request-extra-headers `(("Authorization" . @@ -174,16 +176,16 @@ is not known when `mastodon-async--setup-buffer' is called." "Adds local variables to HTTP-BUFFER. NAME is used to generate the display buffer and the queue." - (let ((queue-name(concat " *mastodon-async-queue-" name "-" + (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) - (buffer-name(concat "*mastodon-async-display-" name "-" + (buffer-name (concat "*mastodon-async-display-" name "-" mastodon-instance-url "*"))) (mastodon-async--set-local-variables http-buffer http-buffer buffer-name queue-name))) (defun mastodon-async--setup-queue (http-buffer name) "Sets up the buffer for the async queue." - (let ((queue-name(concat " *mastodon-async-queue-" name "-" + (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name(concat "*mastodon-async-display-" name "-" mastodon-instance-url "*"))) @@ -194,15 +196,18 @@ NAME is used to generate the display buffer and the queue." (defun mastodon-async--setup-buffer (http-buffer name endpoint) "Sets up the buffer timeline like `mastodon-tl--init'. -HTTP-BUFFER the name of the http-buffer, if unknow set to -NAME is the given name of the stream, like local for public?local -ENPOINT is the specific endpoint for a stream and timeline" +HTTP-BUFFER the name of the http-buffer, if unknown, set to... +NAME is the name of the stream for the buffer name. +ENPOINT is the endpoint for the stream and timeline." (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name (concat "*mastodon-async-display-" name "-" mastodon-instance-url "*")) - ;; if user stream, we need "timelines/home" not "timelines/user" - (endpoint (if (equal endpoint "user") "home" endpoint))) + ;; if user stream, we need "timelines/home" not "timelines/user" + ;; if notifs, we need "notifications" not "timelines/notifications" + (endpoint (if (equal name "notifications") "notifications" + (if (equal name "home") "timelines/home" + (format "timelines/%s" endpoint))))) (mastodon-async--set-local-variables buffer-name http-buffer buffer-name queue-name) ;; Similar to timeline init. @@ -210,16 +215,22 @@ ENPOINT is the specific endpoint for a stream and timeline" (setq inhibit-read-only t) ; for home timeline? (make-local-variable 'mastodon-tl--enable-relative-timestamps) (make-local-variable 'mastodon-tl--display-media-p) - (message (mastodon-http--api (format "timelines/%s" endpoint))) - (mastodon-tl--timeline (mastodon-http--get-json - (mastodon-http--api - (format "timelines/%s" endpoint)))) + (message (mastodon-http--api endpoint)) + (if (equal name "notifications") + (mastodon-notifications--timeline + (mastodon-http--get-json + (mastodon-http--api "notifications"))) + (mastodon-tl--timeline (mastodon-http--get-json + (mastodon-http--api endpoint)))) (mastodon-mode) (setq mastodon-tl--buffer-spec - `(buffer-name ,buffer-name - endpoint ,(format "timelines/%s" endpoint) - update-function - ,'mastodon-tl--timeline)) + `(buffer-name + ,buffer-name + endpoint ,endpoint + update-function + ,(if (equal name "notifications") + 'mastodon-notifications--timeline + 'mastodon-tl--timeline))) (setq-local mastodon-tl--enable-relative-timestamps nil) (setq-local mastodon-tl--display-media-p t) (current-buffer)))) @@ -254,7 +265,7 @@ Filter the toots using FILTER." (funcall filter queue-string)))))))) (defun mastodon-async--process-queue-string (string) - "Parse the output STRING of the queue buffer." + "Parse the output STRING of the queue buffer, returning only update events." (let* ((split-strings (split-string string "\n" t)) (event-type (replace-regexp-in-string "^event: " "" @@ -266,6 +277,20 @@ Filter the toots using FILTER." ;; for now return nil if malformed using `ignore-errors' (ignore-errors (json-read-from-string data))))) +(defun mastodon-async--process-queue-string-notifications (string) + "Parse the output STRING of the queue buffer, returning only notification events." + ;; NB notification events in screams include follow requests + (let* ((split-strings (split-string string "\n" t)) + (event-type (replace-regexp-in-string + "^event: " "" + (car split-strings))) + (data (replace-regexp-in-string + "^data: " "" (cadr split-strings)))) + (when (equal "notification" event-type) + ;; in some casses the data is not fully formed + ;; for now return nil if malformed using `ignore-errors' + (ignore-errors (json-read-from-string data))))) + (defun mastodon-async--process-queue-local-string (string) "Use STRING to limit the public endpoint to displaying local steams only." (let ((json (mastodon-async--process-queue-string string))) @@ -280,8 +305,8 @@ Filter the toots using FILTER." (cdr (assoc 'acct (cdr (assoc 'account json))))))) (defun mastodon-async--output-toot (toot) - "Process TOOT and prepend it to the async user facing buffer." - (if (not(bufferp (get-buffer mastodon-async--buffer))) + "Process TOOT and prepend it to the async user-facing buffer." + (if (not (bufferp (get-buffer mastodon-async--buffer))) (mastodon-async--stop-http) (when toot (with-current-buffer mastodon-async--buffer @@ -290,8 +315,12 @@ Filter the toots using FILTER." (previous (point)) (mastodon-tl--enable-relative-timestamps t) (mastodon-tl--display-media-p t)) - (goto-char (point-min)) - (mastodon-tl--timeline (list toot)) + (goto-char (point-min)) + (if (equal (buffer-name) + (concat "*mastodon-async-display-notifications-" + mastodon-instance-url "*")) + (mastodon-notifications--timeline (list toot)) + (mastodon-tl--timeline (list toot))) (if (equal previous 1) (goto-char 1) (goto-char (+ previous (- (point-max) old-max))))))))) @@ -305,7 +334,7 @@ Full messages are seperated by two newlines" (goto-char (max-char)) (insert (decode-coding-string string 'utf-8)) (goto-char 0) - (let((next(re-search-forward "\n\n" nil t))) + (let ((next (re-search-forward "\n\n" nil t))) (when next (let ((return-string (buffer-substring 1 next)) (inhibit-read-only t)) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index d40815a..4bf30f1 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -140,11 +140,11 @@ (defun mastodon-notifications--get () "Display NOTIFICATIONS in buffer." (interactive) + (message "Loading your nofications...") (mastodon-tl--init - "*mastodon-notifications*" "notifications" - 'mastodon-notifications--timeline) - (message "Loading your nofications...")) + "notifications" + 'mastodon-notifications--timeline)) (provide 'mastodon-notifications) ;;; mastodon-notifications.el ends here diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 6096c55..4d0b940 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -72,6 +72,7 @@ (autoload 'mastodon-async--stream-federated "mastodon-async") (autoload 'mastodon-async--stream-local "mastodon-async") (autoload 'mastodon-async--stream-home "mastodon-async") +(autoload 'mastodon-async--stream-notifications "mastodon-async") (defgroup mastodon nil "Interface with Mastodon." @@ -139,6 +140,10 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "i") #'mastodon-toot--pin-toot-toggle) (define-key map (kbd "v") #'mastodon-profile--view-favourites) (define-key map (kbd "R") #'mastodon-profile--view-follow-requests) + (define-key map (kbd "C-c h") #'mastodon-async--stream-home) + (define-key map (kbd "C-c f") #'mastodon-async--stream-federated) + (define-key map (kbd "C-c l") #'mastodon-async--stream-local) + (define-key map (kbd "C-c n") #'mastodon-async--stream-notifications) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 21bbab0885097ce7e47cbb88f9214c1f507adf87 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 4 Jun 2021 11:16:10 +0200 Subject: handle error on kill async buffer, begin same on borked JSON. --- lisp/mastodon-async.el | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 1be88ae..fcc6c94 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -82,11 +82,9 @@ (delete-process (get-buffer-process mastodon-async--http-buffer)) (kill-buffer mastodon-async--http-buffer) (setq mastodon-async--http-buffer "") - (kill-buffer mastodon-async--queue))) + (when (not (equal "" mastodon-async--queue)) ; error handle on kill async buffer + (kill-buffer mastodon-async--queue)))) -;; Need to handle the notification event -;; The output can be passed to notifications -;; need an alternate process-queue-string function (defun mastodon-async--stream-notifications () "Open a stream of user notifications." (interactive) @@ -96,9 +94,6 @@ "notifications" 'mastodon-async--process-queue-string-notifications)) -;; this will stream both home AND notifications. -;; need to workout how to filter "user" stream -;; and split it (defun mastodon-async--stream-home () "Open a stream of the home timeline." (interactive) @@ -266,20 +261,21 @@ Filter the toots using FILTER." (defun mastodon-async--process-queue-string (string) "Parse the output STRING of the queue buffer, returning only update events." - (let* ((split-strings (split-string string "\n" t)) - (event-type (replace-regexp-in-string - "^event: " "" - (car split-strings))) - (data (replace-regexp-in-string - "^data: " "" (cadr split-strings)))) - (when (equal "update" event-type) - ;; in some casses the data is not fully formed - ;; for now return nil if malformed using `ignore-errors' - (ignore-errors (json-read-from-string data))))) + (let ((split-strings (split-string string "\n" t))) + (when split-strings ; do nothing if we get nothing; just postpones the error + (let ((event-type (replace-regexp-in-string + "^event: " "" + (car split-strings))) + (data (replace-regexp-in-string + "^data: " "" (cadr split-strings)))) + (when (equal "update" event-type) + ;; in some casses the data is not fully formed + ;; for now return nil if malformed using `ignore-errors' + (ignore-errors (json-read-from-string data))))))) (defun mastodon-async--process-queue-string-notifications (string) "Parse the output STRING of the queue buffer, returning only notification events." - ;; NB notification events in screams include follow requests + ;; NB notification events in streams include follow requests (let* ((split-strings (split-string string "\n" t)) (event-type (replace-regexp-in-string "^event: " "" -- cgit v1.2.3 From a32a239d7e64d46df8e76c712a2335cecf8776e9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 5 Jun 2021 12:43:19 +0200 Subject: implement updating user profile note uses a tiny minor mode 'profile-update', with bindings. U is a general binding for it. --- README.org | 8 +++--- lisp/mastodon-http.el | 25 +++++++++++++++++- lisp/mastodon-profile.el | 69 +++++++++++++++++++++++++++++++++++++++++++----- lisp/mastodon.el | 4 ++- 4 files changed, 94 insertions(+), 12 deletions(-) diff --git a/README.org b/README.org index 6da0f4b..c6eab5a 100644 --- a/README.org +++ b/README.org @@ -6,13 +6,15 @@ It adds the following features: | Profiles: | | | | display profile metadata fields | +| | display pinned toots on profiles | | | display relationship (follows you/followed by you) on profiles | | | display toots/follows/followers counts on profiles | -| | links and tags in profiles are tab stops like in posts | +| | links and tags in profiles and metadata fields are tab stops like in posts | | =R=, =a=, =r= | view/accept/reject follow requests | | =v= | view your favorited toots | -| =i= | (un)pin toots, display pinned toots on profiles | +| =i= | (un)pin toots | | =S-C-P= | jump to your profile | +| =U= | update your profile bio note | | Timelines: | | | =W=, =M=, =B= | (un)follow, (un)mute, (un)block users | | | images are links to the full image, can be zoomed/rotated/saved (see their keymap) | @@ -37,7 +39,7 @@ I did this for my own use and to learn more Elisp. If the code is terrible, feel (code adapted from https://github.com/alexjgriffith/mastodon-future.el). -Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream= +Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=. ** NB: dependency diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index e85429f..678e628 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -137,7 +137,7 @@ Pass response buffer to CALLBACK function." (with-temp-buffer (url-retrieve-synchronously url)))) -;; http functions for search: +;; search functions: (defun mastodon-http--process-json-search () "Process JSON returned by a search query to the server." (goto-char (point-min)) @@ -168,6 +168,29 @@ Pass response buffer to CALLBACK function." (url-retrieve-synchronously url) (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) +;; profile update functions + +(defun mastodon-http--patch-json (url) + "Make synchronous PATCH request to URL. Return JSON response." + (with-current-buffer (mastodon-http--patch url) + (mastodon-http--process-json))) + +;; hard coded just for bio note for now: +(defun mastodon-http--patch (base-url &optional note) + "Make synchronous PATCH request to URL. + +Pass response buffer to CALLBACK function." + (let ((url-request-method "PATCH") + (url (if note + (concat base-url "?note=" (url-hexify-string note)) + base-url)) + (url-request-extra-headers + `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))))) + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + ;; Asynchronous functions (defun mastodon-http--get-async (url &optional callback &rest cbargs) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 84664c0..0b7ecc4 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -53,15 +53,28 @@ (autoload 'mastodon-tl--toot-id "mastodon-tl") (autoload 'mastodon-tl--toot "mastodon-tl") (autoload 'mastodon-tl--init "mastodon-tl.el") +(autoload 'mastodon-http--patch "mastodon-http") +(autoload 'mastodon-http--patch-json "mastodon-http") (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) (defvar mastodon-tl--update-point) + (defvar mastodon-profile--account nil "The data for the account being described in the current profile buffer.") (make-variable-buffer-local 'mastodon-profile--account) +;; this way you can update it with C-M-x: +(defvar mastodon-profile-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "O") #'mastodon-profile--open-followers) + (define-key map (kbd "o") #'mastodon-profile--open-following) + (define-key map (kbd "a") #'mastodon-profile--follow-request-accept) + (define-key map (kbd "r") #'mastodon-profile--follow-request-reject) + map) + "Keymap for `mastodon-profile-mode'.") + (define-minor-mode mastodon-profile-mode "Toggle mastodon profile minor mode. @@ -70,12 +83,26 @@ extra keybindings." :init-value nil ;; The mode line indicator. :lighter " Profile" - ;; The key bindings - :keymap '(((kbd "O") . mastodon-profile--open-followers) - ((kbd "o") . mastodon-profile--open-following) - ((kbd "a") . mastodon-profile--follow-request-accept) - ((kbd "r") . mastodon-profile--follow-request-reject)) - :group 'mastodon) + :keymap mastodon-profile-mode-map + ;; :keymap '(((kbd "O") . mastodon-profile--open-followers) + ;; ((kbd "o") . mastodon-profile--open-following) + ;; ((kbd "a") . mastodon-profile--follow-request-accept) + ;; ((kbd "r") . mastodon-profile--follow-request-reject) + :group 'mastodon + :global nil) + +(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) + map) + "Keymap for `mastodon-profile-update-mode'.") + +(define-minor-mode mastodon-profile-update-mode + "Minor mode to update Mastodon user profile." + :group 'mastodon-profile + :keymap mastodon-profile-update-mode-map + :global nil) (defun mastodon-profile--toot-json () "Get the next toot-json." @@ -112,6 +139,7 @@ following the current profile." (defun mastodon-profile--view-favourites () "Open a new buffer displaying the user's favourites." (interactive) + (message "Loading your favourited toots...") (mastodon-tl--init "favourites" "favourites" 'mastodon-tl--timeline)) @@ -164,6 +192,33 @@ following the current profile." name handle)))) (message "No account result at point?")))) +(defun mastodon-profile--update-user-profile-note () + "Fetch user's profile note and display for editing." + (interactive) + (let* ((url (concat mastodon-instance-url + "/api/v1/accounts/update_credentials")) + ;; (buffer (mastodon-http--patch url)) + (json (mastodon-http--patch-json url)) + (source (cdr (assoc 'source json))) + (note (cdr (assoc 'note source))) + (buffer (get-buffer-create "*mastodon-update-profile*")) + (inhibit-read-only t)) + (switch-to-buffer-other-window buffer) + (mastodon-profile-update-mode t) + (insert note) + (goto-char (point-min)) + (message "Edit your profile note. C-c C-c to send, C-c C-k to cancel."))) + +(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))) + (url (concat mastodon-instance-url + "/api/v1/accounts/update_credentials"))) + (kill-buffer-and-window) + (let ((response (mastodon-http--patch url note))) + (mastodon-http--triage response + (lambda () (message "Profile note updated!")))))) (defun mastodon-profile--relationships-get (id) "Fetch info about logged-in user's relationship to user with id ID." @@ -205,7 +260,7 @@ Returns a list of lists." (format " :: %s" (cadr field))) ;; (make-string (- (+ 1 right-width) (length (cdr field))) ?_) ;; " |") - nil)) + field)) ; nil)) ; hack to make links tabstops fields ""))) (defun mastodon-profile--get-statuses-pinned (account) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 4d0b940..c1c4360 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -73,6 +73,7 @@ (autoload 'mastodon-async--stream-local "mastodon-async") (autoload 'mastodon-async--stream-home "mastodon-async") (autoload 'mastodon-async--stream-notifications "mastodon-async") +(autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (defgroup mastodon nil "Interface with Mastodon." @@ -143,7 +144,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-c h") #'mastodon-async--stream-home) (define-key map (kbd "C-c f") #'mastodon-async--stream-federated) (define-key map (kbd "C-c l") #'mastodon-async--stream-local) - (define-key map (kbd "C-c n") #'mastodon-async--stream-notifications) + (define-key map (kbd "C-c n") #'mastodon-async--stream-notifications) + (define-key map (kbd "U") #'mastodon-profile--update-user-profile-note) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 68c2942b4c94cc9c3c10b1b1b6d78f3ff6f43fb9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 7 Jun 2021 17:06:07 +0200 Subject: fix async "local" endpoint, docstrings --- lisp/mastodon-async.el | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index fcc6c94..1690615 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -119,17 +119,17 @@ ;; apparently it the local flag does not work (mastodon-async--mastodon "public" - "local" ;"public?local=true" + "public?local=true" "local" 'mastodon-async--process-queue-local-string)) (defun mastodon-async--mastodon (endpoint timeline name filter) "Make sure that the previous async process has been closed. -Then Start an async mastodon stream at ENDPOINT filtering toots +Then start an async stream at ENDPOINT filtering toots using FILTER. -Argument TIMELINE a specific target, such as federated or home. -Argument NAME the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queue." +TIMELINE is a specific target, such as federated or home. +NAME is the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queue." (let ((buffer (mastodon-async--start-process endpoint filter name))) (with-current-buffer buffer -- cgit v1.2.3 From 93a5c652a97f2b591c32ec4902bbc24781b9a9d7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 7 Jun 2021 17:06:54 +0200 Subject: mastodon-http--get-async, only process json when status is returned (hopefully) --- lisp/mastodon-http.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 678e628..cb211d4 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -208,7 +208,8 @@ Pass response buffer to CALLBACK function with args CBARGS." (mastodon-http--get-async url (lambda (status) - (apply callback (mastodon-http--process-json) args)))) + (when status ;; only when we actually get sth? + (apply callback (mastodon-http--process-json) args))))) (defun mastodon-http--post-async (url args headers &optional callback &rest cbargs) "POST asynchronously to URL with ARGS and HEADERS. -- cgit v1.2.3 From af3705d107a248c1edc0742f6a8533bef533b6a5 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 7 Jun 2021 17:09:10 +0200 Subject: only get-home-timeline if mastodon buffers not already open. requires cl-lib --- lisp/mastodon.el | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index c1c4360..50acc18 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -30,6 +30,8 @@ ;; it is a labor of love. ;;; Code: +(require 'cl-lib) ; for some call in mastodon + (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") (declare-function request "request") @@ -180,8 +182,19 @@ Use. e.g. \"%c\" for your locale's date and time format." (defun mastodon () "Connect Mastodon client to `mastodon-instance-url' instance." (interactive) - (mastodon-tl--get-home-timeline) - (message "Loading Mastodon account %s on %s..." (mastodon-auth--get-account-name) mastodon-instance-url)) + (let* ((tls (list "home" + "local" + "federated" + (concat (mastodon-auth--get-account-name) "-statuses") ; profile + "favourites" + "search")) + (buffer (cl-some (lambda (el) + (get-buffer (concat "*mastodon-" el "*"))) + tls))) ; return first buff that exists + (if buffer + (switch-to-buffer buffer) + (mastodon-tl--get-home-timeline) + (message "Loading Mastodon account %s on %s..." (mastodon-auth--get-account-name) mastodon-instance-url)))) ;;;###autoload (defun mastodon-toot (&optional user reply-to-id) -- cgit v1.2.3 From 0c5139649cfd1698049a06b7cbcdabba4c95e17a Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 7 Jun 2021 20:43:18 +0200 Subject: attempt to handle response errors in mastodon-http--process-json --- lisp/mastodon-http.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index cb211d4..144b446 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -126,7 +126,9 @@ Pass response buffer to CALLBACK function." (buffer-substring-no-properties (point) (point-max)) 'utf-8))) (kill-buffer) - (json-read-from-string json-string))) + (if (not (or (string= "" json-string) (equal nil json-string))) + (json-read-from-string json-string) + (message "Looks like we got no JSON from the server.")))) (defun mastodon-http--delete (url) "Make DELETE request to URL." -- cgit v1.2.3 From dfa1db177bfb2c1d5ff044c99a78a380da89ec33 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 8 Jun 2021 09:49:58 +0200 Subject: use mastodon-auth--user-acct instead of get-account-name in mastodon the former first checks if the value is stored in var mastodon-auth--acct-alist, and only makes a request if it doesn't get the handle from there. and if run it also stores the value. --- lisp/mastodon.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 50acc18..e166671 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -76,6 +76,7 @@ (autoload 'mastodon-async--stream-home "mastodon-async") (autoload 'mastodon-async--stream-notifications "mastodon-async") (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") +(autoload 'mastodon-auth--user-acct "mastodon-auth") (defgroup mastodon nil "Interface with Mastodon." @@ -185,7 +186,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (let* ((tls (list "home" "local" "federated" - (concat (mastodon-auth--get-account-name) "-statuses") ; profile + (concat (mastodon-auth--user-acct) "-statuses") ; profile "favourites" "search")) (buffer (cl-some (lambda (el) @@ -194,7 +195,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (if buffer (switch-to-buffer buffer) (mastodon-tl--get-home-timeline) - (message "Loading Mastodon account %s on %s..." (mastodon-auth--get-account-name) mastodon-instance-url)))) + (message "Loading Mastodon account %s on %s..." (mastodon-auth--user-acct) mastodon-instance-url)))) ;;;###autoload (defun mastodon-toot (&optional user reply-to-id) -- cgit v1.2.3 From c9a80513b451ebab95eca3b4dda7e2ece6bcbbd2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 14 Jun 2021 14:29:42 +0200 Subject: typos and readme --- README.org | 44 +++++++++++++++++++++++------------------- lisp/mastodon-notifications.el | 2 +- lisp/mastodon.el | 2 +- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/README.org b/README.org index c6eab5a..21ae34a 100644 --- a/README.org +++ b/README.org @@ -39,7 +39,11 @@ I did this for my own use and to learn more Elisp. If the code is terrible, feel (code adapted from https://github.com/alexjgriffith/mastodon-future.el). -Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=. +Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=, and you can load various timelines from within a mastodon session like so: +- =C-c h= (home) +- =C-c f= (federated) +- =C-c l= (local) +- =C-c n= (notifications). ** NB: dependency @@ -64,9 +68,9 @@ I might add a few more features if the ones I added turn out to work ok. Possibl It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. -** Original README +* Original README -*** Installation +** Installation Clone this repository and add the lisp directory to your load path. Then, require it and go. @@ -83,7 +87,7 @@ Or, with =use-package=: :ensure t) #+END_SRC -**** MELPA +*** MELPA Add =MELPA= to your archives: @@ -99,12 +103,12 @@ Update and install: =M-x package-install RET mastodon RET= -**** Emoji +*** Emoji =mastodon-mode= will enable [[https://github.com/iqbalansari/emacs-emojify][Emojify]] if it is loaded in your Emacs environment, so there's no need to write your own hook anymore. =emojify-mode= is not required. -**** Discover +*** Discover =mastodon-mode= can provide a context menu for its keybindings if [[https://github.com/mickeynp/discover.el][Discover]] is installed. It is not required. @@ -125,12 +129,12 @@ Or, with =use-package=: (mastodon-discover)) #+END_SRC -*** Usage -**** 2 Factor Auth +** Usage +*** 2 Factor Auth 2FA is not supported yet. It is in the [[https://github.com/jdenen/mastodon.el/milestone/2][plans]] for the =1.0.0= release. If you have 2FA enabled and try to use mastodon.el, your Emacs client will hang until you `C-g` your way out. -**** Instance +*** Instance Set =mastodon-instance-url= in your =.emacs= or =customize=. Defaults to the [[https://mastodon.social][flagship]]. @@ -142,13 +146,13 @@ There is an option to have your user credentials (email address and password) sa The default is not to do this because if not properly configured it would save these unencrypted which is not a good default to have. Customize the variable =mastodon-auth-source-file= if you want to enable this feature. -**** Timelines +*** Timelines =M-x mastodon= Opens a =*mastodon-home*= buffer in the major mode so you can see toots. You will be prompted for email and password. The app registration process will take place if your =mastodon-token-file= does not contain =:client_id= and =:client_secret=. -***** Keybindings +**** Keybindings |-----------------+---------------------------------------------------------| | Key | Action | @@ -181,7 +185,7 @@ Opens a =*mastodon-home*= buffer in the major mode so you can see toots. You wil | =Q= | Quit mastodon buffer and kill window | |-----------------+---------------------------------------------------------| -***** Legend +**** Legend |--------+-------------------------| | Marker | Meaning | @@ -190,7 +194,7 @@ Opens a =*mastodon-home*= buffer in the major mode so you can see toots. You wil | =(F)= | I favourited this toot. | |--------+-------------------------| -**** Toot toot +*** Toot toot =M-x mastodon-toot= @@ -205,12 +209,12 @@ Authentication stores your access token in the =mastodon-auth--token= variable. It is not stored on your filesystem, so you will have to re-authenticate when you close/reopen Emacs. -***** Customization +**** Customization The default toot visibility can be changed by setting or customizing the =mastodon-toot--default-visibility= variable. Valid values are ="public"=, ="unlisted"=, ="private"=, or =direct=. Toot visibility can also be changed on a per-toot basis from the new toot buffer. -***** Keybindings +**** Keybindings |-----------+------------------------| | Key | Action | @@ -221,28 +225,28 @@ Toot visibility can also be changed on a per-toot basis from the new toot buffer | =C-c C-v= | Change toot visibility | |-----------+------------------------| -*** Roadmap +** Roadmap [[https://github.com/jdenen/mastodon.el/milestone/1][Here]] are the features I plan to implement before putting mastodon.el on MELPA. [[https://github.com/jdenen/mastodon.el/milestone/2][Here]] are the plans I have for the =1.0.0= release. -*** Contributing +** Contributing PRs, issues, and feature requests are very welcome! -**** Features +*** Features 1. Create an [[https://github.com/jdenen/mastodon.el/issues][issue]] detailing the feature you'd like to add. 2. Fork the repository and create a branch off of =develop=. 3. Create a pull request referencing the issue created in step 1. -**** Fixes +*** Fixes 1. In an [[https://github.com/jdenen/mastodon.el/issues][issue]], let me know that you're working to fix it. 2. Fork the repository and create a branch off of =develop=. 3. Create a pull request referencing the issue from step 1. -*** Connect +** Connect If you want to get in touch with me, give me a [[https://mastodon.social/@johnson][toot]] or leave an [[https://github.com/jdenen/mastodon.el/issues][issue]]. diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 4bf30f1..51806a3 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -140,7 +140,7 @@ (defun mastodon-notifications--get () "Display NOTIFICATIONS in buffer." (interactive) - (message "Loading your nofications...") + (message "Loading your notifications...") (mastodon-tl--init "notifications" "notifications" diff --git a/lisp/mastodon.el b/lisp/mastodon.el index e166671..430362d 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -30,7 +30,7 @@ ;; it is a labor of love. ;;; Code: -(require 'cl-lib) ; for some call in mastodon +(require 'cl-lib) ; for `some' call in mastodon (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") -- cgit v1.2.3 From f9452225da575a8272b2880214a241b72efd5e4f Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 19 Jun 2021 12:37:07 +0200 Subject: hack to ensure toot buffer bindings are always enabled. make mastodon-toot-mode is run in mastodon-toot--compose-buffer before after-change-functions bugs. this makes mastodon-toot work properly even if mastodon-mode has not yet been run/loaded yet. --- lisp/mastodon-toot.el | 4 ++-- lisp/mastodon.el | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a0f886c..d9f895c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -516,9 +516,9 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (when (not buffer-exists) (mastodon-toot--display-docs-and-status-fields) (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) + (mastodon-toot-mode t) (push #'mastodon-toot--update-status-fields after-change-functions) - (mastodon-toot--update-status-fields) - (mastodon-toot-mode t))) + (mastodon-toot--update-status-fields))) (define-minor-mode mastodon-toot-mode "Minor mode to capture Mastodon toots." diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 430362d..96a092f 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -30,7 +30,7 @@ ;; it is a labor of love. ;;; Code: -(require 'cl-lib) ; for `some' call in mastodon +(require 'cl-lib) ; for `cl-some' call in mastodon (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") -- cgit v1.2.3 From a7148e8c79c7451c035a75217a9349b531752caa Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 19 Jun 2021 13:12:44 +0200 Subject: display boosted polls --- lisp/mastodon-tl.el | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index d90a759..10b867c 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -645,8 +645,11 @@ message is a link which unhides/hides the main body." (defun mastodon-tl--content (toot) "Retrieve text content from TOOT." - (let ((content (mastodon-tl--field 'content toot)) - (poll-p (cdr (assoc 'poll toot)))) + (let* ((content (mastodon-tl--field 'content toot)) + (reblog (cdr (assoc 'reblog toot))) + (poll-p (if reblog + (cdr (assoc 'poll reblog)) + (cdr (assoc 'poll toot))))) (concat (when poll-p (mastodon-tl--get-poll toot)) -- cgit v1.2.3 From 5e022b655b654fe1967c848b45b1400fff502d37 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 19 Jun 2021 15:52:43 +0200 Subject: feed notfication ID to mastodon-notifications--insert-status which is a copy of mastodon-tl--insert-status. this makes the 'toot-id of notifications that of the favoriting/boosting item, rather than the item boosted/favorited. this ID is needed in order to make loading more older notifications work correctly. beforehand, the call would be incorrect and the same latest 20 notifications would load. --- lisp/mastodon-notifications.el | 47 ++++++++++++++++++++++++++++++++++-------- lisp/mastodon-tl.el | 4 ++-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 51806a3..a731ddf 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -65,8 +65,9 @@ (defun mastodon-notifications--mention (note) "Format for a `mention' NOTE." - (let ((status (mastodon-tl--field 'status note))) - (mastodon-tl--insert-status + (let ((id (cdr (assoc 'id note))) + (status (mastodon-tl--field 'status note))) + (mastodon-notifications--insert-status status (mastodon-tl--clean-tabs-and-nl (if (mastodon-tl--has-spoiler status) @@ -75,7 +76,8 @@ 'mastodon-tl--byline-author (lambda (_status) (mastodon-notifications--byline-concat - "Mentioned"))))) + "Mentioned")) + id))) (defun mastodon-notifications--follow (note) "Format for a `follow' NOTE." @@ -92,8 +94,9 @@ (defun mastodon-notifications--favourite (note) "Format for a `favourite' NOTE." - (let ((status (mastodon-tl--field 'status note))) - (mastodon-tl--insert-status + (let ((id (cdr (assoc 'id note))) + (status (mastodon-tl--field 'status note))) + (mastodon-notifications--insert-status status (mastodon-tl--clean-tabs-and-nl (if (mastodon-tl--has-spoiler status) @@ -104,12 +107,14 @@ note)) (lambda (_status) (mastodon-notifications--byline-concat - "Favourited"))))) + "Favourited")) + id))) (defun mastodon-notifications--reblog (note) "Format for a `boost' NOTE." - (let ((status (mastodon-tl--field 'status note))) - (mastodon-tl--insert-status + (let ((id (cdr (assoc 'id note))) + (status (mastodon-tl--field 'status note))) + (mastodon-notifications--insert-status status (mastodon-tl--clean-tabs-and-nl (if (mastodon-tl--has-spoiler status) @@ -120,7 +125,31 @@ note)) (lambda (_status) (mastodon-notifications--byline-concat - "Boosted"))))) + "Boosted")) + id))) + +(defun mastodon-notifications--insert-status (toot body author-byline action-byline &optional id) + "Display the content and byline of timeline element TOOT. + +BODY will form the section of the toot above the byline. +AUTHOR-BYLINE is an optional function for adding the author portion of +the byline that takes one variable. By default it is `mastodon-tl--byline-author' +ACTION-BYLINE is also an optional function for adding an action, such as boosting +favouriting and following to the byline. It also takes a single function. By default +it is `mastodon-tl--byline-boosted'" + (let ((start-pos (point))) + (insert + (propertize + (concat "\n" + body + " \n" + (mastodon-tl--byline toot author-byline action-byline)) + 'toot-id id + 'base-toot-id (mastodon-tl--toot-id toot) + 'toot-json toot) + "\n") + (when mastodon-tl--display-media-p + (mastodon-media--inline-images start-pos (point))))) (defun mastodon-notifications--by-type (note) "Filters NOTE for those listed in `mastodon-notifications--types-alist'." diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 10b867c..77caf13 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1171,8 +1171,8 @@ UPDATE-FUNCTION is used to recieve more toots." (with-current-buffer buffer (setq mastodon-tl--buffer-spec `(buffer-name ,buffer - endpoint ,endpoint update-function - ,update-function) + endpoint ,endpoint + update-function ,update-function) mastodon-tl--timestamp-update-timer (when mastodon-tl--enable-relative-timestamps (run-at-time mastodon-tl--timestamp-next-update -- cgit v1.2.3 From 7afc5a08e35c86acc9f009404045a787ef61b77b Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 21 Jun 2021 11:33:40 +0200 Subject: typo in async http-layer, unless in http process-json, typo in readm --- README.org | 2 +- lisp/mastodon-async.el | 2 +- lisp/mastodon-http.el | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.org b/README.org index 21ae34a..5adab37 100644 --- a/README.org +++ b/README.org @@ -37,7 +37,7 @@ I did this for my own use and to learn more Elisp. If the code is terrible, feel ** live-updating timelines -(code adapted from https://github.com/alexjgriffith/mastodon-future.el). +(code adapted from https://github.com/alexjgriffith/mastodon-future.el.) Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=, and you can load various timelines from within a mastodon session like so: - =C-c h= (home) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 1690615..4367cc9 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -342,7 +342,7 @@ Full messages are seperated by two newlines" It then processes its output." (with-current-buffer (process-buffer proc) - (let ((start (max 1 ( - (point-max) 2)))) + (let ((start (max 1 (- (point-max) 2)))) (url-http-generic-filter proc data) (when (> url-http-end-of-headers start) (setq start url-http-end-of-headers)) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 144b446..e8fd4d3 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -126,9 +126,8 @@ Pass response buffer to CALLBACK function." (buffer-substring-no-properties (point) (point-max)) 'utf-8))) (kill-buffer) - (if (not (or (string= "" json-string) (equal nil json-string))) - (json-read-from-string json-string) - (message "Looks like we got no JSON from the server.")))) + (unless (or (string= "" json-string) (equal nil json-string))) + (json-read-from-string json-string))) (defun mastodon-http--delete (url) "Make DELETE request to URL." -- cgit v1.2.3 From 43fa09ef3e080b5e36338554ff7b0d0152ff3a53 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 16 Jul 2021 20:52:13 +0200 Subject: move follow req acc/rej bindings so they don't shadow profiles --- lisp/mastodon-profile.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 0b7ecc4..c94ed35 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -70,8 +70,8 @@ (let ((map (make-sparse-keymap))) (define-key map (kbd "O") #'mastodon-profile--open-followers) (define-key map (kbd "o") #'mastodon-profile--open-following) - (define-key map (kbd "a") #'mastodon-profile--follow-request-accept) - (define-key map (kbd "r") #'mastodon-profile--follow-request-reject) + (define-key map (kbd "C-c a") #'mastodon-profile--follow-request-accept) + (define-key map (kbd "C-c r") #'mastodon-profile--follow-request-reject) map) "Keymap for `mastodon-profile-mode'.") -- cgit v1.2.3 From f919763630dbc0fbc5ed86666bce380aa09562e6 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 28 Jul 2021 14:38:37 +0200 Subject: readme mastodon-toot bugs --- README.org | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.org b/README.org index 5adab37..2eec284 100644 --- a/README.org +++ b/README.org @@ -53,6 +53,8 @@ This version depends on the library =request= (for uploading attachments). You c As it stands the client still has some bugs. In particular, when composing a toot, hit =C-g= before sending your toot. If you don't, your draft may disappear. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. +In addition, if you create and send a toot with =mastodon-toot= / =C-c t= before otherwise opening the client, various little things break. + Some people have also had niggling troubles with initial auth and set-up, but I couldn't reproduce. ** roadmap-ish -- cgit v1.2.3 From 2bff9c7dfbdb71fab520e876df7f2a8fc864a30e Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 7 Aug 2021 10:18:26 +0200 Subject: fix tests to work with my changes: bylines + notifs async --- test/mastodon-notifications-test.el | 6 ++-- test/mastodon-tl-tests.el | 58 ++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el index ba08bd4..19b591d 100644 --- a/test/mastodon-notifications-test.el +++ b/test/mastodon-notifications-test.el @@ -185,7 +185,7 @@ "Ensure get request format for notifictions is accurate." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications")) + (mock (mastodon-http--get-json-async "https://instance.url/api/v1/notifications" 'mastodon-tl--init* "*mastodon-notifications*" "notifications" 'mastodon-notifications--timeline)) (mastodon-notifications--get)))) (defun mastodon-notifications--test-type (fun sample) @@ -205,9 +205,9 @@ notification to be tested." (mastodon-notifications--byline-concat "Mentioned")) (string= " Followed you" (mastodon-notifications--byline-concat "Followed")) - (string= " Favourited your status" + (string= " Favourited your status from" (mastodon-notifications--byline-concat "Favourited")) - (string= " Boosted your status" + (string= " Boosted your status from" (mastodon-notifications--byline-concat "Boosted"))))) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index 851dc39..c7dfc9a 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -81,7 +81,7 @@ (username . "acct42"))]) (tags . []) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") - (content . "

@acct42 boost

") + (content . "

@acct42 boost

") (url . "https://example.space/users/acct42/updates/123456789") (reblogs_count . 1) (favourites_count . 1) @@ -262,9 +262,9 @@ a string or a numeric." (handle-location 20)) (should (string= (substring-no-properties byline) - " - | Account 42 (@acct42@example.space) 2999-99-99 00:11:22 - ------------")) + "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + ------------ +")) (should (eq (get-text-property handle-location 'mastodon-tab-stop byline) 'user-handle)) (should (string= (get-text-property handle-location 'mastodon-handle byline) @@ -285,9 +285,9 @@ a string or a numeric." (mastodon-tl--byline mastodon-tl-test-base-toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " - | Account 42 (@acct42@example.space) 2999-99-99 00:11:22 - ------------"))))) + " Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + ------------ +"))))) (ert-deftest mastodon-tl--byline-boosted () "Should format the boosted toot correctly." @@ -302,9 +302,9 @@ a string or a numeric." (mastodon-tl--byline toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " - | (B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 - ------------"))))) + "(B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + ------------ +"))))) (ert-deftest mastodon-tl--byline-favorited () "Should format the favourited toot correctly." @@ -319,9 +319,9 @@ a string or a numeric." (mastodon-tl--byline toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " - | (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 - ------------"))))) + "(F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + ------------ +"))))) (ert-deftest mastodon-tl--byline-boosted/favorited () @@ -337,9 +337,9 @@ a string or a numeric." (mastodon-tl--byline toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " - | (B) (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 - ------------"))))) + "(B) (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + ------------ +"))))) (ert-deftest mastodon-tl--byline-reblogged () "Should format the reblogged toot correctly." @@ -362,9 +362,10 @@ a string or a numeric." (handle1-location 20) (handle2-location 65)) (should (string= (substring-no-properties byline) - " - | Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time - ------------")) + "Account 42 (@acct42@example.space) + Boosted Account 43 (@acct43@example.space) original time + ------------ +")) (should (eq (get-text-property handle1-location 'mastodon-tab-stop byline) 'user-handle)) (should (equal (get-text-property handle1-location 'help-echo byline) @@ -393,9 +394,11 @@ a string or a numeric." (should (string= (substring-no-properties (mastodon-tl--byline toot 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted))" - | Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time - ------------"))))) + 'mastodon-tl--byline-boosted)) + " Account 42 (@acct42@example.space) + Boosted Account 43 (@acct43@example.space) original time + ------------ +"))))) (ert-deftest mastodon-tl--byline-reblogged-boosted/favorited () "Should format the reblogged toot that was also boosted & favoritedcorrectly." @@ -416,9 +419,10 @@ a string or a numeric." (mastodon-tl--byline toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " - | (B) (F) Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time - ------------"))))) + "(B) (F) Account 42 (@acct42@example.space) + Boosted Account 43 (@acct43@example.space) original time + ------------ +"))))) (ert-deftest mastodon-tl--byline-timestamp-has-relative-display () "Should display the timestamp with a relative time." @@ -841,14 +845,14 @@ constant." 'toot-id (cdr (assoc 'id normal-toot-with-spoiler)))) (goto-char toot-start) - (should (eq t (looking-at "This is the spoiler warning text"))) + ;; (should (eq t (looking-at "This is the spoiler warning text"))) (setq link-region (mastodon-tl--find-next-or-previous-property-range 'mastodon-tab-stop toot-start nil)) ;; There should be a link following the text: (should-not (null link-region)) (goto-char (car link-region)) - (should (eq t (looking-at "Content Warning"))) + (should (eq t (looking-at "CW: This is the spoiler warning text"))) ;Content Warning"))) (setq body-position (+ 25 (cdr link-region))) ;; 25 is enough to skip the "\n--------------...." -- cgit v1.2.3 From d0d7c05519ea8f51df736d74e541517769bbffe0 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 7 Aug 2021 15:19:30 +0200 Subject: fix mentions broken when on local instance --- lisp/mastodon-tl.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 77caf13..3cde7c3 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -432,15 +432,18 @@ links in the text. If TOOT is nil no parsing occurs." mastodon-instance-url)) (maybe-hashtag (mastodon-tl--extract-hashtag-from-url url toot-instance-url)) - (maybe-userhandle (mastodon-tl--extract-userhandle-from-url - url (buffer-substring-no-properties start end)))) + (url-instance (concat "https://" + (url-host (url-generic-parse-url url)))) + (maybe-userhandle (if (string= mastodon-instance-url url-instance) + (buffer-substring-no-properties start end) + (mastodon-tl--extract-userhandle-from-url + url (buffer-substring-no-properties start end))))) (cond (;; Hashtags: maybe-hashtag (setq mastodon-tab-stop-type 'hashtag keymap mastodon-tl--link-keymap help-echo (concat "Browse tag #" maybe-hashtag) extra-properties (list 'mastodon-tag maybe-hashtag))) - (;; User handles: maybe-userhandle (let ((maybe-userid (mastodon-tl--extract-userid-toot @@ -566,6 +569,7 @@ LINK-TYPE is the type of link to produce." (mastodon-tl--toggle-spoiler-text position)) ((eq link-type 'hashtag) (mastodon-tl--show-tag-timeline (get-text-property position 'mastodon-tag))) + ;; FIXME: user-handle / account / account-id is broken/empty ((eq link-type 'user-handle) (let ((account-json (get-text-property position 'account)) (account-id (get-text-property position 'account-id))) -- cgit v1.2.3 From 1a44f09a1e8ecc1255c45220c7a0e1e11525e219 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 7 Aug 2021 15:57:36 +0200 Subject: replace 'toot-id with base-toot-id in mastodon-tl--oldest-id this is an attempt to avoid adding same toots instead of older toots on timelines. it seems to only happen sometimes, my guess it is happens when last toot displayed is favorited or boosted, perhaps only by the logged-in user. --- lisp/mastodon-tl.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 3cde7c3..9a69599 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -435,6 +435,7 @@ links in the text. If TOOT is nil no parsing occurs." (url-instance (concat "https://" (url-host (url-generic-parse-url url)))) (maybe-userhandle (if (string= mastodon-instance-url url-instance) + ; if handle is local, then no instance suffix: (buffer-substring-no-properties start end) (mastodon-tl--extract-userhandle-from-url url (buffer-substring-no-properties start end))))) @@ -787,7 +788,7 @@ Move forward (down) the timeline unless BACKWARD is non-nil." "Return toot-id from the bottom of the buffer." (save-excursion (goto-char (point-max)) - (mastodon-tl--property 'toot-id t))) + (mastodon-tl--property 'base-toot-id t))) (defun mastodon-tl--as-string (numeric) "Convert NUMERIC to string." -- cgit v1.2.3 From 13ddb9e3a3a7eac72fca95475baad0bd7792b6d9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 8 Aug 2021 16:31:16 +0200 Subject: fix typo in mastodon-tl--process-link setting 'account-id prop this prevented the 'account-id from being attached to mentions --- lisp/mastodon-profile.el | 2 +- lisp/mastodon-tl.el | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index c94ed35..0c1ec91 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -330,7 +330,7 @@ Returns a list of lists." 'face 'default) "\n ------------\n" (mastodon-tl--render-text note account) - ; account here to enable tab-stops in profile note + ;; account here to enable tab-stops in profile note (if fields (progn (concat "\n" diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 9a69599..d7c5f86 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -447,6 +447,7 @@ links in the text. If TOOT is nil no parsing occurs." extra-properties (list 'mastodon-tag maybe-hashtag))) (;; User handles: maybe-userhandle + ;; this fails on mentions in profile notes: (let ((maybe-userid (mastodon-tl--extract-userid-toot toot maybe-userhandle))) (setq mastodon-tab-stop-type 'user-handle @@ -455,7 +456,7 @@ links in the text. If TOOT is nil no parsing occurs." extra-properties (append (list 'mastodon-handle maybe-userhandle) (when maybe-userid - (list 'acccount-id maybe-userid)))))) + (list 'account-id maybe-userid)))))) ;; Anything else: (t ;; Leave it as a url handled by shr.el. @@ -570,7 +571,8 @@ LINK-TYPE is the type of link to produce." (mastodon-tl--toggle-spoiler-text position)) ((eq link-type 'hashtag) (mastodon-tl--show-tag-timeline (get-text-property position 'mastodon-tag))) - ;; FIXME: user-handle / account / account-id is broken/empty + ;; FIXME: 'account / 'account-id is not set for mentions + ;; only works for bylines, not mentions ((eq link-type 'user-handle) (let ((account-json (get-text-property position 'account)) (account-id (get-text-property position 'account-id))) -- cgit v1.2.3 From 8282ad9e124c5eff70b611613d6f345b6b650000 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 8 Aug 2021 17:27:07 +0200 Subject: include follow-requests in notifications --- lisp/mastodon-notifications.el | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index a731ddf..676b4a8 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -45,14 +45,16 @@ '(("mention" . mastodon-notifications--mention) ("follow" . mastodon-notifications--follow) ("favourite" . mastodon-notifications--favourite) - ("reblog" . mastodon-notifications--reblog)) + ("reblog" . mastodon-notifications--reblog) + ("follow_request" . mastodon-notifications--follow-request)) "Alist of notification types and their corresponding function.") (defvar mastodon-notifications--response-alist '(("Mentioned" . "you") ("Followed" . "you") ("Favourited" . "your status from") - ("Boosted" . "your status from")) + ("Boosted" . "your status from") + ("Follow request" . "requested to follow you")) "Alist of subjects for notification types.") (defun mastodon-notifications--byline-concat (message) @@ -92,6 +94,23 @@ (mastodon-notifications--byline-concat "Followed")))) +(defun mastodon-notifications--follow-request (note) + "Format for a `follow-request' NOTE." + (let ((id (cdr (assoc 'id note))) + (status (mastodon-tl--field 'status note)) + (follower (cdr (assoc 'username (cdr (assoc 'account note)))))) + (mastodon-notifications--insert-status + ;; Using reblog with an empty id will mark this as something + ;; non-boostable/non-favable. + (cons '(reblog (id . nil)) note) + (propertize (format "You have a follow request from... %s" follower) + 'face 'default) + 'mastodon-tl--byline-author + (lambda (_status) + (mastodon-notifications--byline-concat + "Requested to follow you")) + id))) + (defun mastodon-notifications--favourite (note) "Format for a `favourite' NOTE." (let ((id (cdr (assoc 'id note))) -- cgit v1.2.3 From 153c73190de9d626d8748d22c7afe48c83d7f861 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 8 Aug 2021 17:45:57 +0200 Subject: revert 'base-toot-id to 'toot-id in tl oldest toot --- 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 d7c5f86..6fdf950 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -790,7 +790,7 @@ Move forward (down) the timeline unless BACKWARD is non-nil." "Return toot-id from the bottom of the buffer." (save-excursion (goto-char (point-max)) - (mastodon-tl--property 'base-toot-id t))) + (mastodon-tl--property 'toot-id t))) (defun mastodon-tl--as-string (numeric) "Convert NUMERIC to string." -- cgit v1.2.3 From cef6093d477323635e553655498703c480bf00aa Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 9 Aug 2021 13:00:04 +0200 Subject: readme update --- README.org | 57 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/README.org b/README.org index 2eec284..cb4a37a 100644 --- a/README.org +++ b/README.org @@ -4,28 +4,29 @@ This is a fork of of the great but seemingly dormant https://github.com/jdenen/m It adds the following features: -| Profiles: | | -| | display profile metadata fields | -| | display pinned toots on profiles | -| | display relationship (follows you/followed by you) on profiles | -| | display toots/follows/followers counts on profiles | -| | links and tags in profiles and metadata fields are tab stops like in posts | -| =R=, =a=, =r= | view/accept/reject follow requests | -| =v= | view your favorited toots | -| =i= | (un)pin toots | -| =S-C-P= | jump to your profile | -| =U= | update your profile bio note | -| Timelines: | | -| =W=, =M=, =B= | (un)follow, (un)mute, (un)block users | -| | images are links to the full image, can be zoomed/rotated/saved (see their keymap) | -| =C= | copy url of toot at point | -| =d= | delete your toot at point | -| | display polls (very basic for now) | -| Toots: | | -| =C-c C-a= (=C-c C-n=) | media uploads (and sensitive/nsfw flag) | -| | mention booster in replies by default | -| Search: | | -| =S= | search (posts, users, tags) (improved! but still pretty basic!) | +| Profiles: | | +| | display profile metadata fields | +| | display pinned toots on profiles | +| | display relationship (follows you/followed by you) on profiles | +| | display toots/follows/followers counts on profiles | +| | links/tags/mentions in profiles are active links | +| =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | +| =v= | view your favorited toots | +| =i= | toggle pinning of toots | +| =S-C-P= | jump to your profile | +| =U= | update your profile bio note | +| Timelines: | | +| =C= | copy url of toot at point | +| =d= | delete your toot at point | +| =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | +| | display polls (very basic for now) | +| | images are links to the full image, can be zoomed/rotated/saved (see their keymap) | +| Toots: | | +| | mention booster in replies by default | +| =C-c C-a= | media uploads | +| =C-c C-n= | and sensitive media/nsfw flag | +| Search: | | +| =S= | search (posts, users, tags) (improved! but still rly basic!) (NB: by default, posts searched will only be those you have interacted with in some way; your instance can optionally enable full search) | It also makes some small cosmetic changes to make timelines easier to read, and makes some functions asynchronous, based on https://github.com/ieure/mastodon.el. @@ -33,17 +34,17 @@ This updated version is not on MELPA, to use it you need to clone and require it The minimum Emacs version is now 25.1. But if you are running an older version it shouldn't be very hard to get it working. -I did this for my own use and to learn more Elisp. If the code is terrible, feel free to improve or replace it. It surely still contains errors, I'm only weeding them out as I find them. +I did this for my own use and to learn more Elisp. Feel free to improve it. ** live-updating timelines (code adapted from https://github.com/alexjgriffith/mastodon-future.el.) -Works for federated, local, and home timelines and for notifications. It's pretty necro, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=, and you can load various timelines from within a mastodon session like so: +Works for federated, local, and home timelines and for notifications. It's pretty necro, sometimes it goes off the rails, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=, and you can load various timelines from within a mastodon session like so: - =C-c h= (home) - =C-c f= (federated) - =C-c l= (local) -- =C-c n= (notifications). +- =C-c n= (notifications) ** NB: dependency @@ -53,17 +54,17 @@ This version depends on the library =request= (for uploading attachments). You c As it stands the client still has some bugs. In particular, when composing a toot, hit =C-g= before sending your toot. If you don't, your draft may disappear. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. -In addition, if you create and send a toot with =mastodon-toot= / =C-c t= before otherwise opening the client, various little things break. - Some people have also had niggling troubles with initial auth and set-up, but I couldn't reproduce. ** roadmap-ish I might add a few more features if the ones I added turn out to work ok. Possible additions/amendments: -- update profile note. +- [X] update profile note. +- [X] fix loading more notifications re-loads the same ones - voting on polls - better display of polls +- display number of boosts/faves in toot byline - mention all thread participants in replies - handle newlines in toots better, for poetry, etc. - improve async. -- cgit v1.2.3 From 2efdb5eb4ddc824ad269af096cb508b8f6867077 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 9 Aug 2021 17:46:19 +0200 Subject: follow requests accept/reject from notifications + - new bindings for f-req accept/reject (in both notifs and in f-req views) - check if we are at an f-req before accept/rejecting - flycheck / docstrings - fix notifs byline formatting for f-reqs --- README.org | 1 + lisp/mastodon-notifications.el | 77 ++++++++++++++++++++++++++++++++------- lisp/mastodon-profile.el | 81 ++++++++++++++++++++++-------------------- lisp/mastodon.el | 4 +++ 4 files changed, 111 insertions(+), 52 deletions(-) diff --git a/README.org b/README.org index cb4a37a..5969950 100644 --- a/README.org +++ b/README.org @@ -62,6 +62,7 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] update profile note. - [X] fix loading more notifications re-loads the same ones +- [X] view/accept/reject follow requests in notifications view. - voting on polls - better display of polls - display number of boosts/faves in toot byline diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 676b4a8..caeb9cd 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -54,7 +54,7 @@ ("Followed" . "you") ("Favourited" . "your status from") ("Boosted" . "your status from") - ("Follow request" . "requested to follow you")) + ("Requested to follow" . "you")) "Alist of subjects for notification types.") (defun mastodon-notifications--byline-concat (message) @@ -65,6 +65,59 @@ " " (cdr (assoc message mastodon-notifications--response-alist)))) + +(defun mastodon-notifications--follow-request-accept-notifs () + "Accept the follow request of user at point, in notifications view." + (interactive) + (when (mastodon-tl--find-property-range 'toot-json (point)) + (let* ((toot-json (mastodon-tl--property 'toot-json)) + (f-req-p (string= "follow_request" (cdr (assoc 'type toot-json))))) + (if f-req-p + (let* ((account (cdr (assoc 'account toot-json))) + (id (cdr (assoc 'id account))) + (handle (cdr (assoc 'acct account))) + (name (cdr (assoc 'username account)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/authorize" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (mastodon-notifications--get) + (message "Follow request of %s (@%s) accepted!" + name handle)))) + (message "No account result at point?"))) + (message "No follow request at point?"))))) + +(defun mastodon-notifications--follow-request-reject-notifs () + "Reject the follow request of user at point, in notifications view." + (interactive) + (when (mastodon-tl--find-property-range 'toot-json (point)) + (let* ((toot-json (mastodon-tl--property 'toot-json)) + (f-req-p (string= "follow_request" (cdr (assoc 'type toot-json))))) + (if f-req-p + (let* ((account (cdr (assoc 'account toot-json))) + (id (cdr (assoc 'id account))) + (handle (cdr (assoc 'acct account))) + (name (cdr (assoc 'username account)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/reject" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (mastodon-notifications--get) + (message "Follow request of %s (@%s) rejected!" + name handle)))) + (message "No account result at point?"))) + (message "No follow request at point?"))))) + (defun mastodon-notifications--mention (note) "Format for a `mention' NOTE." (let ((id (cdr (assoc 'id note))) @@ -97,19 +150,16 @@ (defun mastodon-notifications--follow-request (note) "Format for a `follow-request' NOTE." (let ((id (cdr (assoc 'id note))) - (status (mastodon-tl--field 'status note)) (follower (cdr (assoc 'username (cdr (assoc 'account note)))))) (mastodon-notifications--insert-status - ;; Using reblog with an empty id will mark this as something - ;; non-boostable/non-favable. - (cons '(reblog (id . nil)) note) - (propertize (format "You have a follow request from... %s" follower) - 'face 'default) - 'mastodon-tl--byline-author - (lambda (_status) - (mastodon-notifications--byline-concat - "Requested to follow you")) - id))) + (cons '(reblog (id . nil)) note) + (propertize (format "You have a follow request from... %s" follower) + 'face 'default) + 'mastodon-tl--byline-author + (lambda (_status) + (mastodon-notifications--byline-concat + "Requested to follow")) + id))) (defun mastodon-notifications--favourite (note) "Format for a `favourite' NOTE." @@ -155,7 +205,8 @@ AUTHOR-BYLINE is an optional function for adding the author portion of the byline that takes one variable. By default it is `mastodon-tl--byline-author' ACTION-BYLINE is also an optional function for adding an action, such as boosting favouriting and following to the byline. It also takes a single function. By default -it is `mastodon-tl--byline-boosted'" +it is `mastodon-tl--byline-boosted'. +ID is the notification's own id, which is attached as a property." (let ((start-pos (point))) (insert (propertize diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 0c1ec91..82eb4db 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -46,6 +46,7 @@ (autoload 'mastodon-tl--byline-author "mastodon-tl.el") (autoload 'mastodon-tl--goto-next-toot "mastodon-tl.el") (autoload 'mastodon-tl--property "mastodon-tl.el") +(autoload 'mastodon-tl--find-property-range "mastodon-tl.el") (autoload 'mastodon-tl--render-text "mastodon-tl.el") (autoload 'mastodon-tl--set-face "mastodon-tl.el") (autoload 'mastodon-tl--timeline "mastodon-tl.el") @@ -70,8 +71,8 @@ (let ((map (make-sparse-keymap))) (define-key map (kbd "O") #'mastodon-profile--open-followers) (define-key map (kbd "o") #'mastodon-profile--open-following) - (define-key map (kbd "C-c a") #'mastodon-profile--follow-request-accept) - (define-key map (kbd "C-c r") #'mastodon-profile--follow-request-reject) + (define-key map (kbd "a") #'mastodon-profile--follow-request-accept) + (define-key map (kbd "j") #'mastodon-profile--follow-request-reject) map) "Keymap for `mastodon-profile-mode'.") @@ -110,13 +111,12 @@ extra keybindings." (mastodon-tl--property 'toot-json)) (defun mastodon-profile--make-author-buffer (account) - "Take a ACCOUNT and inserts a user account into a new buffer." + "Take a ACCOUNT and insert a user account into a new buffer." (mastodon-profile--make-profile-buffer-for account "statuses" #'mastodon-tl--timeline)) (defun mastodon-profile--open-following () - "Open a profile buffer for the current profile showing the accounts -that current profile follows." + "Open a profile buffer showing the accounts that current profile follows." (interactive) (if mastodon-profile--account (mastodon-profile--make-profile-buffer-for @@ -126,8 +126,7 @@ that current profile follows." (error "Not in a mastodon profile"))) (defun mastodon-profile--open-followers () - "Open a profile buffer for the current profile showing the accounts -following the current profile." + "Open a profile buffer showing the accounts following the current profile." (interactive) (if mastodon-profile--account (mastodon-profile--make-profile-buffer-for @@ -155,42 +154,46 @@ following the current profile." (defun mastodon-profile--follow-request-accept () "Accept the follow request of user at point." (interactive) - (let* ((acct-json (mastodon-profile--toot-json)) - (id (cdr (assoc 'id acct-json))) - (handle (cdr (assoc 'acct acct-json))) - (name (cdr (assoc 'username acct-json)))) - (if id - (let ((response - (mastodon-http--post - (concat - (mastodon-http--api "follow_requests") - (format "/%s/authorize" id)) - nil nil))) - (mastodon-http--triage response - (lambda () - (message "Follow request of %s (@%s) accepted!" - name handle)))) - (message "No account result at point?")))) + (if (mastodon-tl--find-property-range 'toot-json (point)) + (let* ((acct-json (mastodon-profile--toot-json)) + (id (cdr (assoc 'id acct-json))) + (handle (cdr (assoc 'acct acct-json))) + (name (cdr (assoc 'username acct-json)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/authorize" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (message "Follow request of %s (@%s) accepted!" + name handle)))) + (message "No account result at point?"))) + (message "No follow request at point?"))) (defun mastodon-profile--follow-request-reject () "Reject the follow request of user at point." (interactive) - (let* ((acct-json (mastodon-profile--toot-json)) - (id (cdr (assoc 'id acct-json))) - (handle (cdr (assoc 'acct acct-json))) - (name (cdr (assoc 'username acct-json)))) - (if id - (let ((response - (mastodon-http--post - (concat - (mastodon-http--api "follow_requests") - (format "/%s/reject" id)) - nil nil))) - (mastodon-http--triage response - (lambda () - (message "Follow request of %s (@%s) rejected!" - name handle)))) - (message "No account result at point?")))) + (if (mastodon-tl--find-property-range 'toot-json (point)) + (let* ((acct-json (mastodon-profile--toot-json)) + (id (cdr (assoc 'id acct-json))) + (handle (cdr (assoc 'acct acct-json))) + (name (cdr (assoc 'username acct-json)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/reject" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (message "Follow request of %s (@%s) rejected!" + name handle)))) + (message "No account result at point?"))) + (message "No follow request at point?"))) (defun mastodon-profile--update-user-profile-note () "Fetch user's profile note and display for editing." diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 96a092f..a918b44 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -66,6 +66,8 @@ (autoload 'mastodon-profile--my-profile "mastodon-profile") (autoload 'mastodon-profile--view-favourites "mastodon-profile") (autoload 'mastodon-profile--view-follow-requests "mastodon-profile") +(autoload 'mastodon-notifications--follow-request-accept-notifs "mastodon-profile") +(autoload 'mastodon-notifications--follow-request-reject-notifs "mastodon-profile") (autoload 'mastodon-search--search-query "mastodon-search") (autoload 'mastodon-toot--delete-toot "mastodon-toot") (autoload 'mastodon-toot--copy-toot-url "mastodon-toot") @@ -149,6 +151,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-c l") #'mastodon-async--stream-local) (define-key map (kbd "C-c n") #'mastodon-async--stream-notifications) (define-key map (kbd "U") #'mastodon-profile--update-user-profile-note) + (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) + (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 8ffa61e0d46c5a263d5afeaa95069608148405a3 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 9 Aug 2021 19:49:17 +0200 Subject: use either display_name or username in author byline this fixes the situation where accounts with nothing in "display_name" would appear as only as a handle --- 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 6fdf950..8f368a3 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -257,7 +257,9 @@ Optionally start from POS." "Propertize author of TOOT." (let* ((account (cdr (assoc 'account toot))) (handle (cdr (assoc 'acct account))) - (name (cdr (assoc 'display_name account))) + (name (if (not (string= "" (cdr (assoc 'display_name account)))) + (cdr (assoc 'display_name account)) + (cdr (assoc 'username account)))) (profile-url (cdr (assoc 'url account))) (avatar-url (cdr (assoc 'avatar account)))) ;; TODO: Once we have a view for a user (e.g. their posts -- cgit v1.2.3 From 99adf9b1b8a02d9ca8d6dee87f51dc952ab76318 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 9 Aug 2021 23:13:50 +0200 Subject: mastodon-http--triage - messages errors rather than response buffer --- lisp/mastodon-http.el | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index e8fd4d3..94aa85d 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -67,15 +67,28 @@ (string-match "[0-9][0-9][0-9]" status-line) (match-string 0 status-line))) +;; (defun mastodon-http--triage (response success) +;; "Determine if RESPONSE was successful. Call SUCCESS if successful. + +;; Open RESPONSE buffer if unsuccessful." +;; (let ((status (with-current-buffer response +;; (mastodon-http--status)))) +;; (if (string-prefix-p "2" status) +;; (funcall success) +;; (switch-to-buffer response)))) + (defun mastodon-http--triage (response success) "Determine if RESPONSE was successful. Call SUCCESS if successful. -Open RESPONSE buffer if unsuccessful." +Message status and JSON error from RESPONSE if unsuccessful." (let ((status (with-current-buffer response (mastodon-http--status)))) (if (string-prefix-p "2" status) (funcall success) - (switch-to-buffer response)))) + (progn + (switch-to-buffer response) + (let ((json-response (mastodon-http--process-json))) + (message "Error %s: %s" status (cdr (assoc 'error json-response)))))))) (defun mastodon-http--post (url args headers &optional unauthenticed-p) "POST synchronously to URL with ARGS and HEADERS. -- cgit v1.2.3 From d91d881a634f84e50c70e8be882bcfb278c64823 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 9 Aug 2021 23:14:44 +0200 Subject: functions to vote on polls in timelines, bound to "v" - masto view favorites binding moved to "V", in line with other separate views being in capitals --- README.org | 5 +++-- lisp/mastodon-tl.el | 46 ++++++++++++++++++++++++++++++++++++++++++---- lisp/mastodon.el | 4 +++- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/README.org b/README.org index 5969950..6cf318e 100644 --- a/README.org +++ b/README.org @@ -63,12 +63,13 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] update profile note. - [X] fix loading more notifications re-loads the same ones - [X] view/accept/reject follow requests in notifications view. -- voting on polls +- [X] fix sometimes usernames don't appear in timelines +- [X] voting on polls - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies - handle newlines in toots better, for poetry, etc. -- improve async. +- improve (or even partially disable) async. It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 8f368a3..107f7eb 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -52,7 +52,7 @@ (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-http--get-json-async "mastodon-http") (autoload 'mastodon-profile--lookup-account-in-status "mastodon-profile") - +(autoload 'mastodon-profile-mode "mastodon-profile") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this @@ -691,15 +691,53 @@ it is `mastodon-tl--byline-boosted'" (defun mastodon-tl--get-poll (toot) "If post TOOT is a poll, return a formatted string of poll." (let* ((poll (mastodon-tl--field 'poll toot)) - (options (mastodon-tl--field 'options poll))) + (options (mastodon-tl--field 'options poll)) + (option-counter 0)) (concat "Poll: \n\n" (mapconcat (lambda (option) - (format "Option: %s, %s votes.\n" + (progn + (format "Option %s: %s, %s votes.\n" + (setq option-counter (1+ option-counter)) (cdr (assoc 'title option)) - (cdr (assoc 'votes_count option)))) + (cdr (assoc 'votes_count option))))) options "\n") "\n"))) +(defun mastodon-tl--poll-vote () + "If toot at point is poll, call `mastodon-tl--poll-vote-yes'." + (interactive) + ;; hack coz i don't know how to put this if test before my interactive + (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) + (message "No poll here.") + (call-interactively 'mastodon-tl--poll-vote-yes))) + +(defun mastodon-tl--poll-vote-yes (option) + "Prompt user for OPTION to vote on poll at point." + (interactive + (list + (let* ((toot (mastodon-tl--property 'toot-json)) + (poll (mastodon-tl--field 'poll toot)) + (options (mastodon-tl--field 'options poll)) + (options-number-seq (number-sequence 1 (length options))) + (options-numbers (mapcar (lambda(x) + (number-to-string x)) + options-number-seq))) + (completing-read "Poll option to vote for: " + options-numbers + nil ;predicate + t)))) ;require match + (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) + (message "No poll here.") + (let* ((toot (mastodon-tl--property 'toot-json)) + (poll (mastodon-tl--field 'poll toot)) + (poll-id (cdr (assoc 'id poll))) + (url (mastodon-http--api (format "polls/%s/votes" poll-id))) + (arg `(("choices[]" . ,option))) + (response (mastodon-http--post url arg nil))) + (mastodon-http--triage response + (lambda () + (message "You voted for option %s!" option)))))) + (defun mastodon-tl--toot (toot) "Formats TOOT and insertes it into the buffer." (mastodon-tl--insert-status diff --git a/lisp/mastodon.el b/lisp/mastodon.el index a918b44..fd00ee9 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -79,6 +79,7 @@ (autoload 'mastodon-async--stream-notifications "mastodon-async") (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (autoload 'mastodon-auth--user-acct "mastodon-auth") +(autoload 'mastodon-tl--poll-vote "mastodon-http") (defgroup mastodon nil "Interface with Mastodon." @@ -144,7 +145,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "d") #'mastodon-toot--delete-toot) (define-key map (kbd "C") #'mastodon-toot--copy-toot-url) (define-key map (kbd "i") #'mastodon-toot--pin-toot-toggle) - (define-key map (kbd "v") #'mastodon-profile--view-favourites) + (define-key map (kbd "V") #'mastodon-profile--view-favourites) (define-key map (kbd "R") #'mastodon-profile--view-follow-requests) (define-key map (kbd "C-c h") #'mastodon-async--stream-home) (define-key map (kbd "C-c f") #'mastodon-async--stream-federated) @@ -153,6 +154,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "U") #'mastodon-profile--update-user-profile-note) (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) + (define-key map (kbd "v") #'mastodon-tl--poll-vote) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 27edcd6b2010d4b2e39fe57ce6a5f26ef321d49e Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 10 Aug 2021 00:08:18 +0200 Subject: provide poll option descriptions in completing-read --- lisp/mastodon-tl.el | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 107f7eb..bacbebf 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -703,29 +703,36 @@ it is `mastodon-tl--byline-boosted'" options "\n") "\n"))) -(defun mastodon-tl--poll-vote () - "If toot at point is poll, call `mastodon-tl--poll-vote-yes'." - (interactive) - ;; hack coz i don't know how to put this if test before my interactive - (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) - (message "No poll here.") - (call-interactively 'mastodon-tl--poll-vote-yes))) - -(defun mastodon-tl--poll-vote-yes (option) - "Prompt user for OPTION to vote on poll at point." +(defun mastodon-tl--poll-vote (option) + "If there is a poll at point, prompt user for OPTION to vote on it." (interactive (list (let* ((toot (mastodon-tl--property 'toot-json)) (poll (mastodon-tl--field 'poll toot)) (options (mastodon-tl--field 'options poll)) + (options-titles (mapcar (lambda (x) + (cdr (assoc 'title x))) + options)) (options-number-seq (number-sequence 1 (length options))) (options-numbers (mapcar (lambda(x) (number-to-string x)) - options-number-seq))) - (completing-read "Poll option to vote for: " - options-numbers - nil ;predicate - t)))) ;require match + options-number-seq)) + (options-alist (mapcar* 'cons options-numbers options-titles)) + ;; we display both option number and the option title + ;; but also store option number as cdr, as we need it alone below + (candidates (mapcar (lambda (cell) + (cons (format "%s | %s" (car cell) (cdr cell)) + (car cell))) + options-alist))) + (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) + (message "No poll here.") + ;; var "option" = just the cdr, just the option number + (cdr (assoc + (completing-read "Poll option to vote for: " + candidates + nil ;predicate + t) ;require match + candidates)))))) (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) (message "No poll here.") (let* ((toot (mastodon-tl--property 'toot-json)) -- cgit v1.2.3 From 838c75295301e3154c4029792565d661e67e0672 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 10 Aug 2021 00:46:05 +0200 Subject: try to handle reblogged polls --- README.org | 2 +- lisp/mastodon-tl.el | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.org b/README.org index 6cf318e..e7960bf 100644 --- a/README.org +++ b/README.org @@ -19,7 +19,7 @@ It adds the following features: | =C= | copy url of toot at point | | =d= | delete your toot at point | | =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | -| | display polls (very basic for now) | +| | display polls and vote on polls (very basic for now) | | | images are links to the full image, can be zoomed/rotated/saved (see their keymap) | | Toots: | | | | mention booster in replies by default | diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index bacbebf..cf87c0a 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -708,7 +708,9 @@ it is `mastodon-tl--byline-boosted'" (interactive (list (let* ((toot (mastodon-tl--property 'toot-json)) - (poll (mastodon-tl--field 'poll toot)) + (reblog (cdr (assoc 'reblog toot))) + (poll (or (cdr (assoc 'poll reblog)) + (mastodon-tl--field 'poll toot))) (options (mastodon-tl--field 'options poll)) (options-titles (mapcar (lambda (x) (cdr (assoc 'title x))) @@ -735,6 +737,8 @@ it is `mastodon-tl--byline-boosted'" candidates)))))) (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) (message "No poll here.") + ;; TODO: match option number up to option titles so we can message + ;; the full option description, not just the number (let* ((toot (mastodon-tl--property 'toot-json)) (poll (mastodon-tl--field 'poll toot)) (poll-id (cdr (assoc 'id poll))) -- cgit v1.2.3 From 32546f483ec09433464dfbf2a041b8ec0cd369f9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 10 Aug 2021 10:37:09 +0200 Subject: zero index our poll vote, message choice + number on success zero indexing the vote means we vote for the option we actually chose --- lisp/mastodon-tl.el | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index cf87c0a..b7c14e2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -721,33 +721,35 @@ it is `mastodon-tl--byline-boosted'" options-number-seq)) (options-alist (mapcar* 'cons options-numbers options-titles)) ;; we display both option number and the option title - ;; but also store option number as cdr, as we need it alone below + ;; but also store both as cons cell as cdr, as we need it below (candidates (mapcar (lambda (cell) (cons (format "%s | %s" (car cell) (cdr cell)) - (car cell))) + cell)) options-alist))) (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) (message "No poll here.") - ;; var "option" = just the cdr, just the option number + ;; var "option" = just the cdr, a cons of option number and desc (cdr (assoc (completing-read "Poll option to vote for: " candidates - nil ;predicate - t) ;require match + nil ; (predicate) + t) ; require match candidates)))))) (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) (message "No poll here.") - ;; TODO: match option number up to option titles so we can message - ;; the full option description, not just the number (let* ((toot (mastodon-tl--property 'toot-json)) (poll (mastodon-tl--field 'poll toot)) (poll-id (cdr (assoc 'id poll))) (url (mastodon-http--api (format "polls/%s/votes" poll-id))) - (arg `(("choices[]" . ,option))) + ;; need to zero-index our option: + (option-as-arg (number-to-string (1- (string-to-number (car option))))) + ;; (option-indexed + (arg `(("choices[]" . ,option-as-arg))) (response (mastodon-http--post url arg nil))) (mastodon-http--triage response (lambda () - (message "You voted for option %s!" option)))))) + (message "You voted for option %s: %s!" + (car option) (cdr option))))))) (defun mastodon-tl--toot (toot) "Formats TOOT and insertes it into the buffer." -- cgit v1.2.3 From e1f9acd7c1e71b1bbaa3b6b4aca237156f3d614f Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 11 Aug 2021 11:28:39 +0200 Subject: improve docstrings in mastodon-auth so i know what it does. --- lisp/mastodon-auth.el | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 4bd1cce..4628e74 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -61,14 +61,16 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." "Alist of account accts (name@domain) keyed by instance url.") (defun mastodon-auth--generate-token () - "Make POST to generate auth token." + "Make POST to generate auth token. + +If no auth-sources file, runs `mastodon-auth--generate-token-no-storing-credentials'. If auth-sources file exists, runs `mastodon-auth--generate-token-and-store'." (if (or (null mastodon-auth-source-file) (string= "" mastodon-auth-source-file)) (mastodon-auth--generate-token-no-storing-credentials) (mastodon-auth--generate-token-and-store))) (defun mastodon-auth--generate-token-no-storing-credentials () - "Make POST to generate auth token." + "Make POST to generate auth token, without using auth-sources file." (mastodon-http--post (concat mastodon-instance-url "/oauth/token") `(("client_id" . ,(plist-get (mastodon-client) :client_id)) @@ -83,7 +85,7 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defun mastodon-auth--generate-token-and-store () "Make POST to generate auth token. -Reads and/or stores secres in `MASTODON-AUTH-SOURCE-FILE'." +Reads and/or stores secrets in `MASTODON-AUTH-SOURCE-FILE'." (let* ((auth-sources (list mastodon-auth-source-file)) (auth-source-creation-prompts '((user . "Enter email for %h: ") @@ -111,7 +113,7 @@ Reads and/or stores secres in `MASTODON-AUTH-SOURCE-FILE'." (funcall (plist-get credentials-plist :save-function)))))) (defun mastodon-auth--get-token () - "Make auth token request and return JSON response." + "Make a request to generate an auth token and return JSON response." (with-current-buffer (mastodon-auth--generate-token) (goto-char (point-min)) (re-search-forward "^$" nil 'move) @@ -122,15 +124,18 @@ Reads and/or stores secres in `MASTODON-AUTH-SOURCE-FILE'." (json-read-from-string json-string)))) (defun mastodon-auth--access-token () - "Return the access token to use with the current `mastodon-instance-url'. + "If an access token for the current `mastodon-instance-url' exists in `mastodon-auth--token-alist', return it. -Generate token and set if none known yet." +Otherwise, generate a token and pass it to `mastodon-auth--handle-token-reponse'." (if-let ((token (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) token (mastodon-auth--handle-token-response (mastodon-auth--get-token)))) (defun mastodon-auth--handle-token-response (response) + "Add the token in RESPONSE returned by `mastodon-auth--get-token' in `mastodon-auth--token-alist'. + +Handle any errors from the server." (pcase response ((and (let token (plist-get response :access_token)) (guard token)) -- cgit v1.2.3 From 99a69f0cb267dcc22e3e1476f0e9f8d6dc46faa7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 8 Sep 2021 16:57:13 +0200 Subject: fix RET/i not working on image attachments in notifications. notifications only have a url and a preview_url, but no remote_url. we still prefer remote_url in home timelines (inc. boosts) though. --- 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 b7c14e2..d34371a 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -641,7 +641,10 @@ message is a link which unhides/hides the main body." (let ((preview-url (cdr (assoc 'preview_url media-attachement))) (remote-url - (cdr (assoc 'remote_url media-attachement)))) + (if (cdr (assoc 'remote_url media-attachement)) + (cdr (assoc 'remote_url media-attachement)) + ;; fallback b/c notifications don't have remote_url + (cdr (assoc 'url media-attachement))))) (if mastodon-tl--display-media-p (mastodon-media--get-media-link-rendering preview-url remote-url) ; 2nd arg for shr-browse-url -- cgit v1.2.3 From 14842fce7caa96c0f6234308c85a82a8e556f18f Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 13 Sep 2021 20:14:28 +0200 Subject: use inbuilt image scaling if emacs version => 27.1 and put point at point-min on profile load --- lisp/mastodon-media.el | 17 ++++++++++++----- lisp/mastodon-profile.el | 3 ++- lisp/mastodon-tl.el | 4 +++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 381d994..2100553 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -41,7 +41,7 @@ :prefix "mastodon-media-" :group 'mastodon) -(defcustom mastodon-media--avatar-height 30 +(defcustom mastodon-media--avatar-height 20 "Height of the user avatar images (if shown)." :group 'mastodon-media :type 'integer) @@ -146,7 +146,10 @@ REGION-LENGTH is the length of the region that should be replaced with the image (search-forward "\n\n") (buffer-substring (point) (point-max)))) (image (when data - (apply #'create-image data (when image-options 'imagemagick) + (apply #'create-image data + (if (version< emacs-version "27.1") + (when image-options 'imagemagick) + nil) ; inbuilt scaling in 27.1 t image-options)))) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer @@ -170,7 +173,8 @@ REGION-LENGTH is the length of the region that should be replaced with the image MEDIA-TYPE is a symbol and either 'avatar or 'media-link." ;; TODO: Cache the avatars - (let ((image-options (when (image-type-available-p 'imagemagick) + (let ((image-options (when (or (image-type-available-p 'imagemagick) + (image-transforms-p)) ; inbuilt scaling in 27.1 (cond ((eq media-type 'avatar) `(:height ,mastodon-media--avatar-height)) @@ -251,7 +255,8 @@ replacing them with the referenced image." ;; We use just an empty space as the textual representation. ;; This is what a user will see on a non-graphical display ;; where not showing an avatar at all is preferable. - (let ((image-options (when (image-type-available-p 'imagemagick) + (let ((image-options (when (or (image-type-available-p 'imagemagick) + (image-transforms-p)) ; inbuilt scaling in 27.1 `(:height ,mastodon-media--avatar-height)))) (concat (propertize " " @@ -259,7 +264,9 @@ replacing them with the referenced image." 'media-state 'needs-loading 'media-type 'avatar 'display (apply #'create-image mastodon-media--generic-avatar-data - (when image-options 'imagemagick) + (if (version< emacs-version "27.1") + (when image-options 'imagemagick) + nil) ; inbuilt scaling in 27.1 t image-options)) " "))) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 82eb4db..eb75247 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -372,7 +372,8 @@ Returns a list of lists." (if (and pinned (equal endpoint-type "statuses")) (mastodon-profile--insert-statuses-pinned pinned)) (funcall update-function json))) - (mastodon-tl--goto-next-toot))) + ;;(mastodon-tl--goto-next-toot) + (goto-char (point-min)))) (defun mastodon-profile--get-toot-author () "Open profile of author of toot under point. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index d34371a..a6f3f9a 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -83,7 +83,9 @@ width fonts when rendering HTML text")) (make-variable-buffer-local 'mastodon-tl--buffer-spec) (defvar mastodon-tl--show-avatars-p - (image-type-available-p 'imagemagick) + (if (version< emacs-version "27.1") + (image-type-available-p 'imagemagick) + (image-transforms-p)) "A boolean value stating whether to show avatars in timelines.") (defvar mastodon-tl--update-point nil -- cgit v1.2.3 From a2cf6af06ab076dfcc9b032220259574ed3fcd9a Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 13 Sep 2021 21:58:11 +0200 Subject: make display of (scaled) avatars a customize option --- lisp/mastodon-tl.el | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index a6f3f9a..c5240db 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -82,11 +82,16 @@ width fonts when rendering HTML text")) "A unique identifier and functions for each Mastodon buffer.") (make-variable-buffer-local 'mastodon-tl--buffer-spec) -(defvar mastodon-tl--show-avatars-p - (if (version< emacs-version "27.1") - (image-type-available-p 'imagemagick) - (image-transforms-p)) - "A boolean value stating whether to show avatars in timelines.") +(defcustom mastodon-tl--show-avatars-p t + "Whether to enable display of user avatars in timelines." + :group 'mastodon-tl + :type '(boolean :tag "Whether to display user avatars in timelines")) + +;; (defvar mastodon-tl--show-avatars-p nil + ;; (if (version< emacs-version "27.1") + ;; (image-type-available-p 'imagemagick) + ;; (image-transforms-p)) + ;; "A boolean value stating whether to show avatars in timelines.") (defvar mastodon-tl--update-point nil "When updating a mastodon buffer this is where new toots will be inserted. @@ -267,7 +272,11 @@ Optionally start from POS." ;; TODO: Once we have a view for a user (e.g. their posts ;; timeline) make this a tab-stop and attach an action (concat - (when (and mastodon-tl--show-avatars-p mastodon-tl--display-media-p) + (when (and mastodon-tl--show-avatars-p + mastodon-tl--display-media-p + (if (version< emacs-version "27.1") + (image-type-available-p 'imagemagick) + (image-transforms-p))) (mastodon-media--get-avatar-rendering avatar-url)) (propertize name 'face 'mastodon-display-name-face) " (" -- cgit v1.2.3 From 53616d194cfcab743558f91e88526e83204ee704 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 22 Sep 2021 17:48:10 +0200 Subject: package-lint: bump to emacs 26.1, disable stream keybindings --- README.org | 10 +++------- lisp/mastodon-async.el | 2 +- lisp/mastodon-auth--test.el | 2 +- lisp/mastodon-auth.el | 2 +- lisp/mastodon-client.el | 2 +- 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-search.el | 2 +- lisp/mastodon-tl.el | 2 +- lisp/mastodon-toot.el | 2 +- lisp/mastodon.el | 18 +++++++++--------- 15 files changed, 25 insertions(+), 29 deletions(-) diff --git a/README.org b/README.org index e7960bf..4be82c6 100644 --- a/README.org +++ b/README.org @@ -32,19 +32,15 @@ It also makes some small cosmetic changes to make timelines easier to read, and This updated version is not on MELPA, to use it you need to clone and require it as per the installation instructions below. -The minimum Emacs version is now 25.1. But if you are running an older version it shouldn't be very hard to get it working. +The minimum Emacs version is now 26.1. But if you are running an older version it shouldn't be very hard to get it working. I did this for my own use and to learn more Elisp. Feel free to improve it. ** live-updating timelines -(code adapted from https://github.com/alexjgriffith/mastodon-future.el.) +(code taken from https://github.com/alexjgriffith/mastodon-future.el.) -Works for federated, local, and home timelines and for notifications. It's pretty necro, sometimes it goes off the rails, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=, and you can load various timelines from within a mastodon session like so: -- =C-c h= (home) -- =C-c f= (federated) -- =C-c l= (local) -- =C-c n= (notifications) +Works for federated, local, and home timelines and for notifications. It's pretty necro, sometimes it goes off the rails, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=. ** NB: dependency diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 4367cc9..6a421d1 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.7.1 -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-auth--test.el b/lisp/mastodon-auth--test.el index b8705f5..9a765b9 100644 --- a/lisp/mastodon-auth--test.el +++ b/lisp/mastodon-auth--test.el @@ -5,7 +5,7 @@ ;; Author: Ian Eure ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 4628e74..3f4ee7d 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 90f1375..6439c0a 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 2387feb..9c946be 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 94aa85d..31ea483 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "25.1") (request "0.2.0")) +;; Package-Requires: ((emacs "26.1") (request "0.2.0")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index c5a8d5d..9559b21 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 2100553..c3873df 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index caeb9cd..7524038 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index eb75247..98d11f7 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "25.1") (seq "1.8")) +;; Package-Requires: ((emacs "26.1") (seq "1.8")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 5e8253f..3b7e399 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen , martyhiatt ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index c5240db..af6f0a2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d9f895c..c9184fc 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Version: 0.9.1 ;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "25.1")) +;; Package-Requires: ((emacs "26.1")) ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon.el b/lisp/mastodon.el index fd00ee9..460fe29 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "25.1") (request "0.2.0") (seq "1.8")) +;; Package-Requires: ((emacs "26.1") (request "0.2.0") (seq "1.8")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. @@ -73,10 +73,10 @@ (autoload 'mastodon-toot--copy-toot-url "mastodon-toot") (autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") (autoload 'mastodon-auth--get-account-name "mastodon-auth") -(autoload 'mastodon-async--stream-federated "mastodon-async") -(autoload 'mastodon-async--stream-local "mastodon-async") -(autoload 'mastodon-async--stream-home "mastodon-async") -(autoload 'mastodon-async--stream-notifications "mastodon-async") +;; (autoload 'mastodon-async--stream-federated "mastodon-async") +;; (autoload 'mastodon-async--stream-local "mastodon-async") +;; (autoload 'mastodon-async--stream-home "mastodon-async") +;; (autoload 'mastodon-async--stream-notifications "mastodon-async") (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-tl--poll-vote "mastodon-http") @@ -147,10 +147,10 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "i") #'mastodon-toot--pin-toot-toggle) (define-key map (kbd "V") #'mastodon-profile--view-favourites) (define-key map (kbd "R") #'mastodon-profile--view-follow-requests) - (define-key map (kbd "C-c h") #'mastodon-async--stream-home) - (define-key map (kbd "C-c f") #'mastodon-async--stream-federated) - (define-key map (kbd "C-c l") #'mastodon-async--stream-local) - (define-key map (kbd "C-c n") #'mastodon-async--stream-notifications) + ;; (define-key map (kbd "C-c h") #'mastodon-async--stream-home) + ;; (define-key map (kbd "C-c f") #'mastodon-async--stream-federated) + ;; (define-key map (kbd "C-c l") #'mastodon-async--stream-local) + ;; (define-key map (kbd "C-c n") #'mastodon-async--stream-notifications) (define-key map (kbd "U") #'mastodon-profile--update-user-profile-note) (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) -- cgit v1.2.3 From 7bfcc9909ad7282ac41eb85b013a3845028aa531 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 22 Sep 2021 21:34:39 +0200 Subject: rename show-avatars-p custom to show-avatars --- 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 af6f0a2..d1e82d7 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -82,12 +82,12 @@ width fonts when rendering HTML text")) "A unique identifier and functions for each Mastodon buffer.") (make-variable-buffer-local 'mastodon-tl--buffer-spec) -(defcustom mastodon-tl--show-avatars-p t +(defcustom mastodon-tl--show-avatars t "Whether to enable display of user avatars in timelines." :group 'mastodon-tl :type '(boolean :tag "Whether to display user avatars in timelines")) -;; (defvar mastodon-tl--show-avatars-p nil +;; (defvar mastodon-tl--show-avatars nil ;; (if (version< emacs-version "27.1") ;; (image-type-available-p 'imagemagick) ;; (image-transforms-p)) @@ -272,7 +272,7 @@ Optionally start from POS." ;; TODO: Once we have a view for a user (e.g. their posts ;; timeline) make this a tab-stop and attach an action (concat - (when (and mastodon-tl--show-avatars-p + (when (and mastodon-tl--show-avatars mastodon-tl--display-media-p (if (version< emacs-version "27.1") (image-type-available-p 'imagemagick) -- cgit v1.2.3 From f0822a697317e2e8bf320540e7ae1c80163bc90f Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 11:41:35 +0200 Subject: on delete toot, redraw current timeline or profile --- lisp/mastodon-tl.el | 15 +++++++++++++++ lisp/mastodon-toot.el | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index d1e82d7..6304284 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1054,6 +1054,21 @@ webapp" (message "User %s (@%s) unblocked!" name user-handle))))) (message "Cannot find a user with handle %S" user-handle)))) +(defun mastodon-tl--reload-timeline-or-profile () + "Reload the current timeline or profile page. +For use after e.g. deleting a toot." + (cond ((equal (mastodon-tl--get-endpoint) "timelines/home") + (mastodon-tl--get-home-timeline)) + ((equal (mastodon-tl--get-endpoint) "timelines/public") + (mastodon-tl--get-federated-timeline)) + ((equal (mastodon-tl--get-endpoint) "timelines/public?local=true") + (mastodon-tl--get-local-timeline)) + ((equal (mastodon-tl--get-endpoint) "notifications") + (mastodon-notifications--get)) + ((equal (mastodon-tl--buffer-name) + (concat "*mastodon-" (mastodon-auth--get-account-name) "-statuses*")) + (mastodon-profile--my-profile)))) + (defun mastodon-tl--more () "Append older toots to timeline." (interactive) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index c9184fc..d86eefd 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -46,6 +46,7 @@ (autoload 'mastodon-toot "mastodon") (autoload 'mastodon-http--post-media-attachment "mastodon-http") (autoload 'mastodon-tl--toot-id "mastodon-tl") +(autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl") (defgroup mastodon-toot nil "Tooting in Mastodon." @@ -215,7 +216,6 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (kill-new url) (message "Toot URL copied to the clipboard."))) -;; TODO redraw buffer on success? (defun mastodon-toot--delete-toot () "Delete user's toot at point synchronously." (interactive) @@ -231,6 +231,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (let ((response (mastodon-http--delete url))) (mastodon-http--triage response (lambda () + (mastodon-tl--reload-timeline-or-profile) (message "Toot deleted!")))))))) (defun mastodon-toot--kill () -- cgit v1.2.3 From 7e78f3ef2ce5001de9b06488acff246a7f1fc3ce Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 11:41:59 +0200 Subject: disable avatars by default --- 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 6304284..da18a94 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -82,7 +82,7 @@ width fonts when rendering HTML text")) "A unique identifier and functions for each Mastodon buffer.") (make-variable-buffer-local 'mastodon-tl--buffer-spec) -(defcustom mastodon-tl--show-avatars t +(defcustom mastodon-tl--show-avatars nil "Whether to enable display of user avatars in timelines." :group 'mastodon-tl :type '(boolean :tag "Whether to display user avatars in timelines")) -- cgit v1.2.3 From 21c6572d62d9129b48003129e60c97d0f64868d0 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 11:42:14 +0200 Subject: hacks to minimize toot bug: copy text, only kill buffer after post --- lisp/mastodon-toot.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d86eefd..1c8a475 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -301,10 +301,12 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (message "Looks like your uploads are not yet ready...") (if empty-toot-p (message "Empty toot. Cowardly refusing to post this.") - (mastodon-toot--kill) - (let ((response (mastodon-http--post endpoint args nil))) + (let ((response (mastodon-http--post endpoint args nil))) (mastodon-http--triage response - (lambda () (message "Toot toot!")))))))) + (lambda () + (kill-new toot) ; copy toot text to kill ring + (mastodon-toot--kill) ; only kill buffer after sending + (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) "Adds domain to local ACCT and replaces the curent user name with \"\". -- cgit v1.2.3 From 4499e9471c4a7ba923ef950954a9e42f9a7ed6e9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 13:09:17 +0200 Subject: basic delete-and-redraft-toot, text status only for now. --- lisp/mastodon-toot.el | 25 +++++++++++++++++++++++++ lisp/mastodon.el | 2 ++ 2 files changed, 27 insertions(+) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 1c8a475..1f65cbf 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -234,6 +234,31 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (mastodon-tl--reload-timeline-or-profile) (message "Toot deleted!")))))))) +;; TODO: handle media/poll for redrafting toots +(defun mastodon-toot--delete-and-redraft-toot () + "Delete and redraft user's toot at point synchronously." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s" id)))) + (if (or (cdr (assoc 'reblog toot)) + (not (equal (cdr (assoc 'acct + (cdr (assoc 'account toot)))) + (mastodon-auth--user-acct)))) + (message "You can only delete and redraft your own toots.") + (if (y-or-n-p (format "Delete and redraft this toot? ")) + (let* ((response (mastodon-http--delete url))) + (mastodon-http--triage + response + (lambda () + (with-current-buffer response + (let* ((json-response (mastodon-http--process-json)) + (content (cdr (assoc 'text json-response))) + (media (cdr (assoc 'media_attachments json-response)))) + (mastodon-toot--compose-buffer nil nil) + (goto-char (point-max)) + (insert content)))))))))) + (defun mastodon-toot--kill () "Kill `mastodon-toot-mode' buffer and window." (kill-buffer-and-window)) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 460fe29..acb9e12 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -80,6 +80,7 @@ (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-tl--poll-vote "mastodon-http") +(autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") (defgroup mastodon nil "Interface with Mastodon." @@ -143,6 +144,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) (define-key map (kbd "S") #'mastodon-search--search-query) (define-key map (kbd "d") #'mastodon-toot--delete-toot) + (define-key map (kbd "D") #'mastodon-toot--delete-and-redraft-toot) (define-key map (kbd "C") #'mastodon-toot--copy-toot-url) (define-key map (kbd "i") #'mastodon-toot--pin-toot-toggle) (define-key map (kbd "V") #'mastodon-profile--view-favourites) -- cgit v1.2.3 From d1458ad0c1bf95a685a3b9ff3e4750ce82305d7a Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 13:18:44 +0200 Subject: fix formatting of mastodon-toot-default-visibility --- lisp/mastodon-toot.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 1f65cbf..97841b5 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -58,10 +58,11 @@ Must be one of \"public\", \"unlisted\", \"private\", or \"direct\"." :group 'mastodon-toot - :type '(choice ("public" - "unlisted" - "private" - "direct"))) + :type 'choice + :options '("public" + "unlisted" + "private" + "direct")) (defvar mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") -- cgit v1.2.3 From 6b7d03538afb6679d9f614d861743e2b0150c191 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 14:19:36 +0200 Subject: display "followers-only" for "private" post visibility --- lisp/mastodon-toot.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 97841b5..95f562c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -56,7 +56,7 @@ (defcustom mastodon-toot--default-visibility "public" "The default visibility for new toots. -Must be one of \"public\", \"unlisted\", \"private\", or \"direct\"." +Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \"direct\"." :group 'mastodon-toot :type 'choice :options '("public" @@ -75,7 +75,7 @@ Must be one of \"public\", \"unlisted\", \"private\", or \"direct\"." (defvar mastodon-toot--visibility "public" "A string indicating the visibility of the toot being composed. -Valid values are \"direct\", \"private\", \"unlisted\", and \"public\".") +Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"public\".") (make-variable-buffer-local 'mastodon-toot--visibility) (defvar mastodon-toot--media-attachments nil @@ -520,7 +520,11 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (add-text-properties (car visibility-region) (cdr visibility-region) (list 'display (format "Visibility: %s" - mastodon-toot--visibility))) + (if (equal + mastodon-toot--visibility + "private") + "followers-only" + mastodon-toot--visibility)))) (add-text-properties (car attachment-region) (cdr attachment-region) (list 'display (format "Attached: %s" -- cgit v1.2.3 From bdf9661de4a67a45cd41f3312c96b26c30396c80 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Sep 2021 16:58:45 +0200 Subject: readme update --- README.org | 55 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/README.org b/README.org index 4be82c6..b8fe9d2 100644 --- a/README.org +++ b/README.org @@ -4,29 +4,32 @@ This is a fork of of the great but seemingly dormant https://github.com/jdenen/m It adds the following features: -| Profiles: | | -| | display profile metadata fields | -| | display pinned toots on profiles | -| | display relationship (follows you/followed by you) on profiles | -| | display toots/follows/followers counts on profiles | -| | links/tags/mentions in profiles are active links | -| =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | -| =v= | view your favorited toots | -| =i= | toggle pinning of toots | -| =S-C-P= | jump to your profile | -| =U= | update your profile bio note | -| Timelines: | | -| =C= | copy url of toot at point | -| =d= | delete your toot at point | -| =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | -| | display polls and vote on polls (very basic for now) | -| | images are links to the full image, can be zoomed/rotated/saved (see their keymap) | -| Toots: | | -| | mention booster in replies by default | -| =C-c C-a= | media uploads | -| =C-c C-n= | and sensitive media/nsfw flag | -| Search: | | -| =S= | search (posts, users, tags) (improved! but still rly basic!) (NB: by default, posts searched will only be those you have interacted with in some way; your instance can optionally enable full search) | +| Profiles: | | +| | display profile metadata fields | +| | display pinned toots on profiles | +| | display relationship (follows you/followed by you) on profiles | +| | display toots/follows/followers counts on profiles | +| | links/tags/mentions in profiles are active links | +| =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | +| =v= | view your favorited toots | +| =i= | toggle pinning of toots | +| =S-C-P= | jump to your profile | +| =U= | update your profile bio note | +| Timelines: | | +| =C= | copy url of toot at point | +| =d= | delete your toot at point, and reload current timeline | +| =D= | delete and redraft toot at point | +| =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | +| | display polls and vote on polls (pretty basic for now) | +| | images are links to the full image, can be zoomed/rotated/saved (see image keymap) | +| Toots: | | +| | mention booster in replies by default | +| =C-c C-a= | media uploads | +| =C-c C-n= | and sensitive media/nsfw flag | +| | | +| Search: | | +| =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | +| | | It also makes some small cosmetic changes to make timelines easier to read, and makes some functions asynchronous, based on https://github.com/ieure/mastodon.el. @@ -48,9 +51,9 @@ This version depends on the library =request= (for uploading attachments). You c ** NB: bugs -As it stands the client still has some bugs. In particular, when composing a toot, hit =C-g= before sending your toot. If you don't, your draft may disappear. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. +As it stands the client still has some bugs. In particular, when composing a toot, there is a bug in the live character counting. For the moment, you'll likely need to hit =C-c C-c= twice rather than once to send a post. In case your toot buffed disappears and your toot does not post, the toot contents are also copied to the kill ring. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. -Some people have also had niggling troubles with initial auth and set-up, but I couldn't reproduce. +Some people have also had trouble with initial auth and set-up, but these should be fixed by =50062c5=, by Ian Eure. ** roadmap-ish @@ -61,6 +64,8 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] view/accept/reject follow requests in notifications view. - [X] fix sometimes usernames don't appear in timelines - [X] voting on polls +- [X] delete and redraft toots +- [X] prevent loss of draft toots by the toot-send bug - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies -- cgit v1.2.3 From e9188a2cdb2575e9b0c1c322431e1ebd686c4b9b Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 1 Oct 2021 14:09:09 +0200 Subject: kill-current-buffer instead of kill-this-buffer kill-this-buffer doesn't always work if not called from the menu bar, as stated in its docstring. --- lisp/mastodon.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index acb9e12..a06b18d 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -122,7 +122,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "P") #'mastodon-profile--show-user) (define-key map (kbd "T") #'mastodon-tl--thread) ;; navigation out of mastodon - (define-key map (kbd "q") #'kill-this-buffer) + (define-key map (kbd "q") #'kill-current-buffer) (define-key map (kbd "Q") #'kill-buffer-and-window) ;; timeline actions (define-key map (kbd "b") #'mastodon-toot--toggle-boost) -- cgit v1.2.3 From 77f0d464c39693ffef7146aced2804e787a870de Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 2 Oct 2021 00:27:24 +0200 Subject: repair somewhat the media-upload functions and error handling --- lisp/mastodon-http.el | 26 +++++++++++++------------- lisp/mastodon-toot.el | 6 +----- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 31ea483..cd89cc5 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -249,11 +249,11 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (defun mastodon-http--post-media-attachment (url filename caption) "Make POST request to upload FILENAME with CAPTION to the server's media URL. -The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, `mastodon-toot--media-attachments' is set to t, and `mastodon-toot--update-status-fields' is run." +The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, and `mastodon-toot--update-status-fields' is run." (let* ((file (file-name-nondirectory filename)) - (request-backend 'curl) - (response - (request + (request-backend 'curl)) + ;; (response + (request url :type "POST" :params `(("description" . ,caption)) @@ -278,15 +278,15 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' (mastodon-toot--update-status-fields))))) :error (cl-function (lambda (&key error-thrown &allow-other-keys) - (message "Got error: %s" error-thrown)))))) - (pcase (request-response-status-code response) - (200 - (request-response-data response)) - (401 - (error "Unauthorized: The access token is invalid")) - (422 - (error "Unprocessable entity: file or file type is unsupported or invalid")) - (_ (error "Shit went south"))))) + (message "%s" (car (last error-thrown))) + (message "%s" (type-of (car (last error-thrown)))) + (cond ((= (car (last error-thrown)) 401) + (message "Got error: %s Unauthorized: The access token is invalid" error-thrown)) + ((= (car (last error-thrown)) 422) + (message "Got error: %s Unprocessable entity: file or file type is unsupported or invalid" error-thrown)) + (t + (message "Got error: %s Shit went south" + error-thrown)))))))) (provide 'mastodon-http) ;;; mastodon-http.el ends here diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 95f562c..0c3c784 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -78,10 +78,6 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"public\".") (make-variable-buffer-local 'mastodon-toot--visibility) -(defvar mastodon-toot--media-attachments nil - "A flag indicating if the toot being composed has media attachments.") -(make-variable-buffer-local 'mastodon-toot--media-attachments) - (defvar mastodon-toot--media-attachment-ids nil "A list of any media attachment ids of the toot being composed.") (make-variable-buffer-local 'mastodon-toot--media-attachment-ids) @@ -316,7 +312,7 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (symbol-name t))) ("spoiler_text" . ,spoiler))) (args-media - (when mastodon-toot--media-attachments + (when mastodon-toot--media-attachment-ids (mapcar (lambda (id) (cons "media_ids[]" id)) -- cgit v1.2.3 From a311de00bd4fb2ad467c955e1fa12fd5613b58b2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 2 Oct 2021 00:27:57 +0200 Subject: add emojify-insert-emoji binding in mastodon new toot buffer --- lisp/mastodon-toot.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 0c3c784..fc8949a 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -31,6 +31,8 @@ (defvar mastodon-instance-url) +(declare-function #'emojify-insert-emoji "emojify") + (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") @@ -98,6 +100,8 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (define-key map (kbd "C-c C-n") #'mastodon-toot--toggle-nsfw) (define-key map (kbd "C-c C-v") #'mastodon-toot--change-visibility) (define-key map (kbd "C-c C-a") #'mastodon-toot--add-media-attachment) + (when (require 'emojify nil :noerror) + (define-key map (kbd "C-c C-e") #'mastodon-toot--insert-emoji)) map) "Keymap for `mastodon-toot'.") @@ -265,6 +269,10 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (interactive) (mastodon-toot--kill)) +(defun mastodon-toot--insert-emoji () + "Prompt to insert an emoji." + (emojify-insert-emoji)) + (defun mastodon-toot--remove-docs () "Get the body of a toot from the current compose buffer." (let ((header-region (mastodon-tl--find-property-range 'toot-post-header -- cgit v1.2.3 From d13fa5fb1a4f41db6c97927776c79194f7bc9da6 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 2 Oct 2021 13:15:58 +0200 Subject: flycheck: docstrings, autoloads, declarations --- lisp/mastodon-http.el | 6 +++- lisp/mastodon-search.el | 3 +- lisp/mastodon-tl.el | 96 ++++++++++++++++++++++++++++++++----------------- lisp/mastodon-toot.el | 14 ++++---- 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index cd89cc5..abd9af0 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -191,7 +191,9 @@ Pass response buffer to CALLBACK function." ;; hard coded just for bio note for now: (defun mastodon-http--patch (base-url &optional note) - "Make synchronous PATCH request to URL. + "Make synchronous PATCH request to BASE-URL. + +Optionally specify the NOTE to edit. Pass response buffer to CALLBACK function." (let ((url-request-method "PATCH") @@ -228,6 +230,8 @@ Pass response buffer to CALLBACK function with args CBARGS." (defun mastodon-http--post-async (url args headers &optional callback &rest cbargs) "POST asynchronously to URL with ARGS and HEADERS. +Then run function CALLBACK with arguements CBARGS. + Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (let ((url-request-method "POST") (request-timeout 5) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 3b7e399..537a746 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -41,8 +41,7 @@ (defvar mastodon-instance-url) (defvar mastodon-tl--link-keymap) - -(defconst mastodon-http--timeout 5) +(defvar mastodon-http--timeout) (defun mastodon-search--search-query (query) "Prompt for a search QUERY and return accounts, statuses, and hashtags." diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index da18a94..48237d9 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -33,6 +33,7 @@ (require 'thingatpt) ;; for word-at-point (require 'time-date) +(autoload 'mastodon-auth--get-account-name "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-media--get-avatar-rendering "mastodon-media") @@ -53,10 +54,13 @@ (autoload 'mastodon-http--get-json-async "mastodon-http") (autoload 'mastodon-profile--lookup-account-in-status "mastodon-profile") (autoload 'mastodon-profile-mode "mastodon-profile") +(autoload 'mastodon-notifications--get "mastodon-notifications") (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this +(declare-function mapcar* "cl") + (defgroup mastodon-tl nil "Timelines in Mastodon." :prefix "mastodon-tl-" @@ -116,7 +120,7 @@ If nil `(point-min)' is used instead.") (define-key map [mouse-2] 'mastodon-tl--do-link-action) (define-key map [follow-link] 'mouse-face) (keymap-canonicalize map)) - "The keymap set for things in the buffer that act like links (except for shr.el generate links). + "The keymap for link-like things in buffer (except for shr.el generate links). This will make the region of text act like like a link with mouse highlighting, mouse click action tabbing to next/previous link @@ -175,9 +179,10 @@ This also skips tab items in invisible text, i.e. hidden spoiler text." (defun mastodon-tl--previous-tab-item () "Move to the previous interesting item. -This could be the previous toot, link, or image; whichever comes first. -Don't move if nothing else to move to is found, i.e. near the start of the buffer. -This also skips tab items in invisible text, i.e. hidden spoiler text." +This could be the previous toot, link, or image; whichever comes +first. Don't move if nothing else to move to is found, i.e. near +the start of the buffer. This also skips tab items in invisible +text, i.e. hidden spoiler text." (interactive) (let (next-range (search-pos (point))) @@ -310,7 +315,7 @@ Return value from boosted content if available." (cdr (assoc field toot)))) (defun mastodon-tl--relative-time-details (timestamp &optional current-time) - "Returns cons of (descriptive string . next change) for the TIMESTAMP. + "Return cons of (descriptive string . next change) for the TIMESTAMP. Use the optional CURRENT-TIME as the current time (only used for reliable testing). @@ -365,7 +370,7 @@ TIMESTAMP is assumed to be in the past." (time-add timestamp (seconds-to-time (cdr relative-result)))))) (defun mastodon-tl--relative-time-description (timestamp &optional current-time) - "Returns a string with a human readable description of TIMESTAMP relative to the current time. + "Return a string with a human readable TIMESTAMP relative to the current time. Use the optional CURRENT-TIME as the current time (only used for reliable testing). @@ -380,8 +385,8 @@ TIME-STAMP is assumed to be in the past." AUTHOR-BYLINE is function for adding the author portion of the byline that takes one variable. ACTION-BYLINE is a function for adding an action, such as boosting -favouriting and following to the byline. It also takes a single function. By default -it is `mastodon-tl--byline-boosted'" +favouriting and following to the byline. It also takes a single function. +By default it is `mastodon-tl--byline-boosted'" (let ((parsed-time (date-to-time (mastodon-tl--field 'created_at toot))) (faved (equal 't (mastodon-tl--field 'favourited toot))) (boosted (equal 't (mastodon-tl--field 'reblogged toot)))) @@ -411,7 +416,7 @@ it is `mastodon-tl--byline-boosted'" 'byline t)))) (defun mastodon-tl--render-text (string toot) - "Returns a propertized text giving the rendering of the given HTML string STRING. + "Return a propertized text rendering the given HTML string STRING. The contents comes from the given TOOT which is used in parsing links in the text. If TOOT is nil no parsing occurs." @@ -433,6 +438,8 @@ links in the text. If TOOT is nil no parsing occurs." (buffer-string))) (defun mastodon-tl--process-link (toot start end url) + "Process link URL in TOOT as hashtag, userhandle, or normal link. +START and END are the boundaries of the link in the toot." (let* (mastodon-tab-stop-type keymap (help-echo (get-text-property start 'help-echo)) @@ -499,7 +506,7 @@ links in the text. If TOOT is nil no parsing occurs." return)) (defun mastodon-tl--extract-userhandle-from-url (url buffer-text) - "Returns the user hande the URL points to or nil if it is not a profile link. + "Return the user hande the URL points to or nil if it is not a profile link. BUFFER-TEXT is the text covered by the link with URL, for a user profile this should be of the form , e.g. \"@Gargon\"." @@ -510,7 +517,7 @@ this should be of the form , e.g. \"@Gargon\"." (concat buffer-text "@" (url-host parsed-url))))) (defun mastodon-tl--extract-hashtag-from-url (url instance-url) - "Returns the hashtag that URL points to or nil if URL is not a tag link. + "Return the hashtag that URL points to or nil if URL is not a tag link. INSTANCE-URL is the url of the instance for the toot that the link came from (tag links always point to a page on the instance publishing @@ -526,7 +533,7 @@ the toot)." (t nil))) (defun mastodon-tl--set-face (string face) - "Returns the propertized STRING with the face property set to FACE." + "Return the propertized STRING with the face property set to FACE." (propertize string 'face face)) (defun mastodon-tl--toggle-spoiler-text (position) @@ -568,7 +575,7 @@ LINK-TYPE is the type of link to produce." ((eq link-type 'content-warning) "Toggle hidden text") (t - (error "unknown link type %s" link-type))))) + (error "Unknown link type %s" link-type))))) (propertize string 'mastodon-tab-stop link-type @@ -577,7 +584,8 @@ LINK-TYPE is the type of link to produce." 'help-echo help-text))) (defun mastodon-tl--do-link-action-at-point (position) - ;; called by RET + "Do the action of the link at POSITION. +Used for hitting on a given link." (interactive "d") (let ((link-type (get-text-property position 'mastodon-tab-stop))) (cond ((eq link-type 'content-warning) @@ -601,10 +609,11 @@ LINK-TYPE is the type of link to produce." (mastodon-profile--search-account-by-handle (get-text-property position 'mastodon-handle))))))) (t - (error "unknown link type %s" link-type))))) + (error "Unknown link type %s" link-type))))) (defun mastodon-tl--do-link-action (event) - ;; called by mouse click + "Do the action of the link at. +Used for a mouse-click EVENT on a link." (interactive "e") (mastodon-tl--do-link-action-at-point (posn-point (event-end event)))) @@ -614,6 +623,7 @@ LINK-TYPE is the type of link to produce." (and spoiler (> (length spoiler) 0)))) (defun mastodon-tl--clean-tabs-and-nl (string) + "Remove tabs and newlines from STRING." (replace-regexp-in-string "[\t\n ]*\\'" "" string)) @@ -683,11 +693,13 @@ message is a link which unhides/hides the main body." "Display the content and byline of timeline element TOOT. BODY will form the section of the toot above the byline. -AUTHOR-BYLINE is an optional function for adding the author portion of -the byline that takes one variable. By default it is `mastodon-tl--byline-author' -ACTION-BYLINE is also an optional function for adding an action, such as boosting -favouriting and following to the byline. It also takes a single function. By default -it is `mastodon-tl--byline-boosted'" +AUTHOR-BYLINE is an optional function for adding the author +portion of the byline that takes one variable. By default it is +`mastodon-tl--byline-author' +ACTION-BYLINE is also an optional function for adding an action, +such as boosting favouriting and following to the byline. It also +takes a single function. By default it is +`mastodon-tl--byline-boosted'" (let ((start-pos (point))) (insert (propertize @@ -782,23 +794,26 @@ it is `mastodon-tl--byline-boosted'" (goto-char (point-min))) (defun mastodon-tl--get-update-function (&optional buffer) - "Get the UPDATE-FUNCTION stored in `mastodon-tl--buffer-spec'" + "Get the UPDATE-FUNCTION stored in `mastodon-tl--buffer-spec'. +Optionally get it for BUFFER." (mastodon-tl--get-buffer-property 'update-function buffer)) (defun mastodon-tl--get-endpoint (&optional buffer) - "Get the ENDPOINT stored in `mastodon-tl--buffer-spec'" + "Get the ENDPOINT stored in `mastodon-tl--buffer-spec'. +Optionally set it for BUFFER." (mastodon-tl--get-buffer-property 'endpoint buffer)) (defun mastodon-tl--buffer-name (&optional buffer) - "Get the BUFFER-NAME stored in `mastodon-tl--buffer-spec'" + "Get the BUFFER-NAME stored in `mastodon-tl--buffer-spec'. +Optionally get it for BUFFER." (mastodon-tl--get-buffer-property 'buffer-name buffer )) (defun mastodon-tl--get-buffer-property (property &optional buffer) - "Get `MASTODON-TL--BUFFER-SPEC' in BUFFER or `CURRENT-BUFFER'" + "Get PROPERTY from `mastodon-tl--buffer-spec' in BUFFER or `current-buffer'." (with-current-buffer (or buffer (current-buffer)) (if (plist-get mastodon-tl--buffer-spec property) (plist-get mastodon-tl--buffer-spec property) - (error "mastodon-tl--buffer-spec is not defined for buffer %s" + (error "Mastodon-tl--buffer-spec is not defined for buffer %s" (or buffer (current-buffer)))))) (defun mastodon-tl--more-json (endpoint id) @@ -813,7 +828,8 @@ it is `mastodon-tl--byline-boosted'" (mastodon-http--get-json url))) (defun mastodon-tl--more-json-async (endpoint id callback &rest cbargs) - "Return JSON for timeline ENDPOINT before ID." + "Return JSON for timeline ENDPOINT before ID. +Then run CALLBACK with arguments CBARGS." (let* ((url (mastodon-http--api (concat endpoint (if (string-match-p "?" endpoint) @@ -891,6 +907,11 @@ webapp" 'mastodon-tl--thread* id toot buffer))) (defun mastodon-tl--thread* (context id toot buffer) + "Callback for async `mastodon-tl--thread'. + +Open thread buffer for TOOT with id ID under `point'asynchronously, +in new BUFFER. +CONTEXT is the previous and subsequent toots in the thread." (when (member (cdr (assoc 'type toot)) '("reblog" "favourite")) (setq toot (cdr (assoc 'status toot)))) (if (> (+ (length (cdr (assoc 'ancestors context))) @@ -1054,6 +1075,7 @@ webapp" (message "User %s (@%s) unblocked!" name user-handle))))) (message "Cannot find a user with handle %S" user-handle)))) +;; TODO: add this to new posts in some cases, e.g. in thread view. (defun mastodon-tl--reload-timeline-or-profile () "Reload the current timeline or profile page. For use after e.g. deleting a toot." @@ -1070,12 +1092,15 @@ For use after e.g. deleting a toot." (mastodon-profile--my-profile)))) (defun mastodon-tl--more () - "Append older toots to timeline." + "Append older toots to timeline, asynchronously." (interactive) (mastodon-tl--more-json-async (mastodon-tl--get-endpoint) (mastodon-tl--oldest-id) 'mastodon-tl--more* (current-buffer) (point))) (defun mastodon-tl--more* (json buffer point-before) + "Append older toots to timeline, asynchronously. +Runs the timeline's update function on JSON, in BUFFER. +When done, places point at POINT-BEFORE." (with-current-buffer buffer (when json (let ((inhibit-read-only t)) @@ -1084,7 +1109,7 @@ For use after e.g. deleting a toot." (goto-char point-before))))) (defun mastodon-tl--find-property-range (property start-point &optional search-backwards) - "Returns `nil` if no such range is found. + "Return `nil` if no such range is found. If PROPERTY is set at START-POINT returns a range around START-POINT otherwise before/after START-POINT. @@ -1120,9 +1145,12 @@ before (non-nil) or after (nil)" (defun mastodon-tl--find-next-or-previous-property-range (property start-point search-backwards) - "Finds (start . end) range after/before START-POINT where PROPERTY is set to a consistent value (different from the value at START-POINT if that is set). + "Find (start . end) property range after/before START-POINT. + +Does so while PROPERTY is set to a consistent value (different +from the value at START-POINT if that is set). -Returns nil if no such range exists. +Return nil if no such range exists. If SEARCH-BACKWARDS is non-nil it find a region before START-POINT otherwise after START-POINT." @@ -1237,7 +1265,7 @@ from the start if it is nil." (funcall update-function json))))) (defun mastodon-tl--init (buffer-name endpoint update-function) - "Initialize BUFFER-NAME with timeline targeted by ENDPOINT. + "Initialize BUFFER-NAME with timeline targeted by ENDPOINT asynchronously. UPDATE-FUNCTION is used to recieve more toots." (let ((url (mastodon-http--api endpoint)) @@ -1246,6 +1274,10 @@ UPDATE-FUNCTION is used to recieve more toots." url 'mastodon-tl--init* buffer endpoint update-function))) (defun mastodon-tl--init* (json buffer endpoint update-function) + "Initialize BUFFER with timeline targeted by ENDPOINT. + +UPDATE-FUNCTION is used to recieve more toots. +JSON is the data returned from the server." (with-output-to-temp-buffer buffer (switch-to-buffer buffer) (setq diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index fc8949a..9fb31d1 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -31,13 +31,15 @@ (defvar mastodon-instance-url) -(declare-function #'emojify-insert-emoji "emojify") +(when (require 'emojify nil :noerror) + (declare-function emojify-insert-emoji "emojify")) (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") +(autoload 'mastodon-http--process-json "mastodon-http") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") @@ -254,8 +256,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (lambda () (with-current-buffer response (let* ((json-response (mastodon-http--process-json)) - (content (cdr (assoc 'text json-response))) - (media (cdr (assoc 'media_attachments json-response)))) + (content (cdr (assoc 'text json-response)))) + ;; (media (cdr (assoc 'media_attachments json-response)))) (mastodon-toot--compose-buffer nil nil) (goto-char (point-max)) (insert content)))))))))) @@ -280,7 +282,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (buffer-substring (cdr header-region) (point-max)))) (defun mastodon-toot--set-visibility (visibility) - "Sets the visiblity of the next toot to VISIBILITY." + "Set the visiblity of the next toot to VISIBILITY." (interactive (list (completing-read "Visiblity: " '("public" "unlisted" @@ -339,7 +341,7 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) - "Adds domain to local ACCT and replaces the curent user name with \"\". + "Add domain to local ACCT and replace the curent user name with \"\". Mastodon requires the full user@domain, even in the case of local accts. eg. \"user\" -> \"user@local.social \" (when local.social is the domain of the @@ -502,7 +504,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (insert (format "%s " reply-to-user)) (setq mastodon-toot--reply-to-id reply-to-id))) -(defun mastodon-toot--update-status-fields (&rest args) +(defun mastodon-toot--update-status-fields () ;(&rest args) "Update the status fields in the header based on the current state." (let ((inhibit-read-only t) (header-region (mastodon-tl--find-property-range 'toot-post-header -- cgit v1.2.3 From 3ab777cd650825c525c469ce640204064fca7692 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 2 Oct 2021 13:16:25 +0200 Subject: customize option default-media-directory --- lisp/mastodon-toot.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9fb31d1..17b3a6c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -68,6 +68,11 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" "private" "direct")) +(defcustom mastodon-toot--default-media-directory "~/" + "The default directory when prompting for a media file to upload." + :group 'mastodon-toot + :type 'string) + (defvar mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") (make-variable-buffer-local 'mastodon-toot--content-warning) @@ -296,7 +301,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." Set `mastodon-toot--media-attachment-ids' to the item's id so it can be attached to the toot." (interactive) - (let* ((filename (read-file-name "Choose file to attach to this toot: ")) + (let* ((filename (read-file-name "Choose file to attach to this toot: " + mastodon-toot--default-media-directory)) (caption (read-string "Enter a caption: ")) (url (concat mastodon-instance-url "/api/v1/media"))) (message "Uploading %s..." (file-name-nondirectory filename)) -- cgit v1.2.3 From 0be3f27b8e97b4e765fc67dfc4b6c0a107d685bd Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 2 Oct 2021 13:16:54 +0200 Subject: restore var toot--media-attachments --- lisp/mastodon-toot.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 17b3a6c..dfe9ead 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -87,6 +87,10 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"public\".") (make-variable-buffer-local 'mastodon-toot--visibility) +(defvar mastodon-toot--media-attachments nil + "A flag indicating if the toot being composed has media attachments.") +(make-variable-buffer-local 'mastodon-toot--media-attachments) + (defvar mastodon-toot--media-attachment-ids nil "A list of any media attachment ids of the toot being composed.") (make-variable-buffer-local 'mastodon-toot--media-attachment-ids) @@ -469,9 +473,9 @@ e.g. mastodon-toot--send -> Send." (mastodon-toot--format-kbinds kbinds)))) (defun mastodon-toot--display-docs-and-status-fields () - "Insert propertized text with documentation about mastodon-toot mode and the -status fields which will get updated based on the status of NSFW, content -warning flags etc." + "Insert propertized text with documentation about `mastodon-toot-mode'. +Also includes and the status fields which will get updated based +on the status of NSFW, content warning flags, media attachments, etc." (let ((divider "|=================================================================|")) (insert -- cgit v1.2.3 From 8477f3aa37f2145a16e6aa627de92844094c2453 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 3 Oct 2021 20:33:56 +0200 Subject: make mastodon-toot--insert-emoji an alias --- 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 dfe9ead..c28bcb1 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -280,9 +280,9 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (interactive) (mastodon-toot--kill)) -(defun mastodon-toot--insert-emoji () - "Prompt to insert an emoji." - (emojify-insert-emoji)) +(defalias 'mastodon-toot--insert-emoji + 'emojify-insert-emoji + "Prompt to insert an emoji.") (defun mastodon-toot--remove-docs () "Get the body of a toot from the current compose buffer." -- cgit v1.2.3 From 26d0c9af7e9154e2ba1e9fbc0322d3679d07f4f1 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Thu, 21 Feb 2019 20:15:07 +0000 Subject: Fix: make after-change-functions buffer local. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See issue #218 — we mistakenly modified the global value and `mastodon-toot--update-status-fields` makes no sense outside the toot compose buffer. --- lisp/mastodon-toot.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index c28bcb1..16eae12 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -514,7 +514,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (insert (format "%s " reply-to-user)) (setq mastodon-toot--reply-to-id reply-to-id))) -(defun mastodon-toot--update-status-fields () ;(&rest args) +(defun mastodon-toot--update-status-fields (&rest args) "Update the status fields in the header based on the current state." (let ((inhibit-read-only t) (header-region (mastodon-tl--find-property-range 'toot-post-header @@ -566,6 +566,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (mastodon-toot--display-docs-and-status-fields) (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) (mastodon-toot-mode t) + (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) (mastodon-toot--update-status-fields))) -- cgit v1.2.3 From 998c27982cb96ccadd86b987f8e7e02ee517f1cf Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 3 Oct 2021 20:40:32 +0200 Subject: revert bug workaround copying toot to kill ring --- lisp/mastodon-toot.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 16eae12..a8b121b 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -346,8 +346,7 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (let ((response (mastodon-http--post endpoint args nil))) (mastodon-http--triage response (lambda () - (kill-new toot) ; copy toot text to kill ring - (mastodon-toot--kill) ; only kill buffer after sending + (mastodon-toot--kill) (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) -- cgit v1.2.3 From 23c61a59242fcf68ab1cc2b7fcc620b59fe11704 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 3 Oct 2021 20:48:12 +0200 Subject: readme re bugs --- README.org | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.org b/README.org index b8fe9d2..ed080da 100644 --- a/README.org +++ b/README.org @@ -26,6 +26,7 @@ It adds the following features: | | mention booster in replies by default | | =C-c C-a= | media uploads | | =C-c C-n= | and sensitive media/nsfw flag | +| =C-c C-e= | add emoji (if =emojify= installed) | | | | | Search: | | | =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | @@ -49,12 +50,6 @@ Works for federated, local, and home timelines and for notifications. It's prett This version depends on the library =request= (for uploading attachments). You can install it from MELPA, or https://github.com/tkf/emacs-request. -** NB: bugs - -As it stands the client still has some bugs. In particular, when composing a toot, there is a bug in the live character counting. For the moment, you'll likely need to hit =C-c C-c= twice rather than once to send a post. In case your toot buffed disappears and your toot does not post, the toot contents are also copied to the kill ring. You may also see a related error when you try to add a media attachment. You should be able to run the command again and it should work. See the issues on the original repo. - -Some people have also had trouble with initial auth and set-up, but these should be fixed by =50062c5=, by Ian Eure. - ** roadmap-ish I might add a few more features if the ones I added turn out to work ok. Possible additions/amendments: @@ -66,6 +61,7 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] voting on polls - [X] delete and redraft toots - [X] prevent loss of draft toots by the toot-send bug +- [ ] display post visibility status - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies -- cgit v1.2.3 From 7b2dd904c73b75f3c653db193c85ba61ff9642ca Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 3 Oct 2021 21:40:39 +0200 Subject: flycheck: docstrings, autoloads, etc --- README.org | 3 ++- lisp/mastodon-auth.el | 8 +++++--- lisp/mastodon-client.el | 2 +- lisp/mastodon-discover.el | 2 ++ lisp/mastodon-media.el | 21 ++++++++++++--------- lisp/mastodon-notifications.el | 22 +++++++++++++++++----- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/README.org b/README.org index ed080da..1dc23e1 100644 --- a/README.org +++ b/README.org @@ -61,7 +61,8 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] voting on polls - [X] delete and redraft toots - [X] prevent loss of draft toots by the toot-send bug -- [ ] display post visibility status +- [X] fix scaling of images +- [ ] display post visibility status in timelines - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 3f4ee7d..0b0c703 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -124,7 +124,7 @@ Reads and/or stores secrets in `MASTODON-AUTH-SOURCE-FILE'." (json-read-from-string json-string)))) (defun mastodon-auth--access-token () - "If an access token for the current `mastodon-instance-url' exists in `mastodon-auth--token-alist', return it. + "If an access token for `mastodon-instance-url' is in `mastodon-auth--token-alist', return it. Otherwise, generate a token and pass it to `mastodon-auth--handle-token-reponse'." (if-let ((token (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) @@ -133,7 +133,9 @@ Otherwise, generate a token and pass it to `mastodon-auth--handle-token-reponse' (mastodon-auth--handle-token-response (mastodon-auth--get-token)))) (defun mastodon-auth--handle-token-response (response) - "Add the token in RESPONSE returned by `mastodon-auth--get-token' in `mastodon-auth--token-alist'. + "Add token RESPONSE to `mastodon-auth--token-alist'. + +The token is returned by `mastodon-auth--get-token'. Handle any errors from the server." (pcase response @@ -143,7 +145,7 @@ Handle any errors from the server." mastodon-auth--token-alist))) (`(:error ,class :error_description ,error) - (error "mastodon-auth--access-token: %s: %s" class error)) + (error "Mastodon-auth--access-token: %s: %s" class error)) (_ (error "Unknown response from mastodon-auth--get-token!")))) diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 6439c0a..bdfbca9 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -94,7 +94,7 @@ Make `mastodon-client--fetch' call to determine client values." (cdr mastodon))) (defun mastodon-client () - "Return variable client secrets to use for the current `mastodon-instance-url'.. + "Return variable client secrets to use for `mastodon-instance-url'. Read plist from `mastodon-client--token-file' if variable is nil. Fetch and store plist if `mastodon-client--read' returns nil." diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 9c946be..8c47fbd 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -32,6 +32,8 @@ ;;; Code: +(declare-function discover-add-context-menu "discover") + (defun mastodon-discover () "Plug Mastodon functionality into `discover'." (interactive) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index c3873df..b58eab6 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -87,7 +87,7 @@ m836fL6tra0jYkUiEb/fz8k3waLhikQiXq+3/NtiSayNjY1fv35BbVP5fN7pdG5tbR0Fy+12c360 Hxzz5a8KI6V6EMMwzo/2fZ2YTqej0WgqlSoVLqRUDwYCAajNiqKoYDBYphOLY8ViscItVG1VJEmu r6+XeU8sjhWPxzc3N9sNiyAIDMOqS1YbDqwKx1YRrFQqxc7HJDRnpdPpUuEqgoVhWL0+i6hFz6tL ja3iM4u1zw1qwhlfJihI0bfCNhxYe4NSqg3/A862hQAbrdtHAAAAAElFTkSuQmCC") - "The PNG data for a generic 100x100 avatar") + "The PNG data for a generic 100x100 avatar.") (defvar mastodon-media--generic-broken-image-data (base64-decode-string @@ -169,9 +169,11 @@ REGION-LENGTH is the length of the region that should be replaced with the image (kill-buffer url-buffer))))))) (defun mastodon-media--load-image-from-url (url media-type start region-length) - "Takes a URL and MEDIA-TYPE and load the image asynchronously. + "Take a URL and MEDIA-TYPE and load the image asynchronously. -MEDIA-TYPE is a symbol and either 'avatar or 'media-link." +MEDIA-TYPE is a symbol and either 'avatar or 'media-link. +START is the position where we start loading the image. +REGION-LENGTH is the range from start to propertize." ;; TODO: Cache the avatars (let ((image-options (when (or (image-type-available-p 'imagemagick) (image-transforms-p)) ; inbuilt scaling in 27.1 @@ -222,17 +224,17 @@ found." (list next-pos (+ next-pos 5) 'media-link))))))) (defun mastodon-media--valid-link-p (link) - "Checks to make sure that the missing string has + "Check if LINK is valid. -not been returned." +Checks to make sure the missing string has not been returned." (and link (> (length link) 8) (or (string= "http://" (substring link 0 7)) (string= "https://" (substring link 0 8))))) (defun mastodon-media--inline-images (search-start search-end) - "Find all `Media_Links:' in the range from SEARCH-START to SEARCH-END -replacing them with the referenced image." + "Find all `Media_Links:' in the range from SEARCH-START to SEARCH-END. +Replace them with the referenced image." (save-excursion (goto-char search-start) (let (line-details) @@ -251,7 +253,7 @@ replacing them with the referenced image." image-url media-type start (- end start)))))))) (defun mastodon-media--get-avatar-rendering (avatar-url) - "Returns the string to be written that renders the avatar at AVATAR-URL." + "Return the string to be written that renders the avatar at AVATAR-URL." ;; We use just an empty space as the textual representation. ;; This is what a user will see on a non-graphical display ;; where not showing an avatar at all is preferable. @@ -271,7 +273,8 @@ replacing them with the referenced image." " "))) (defun mastodon-media--get-media-link-rendering (media-url &optional full-remote-url) - "Returns the string to be written that renders the image at MEDIA-URL." + "Return the string to be written that renders the image at MEDIA-URL. +FULL-REMOTE-URL is used for `shr-browse-image'." (concat (propertize "[img]" 'media-url media-url diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 7524038..c917124 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -33,11 +33,18 @@ (autoload 'mastodon-tl--byline-author "mastodon-tl.el") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl.el") (autoload 'mastodon-tl--content "mastodon-tl.el") +(autoload 'mastodon-tl--byline "mastodon-tl.el") +(autoload 'mastodon-tl--toot-id "mastodon-tl.el") (autoload 'mastodon-tl--field "mastodon-tl.el") (autoload 'mastodon-tl--has-spoiler "mastodon-tl.el") (autoload 'mastodon-tl--init "mastodon-tl.el") (autoload 'mastodon-tl--insert-status "mastodon-tl.el") (autoload 'mastodon-tl--spoiler "mastodon-tl.el") +(autoload 'mastodon-tl--property "mastodon-tl.el") +(autoload 'mastodon-tl--find-property-range "mastodon-tl.el") +(autoload 'mastodon-http--triage "mastodon-http.el") +(autoload 'mastodon-http--post "mastodon-http.el") +(autoload 'mastodon-http--api "mastodon-http.el") (defvar mastodon-tl--display-media-p) @@ -201,11 +208,16 @@ "Display the content and byline of timeline element TOOT. BODY will form the section of the toot above the byline. -AUTHOR-BYLINE is an optional function for adding the author portion of -the byline that takes one variable. By default it is `mastodon-tl--byline-author' -ACTION-BYLINE is also an optional function for adding an action, such as boosting -favouriting and following to the byline. It also takes a single function. By default -it is `mastodon-tl--byline-boosted'. + +AUTHOR-BYLINE is an optional function for adding the author +portion of the byline that takes one variable. By default it is +`mastodon-tl--byline-author'. + +ACTION-BYLINE is also an optional function for adding an action, +such as boosting favouriting and following to the byline. It also +takes a single function. By default it is +`mastodon-tl--byline-boosted'. + ID is the notification's own id, which is attached as a property." (let ((start-pos (point))) (insert -- cgit v1.2.3 From 88bcf746aaa10f6e9dbefbd79594ef1def7f6a69 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 3 Oct 2021 22:01:08 +0200 Subject: readme --- README.org | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.org b/README.org index 1dc23e1..2f48aac 100644 --- a/README.org +++ b/README.org @@ -22,11 +22,12 @@ It adds the following features: | =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | | | display polls and vote on polls (pretty basic for now) | | | images are links to the full image, can be zoomed/rotated/saved (see image keymap) | +| | images scale properly | | Toots: | | | | mention booster in replies by default | | =C-c C-a= | media uploads | | =C-c C-n= | and sensitive media/nsfw flag | -| =C-c C-e= | add emoji (if =emojify= installed) | +| =C-c C-e= | add emoji (if =emojify= installed) | | | | | Search: | | | =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | -- cgit v1.2.3 From 4dd84c9d5214369ea6c51cad04148aa067b69f8f Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 4 Oct 2021 12:24:34 +0200 Subject: make updating new toots inserts them after any pinned toots --- lisp/mastodon-profile.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 98d11f7..28f2e46 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -111,7 +111,7 @@ extra keybindings." (mastodon-tl--property 'toot-json)) (defun mastodon-profile--make-author-buffer (account) - "Take a ACCOUNT and insert a user account into a new buffer." + "Take an ACCOUNT json and insert a user account into a new buffer." (mastodon-profile--make-profile-buffer-for account "statuses" #'mastodon-tl--timeline)) @@ -369,8 +369,9 @@ Returns a list of lists." (setq mastodon-tl--update-point (point)) (mastodon-media--inline-images (point-min) (point)) ;; insert pinned toots first - (if (and pinned (equal endpoint-type "statuses")) - (mastodon-profile--insert-statuses-pinned pinned)) + (when (and pinned (equal endpoint-type "statuses")) + (mastodon-profile--insert-statuses-pinned pinned) + (setq mastodon-tl--update-point (point))) ;updates to follow pinned toots (funcall update-function json))) ;;(mastodon-tl--goto-next-toot) (goto-char (point-min)))) -- cgit v1.2.3 From 1d141a98479b4ca09f396adfd82f19f8709242e6 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 4 Oct 2021 12:26:56 +0200 Subject: make updating new toots inserts them after any pinned toots --- lisp/mastodon-profile.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 98d11f7..28f2e46 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -111,7 +111,7 @@ extra keybindings." (mastodon-tl--property 'toot-json)) (defun mastodon-profile--make-author-buffer (account) - "Take a ACCOUNT and insert a user account into a new buffer." + "Take an ACCOUNT json and insert a user account into a new buffer." (mastodon-profile--make-profile-buffer-for account "statuses" #'mastodon-tl--timeline)) @@ -369,8 +369,9 @@ Returns a list of lists." (setq mastodon-tl--update-point (point)) (mastodon-media--inline-images (point-min) (point)) ;; insert pinned toots first - (if (and pinned (equal endpoint-type "statuses")) - (mastodon-profile--insert-statuses-pinned pinned)) + (when (and pinned (equal endpoint-type "statuses")) + (mastodon-profile--insert-statuses-pinned pinned) + (setq mastodon-tl--update-point (point))) ;updates to follow pinned toots (funcall update-function json))) ;;(mastodon-tl--goto-next-toot) (goto-char (point-min)))) -- cgit v1.2.3 From b4dc8738efad0355ccfa3c1c89f81e4b4466eaa7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 4 Oct 2021 14:08:39 +0200 Subject: readme re fixes --- README.org | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.org b/README.org index 2f48aac..60f04eb 100644 --- a/README.org +++ b/README.org @@ -51,6 +51,12 @@ Works for federated, local, and home timelines and for notifications. It's prett This version depends on the library =request= (for uploading attachments). You can install it from MELPA, or https://github.com/tkf/emacs-request. +** NB: bugs + +This repo also incorporates fixes for two bugs that were never merged into the upstream repo: +- https://github.com/jdenen/mastodon.el/issues/227 (and https://github.com/jdenen/mastodon.el/issues/234) +- https://github.com/jdenen/mastodon.el/issues/228 + ** roadmap-ish I might add a few more features if the ones I added turn out to work ok. Possible additions/amendments: -- cgit v1.2.3 From fdd3ea487b6485dd210f5ee99836f900f23823b4 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 5 Oct 2021 18:51:00 +0200 Subject: set a larger mastodon-http--timeout. loading profiles would often not make in 5 seconds on a slower connection --- lisp/mastodon-http.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index abd9af0..bc48e8d 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -42,7 +42,7 @@ (defvar mastodon-http--api-version "v1") -(defconst mastodon-http--timeout 5 +(defconst mastodon-http--timeout 15 "HTTP request timeout, in seconds. Has no effect on Emacs < 26.1.") (defun mastodon-http--api (endpoint) -- cgit v1.2.3 From 3df45c1cd655f3c3555c47d6cfaf023ef13b6ca7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 5 Oct 2021 18:52:05 +0200 Subject: get relationships for a user with 1 rather than 2 requests --- lisp/mastodon-profile.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 28f2e46..2c364da 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -297,10 +297,11 @@ Returns a list of lists." (toots-count (mastodon-tl--as-string (mastodon-profile--account-field account 'statuses_count))) + (relationships (mastodon-profile--relationships-get id)) (followed-by-you (cdr (assoc 'following - (aref (mastodon-profile--relationships-get id) 0)))) + (aref relationships 0)))) (follows-you (cdr (assoc 'followed_by - (aref (mastodon-profile--relationships-get id) 0)))) + (aref relationships 0)))) (followsp (or (equal follows-you 't) (equal followed-by-you 't))) (fields (mastodon-profile--fields-get account)) (pinned (mastodon-profile--get-statuses-pinned account))) -- cgit v1.2.3 From 0129bcf466a4913bdda095b977cd06560c406a30 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 9 Oct 2021 13:22:04 +0200 Subject: handle cached images when we fetch images, check if they are cached, and if so use the cached version. for now, images aren't cached explicitly, but this should work if the user has `url-automatic-caching' enabled. --- lisp/mastodon-media.el | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index b58eab6..8ef9c44 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -189,9 +189,15 @@ REGION-LENGTH is the range from start to propertize." (condition-case nil ;; catch any errors in url-retrieve so as to not abort ;; whatever called us - (url-retrieve url - #'mastodon-media--process-image-response - (list marker image-options region-length)) + (if (url-is-cached url) + (with-current-buffer (url-fetch-from-cache url) + (set-buffer-multibyte nil) + (goto-char (point-min)) + (zlib-decompress-region (goto-char (search-forward "\n\n")) (point-max)) + (mastodon-media--process-image-response nil marker image-options region-length)) + (url-retrieve url + #'mastodon-media--process-image-response + (list marker image-options region-length))) (error (with-current-buffer buffer ;; TODO: Consider adding retries (put-text-property marker @@ -199,7 +205,7 @@ REGION-LENGTH is the range from start to propertize." 'media-state 'loading-failed) :loading-failed)))))) - +H (defun mastodon-media--select-next-media-line (end-pos) "Find coordinates of the next media to load before END-POS. -- cgit v1.2.3 From 0034797ed285eff9ca85448b21a39fa27f40a3ce Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 9 Oct 2021 15:18:41 +0200 Subject: handle caching of images we now store images ourselves for caching rather than relying on url-automatic-caching. --- lisp/mastodon-media.el | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 8ef9c44..8aadf0a 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -130,7 +130,7 @@ fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") "The PNG data for a generic 200x200 'broken image' view.") (defun mastodon-media--process-image-response - (status-plist marker image-options region-length) + (status-plist marker image-options region-length url) "Callback function processing the url retrieve response for URL. STATUS-PLIST is the usual plist of status events as per `url-retrieve'. @@ -151,6 +151,8 @@ REGION-LENGTH is the length of the region that should be replaced with the image (when image-options 'imagemagick) nil) ; inbuilt scaling in 27.1 t image-options)))) + (unless (url-is-cached url) ; cache image if not already cached + (url-store-in-cache url-buffer)) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer (let ((inhibit-read-only t)) @@ -190,14 +192,16 @@ REGION-LENGTH is the range from start to propertize." ;; catch any errors in url-retrieve so as to not abort ;; whatever called us (if (url-is-cached url) + ;; if image url is cached, decompress and use it (with-current-buffer (url-fetch-from-cache url) (set-buffer-multibyte nil) (goto-char (point-min)) (zlib-decompress-region (goto-char (search-forward "\n\n")) (point-max)) - (mastodon-media--process-image-response nil marker image-options region-length)) + (mastodon-media--process-image-response nil marker image-options region-length url)) + ;; else fetch as usual and process-image-response will cache it (url-retrieve url #'mastodon-media--process-image-response - (list marker image-options region-length))) + (list marker image-options region-length url))) (error (with-current-buffer buffer ;; TODO: Consider adding retries (put-text-property marker @@ -205,7 +209,7 @@ REGION-LENGTH is the range from start to propertize." 'media-state 'loading-failed) :loading-failed)))))) -H + (defun mastodon-media--select-next-media-line (end-pos) "Find coordinates of the next media to load before END-POS. -- cgit v1.2.3 From 547e4cf02a62d4a625ba13017b65908d77da50a6 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 14 Oct 2021 12:34:17 +0200 Subject: readme --- README.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.org b/README.org index 60f04eb..dcccccf 100644 --- a/README.org +++ b/README.org @@ -70,10 +70,10 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] prevent loss of draft toots by the toot-send bug - [X] fix scaling of images - [ ] display post visibility status in timelines +- [ ] caching of images / avatars - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies -- handle newlines in toots better, for poetry, etc. - improve (or even partially disable) async. It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. -- cgit v1.2.3 From 1f2ebe94c647fef509e06e9ef6f79697ef98a356 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 12:57:41 +0200 Subject: first test merge of hdurer's WIP: Posting of images --- lisp/mastodon-auth.el | 30 +++++------ lisp/mastodon-client.el | 8 +-- lisp/mastodon-http.el | 64 +++++++++++++++++++---- lisp/mastodon-media.el | 5 ++ lisp/mastodon-toot.el | 133 +++++++++++++++++++++++++++++++++++------------- 5 files changed, 176 insertions(+), 64 deletions(-) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 0b0c703..cd74ef8 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -73,12 +73,12 @@ If no auth-sources file, runs `mastodon-auth--generate-token-no-storing-credenti "Make POST to generate auth token, without using auth-sources file." (mastodon-http--post (concat mastodon-instance-url "/oauth/token") - `(("client_id" . ,(plist-get (mastodon-client) :client_id)) - ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) - ("grant_type" . "password") - ("username" . ,(read-string "Email: " user-mail-address)) - ("password" . ,(read-passwd "Password: ")) - ("scope" . "read write follow")) + `(("client_id" ,(plist-get (mastodon-client) :client_id)) + ("client_secret" ,(plist-get (mastodon-client) :client_secret)) + ("grant_type" "password") + ("username" ,(read-string "Email: " user-mail-address)) + ("password" ,(read-passwd "Password: ")) + ("scope" "read write follow")) nil :unauthenticated)) @@ -98,15 +98,15 @@ Reads and/or stores secrets in `MASTODON-AUTH-SOURCE-FILE'." (prog1 (mastodon-http--post (concat mastodon-instance-url "/oauth/token") - `(("client_id" . ,(plist-get (mastodon-client) :client_id)) - ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) - ("grant_type" . "password") - ("username" . ,(plist-get credentials-plist :user)) - ("password" . ,(let ((secret (plist-get credentials-plist :secret))) - (if (functionp secret) - (funcall secret) - secret))) - ("scope" . "read write follow")) + `(("client_id" ,(plist-get (mastodon-client) :client_id)) + ("client_secret" ,(plist-get (mastodon-client) :client_secret)) + ("grant_type" "password") + ("username" ,(plist-get credentials-plist :user)) + ("password" ,(let ((secret (plist-get credentials-plist :secret))) + (if (functionp secret) + (funcall secret) + secret))) + ("scope" "read write follow")) nil :unauthenticated) (when (functionp (plist-get credentials-plist :save-function)) diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index bdfbca9..4503d6d 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -49,10 +49,10 @@ "POST client to Mastodon." (mastodon-http--post (mastodon-http--api "apps") - '(("client_name" . "mastodon.el") - ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") - ("scopes" . "read write follow") - ("website" . "https://github.com/jdenen/mastodon.el")) + '(("client_name" "mastodon.el") + ("redirect_uris" "urn:ietf:wg:oauth:2.0:oob") + ("scopes" "read write follow") + ("website" "https://github.com/jdenen/mastodon.el")) nil :unauthenticated)) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index bc48e8d..85ee588 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -90,29 +90,75 @@ Message status and JSON error from RESPONSE if unsuccessful." (let ((json-response (mastodon-http--process-json))) (message "Error %s: %s" status (cdr (assoc 'error json-response)))))))) +(defun mastodon-http--encode-multipart-form-data (boundary fields) + "Encode FIELDS suitable to post as multipart/form-data. + +It uses BOUNDARY as the boundary for the values. +FIELDS should be a list of either 2-element (name contents) lists +or 4-element list of (name file-name content-type contents)." + (with-temp-buffer + (dolist (field fields) + (insert "--" boundary "\r\n") + (if (= (length field) 2) + ;; a 2-element list is a simple name=value item: + (insert "Content-Disposition: form-data; name=\"" + (url-hexify-string (car field)) + "\"\r\n" + "\r\n" + (cadr field) "\r\n") + ;; a 4-element list ist a file to be attached: + (insert "Content-Disposition: form-data; name=\"" + (url-hexify-string (car field)) + "\"; filename=\"" + (url-hexify-string (cadr field)) + "\"\r\n" + "Content-type: " (caddr field) "\r\n" + "\r\n" + (cadddr field) "\r\n"))) + ;; Finally add the terminating boundary and another empty line: + (insert "--" boundary "--\r\n" + "\r\n") + (string-to-unibyte (buffer-string)))) + (defun mastodon-http--post (url args headers &optional unauthenticed-p) "POST synchronously to URL with ARGS and HEADERS. Authorization header is included by default unless UNAUTHENTICED-P is non-nil." - (let ((url-request-method "POST") - (url-request-data - (when args - (mapconcat (lambda (arg) - (concat (url-hexify-string (car arg)) - "=" - (url-hexify-string (cdr arg)))) - args - "&"))) + (let* ((url-request-method "POST") + (boundary (md5 (format "b%s-%s-%s-%s" + (random 1000000000) (random 1000000000) + (random 1000000000) (random 1000000000)))) + (needs-multi-form (> (apply #'max (mapcar #'length args)) 2)) + (url-request-data + (when args + (if needs-multi-form + (mastodon-http--encode-multipart-form-data boundary args) + (mapconcat (lambda (arg) + (concat (url-hexify-string (car arg)) + "=" + (url-hexify-string (cadr arg)))) + args + "&")))) (url-request-extra-headers (append + (when needs-multi-form + `(("Content-Type" . + ,(concat "multipart/form-data; boundary=\"" boundary "\"")))) (unless unauthenticed-p `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token))))) headers))) + (message "Posting to %s with %d bytes of request data and headers %s" url (length url-request-data) url-request-extra-headers) (with-temp-buffer (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) (url-retrieve-synchronously url) (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) +(defun mastodon-http--read-file-as-string (filename) + "" + (with-temp-buffer + (insert-file-contents filename) + (string-to-unibyte (buffer-string)))) + (defun mastodon-http--get (url) "Make synchronous GET request to URL. diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 8aadf0a..fd2a6b7 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -51,6 +51,11 @@ :group 'mastodon-media :type 'integer) +(defcustom mastodon-media--attachment-height 100 + "Height of the attached images preview." + :group 'mastodon-media + :type 'integer) + (defvar mastodon-media--generic-avatar-data (base64-decode-string "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a8b121b..6c08859 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -30,6 +30,7 @@ ;;; Code: (defvar mastodon-instance-url) +(defvar mastodon-media--attachment-height) (when (require 'emojify nil :noerror) (declare-function emojify-insert-emoji "emojify")) @@ -103,6 +104,10 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p "Buffer-local variable to hold the id of the toot being replied to.") (make-variable-buffer-local 'mastodon-toot--reply-to-id) +(defvar mastodon-toot--media-attachments nil + "Buffer-local variable to hold the list of media attachments.") +(make-variable-buffer-local 'mastodon-toot--media-attachments) + (defvar mastodon-toot-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-toot--send) @@ -110,9 +115,10 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (define-key map (kbd "C-c C-w") #'mastodon-toot--toggle-warning) (define-key map (kbd "C-c C-n") #'mastodon-toot--toggle-nsfw) (define-key map (kbd "C-c C-v") #'mastodon-toot--change-visibility) - (define-key map (kbd "C-c C-a") #'mastodon-toot--add-media-attachment) (when (require 'emojify nil :noerror) (define-key map (kbd "C-c C-e") #'mastodon-toot--insert-emoji)) + (define-key map (kbd "C-c C-a") #'mastodon-toot--attach-media) + (define-key map (kbd "C-c !") #'mastodon-toot--clear-all-attachments) map) "Keymap for `mastodon-toot'.") @@ -147,6 +153,14 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response callback)))) +(defun mastodon-toot--post-media (contents content-type description) + (let* ((url (mastodon-http--api "media")) + (response (mastodon-http--post + url + (list (list "description" description) + (list "file" "file" content-type contents))))) + response)) + (defun mastodon-toot--toggle-boost () "Boost/unboost toot at `point'." (interactive) @@ -414,6 +428,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (interactive) (setq mastodon-toot--content-nsfw (not mastodon-toot--content-nsfw)) + (message "NSFW flag is now %s" (if mastodon-toot--content-nsfw "on" "off")) (mastodon-toot--update-status-fields)) (defun mastodon-toot--change-visibility () @@ -430,6 +445,54 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." "public"))) (mastodon-toot--update-status-fields)) +(defun mastodon-toot--clear-all-attachments () + "" + (interactive) + (setq mastodon-toot--media-attachments nil) + (mastodon-toot--refresh-attachments-display) + (mastodon-toot--update-status-fields)) + +(defun mastodon-toot--attach-media (file content-type description) + "" + (interactive "fFilename: \nsContent type: \nsDescription: ") + (when (>= (length mastodon-toot--media-attachments) 4) + ;; Only a max. of 4 attachments are allowed, so pop the oldest one. + (pop mastodon-toot--media-attachments)) + (setq mastodon-toot--media-attachments + (nconc mastodon-toot--media-attachments + `(((:contents . ,(mastodon-http--read-file-as-string file)) + (:content-type . ,content-type) + (:description . ,description))))) + (mastodon-toot--refresh-attachments-display)) + +(defun mastodon-toot--refresh-attachments-display () + (let ((inhibit-read-only t) + (attachments-region (mastodon-tl--find-property-range + 'toot-attachments (point-min))) + (display-specs (mastodon-toot--format-attachments))) + (dotimes (i (- (cdr attachments-region) (car attachments-region))) + (add-text-properties (+ (car attachments-region) i) + (+ (car attachments-region) i 1) + (list 'display (or (nth i display-specs) "")))))) + +(defun mastodon-toot--format-attachments () + (or (let ((counter 0) + (image-options (when (image-type-available-p 'imagemagick) + `(:height ,mastodon-media--attachment-height)))) + (mapcan (lambda (attachment) + (let* ((data (cdr (assoc :contents attachment))) + (image (apply #'create-image data + (when image-options 'imagemagick) + t image-options)) + (type (cdr (assoc :content-type attachment))) + (description (cdr (assoc :description attachment)))) + (setq counter (1+ counter)) + (list (format "\n %d: " counter) + image + (format " \"%s\" (%s)" description type)))) + mastodon-toot--media-attachments)) + (list "None")) + ) ;; we'll need to revisit this if the binds get ;; more diverse than two-chord bindings (defun mastodon-toot--get-mode-kbinds () @@ -483,6 +546,10 @@ on the status of NSFW, content warning flags, media attachments, etc." divider "\n" (mastodon-toot--make-mode-docs) "\n" divider "\n" + " Attachments: " + (propertize "None " 'toot-attachments t) + "\n" + divider "\n" " " (propertize "Count" 'toot-post-counter t) @@ -515,43 +582,35 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (defun mastodon-toot--update-status-fields (&rest args) "Update the status fields in the header based on the current state." - (let ((inhibit-read-only t) - (header-region (mastodon-tl--find-property-range 'toot-post-header + (ignore-errors ;; called from after-change-functions so let's not leak errors + (let ((inhibit-read-only t) + (header-region (mastodon-tl--find-property-range 'toot-post-header + (point-min))) + (count-region (mastodon-tl--find-property-range 'toot-post-counter (point-min))) - (count-region (mastodon-tl--find-property-range 'toot-post-counter + (visibility-region (mastodon-tl--find-property-range + 'toot-post-visibility (point-min))) + (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag (point-min))) - (visibility-region (mastodon-tl--find-property-range - 'toot-post-visibility (point-min))) - (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag - (point-min))) - (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag - (point-min))) - (attachment-region (mastodon-tl--find-property-range - 'toot-attachment (point-min)))) - (add-text-properties (car count-region) (cdr count-region) - (list 'display - (format "%s characters" - (- (point-max) (cdr header-region))))) - (add-text-properties (car visibility-region) (cdr visibility-region) - (list 'display - (format "Visibility: %s" - (if (equal - mastodon-toot--visibility - "private") - "followers-only" - mastodon-toot--visibility)))) - (add-text-properties (car attachment-region) (cdr attachment-region) - (list 'display - (format "Attached: %s" - (mapconcat 'identity - mastodon-toot--media-attachment-filenames - ", ")))) - (add-text-properties (car nsfw-region) (cdr nsfw-region) - (list 'invisible (not mastodon-toot--content-nsfw) - 'face 'mastodon-cw-face)) - (add-text-properties (car cw-region) (cdr cw-region) - (list 'invisible (not mastodon-toot--content-warning) - 'face 'mastodon-cw-face)))) + (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag + (point-min)))) + (add-text-properties (car count-region) (cdr count-region) + (list 'display + (format "%s characters in message" + (- (point-max) (cdr header-region))))) + (add-text-properties (car visibility-region) (cdr visibility-region) + (list 'display + (format "Visibility: %s" + mastodon-toot--visibility))) + (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)") + "") + 'face 'mastodon-cw-face)) + (add-text-properties (car cw-region) (cdr cw-region) + (list 'invisible (not mastodon-toot--content-warning) + 'face 'mastodon-cw-face))))) (defun mastodon-toot--compose-buffer (reply-to-user reply-to-id) "Create a new buffer to capture text for a new toot. @@ -561,12 +620,14 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (buffer (or buffer-exists (get-buffer-create "*new toot*"))) (inhibit-read-only t)) (switch-to-buffer-other-window buffer) + (mastodon-toot-mode t) (when (not buffer-exists) (mastodon-toot--display-docs-and-status-fields) (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) (mastodon-toot-mode t) (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) + (mastodon-toot--refresh-attachments-display) (mastodon-toot--update-status-fields))) (define-minor-mode mastodon-toot-mode -- cgit v1.2.3 From 72c14d797fe3848429b64812fb7145d11253fc88 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 13:13:38 +0200 Subject: handle image scaling with image-transforms-p (when emacs >= 27.1) --- lisp/mastodon-toot.el | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 6c08859..1afad8a 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -477,12 +477,15 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (defun mastodon-toot--format-attachments () (or (let ((counter 0) - (image-options (when (image-type-available-p 'imagemagick) + (image-options (when (or (image-type-available-p 'imagemagick) + (image-transforms-p)) `(:height ,mastodon-media--attachment-height)))) (mapcan (lambda (attachment) (let* ((data (cdr (assoc :contents attachment))) (image (apply #'create-image data - (when image-options 'imagemagick) + (if (version< emacs-version "27.1") + (when image-options 'imagemagick) + nil) ; inbuilt scaling in 27.1 t image-options)) (type (cdr (assoc :content-type attachment))) (description (cdr (assoc :description attachment)))) @@ -491,8 +494,8 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." image (format " \"%s\" (%s)" description type)))) mastodon-toot--media-attachments)) - (list "None")) - ) + (list "None"))) + ;; we'll need to revisit this if the binds get ;; more diverse than two-chord bindings (defun mastodon-toot--get-mode-kbinds () @@ -596,7 +599,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (point-min)))) (add-text-properties (car count-region) (cdr count-region) (list 'display - (format "%s characters in message" + (format "%s characters" (- (point-max) (cdr header-region))))) (add-text-properties (car visibility-region) (cdr visibility-region) (list 'display -- cgit v1.2.3 From 13064aa96e0152da0dfbe93e5349aaef61646731 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 14:51:32 +0200 Subject: revert "private" visibility = "followers only" in toot draft --- lisp/mastodon-toot.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 1afad8a..5b7d537 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -602,9 +602,13 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (format "%s characters" (- (point-max) (cdr header-region))))) (add-text-properties (car visibility-region) (cdr visibility-region) - (list 'display - (format "Visibility: %s" - mastodon-toot--visibility))) + (list 'display + (format "Visibility: %s" + (if (equal + mastodon-toot--visibility + "private") + "followers-only" + mastodon-toot--visibility)))) (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 ff76a83fc57817731c407da3cf8a6ef6a71434c5 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 14:59:03 +0200 Subject: revert mastodon-http changes - we will keep my old implementation of attachment uploading, as it already works with the media_ids[] of the API. --- lisp/mastodon-http.el | 58 ++++++++------------------------------------------- 1 file changed, 9 insertions(+), 49 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 85ee588..052218c 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -90,64 +90,24 @@ Message status and JSON error from RESPONSE if unsuccessful." (let ((json-response (mastodon-http--process-json))) (message "Error %s: %s" status (cdr (assoc 'error json-response)))))))) -(defun mastodon-http--encode-multipart-form-data (boundary fields) - "Encode FIELDS suitable to post as multipart/form-data. - -It uses BOUNDARY as the boundary for the values. -FIELDS should be a list of either 2-element (name contents) lists -or 4-element list of (name file-name content-type contents)." - (with-temp-buffer - (dolist (field fields) - (insert "--" boundary "\r\n") - (if (= (length field) 2) - ;; a 2-element list is a simple name=value item: - (insert "Content-Disposition: form-data; name=\"" - (url-hexify-string (car field)) - "\"\r\n" - "\r\n" - (cadr field) "\r\n") - ;; a 4-element list ist a file to be attached: - (insert "Content-Disposition: form-data; name=\"" - (url-hexify-string (car field)) - "\"; filename=\"" - (url-hexify-string (cadr field)) - "\"\r\n" - "Content-type: " (caddr field) "\r\n" - "\r\n" - (cadddr field) "\r\n"))) - ;; Finally add the terminating boundary and another empty line: - (insert "--" boundary "--\r\n" - "\r\n") - (string-to-unibyte (buffer-string)))) - (defun mastodon-http--post (url args headers &optional unauthenticed-p) "POST synchronously to URL with ARGS and HEADERS. Authorization header is included by default unless UNAUTHENTICED-P is non-nil." - (let* ((url-request-method "POST") - (boundary (md5 (format "b%s-%s-%s-%s" - (random 1000000000) (random 1000000000) - (random 1000000000) (random 1000000000)))) - (needs-multi-form (> (apply #'max (mapcar #'length args)) 2)) - (url-request-data - (when args - (if needs-multi-form - (mastodon-http--encode-multipart-form-data boundary args) - (mapconcat (lambda (arg) - (concat (url-hexify-string (car arg)) - "=" - (url-hexify-string (cadr arg)))) - args - "&")))) + (let ((url-request-method "POST") + (url-request-data + (when args + (mapconcat (lambda (arg) + (concat (url-hexify-string (car arg)) + "=" + (url-hexify-string (cdr arg)))) + args + "&"))) (url-request-extra-headers (append - (when needs-multi-form - `(("Content-Type" . - ,(concat "multipart/form-data; boundary=\"" boundary "\"")))) (unless unauthenticed-p `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token))))) headers))) - (message "Posting to %s with %d bytes of request data and headers %s" url (length url-request-data) url-request-extra-headers) (with-temp-buffer (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) (url-retrieve-synchronously url) -- cgit v1.2.3 From 6b2207251c9b44cd47cc03c8f9a68970e123c5d6 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 15:00:21 +0200 Subject: merge hdurers attachment upload and my own replace hdurer's mastodon-toot--post-media and my mastodon-toot--add-media-attachment with hdurer's mastodon-toot--attach-media (which holds the data in the toot draft) and my mastodon-toot--upload-media-attachments (which actually uploads them) --- lisp/mastodon-toot.el | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 5b7d537..7407a7c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -89,7 +89,7 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (make-variable-buffer-local 'mastodon-toot--visibility) (defvar mastodon-toot--media-attachments nil - "A flag indicating if the toot being composed has media attachments.") + "A list of the media attachments of the toot being composed .") (make-variable-buffer-local 'mastodon-toot--media-attachments) (defvar mastodon-toot--media-attachment-ids nil @@ -153,14 +153,6 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response callback)))) -(defun mastodon-toot--post-media (contents content-type description) - (let* ((url (mastodon-http--api "media")) - (response (mastodon-http--post - url - (list (list "description" description) - (list "file" "file" content-type contents))))) - response)) - (defun mastodon-toot--toggle-boost () "Boost/unboost toot at `point'." (interactive) @@ -314,19 +306,6 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (setq mastodon-toot--visibility visibility) (message "Visibility set to %s" visibility)) -(defun mastodon-toot--add-media-attachment () - "Prompt the user for a file and POST it to the media endpoint on the server. - -Set `mastodon-toot--media-attachment-ids' to the item's id so it can be attached to the toot." - (interactive) - (let* ((filename (read-file-name "Choose file to attach to this toot: " - mastodon-toot--default-media-directory)) - (caption (read-string "Enter a caption: ")) - (url (concat mastodon-instance-url "/api/v1/media"))) - (message "Uploading %s..." (file-name-nondirectory filename)) - (mastodon-http--post-media-attachment url filename caption) - (setq mastodon-toot--media-attachments t))) - (defun mastodon-toot--send () "Kill new-toot buffer/window and POST contents to the Mastodon instance. @@ -357,11 +336,11 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (message "Looks like your uploads are not yet ready...") (if empty-toot-p (message "Empty toot. Cowardly refusing to post this.") - (let ((response (mastodon-http--post endpoint args nil))) + (let ((response (mastodon-http--post endpoint args nil))) (mastodon-http--triage response (lambda () (mastodon-toot--kill) - (message "Toot toot!")))))))) + (message "Toot toot!"))))))) (defun mastodon-toot--process-local (acct) "Add domain to local ACCT and replace the curent user name with \"\". @@ -446,14 +425,16 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (mastodon-toot--update-status-fields)) (defun mastodon-toot--clear-all-attachments () - "" + "Remove all attachments from a toot draft." (interactive) (setq mastodon-toot--media-attachments nil) (mastodon-toot--refresh-attachments-display) (mastodon-toot--update-status-fields)) (defun mastodon-toot--attach-media (file content-type description) - "" + "Prompt for a attachment FILE of CONTENT-TYPE with DESCRIPTION. +A preview is displayed in the toot create buffer, and the file +will be uploaded and attached to the toot upon sending." (interactive "fFilename: \nsContent type: \nsDescription: ") (when (>= (length mastodon-toot--media-attachments) 4) ;; Only a max. of 4 attachments are allowed, so pop the oldest one. @@ -462,9 +443,22 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (nconc mastodon-toot--media-attachments `(((:contents . ,(mastodon-http--read-file-as-string file)) (:content-type . ,content-type) - (:description . ,description))))) + (:description . ,description) + (:filename . ,(file-name-nondirectory file)))))) (mastodon-toot--refresh-attachments-display)) +(defun mastodon-toot--upload-media-attachments () + "Actually upload the attachment files using `mastodon-http--post-media-attachment'. +It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used to actually attach them to a toot after uploading." + (interactive) + (mapcar (lambda (attachment) + (let* ((filename (cdr (assoc :filename attachment))) + (caption (cdr (assoc :description attachment))) + (url (concat mastodon-instance-url "/api/v1/media"))) + (message "Uploading %s..." filename) + (mastodon-http--post-media-attachment url filename caption))) + mastodon-toot--media-attachments)) + (defun mastodon-toot--refresh-attachments-display () (let ((inhibit-read-only t) (attachments-region (mastodon-tl--find-property-range -- cgit v1.2.3 From e93adbde20d8f8f0d0e3810ebc3f1890d362dae4 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 15:10:13 +0200 Subject: rever auth / client changes too --- lisp/mastodon-auth.el | 18 +++++++++--------- lisp/mastodon-client.el | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index cd74ef8..6729e81 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -98,15 +98,15 @@ Reads and/or stores secrets in `MASTODON-AUTH-SOURCE-FILE'." (prog1 (mastodon-http--post (concat mastodon-instance-url "/oauth/token") - `(("client_id" ,(plist-get (mastodon-client) :client_id)) - ("client_secret" ,(plist-get (mastodon-client) :client_secret)) - ("grant_type" "password") - ("username" ,(plist-get credentials-plist :user)) - ("password" ,(let ((secret (plist-get credentials-plist :secret))) - (if (functionp secret) - (funcall secret) - secret))) - ("scope" "read write follow")) + `(("client_id" . ,(plist-get (mastodon-client) :client_id)) + ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) + ("grant_type" . "password") + ("username" . ,(plist-get credentials-plist :user)) + ("password" . ,(let ((secret (plist-get credentials-plist :secret))) + (if (functionp secret) + (funcall secret) + secret))) + ("scope" . "read write follow")) nil :unauthenticated) (when (functionp (plist-get credentials-plist :save-function)) diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 4503d6d..bdfbca9 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -49,10 +49,10 @@ "POST client to Mastodon." (mastodon-http--post (mastodon-http--api "apps") - '(("client_name" "mastodon.el") - ("redirect_uris" "urn:ietf:wg:oauth:2.0:oob") - ("scopes" "read write follow") - ("website" "https://github.com/jdenen/mastodon.el")) + '(("client_name" . "mastodon.el") + ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") + ("scopes" . "read write follow") + ("website" . "https://github.com/jdenen/mastodon.el")) nil :unauthenticated)) -- cgit v1.2.3 From 9564994df6ade898831789200d3ac133ba9de07e Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 15:19:20 +0200 Subject: flycheck toot.el --- lisp/mastodon-toot.el | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 7407a7c..a040efc 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -50,6 +50,7 @@ (autoload 'mastodon-tl--find-property-range "mastodon-tl") (autoload 'mastodon-toot "mastodon") (autoload 'mastodon-http--post-media-attachment "mastodon-http") +(autoload 'mastodon-http--read-file-as-string "mastodon-http") (autoload 'mastodon-tl--toot-id "mastodon-tl") (autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl") @@ -331,9 +332,9 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (cons "media_ids[]" id)) mastodon-toot--media-attachment-ids))) (args (append args-no-media args-media))) - (if (and mastodon-toot--media-attachments + (when (and mastodon-toot--media-attachments (equal mastodon-toot--media-attachment-ids nil)) - (message "Looks like your uploads are not yet ready...") + (message "Looks like your uploads are not yet ready...")) (if empty-toot-p (message "Empty toot. Cowardly refusing to post this.") (let ((response (mastodon-http--post endpoint args nil))) @@ -448,7 +449,7 @@ will be uploaded and attached to the toot upon sending." (mastodon-toot--refresh-attachments-display)) (defun mastodon-toot--upload-media-attachments () - "Actually upload the attachment files using `mastodon-http--post-media-attachment'. + "Actually upload attachments using `mastodon-http--post-media-attachment'. It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used to actually attach them to a toot after uploading." (interactive) (mapcar (lambda (attachment) @@ -460,6 +461,7 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t mastodon-toot--media-attachments)) (defun mastodon-toot--refresh-attachments-display () + "Display attachment previews in toot draft buffer." (let ((inhibit-read-only t) (attachments-region (mastodon-tl--find-property-range 'toot-attachments (point-min))) @@ -470,6 +472,7 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t (list 'display (or (nth i display-specs) "")))))) (defun mastodon-toot--format-attachments () + "Format the attachment previews in toot draft buffer." (or (let ((counter 0) (image-options (when (or (image-type-available-p 'imagemagick) (image-transforms-p)) -- cgit v1.2.3 From 46a2f82edf61b370aa5e8432a4f3f17614293e25 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 15:27:22 +0200 Subject: disambiguate media--attachment-height and preview-max-height --- lisp/mastodon-media.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index fd2a6b7..28fbd19 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -47,12 +47,12 @@ :type 'integer) (defcustom mastodon-media--preview-max-height 250 - "Max height of any media attachment preview to be shown." + "Max height of any media attachment preview to be shown in timelines." :group 'mastodon-media :type 'integer) -(defcustom mastodon-media--attachment-height 100 - "Height of the attached images preview." +(defcustom mastodon-media--attachment-height 80 + "Height of the attached images preview in the toot draft buffer." :group 'mastodon-media :type 'integer) -- cgit v1.2.3 From 1f25073c25ae6c8e44c72028fbf873f24544b8e9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 15:27:51 +0200 Subject: remove my old attachment display --- lisp/mastodon-toot.el | 3 --- 1 file changed, 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a040efc..8dfe00b 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -557,9 +557,6 @@ on the status of NSFW, content warning flags, media attachments, etc." (propertize "Visibility" 'toot-post-visibility t) " ⋅ " - (propertize "Attachment" - 'toot-attachment t) - " ⋅ " (propertize "CW" 'toot-post-cw-flag t) " " -- cgit v1.2.3 From 1ccf12b34c14c3cc5c58ccf214865b3af1719d54 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 17:13:47 +0200 Subject: binding to upload media, and check uploads up before posting toot --- lisp/mastodon-toot.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 8dfe00b..86cecfd 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -118,6 +118,7 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (define-key map (kbd "C-c C-v") #'mastodon-toot--change-visibility) (when (require 'emojify nil :noerror) (define-key map (kbd "C-c C-e") #'mastodon-toot--insert-emoji)) + (define-key map (kbd "C-c C-u") #'mastodon-toot--upload-attached-media) (define-key map (kbd "C-c C-a") #'mastodon-toot--attach-media) (define-key map (kbd "C-c !") #'mastodon-toot--clear-all-attachments) map) @@ -332,16 +333,16 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (cons "media_ids[]" id)) mastodon-toot--media-attachment-ids))) (args (append args-no-media args-media))) - (when (and mastodon-toot--media-attachments + (if (and mastodon-toot--media-attachments (equal mastodon-toot--media-attachment-ids nil)) - (message "Looks like your uploads are not yet ready...")) + (message "Looks like your uploads are not up: C-c C-u to upload...") (if empty-toot-p (message "Empty toot. Cowardly refusing to post this.") (let ((response (mastodon-http--post endpoint args nil))) (mastodon-http--triage response (lambda () (mastodon-toot--kill) - (message "Toot toot!"))))))) + (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) "Add domain to local ACCT and replace the curent user name with \"\". @@ -448,7 +449,7 @@ will be uploaded and attached to the toot upon sending." (:filename . ,(file-name-nondirectory file)))))) (mastodon-toot--refresh-attachments-display)) -(defun mastodon-toot--upload-media-attachments () +(defun mastodon-toot--upload-attached-media () "Actually upload attachments using `mastodon-http--post-media-attachment'. It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used to actually attach them to a toot after uploading." (interactive) -- cgit v1.2.3 From 765da49f980673863b09a814630646c8044c96ad Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 17:14:13 +0200 Subject: FIX the filename we send to post-media-attachement - it needs to be with full path of course! --- 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 86cecfd..c00e4bf 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -446,7 +446,7 @@ will be uploaded and attached to the toot upon sending." `(((:contents . ,(mastodon-http--read-file-as-string file)) (:content-type . ,content-type) (:description . ,description) - (:filename . ,(file-name-nondirectory file)))))) + (:filename . ,file))))) (mastodon-toot--refresh-attachments-display)) (defun mastodon-toot--upload-attached-media () @@ -457,9 +457,9 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t (let* ((filename (cdr (assoc :filename attachment))) (caption (cdr (assoc :description attachment))) (url (concat mastodon-instance-url "/api/v1/media"))) - (message "Uploading %s..." filename) + (message "Uploading %s..." (file-name-nondirectory filename)) (mastodon-http--post-media-attachment url filename caption))) - mastodon-toot--media-attachments)) + mastodon-toot--media-attachments)) (defun mastodon-toot--refresh-attachments-display () "Display attachment previews in toot draft buffer." -- cgit v1.2.3 From e0cabe76d4107610c44b1bc6c570840ebadb5467 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 15 Oct 2021 18:47:52 +0200 Subject: docstrings --- 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 c00e4bf..ec5a8ac 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -462,7 +462,7 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t mastodon-toot--media-attachments)) (defun mastodon-toot--refresh-attachments-display () - "Display attachment previews in toot draft buffer." + "Update the display attachment previews in toot draft buffer." (let ((inhibit-read-only t) (attachments-region (mastodon-tl--find-property-range 'toot-attachments (point-min))) @@ -473,7 +473,7 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t (list 'display (or (nth i display-specs) "")))))) (defun mastodon-toot--format-attachments () - "Format the attachment previews in toot draft buffer." + "Format the attachment previews for display in toot draft buffer." (or (let ((counter 0) (image-options (when (or (image-type-available-p 'imagemagick) (image-transforms-p)) -- cgit v1.2.3 From f0dbd664537bab060f2b4d8b7f1d6e439f6a2530 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 14 Oct 2021 12:34:17 +0200 Subject: readme --- README.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.org b/README.org index 60f04eb..dcccccf 100644 --- a/README.org +++ b/README.org @@ -70,10 +70,10 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] prevent loss of draft toots by the toot-send bug - [X] fix scaling of images - [ ] display post visibility status in timelines +- [ ] caching of images / avatars - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies -- handle newlines in toots better, for poetry, etc. - improve (or even partially disable) async. It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. -- cgit v1.2.3 From ba15ee5892907ddb6ad653dfcb3850f9622d7517 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 9 Oct 2021 13:22:04 +0200 Subject: handle cached images when we fetch images, check if they are cached, and if so use the cached version. for now, images aren't cached explicitly, but this should work if the user has `url-automatic-caching' enabled. --- lisp/mastodon-media.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 8aadf0a..b526841 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -209,7 +209,7 @@ REGION-LENGTH is the range from start to propertize." 'media-state 'loading-failed) :loading-failed)))))) - +H (defun mastodon-media--select-next-media-line (end-pos) "Find coordinates of the next media to load before END-POS. -- cgit v1.2.3 From 6d6c0a1c2b105e8adfdb24e6d6a2a65ebe78d1f3 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 18 Oct 2021 20:53:19 +0200 Subject: typo --- lisp/mastodon-media.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index b526841..8aadf0a 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -209,7 +209,7 @@ REGION-LENGTH is the range from start to propertize." 'media-state 'loading-failed) :loading-failed)))))) -H + (defun mastodon-media--select-next-media-line (end-pos) "Find coordinates of the next media to load before END-POS. -- cgit v1.2.3 From 7bcf78751c7e0f8ac6d5ad03be8e87e8ed30f9a3 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 18 Oct 2021 20:54:03 +0200 Subject: Revert "handle cached images" -- caching images with url.el locks up mastodon.el This reverts commit 0129bcf466a4913bdda095b977cd06560c406a30. --- lisp/mastodon-media.el | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 8ef9c44..b58eab6 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -189,15 +189,9 @@ REGION-LENGTH is the range from start to propertize." (condition-case nil ;; catch any errors in url-retrieve so as to not abort ;; whatever called us - (if (url-is-cached url) - (with-current-buffer (url-fetch-from-cache url) - (set-buffer-multibyte nil) - (goto-char (point-min)) - (zlib-decompress-region (goto-char (search-forward "\n\n")) (point-max)) - (mastodon-media--process-image-response nil marker image-options region-length)) - (url-retrieve url - #'mastodon-media--process-image-response - (list marker image-options region-length))) + (url-retrieve url + #'mastodon-media--process-image-response + (list marker image-options region-length)) (error (with-current-buffer buffer ;; TODO: Consider adding retries (put-text-property marker @@ -205,7 +199,7 @@ REGION-LENGTH is the range from start to propertize." 'media-state 'loading-failed) :loading-failed)))))) -H + (defun mastodon-media--select-next-media-line (end-pos) "Find coordinates of the next media to load before END-POS. -- cgit v1.2.3 From 1d94efdb2de1238cde0673d07e8268ff821ab815 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 20 Oct 2021 14:41:10 +0200 Subject: first go at company completion for mentions in new toots --- lisp/mastodon-search.el | 19 ++++++++++++++++++ lisp/mastodon-toot.el | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 537a746..14e40d8 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -43,6 +43,25 @@ (defvar mastodon-tl--link-keymap) (defvar mastodon-http--timeout) +;; functions for company completion of mentions in mastodon-toot + +(defun mastodon-search--get-user-info-no-url (account) + "Get user handle, display name and account URL from ACCOUNT." + (list (cdr (assoc 'display_name account)) + (cdr (assoc 'acct account)))) + +(defun mastodon-search--search-accounts-query (query) + "Prompt for a search QUERY and return accounts. +Returns a nested list containing user handle, display name, and URL." + (interactive "sSearch mastodon for: ") + (let* ((url (format "%s/api/v1/accounts/search" mastodon-instance-url)) + (buffer (format "*mastodon-search-%s*" query)) + (response (mastodon-http--get-search-json url query))) + (mapcar #'mastodon-search--get-user-info-no-url ;-handle-flat-propertized + response))) + +;; functions for mastodon search + (defun mastodon-search--search-query (query) "Prompt for a search QUERY and return accounts, statuses, and hashtags." (interactive "sSearch mastodon for: ") diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a8b121b..f3cbfb0 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -34,6 +34,9 @@ (when (require 'emojify nil :noerror) (declare-function emojify-insert-emoji "emojify")) +(require 'cl-lib) +(require 'company nil :noerror) + (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") @@ -51,6 +54,7 @@ (autoload 'mastodon-http--post-media-attachment "mastodon-http") (autoload 'mastodon-tl--toot-id "mastodon-tl") (autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl") +(autoload 'mastodon-search--search-accounts-query "mastodon-search") (defgroup mastodon-toot nil "Tooting in Mastodon." @@ -73,6 +77,12 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" :group 'mastodon-toot :type 'string) +(when (require 'company nil :noerror) + (defcustom mastodon-toot--use-company-completion-for-mentions t + "Whether to enable company completion for mentions in toot compose buffer." + :group 'mastodon-toot + :type 'boolean)) + (defvar mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") (make-variable-buffer-local 'mastodon-toot--content-warning) @@ -376,6 +386,46 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (reverse (append mentions nil)) ""))) +;; (defun mastodon-toot--mentions-company-meta (candidate) +;; (format "meta %s of candidate %s" +;; (get-text-property 0 'meta candidate) +;; (substring-no-properties candidate))) + +(defun mastodon-toot--mentions-company-annotation (candidate) + "Construct a company completion CANDIDATE's annotation for display." + (format " %s" (get-text-property 0 'meta candidate))) + +(defun mastodon-toot--mentions-company-candidates (prefix) + "Given a company PREFIX, build a list of candidates. +The prefix string is tested against both user handles and display names." + (let (res) + (dolist (item (mastodon-search--search-accounts-query prefix)) + (when (or (string-prefix-p prefix (cadr item)) + (string-prefix-p prefix (car item))) + (push (mastodon-toot--mentions-company-make-candidate item) res))) + res)) + +(defun mastodon-toot--mentions-company-make-candidate (candidate) + "Construct a company completion CANDIDATE for display." + (let ((display-name (car candidate)) + (handle (cadr candidate))) + (propertize handle 'meta display-name))) + +(defun mastodon-toot--mentions-company-backend (command &optional arg &rest ignored) + "A company completion backend for toot mentions." + (interactive (list 'interactive)) + (cl-case command + (interactive (company-begin-backend 'mastodon-toot--mentions-company-backend)) + (prefix (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode + (save-excursion + (backward-word) + (backward-char) + (looking-at "@")) ; if we have a mention + (company-grab-symbol))) ;; get thing before point, sans @ + (candidates (mastodon-toot--mentions-company-candidates arg)) + (annotation (mastodon-toot--mentions-company-annotation arg)))) + ;; (meta (mastodon-toot--mentions-company-meta arg)))) + (defun mastodon-toot--reply () "Reply to toot at `point'." (interactive) @@ -565,6 +615,9 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (mastodon-toot--display-docs-and-status-fields) (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) (mastodon-toot-mode t) + (when mastodon-toot--use-company-completion-for-mentions + (add-to-list 'company-backends 'mastodon-toot--mentions-company-backend) + (company-mode-on)) (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) (mastodon-toot--update-status-fields))) -- cgit v1.2.3 From b74f24d483d3f7a478fc93eae21aa8c1e6154e24 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 20 Oct 2021 15:16:21 +0200 Subject: revert leftover caching things from merging image-previews branch --- lisp/mastodon-media.el | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 3016d33..a401de5 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -135,7 +135,7 @@ fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") "The PNG data for a generic 200x200 'broken image' view.") (defun mastodon-media--process-image-response - (status-plist marker image-options region-length url) + (status-plist marker image-options region-length) "Callback function processing the url retrieve response for URL. STATUS-PLIST is the usual plist of status events as per `url-retrieve'. @@ -156,8 +156,6 @@ REGION-LENGTH is the length of the region that should be replaced with the image (when image-options 'imagemagick) nil) ; inbuilt scaling in 27.1 t image-options)))) - (unless (url-is-cached url) ; cache image if not already cached - (url-store-in-cache url-buffer)) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer (let ((inhibit-read-only t)) -- cgit v1.2.3 From 0854bc834d5fe35a241d8dc2339721635de2c00e Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 20 Oct 2021 15:37:14 +0200 Subject: revert hdurers alist > plist conv in auth.el --- lisp/mastodon-auth.el | 12 ++++++------ lisp/mastodon-http.el | 6 ------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 6729e81..0b0c703 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -73,12 +73,12 @@ If no auth-sources file, runs `mastodon-auth--generate-token-no-storing-credenti "Make POST to generate auth token, without using auth-sources file." (mastodon-http--post (concat mastodon-instance-url "/oauth/token") - `(("client_id" ,(plist-get (mastodon-client) :client_id)) - ("client_secret" ,(plist-get (mastodon-client) :client_secret)) - ("grant_type" "password") - ("username" ,(read-string "Email: " user-mail-address)) - ("password" ,(read-passwd "Password: ")) - ("scope" "read write follow")) + `(("client_id" . ,(plist-get (mastodon-client) :client_id)) + ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) + ("grant_type" . "password") + ("username" . ,(read-string "Email: " user-mail-address)) + ("password" . ,(read-passwd "Password: ")) + ("scope" . "read write follow")) nil :unauthenticated)) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 052218c..bc48e8d 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -113,12 +113,6 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (url-retrieve-synchronously url) (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) -(defun mastodon-http--read-file-as-string (filename) - "" - (with-temp-buffer - (insert-file-contents filename) - (string-to-unibyte (buffer-string)))) - (defun mastodon-http--get (url) "Make synchronous GET request to URL. -- cgit v1.2.3 From cd2497074c9d44f9fe302aaf3696a79acd93ece8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 11:24:09 +0200 Subject: make add mentions-company-backend to company-backens buffer local - we add to company-backends rather than replacing it, but it is still only buffer local. --- lisp/mastodon-toot.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 4215dec..6f2f8e4 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -678,7 +678,8 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) (mastodon-toot-mode t) (when mastodon-toot--use-company-completion-for-mentions - (add-to-list 'company-backends 'mastodon-toot--mentions-company-backend) + (set (make-local-variable 'company-backends) + (add-to-list 'company-backends 'mastodon-toot--mentions-company-backend)) (company-mode-on)) (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) -- cgit v1.2.3 From a3361877511dbb573ef470caaec78cb9595cffbc Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 14:33:33 +0200 Subject: fix default-toot-visibility customize --- lisp/mastodon-toot.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 6f2f8e4..da559ef 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -68,11 +68,11 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \"direct\"." :group 'mastodon-toot - :type 'choice - :options '("public" - "unlisted" - "private" - "direct")) + :type '(choice + (const :tag "public" "public") + (const :tag "unlisted" "unlisted") + (const :tag "followers only" "private") + (const :tag "direct" "direct"))) (defcustom mastodon-toot--default-media-directory "~/" "The default directory when prompting for a media file to upload." -- cgit v1.2.3 From 156b32132f78ede03e3e6188ecf3bf67790b6846 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 14:34:06 +0200 Subject: remove empty lines from docstrings --- lisp/mastodon-http.el | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index bc48e8d..2d91840 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -192,9 +192,7 @@ Pass response buffer to CALLBACK function." ;; hard coded just for bio note for now: (defun mastodon-http--patch (base-url &optional note) "Make synchronous PATCH request to BASE-URL. - Optionally specify the NOTE to edit. - Pass response buffer to CALLBACK function." (let ((url-request-method "PATCH") (url (if note @@ -211,7 +209,6 @@ Pass response buffer to CALLBACK function." (defun mastodon-http--get-async (url &optional callback &rest cbargs) "Make GET request to URL. - Pass response buffer to CALLBACK function with args CBARGS." (let ((url-request-method "GET") (url-request-extra-headers @@ -229,9 +226,7 @@ Pass response buffer to CALLBACK function with args CBARGS." (defun mastodon-http--post-async (url args headers &optional callback &rest cbargs) "POST asynchronously to URL with ARGS and HEADERS. - Then run function CALLBACK with arguements CBARGS. - Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (let ((url-request-method "POST") (request-timeout 5) @@ -252,7 +247,6 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." ;; TODO: test for curl first? (defun mastodon-http--post-media-attachment (url filename caption) "Make POST request to upload FILENAME with CAPTION to the server's media URL. - The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, and `mastodon-toot--update-status-fields' is run." (let* ((file (file-name-nondirectory filename)) (request-backend 'curl)) -- cgit v1.2.3 From c08bc9dea693388a779d5702fc6cc421353bb889 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 14:35:40 +0200 Subject: improvements to toot mentions completion - customize option for completion off, following-only, or all. - 'following=true' is forwarded to http--get-search accordingly. - use company-grab-symbol-cons + regex, prepend "@" to it - also prepend '@' to the list in get-user-info-no-url - this makes company display user handles prepended with '@', and to match and - enter a handle without duplicating the '@' --- lisp/mastodon-http.el | 14 ++++++++------ lisp/mastodon-search.el | 8 +++++--- lisp/mastodon-toot.el | 23 +++++++++++------------ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 2d91840..fbcf855 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -163,18 +163,20 @@ Pass response buffer to CALLBACK function." (kill-buffer) (json-read-from-string json-string))) -(defun mastodon-http--get-search-json (url query) +(defun mastodon-http--get-search-json (url query &optional param) "Make GET request to URL, searching for QUERY and return JSON response." - (let ((buffer (mastodon-http--get-search url query))) + (let ((buffer (mastodon-http--get-search url query param))) (with-current-buffer buffer (mastodon-http--process-json-search)))) -(defun mastodon-http--get-search (base-url query) +(defun mastodon-http--get-search (base-url query &optional param) "Make GET request to BASE-URL, searching for QUERY. - -Pass response buffer to CALLBACK function." +Pass response buffer to CALLBACK function. +PARAM is a formatted request parameter, eg 'following=true'." (let ((url-request-method "GET") - (url (concat base-url "?q=" (url-hexify-string query))) + (url (if param + (concat base-url "?" param "&q=" (url-hexify-string query)) + (concat base-url "?q=" (url-hexify-string query)))) (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 14e40d8..40f134d 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -48,7 +48,7 @@ (defun mastodon-search--get-user-info-no-url (account) "Get user handle, display name and account URL from ACCOUNT." (list (cdr (assoc 'display_name account)) - (cdr (assoc 'acct account)))) + (concat "@" (cdr (assoc 'acct account))))) (defun mastodon-search--search-accounts-query (query) "Prompt for a search QUERY and return accounts. @@ -56,8 +56,10 @@ Returns a nested list containing user handle, display name, and URL." (interactive "sSearch mastodon for: ") (let* ((url (format "%s/api/v1/accounts/search" mastodon-instance-url)) (buffer (format "*mastodon-search-%s*" query)) - (response (mastodon-http--get-search-json url query))) - (mapcar #'mastodon-search--get-user-info-no-url ;-handle-flat-propertized + (response (if (equal mastodon-toot--enable-completion-for-mentions "followers") + (mastodon-http--get-search-json url query "following=true") + (mastodon-http--get-search-json url query)))) + (mapcar #'mastodon-search--get-user-info-no-url response))) ;; functions for mastodon search diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index da559ef..51c2431 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -80,10 +80,13 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" :type 'string) (when (require 'company nil :noerror) - (defcustom mastodon-toot--use-company-completion-for-mentions t + (defcustom mastodon-toot--enable-completion-for-mentions "followers" "Whether to enable company completion for mentions in toot compose buffer." :group 'mastodon-toot - :type 'boolean)) + :type '(choice + (const :tag "off" nil) + (const :tag "followers only" "followers") + (const :tag "all users" "all")))) (defvar mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") @@ -406,20 +409,16 @@ The prefix string is tested against both user handles and display names." (handle (cadr candidate))) (propertize handle 'meta display-name))) -(defun mastodon-toot--mentions-company-backend (command &optional arg &rest ignored) +(defun mastodon-toot--mentions-completion (command &optional arg &rest ignored) "A company completion backend for toot mentions." (interactive (list 'interactive)) (cl-case command - (interactive (company-begin-backend 'mastodon-toot--mentions-company-backend)) + (interactive (company-begin-backend 'mastodon-toot--mentions-completion)) (prefix (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode - (save-excursion - (backward-word) - (backward-char) - (looking-at "@")) ; if we have a mention - (company-grab-symbol))) ;; get thing before point, sans @ + ;; @ + thing before point + (concat "@" (company-grab-symbol-cons "^@[0-9A-Za-z-.\\_@]+" 2)))) (candidates (mastodon-toot--mentions-company-candidates arg)) (annotation (mastodon-toot--mentions-company-annotation arg)))) - ;; (meta (mastodon-toot--mentions-company-meta arg)))) (defun mastodon-toot--reply () "Reply to toot at `point'." @@ -677,9 +676,9 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (mastodon-toot--display-docs-and-status-fields) (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) (mastodon-toot-mode t) - (when mastodon-toot--use-company-completion-for-mentions + (when mastodon-toot--enable-completion-for-mentions (set (make-local-variable 'company-backends) - (add-to-list 'company-backends 'mastodon-toot--mentions-company-backend)) + (add-to-list 'company-backends 'mastodon-toot--mentions-completion)) (company-mode-on)) (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) -- cgit v1.2.3 From e093be6be4c6bc20d4b55279f2bbf5a3af87b9ac Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 14:56:26 +0200 Subject: fix toot-default-visibility customize --- lisp/mastodon-toot.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index a8b121b..f8e0f70 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -62,11 +62,11 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \"direct\"." :group 'mastodon-toot - :type 'choice - :options '("public" - "unlisted" - "private" - "direct")) + :type '(choice + (const :tag "public" "public") + (const :tag "unlisted" "unlisted") + (const :tag "followers only" "private") + (const :tag "direct" "direct"))) (defcustom mastodon-toot--default-media-directory "~/" "The default directory when prompting for a media file to upload." -- cgit v1.2.3 From 2d8337af15b2b0c988df13cea4cb31c944b21aac Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 14:56:49 +0200 Subject: remove empty lines in docstrings in http --- lisp/mastodon-http.el | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index bc48e8d..2d91840 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -192,9 +192,7 @@ Pass response buffer to CALLBACK function." ;; hard coded just for bio note for now: (defun mastodon-http--patch (base-url &optional note) "Make synchronous PATCH request to BASE-URL. - Optionally specify the NOTE to edit. - Pass response buffer to CALLBACK function." (let ((url-request-method "PATCH") (url (if note @@ -211,7 +209,6 @@ Pass response buffer to CALLBACK function." (defun mastodon-http--get-async (url &optional callback &rest cbargs) "Make GET request to URL. - Pass response buffer to CALLBACK function with args CBARGS." (let ((url-request-method "GET") (url-request-extra-headers @@ -229,9 +226,7 @@ Pass response buffer to CALLBACK function with args CBARGS." (defun mastodon-http--post-async (url args headers &optional callback &rest cbargs) "POST asynchronously to URL with ARGS and HEADERS. - Then run function CALLBACK with arguements CBARGS. - Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (let ((url-request-method "POST") (request-timeout 5) @@ -252,7 +247,6 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." ;; TODO: test for curl first? (defun mastodon-http--post-media-attachment (url filename caption) "Make POST request to upload FILENAME with CAPTION to the server's media URL. - The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, and `mastodon-toot--update-status-fields' is run." (let* ((file (file-name-nondirectory filename)) (request-backend 'curl)) -- cgit v1.2.3 From 299356ebee27abb8b97cdd4546164b9918727844 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 15:28:27 +0200 Subject: replies to toots adopt their visibility status by default. this makes it so that if you reply to a direct message, your toot will also be direct by default. - we feed the reply's full toot JSON through the chain of functions called, all the way down to "setup-as-reply". that way, if anything else needs to be extracted when setting up a reply, it's all there. --- lisp/mastodon-toot.el | 18 +++++++++++------- lisp/mastodon.el | 5 ++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 51c2431..fa44645 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -444,7 +444,7 @@ The prefix string is tested against both user handles and display names." mentions)) (concat (mastodon-toot--process-local user) mentions))) - id))) + id toot))) (defun mastodon-toot--toggle-warning () "Toggle `mastodon-toot--content-warning'." @@ -620,12 +620,16 @@ on the status of NSFW, content warning flags, media attachments, etc." 'read-only "Edit your message below." 'toot-post-header t)))) -(defun mastodon-toot--setup-as-reply (reply-to-user reply-to-id) +(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 the MASTODON-TOOT--REPLY-TO-ID var." - (when reply-to-user - (insert (format "%s " reply-to-user)) - (setq mastodon-toot--reply-to-id reply-to-id))) + (let ((reply-visibility (cdr (assoc 'visibility reply-json)))) + (when reply-to-user + (insert (format "%s " reply-to-user)) + (setq mastodon-toot--reply-to-id reply-to-id) + (if (not (equal mastodon-toot--visibility + reply-visibility)) + (setq mastodon-toot--visibility reply-visibility))))) (defun mastodon-toot--update-status-fields (&rest args) "Update the status fields in the header based on the current state." @@ -663,7 +667,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (list 'invisible (not mastodon-toot--content-warning) 'face 'mastodon-cw-face))))) -(defun mastodon-toot--compose-buffer (reply-to-user reply-to-id) +(defun mastodon-toot--compose-buffer (reply-to-user reply-to-id reply-json) "Create a new buffer to capture text for a new toot. If REPLY-TO-USER is provided, inject their handle into the message. If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." @@ -674,7 +678,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (mastodon-toot-mode t) (when (not buffer-exists) (mastodon-toot--display-docs-and-status-fields) - (mastodon-toot--setup-as-reply reply-to-user reply-to-id)) + (mastodon-toot--setup-as-reply reply-to-user reply-to-id reply-json)) (mastodon-toot-mode t) (when mastodon-toot--enable-completion-for-mentions (set (make-local-variable 'company-backends) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index a06b18d..e6a01f8 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -206,13 +206,12 @@ Use. e.g. \"%c\" for your locale's date and time format." (message "Loading Mastodon account %s on %s..." (mastodon-auth--user-acct) mastodon-instance-url)))) ;;;###autoload -(defun mastodon-toot (&optional user reply-to-id) +(defun mastodon-toot (&optional user reply-to-id reply-json) "Update instance with new toot. Content is captured in a new buffer. - If USER is non-nil, insert after @ symbol to begin new toot. If REPLY-TO-ID is non-nil, attach new toot to a conversation." (interactive) - (mastodon-toot--compose-buffer user reply-to-id)) + (mastodon-toot--compose-buffer user reply-to-id reply-json)) ;;;###autoload (add-hook 'mastodon-mode-hook (lambda () -- cgit v1.2.3 From 74570658d54f1b8afa7eb414516674c5e724ed70 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 15:41:05 +0200 Subject: when toot replied to has a CW, adopt it as default for replying toot --- lisp/mastodon-toot.el | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index fa44645..17ee473 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -92,6 +92,10 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" "A flag whether the toot should be marked with a content warning.") (make-variable-buffer-local 'mastodon-toot--content-warning) +(defvar mastodon-toot--content-warning-from-reply nil + "The content warning of the toot being replied to.") +(make-variable-buffer-local 'mastodon-toot--content-warning) + (defvar mastodon-toot--content-nsfw nil "A flag indicating whether the toot should be marked as NSFW.") (make-variable-buffer-local 'mastodon-toot--content-nsfw) @@ -332,7 +336,7 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (endpoint (mastodon-http--api "statuses")) (spoiler (when (and (not empty-toot-p) mastodon-toot--content-warning) - (read-string "Warning: "))) + (read-string "Warning: " mastodon-toot--content-warning-from-reply))) (args-no-media `(("status" . ,toot) ("in_reply_to_id" . ,mastodon-toot--reply-to-id) ("visibility" . ,mastodon-toot--visibility) @@ -623,13 +627,17 @@ on the status of NSFW, content warning flags, media attachments, etc." (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 the MASTODON-TOOT--REPLY-TO-ID var." - (let ((reply-visibility (cdr (assoc 'visibility reply-json)))) + (let ((reply-visibility (cdr (assoc 'visibility reply-json))) + (reply-cw (cdr (assoc 'spoiler_text reply-json)))) (when reply-to-user (insert (format "%s " reply-to-user)) (setq mastodon-toot--reply-to-id reply-to-id) (if (not (equal mastodon-toot--visibility reply-visibility)) - (setq mastodon-toot--visibility reply-visibility))))) + (setq mastodon-toot--visibility reply-visibility)) + (when reply-cw + (setq mastodon-toot--content-warning t) + (setq mastodon-toot--content-warning-from-reply reply-cw))))) (defun mastodon-toot--update-status-fields (&rest args) "Update the status fields in the header based on the current state." -- cgit v1.2.3 From 8d36399e239826b5a8cc34ce15306f9f51759a7f Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 16:17:43 +0200 Subject: redraft toots adopt visibility and CW of deleted toot --- lisp/mastodon-toot.el | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 17ee473..6e41fc1 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -92,7 +92,7 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" "A flag whether the toot should be marked with a content warning.") (make-variable-buffer-local 'mastodon-toot--content-warning) -(defvar mastodon-toot--content-warning-from-reply nil +(defvar mastodon-toot--content-warning-from-reply-or-redraft nil "The content warning of the toot being replied to.") (make-variable-buffer-local 'mastodon-toot--content-warning) @@ -277,7 +277,9 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s" id)))) + (url (mastodon-http--api (format "statuses/%s" id))) + (toot-cw (cdr (assoc 'spoiler_text toot))) + (toot-visibility (cdr (assoc 'visibility toot)))) (if (or (cdr (assoc 'reblog toot)) (not (equal (cdr (assoc 'acct (cdr (assoc 'account toot)))) @@ -294,7 +296,13 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." ;; (media (cdr (assoc 'media_attachments json-response)))) (mastodon-toot--compose-buffer nil nil) (goto-char (point-max)) - (insert content)))))))))) + (insert content) + ;; adopt visibility and CW from deleted toot: + (setq mastodon-toot--visibility toot-visibility) + (when toot-cw + (setq mastodon-toot--content-warning t) + (setq mastodon-toot--content-warning-from-reply-or-redraft toot-cw)) + (mastodon-toot--update-status-fields)))))))))) (defun mastodon-toot--kill () "Kill `mastodon-toot-mode' buffer and window." @@ -336,7 +344,7 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (endpoint (mastodon-http--api "statuses")) (spoiler (when (and (not empty-toot-p) mastodon-toot--content-warning) - (read-string "Warning: " mastodon-toot--content-warning-from-reply))) + (read-string "Warning: " mastodon-toot--content-warning-from-reply-or-redraft))) (args-no-media `(("status" . ,toot) ("in_reply_to_id" . ,mastodon-toot--reply-to-id) ("visibility" . ,mastodon-toot--visibility) @@ -637,7 +645,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (setq mastodon-toot--visibility reply-visibility)) (when reply-cw (setq mastodon-toot--content-warning t) - (setq mastodon-toot--content-warning-from-reply reply-cw))))) + (setq mastodon-toot--content-warning-from-reply-or-redraft reply-cw))))) (defun mastodon-toot--update-status-fields (&rest args) "Update the status fields in the header based on the current state." @@ -675,7 +683,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (list 'invisible (not mastodon-toot--content-warning) 'face 'mastodon-cw-face))))) -(defun mastodon-toot--compose-buffer (reply-to-user reply-to-id reply-json) +(defun mastodon-toot--compose-buffer (reply-to-user reply-to-id &optional reply-json) "Create a new buffer to capture text for a new toot. If REPLY-TO-USER is provided, inject their handle into the message. If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." -- cgit v1.2.3 From 2329c3a7fc7ab4beb8caaeaedfa2b17ea4cf1db2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 16:40:31 +0200 Subject: revert to forward-whitespace -1 test for company - this is an attempt to only engage company completion when our "word" at point is prefixed with a "@" - for some reason i dont understand, using company-grab-symbol-cons "^@ ..." doesn't work here: typing words with no @ still triggers company --- lisp/mastodon-toot.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 6e41fc1..3a8ae92 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -426,9 +426,13 @@ The prefix string is tested against both user handles and display names." (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'mastodon-toot--mentions-completion)) - (prefix (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode - ;; @ + thing before point - (concat "@" (company-grab-symbol-cons "^@[0-9A-Za-z-.\\_@]+" 2)))) + (prefix (when (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode + (save-excursion + (forward-whitespace -1) + (forward-whitespace 1) + (looking-at "@"))) + ;; @ + thing before point + (concat "@" (company-grab-symbol)))) (candidates (mastodon-toot--mentions-company-candidates arg)) (annotation (mastodon-toot--mentions-company-annotation arg)))) -- cgit v1.2.3 From 45390f6ad1923814a3ac28fc456fd264a8b8cd1e Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 19:00:14 +0200 Subject: restore hdurer's http--read-file-as-string --- lisp/mastodon-http.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index fbcf855..6df2aab 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -113,6 +113,12 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (url-retrieve-synchronously url) (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) +(defun mastodon-http--read-file-as-string (filename) + "" + (with-temp-buffer + (insert-file-contents filename) + (string-to-unibyte (buffer-string)))) + (defun mastodon-http--get (url) "Make synchronous GET request to URL. -- cgit v1.2.3 From 53a9c944d06c01f1efc39e5c89eb362b2436dcc0 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 19:01:06 +0200 Subject: move attachments lower in toot-docs --- lisp/mastodon-toot.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 3a8ae92..9f9abea 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -611,10 +611,8 @@ on the status of NSFW, content warning flags, media attachments, etc." (concat divider "\n" (mastodon-toot--make-mode-docs) "\n" - divider "\n" - " Attachments: " - (propertize "None " 'toot-attachments t) - "\n" + ;; divider "\n" + ;; "\n" divider "\n" " " (propertize "Count" @@ -629,6 +627,9 @@ on the status of NSFW, content warning flags, media attachments, etc." (propertize "NSFW" 'toot-post-nsfw-flag t) "\n" + " Attachments: " + (propertize "None " 'toot-attachments t) + "\n" divider (propertize "\n" 'rear-nonsticky t)) -- cgit v1.2.3 From a3fd610b172ccad89a463709120ddf4aa27469b6 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 19:37:14 +0200 Subject: print toot keybinding docs in two columns --- lisp/mastodon-toot.el | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9f9abea..5866636 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -586,19 +586,51 @@ e.g. mastodon-toot--send -> Send." "Format a single keybinding, KBIND, for display in documentation." (let ((key (help-key-description (car kbind) nil)) (command (mastodon-toot--format-kbind-command (cdr kbind)))) - (format "\t%s - %s" key command))) + (format " %s - %s" key command))) (defun mastodon-toot--format-kbinds (kbinds) "Format a list of keybindings, KBINDS, for display in documentation." - (mapconcat 'identity (cons "" (mapcar #'mastodon-toot--format-kbind kbinds)) - "\n")) + (mapcar #'mastodon-toot--format-kbind kbinds)) + +(defvar mastodon-toot--kbinds-pairs nil + "Contains a list of paired toot compose buffer keybindings for inserting.") +(make-variable-buffer-local 'mastodon-toot--kbinds-pairs) + +(defun mastodon-toot--formatted-kbinds-pairs (kbinds-list longest) + "Return a list of strings each containing two formatted kbinds. +KBINDS-LIST is the list of formatted bindings to pair. +LONGEST is the length of the longest binding." + (when kbinds-list + (push (concat "\n" + (car kbinds-list) + (make-string (- (1+ longest) (length (car kbinds-list))) + ?\ ) + (cadr kbinds-list)) + mastodon-toot--kbinds-pairs) + (mastodon-toot--formatted-kbinds-pairs (cddr kbinds-list) longest)) + (reverse mastodon-toot--kbinds-pairs)) + +(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))) + (car (sort lengths #'>)))) (defun mastodon-toot--make-mode-docs () "Create formatted documentation text for the mastodon-toot-mode." - (let ((kbinds (mastodon-toot--get-mode-kbinds))) + (let* ((kbinds (mastodon-toot--get-mode-kbinds)) + (longest-kbind + (mastodon-toot--formatted-kbinds-longest + (mastodon-toot--format-kbinds kbinds)))) (concat " Compose a new toot here. The following keybindings are available:" - (mastodon-toot--format-kbinds kbinds)))) + ;; (mastodon-toot--format-kbinds kbinds)))) + (mapconcat 'identity + (mastodon-toot--formatted-kbinds-pairs + (mastodon-toot--format-kbinds kbinds) + longest-kbind) + nil)))) (defun mastodon-toot--display-docs-and-status-fields () "Insert propertized text with documentation about `mastodon-toot-mode'. -- cgit v1.2.3 From 56330f7a073c3cb50119debd74338b2c858e1308 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 20:23:12 +0200 Subject: icon displays for message visibility - direct, or private --- lisp/mastodon-tl.el | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 48237d9..904d850 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -389,7 +389,8 @@ favouriting and following to the byline. It also takes a single function. By default it is `mastodon-tl--byline-boosted'" (let ((parsed-time (date-to-time (mastodon-tl--field 'created_at toot))) (faved (equal 't (mastodon-tl--field 'favourited toot))) - (boosted (equal 't (mastodon-tl--field 'reblogged toot)))) + (boosted (equal 't (mastodon-tl--field 'reblogged toot))) + (visibility (mastodon-tl--field 'visibility toot))) (concat ;; (propertize "\n | " 'face 'default) (propertize @@ -400,6 +401,14 @@ By default it is `mastodon-tl--byline-boosted'" (format "(%s) " (propertize "F" 'face 'mastodon-boost-fave-face))) (funcall author-byline toot) + (cond ((equal visibility "direct") + (if (fontp (char-displayable-p #10r128274)) + " 🔒" + " [direct]")) + ((equal visibility "private") + (if (fontp (char-displayable-p #10r9993)) + " ✉" + " [followers]"))) (funcall action-byline toot) " " ;; TODO: Once we have a view for toot (responses etc.) make -- cgit v1.2.3 From 4e4c6358477aa74424638b1df6fdb13a77e6aaa0 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 20:41:44 +0200 Subject: fix cw test for replies and for redrafts: "" not nil. --- 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 5866636..3a53851 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -299,7 +299,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (insert content) ;; adopt visibility and CW from deleted toot: (setq mastodon-toot--visibility toot-visibility) - (when toot-cw + (when (not (equal toot-cw "")) (setq mastodon-toot--content-warning t) (setq mastodon-toot--content-warning-from-reply-or-redraft toot-cw)) (mastodon-toot--update-status-fields)))))))))) @@ -680,7 +680,7 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (if (not (equal mastodon-toot--visibility reply-visibility)) (setq mastodon-toot--visibility reply-visibility)) - (when reply-cw + (when (not (equal reply-cw "")) (setq mastodon-toot--content-warning t) (setq mastodon-toot--content-warning-from-reply-or-redraft reply-cw))))) -- cgit v1.2.3 From 846d588dc87b5135dc18b1d7cc873acadfd4c5a3 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 20:42:28 +0200 Subject: redrafts adopt reply to id from deleted toot --- lisp/mastodon-toot.el | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 3a53851..d6502f8 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -279,7 +279,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) (url (mastodon-http--api (format "statuses/%s" id))) (toot-cw (cdr (assoc 'spoiler_text toot))) - (toot-visibility (cdr (assoc 'visibility toot)))) + (toot-visibility (cdr (assoc 'visibility toot))) + (reply-id (cdr (assoc 'in_reply_to_id toot)))) (if (or (cdr (assoc 'reblog toot)) (not (equal (cdr (assoc 'acct (cdr (assoc 'account toot)))) @@ -297,7 +298,9 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (mastodon-toot--compose-buffer nil nil) (goto-char (point-max)) (insert content) - ;; adopt visibility and CW from deleted toot: + ;; 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) (when (not (equal toot-cw "")) (setq mastodon-toot--content-warning t) -- cgit v1.2.3 From 39bf919327a03b8e34ff28f08422b2cb6d3eab26 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 21 Oct 2021 21:29:46 +0200 Subject: readme --- README.org | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.org b/README.org index dcccccf..030821d 100644 --- a/README.org +++ b/README.org @@ -9,26 +9,32 @@ It adds the following features: | | display pinned toots on profiles | | | display relationship (follows you/followed by you) on profiles | | | display toots/follows/followers counts on profiles | -| | links/tags/mentions in profiles are active links | +| | links/tags/mentions in profile bios are active links | | =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | | =v= | view your favorited toots | | =i= | toggle pinning of toots | | =S-C-P= | jump to your profile | | =U= | update your profile bio note | +| Notifications: | | +| | follow requests now also appear in notifications | +| =a=, =r= | accept/reject follow requests | | Timelines: | | | =C= | copy url of toot at point | | =d= | delete your toot at point, and reload current timeline | -| =D= | delete and redraft toot at point | +| =D= | delete and redraft toot at point, preserving reply/CW/visibility | | =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | | | display polls and vote on polls (pretty basic for now) | | | images are links to the full image, can be zoomed/rotated/saved (see image keymap) | | | images scale properly | +| | toot visibility (direct, followers only) icon appears in toot bylines | | Toots: | | | | mention booster in replies by default | +| | autocompletion of mentions, via company-mode (must be installed to work) | | =C-c C-a= | media uploads | +| | media uploads appear in toot compose buffer to preview | | =C-c C-n= | and sensitive media/nsfw flag | | =C-c C-e= | add emoji (if =emojify= installed) | -| | | +| | replies preserve visibility status/CW of original toot | | Search: | | | =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | | | | @@ -69,8 +75,8 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] delete and redraft toots - [X] prevent loss of draft toots by the toot-send bug - [X] fix scaling of images -- [ ] display post visibility status in timelines -- [ ] caching of images / avatars +- [X] display post visibility status in timelines +- [X] caching of images / avatars - better display of polls - display number of boosts/faves in toot byline - mention all thread participants in replies -- cgit v1.2.3 From b81c3259a5224e296e8cf8a62db19767490a2fcb Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 00:11:48 +0200 Subject: collect max toot chars from server and display in new toot buffer --- lisp/mastodon-toot.el | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d6502f8..76c2f87 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -126,6 +126,9 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p "Buffer-local variable to hold the list of media attachments.") (make-variable-buffer-local 'mastodon-toot--media-attachments) +(defvar mastodon-toot--max-toot-chars nil + "The maximum allowed characters count for a single toot.") + (defvar mastodon-toot-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-toot--send) @@ -141,6 +144,15 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p map) "Keymap for `mastodon-toot'.") +(defun mastodon-toot--get-max-toot-chars () + "" + (let ((instance-json (mastodon-http--get-json + (concat mastodon-instance-url + "/api/v1/instance")))) + (setq mastodon-toot--max-toot-chars + (number-to-string + (cdr (assoc 'max_toot_chars instance-json)))))) + (defun mastodon-toot--action-success (marker byline-region remove) "Insert/remove the text MARKER with 'success face in byline. @@ -703,8 +715,9 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (point-min)))) (add-text-properties (car count-region) (cdr count-region) (list 'display - (format "%s characters" - (- (point-max) (cdr header-region))))) + (format "%s/%s characters" + (- (point-max) (cdr header-region)) + mastodon-toot--max-toot-chars))) (add-text-properties (car visibility-region) (cdr visibility-region) (list 'display (format "Visibility: %s" @@ -736,6 +749,8 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (mastodon-toot--display-docs-and-status-fields) (mastodon-toot--setup-as-reply reply-to-user reply-to-id reply-json)) (mastodon-toot-mode t) + (unless mastodon-toot--max-toot-chars + (mastodon-toot--get-max-toot-chars)) (when mastodon-toot--enable-completion-for-mentions (set (make-local-variable 'company-backends) (add-to-list 'company-backends 'mastodon-toot--mentions-completion)) -- cgit v1.2.3 From 315c5d31195253462e8862a7877d45911bfc9956 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 12:00:21 +0200 Subject: use http--api in max-toot-chars fun --- lisp/mastodon-toot.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 76c2f87..824f0c6 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -145,10 +145,9 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p "Keymap for `mastodon-toot'.") (defun mastodon-toot--get-max-toot-chars () - "" + "Fetch max_toot_chars from `mastodon-instance-url'." (let ((instance-json (mastodon-http--get-json - (concat mastodon-instance-url - "/api/v1/instance")))) + (mastodon-http--api "instance")))) (setq mastodon-toot--max-toot-chars (number-to-string (cdr (assoc 'max_toot_chars instance-json)))))) -- cgit v1.2.3 From c9bae35413ab9570252c44cdd212f1ab291af83f Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 12:00:47 +0200 Subject: docstring typo --- lisp/mastodon-http.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 6df2aab..ea18da8 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -46,7 +46,7 @@ "HTTP request timeout, in seconds. Has no effect on Emacs < 26.1.") (defun mastodon-http--api (endpoint) - "Return Mastondon API URL for ENDPOINT." + "Return Mastodon API URL for ENDPOINT." (concat mastodon-instance-url "/api/" mastodon-http--api-version "/" endpoint)) -- cgit v1.2.3 From a0393146d3424d8e0f249d3947c54a9faf19e509 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 12:00:54 +0200 Subject: bookmark/unbookmark toot funs --- lisp/mastodon-toot.el | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 824f0c6..80c63f6 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -318,6 +318,30 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (setq mastodon-toot--content-warning-from-reply-or-redraft toot-cw)) (mastodon-toot--update-status-fields)))))))))) +(defun mastodon-toot--bookmark-toot () + "Bookmark toot at point synchronously." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s/bookmark" id)))) + (if (y-or-n-p (format "Bookmark this toot? ")) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "Toot bookmarked!"))))))) + +(defun mastodon-toot--unbookmark-toot () + "Bookmark toot at point synchronously." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) + (url (mastodon-http--api (format "statuses/%s/unbookmark" id)))) + (if (y-or-n-p (format "Remove this toot from your bookmarks? ")) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "Toot unbookmarked!"))))))) + (defun mastodon-toot--kill () "Kill `mastodon-toot-mode' buffer and window." (kill-buffer-and-window)) -- cgit v1.2.3 From 545ef7d498f236974c6fe2ae767d645436694a45 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 12:34:28 +0200 Subject: update discover menu --- lisp/mastodon-discover.el | 17 +++++++++++------ lisp/mastodon-profile.el | 8 ++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 8c47fbd..33ce3d5 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -49,7 +49,7 @@ ("A" "View profile of author" mastodon-profile--get-toot-author) ("b" "Boost" mastodon-toot--boost) ("f" "Favourite" mastodon-toot--favourite) - ("c" "Toggle hidden text" mastodon-tl--toggle-spoiler-text-in-toot) + ("c" "Toggle hidden text (CW)" mastodon-tl--toggle-spoiler-text-in-toot) ("n" "Next" mastodon-tl--goto-next-toot) ("p" "Prev" mastodon-tl--goto-prev-toot) ("TAB" "Next link item" mastodon-tl--next-tab-item) @@ -58,18 +58,22 @@ ("r" "Reply" mastodon-toot--reply) ("C" "Copy toot URL" mastodon-toot--copy-toot-url) ("d" "Delete (your) toot" mastodon-toot--delete-toot) + ("D" "Delete and redraft (your) toot" mastodon-toot--delete-toot) ("i" "Pin/Unpin (your) toot" mastodon-toot--pin-toot-toggle) ("P" "View user profile" mastodon-profile--show-user) - ("T" "View thread" mastodon-tl--thread)) + ("T" "View thread" mastodon-tl--thread) + ("v" "Vote on poll" mastodon-tl--poll-vote)) ("Timelines" - ("#" "Tag" mastodon-tl--get-tag-timeline) + ("h" "View mode help/keybindings" describe-mode) + ("#" "Tag search" mastodon-tl--get-tag-timeline) ("F" "Federated" mastodon-tl--get-federated-timeline) ("H" "Home" mastodon-tl--get-home-timeline) ("L" "Local" mastodon-tl--get-local-timeline) ("N" "Notifications" mastodon-notifications--get) ("u" "Update timeline" mastodon-tl--update) ("S" "Search" mastodon-search--search-query) - ("C-S-P" "Jump to my profile" mastodon-profile--my-profile)) + ("C-S-P" "Jump to your profile" mastodon-profile--my-profile) + ("K" "View bookmarks" mastodon-profile--view-bookmarks)) ("Users" ("W" "Follow" mastodon-tl--follow-user) ("C-S-W" "Unfollow" mastodon-tl--unfollow-user) @@ -86,10 +90,11 @@ ("Profile view" ("o" "Show following" mastodon-profile--open-following) ("O" "Show followers" mastodon-profile--open-followers) - ("v" "View favourites" mastodon-profile--view-favourites) + ("R" "View follow requests" mastodon-profile--view-follow-requests) ("a" "Accept follow request" mastodon-profile--follow-request-accept) - ("r" "Reject follow request" mastodon-profile--follow-request-reject)) + ("j" "Reject follow request" mastodon-profile--follow-request-reject) + ("U" "Update your profile note" mastodon-profile--update-user-profile-note)) ("Quit" ("q" "Quit mastodon and bury buffer." kill-this-buffer) ("Q" "Quit mastodon buffer and kill window." kill-buffer-and-window))))))) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 2c364da..a374061 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -143,6 +143,14 @@ extra keybindings." "favourites" 'mastodon-tl--timeline)) +(defun mastodon-profile--view-bookmarks () + "Open a new buffer displaying the user's bookmarks." + (interactive) + (message "Loading your bookmarked toots...") + (mastodon-tl--init "bookmarks" + "bookmarks" + 'mastodon-tl--timeline)) + (defun mastodon-profile--view-follow-requests () "Open a new buffer displaying the user's follow requests." (interactive) -- cgit v1.2.3 From 9dbf6e52c5c9f53a5adcf54bf3f9bcdc51c1332c Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 12:59:43 +0200 Subject: bookmarks keybinding --- lisp/mastodon.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index e6a01f8..e1bd2be 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -81,6 +81,7 @@ (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-tl--poll-vote "mastodon-http") (autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") +(autoload 'mastodon-profile--view-bookmarks "mastodon-profile") (defgroup mastodon nil "Interface with Mastodon." @@ -157,6 +158,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) (define-key map (kbd "v") #'mastodon-tl--poll-vote) + (define-key map (kbd "K") #'mastodon-profile--view-bookmarks) map) "Keymap for `mastodon-mode'.") -- cgit v1.2.3 From 635bf869e3f87ad182d0288f0947ae4bf842ff4d Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 13:00:04 +0200 Subject: flycheck, autoloads, docstrings --- lisp/mastodon-http.el | 5 +++-- lisp/mastodon-search.el | 3 ++- lisp/mastodon-toot.el | 8 ++++++-- lisp/mastodon.el | 3 ++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index ea18da8..f092a2d 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -114,7 +114,7 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) (defun mastodon-http--read-file-as-string (filename) - "" + "Read a file FILENAME as a string. Used to generate image preview." (with-temp-buffer (insert-file-contents filename) (string-to-unibyte (buffer-string)))) @@ -170,7 +170,8 @@ Pass response buffer to CALLBACK function." (json-read-from-string json-string))) (defun mastodon-http--get-search-json (url query &optional param) - "Make GET request to URL, searching for QUERY and return JSON response." + "Make GET request to URL, searching for QUERY and return JSON response. +PARAM is any extra parameters to send with the request." (let ((buffer (mastodon-http--get-search url query param))) (with-current-buffer buffer (mastodon-http--process-json-search)))) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 40f134d..ccac5e6 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -42,6 +42,7 @@ (defvar mastodon-instance-url) (defvar mastodon-tl--link-keymap) (defvar mastodon-http--timeout) +(defvar mastodon-toot--enable-completion-for-mentions) ;; functions for company completion of mentions in mastodon-toot @@ -55,7 +56,7 @@ Returns a nested list containing user handle, display name, and URL." (interactive "sSearch mastodon for: ") (let* ((url (format "%s/api/v1/accounts/search" mastodon-instance-url)) - (buffer (format "*mastodon-search-%s*" query)) + ;; (buffer (format "*mastodon-search-%s*" query)) (response (if (equal mastodon-toot--enable-completion-for-mentions "followers") (mastodon-http--get-search-json url query "following=true") (mastodon-http--get-search-json url query)))) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 80c63f6..d4068ea 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -31,6 +31,7 @@ (defvar mastodon-instance-url) (defvar mastodon-media--attachment-height) +(defvar mastodon-toot--enable-completion-for-mentions) (when (require 'emojify nil :noerror) (declare-function emojify-insert-emoji "emojify")) @@ -44,6 +45,7 @@ (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") (autoload 'mastodon-http--process-json "mastodon-http") +(autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") @@ -709,7 +711,8 @@ on the status of NSFW, content warning flags, media attachments, etc." (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 the MASTODON-TOOT--REPLY-TO-ID var." +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 (cdr (assoc 'visibility reply-json))) (reply-cw (cdr (assoc 'spoiler_text reply-json)))) (when reply-to-user @@ -762,7 +765,8 @@ If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." (defun mastodon-toot--compose-buffer (reply-to-user reply-to-id &optional reply-json) "Create a new buffer to capture text for a new toot. If REPLY-TO-USER is provided, inject their handle into the message. -If REPLY-TO-ID is provided, set the MASTODON-TOOT--REPLY-TO-ID var." +If REPLY-TO-ID is provided, set the `mastodon-toot--reply-to-id' var. +REPLY-JSON is the full JSON of the toot being replied to." (let* ((buffer-exists (get-buffer "*new toot*")) (buffer (or buffer-exists (get-buffer-create "*new toot*"))) (inhibit-read-only t)) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index e1bd2be..387e9eb 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -211,7 +211,8 @@ Use. e.g. \"%c\" for your locale's date and time format." (defun mastodon-toot (&optional user reply-to-id reply-json) "Update instance with new toot. Content is captured in a new buffer. If USER is non-nil, insert after @ symbol to begin new toot. -If REPLY-TO-ID is non-nil, attach new toot to a conversation." +If REPLY-TO-ID is non-nil, attach new toot to a conversation. +If REPLY-JSON is the json of the toot being replied to." (interactive) (mastodon-toot--compose-buffer user reply-to-id reply-json)) -- cgit v1.2.3 From 6c53da8c494367bd1f36f1e28d75c209713a13dd Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 13:06:39 +0200 Subject: readme --- README.org | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.org b/README.org index 030821d..c4ca256 100644 --- a/README.org +++ b/README.org @@ -11,7 +11,8 @@ It adds the following features: | | display toots/follows/followers counts on profiles | | | links/tags/mentions in profile bios are active links | | =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | -| =v= | view your favorited toots | +| =V= | view your favorited toots | +| =K= | view your bookmarked toots | | =i= | toggle pinning of toots | | =S-C-P= | jump to your profile | | =U= | update your profile bio note | -- cgit v1.2.3 From 0a3bf6fcd92a52e8b3988f470fbf73a03a391739 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 14:21:16 +0200 Subject: don't allow posts longer than server's max_toot_chars length --- lisp/mastodon-toot.el | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d4068ea..0153c9b 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -401,13 +401,15 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (if (and mastodon-toot--media-attachments (equal mastodon-toot--media-attachment-ids nil)) (message "Looks like your uploads are not up: C-c C-u to upload...") - (if empty-toot-p - (message "Empty toot. Cowardly refusing to post this.") - (let ((response (mastodon-http--post endpoint args nil))) - (mastodon-http--triage response - (lambda () - (mastodon-toot--kill) - (message "Toot toot!")))))))) + (if (> (length toot) (string-to-number mastodon-toot--max-toot-chars)) + (message "Looks like your toot is longer than that maximum allowed length.") + (if empty-toot-p + (message "Empty toot. Cowardly refusing to post this.") + (let ((response (mastodon-http--post endpoint args nil))) + (mastodon-http--triage response + (lambda () + (mastodon-toot--kill) + (message "Toot toot!"))))))))) (defun mastodon-toot--process-local (acct) "Add domain to local ACCT and replace the curent user name with \"\". -- cgit v1.2.3 From 24adbf94613d1cbeee08db896388e1d7f854a168 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 15:18:05 +0200 Subject: readme --- README.org | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.org b/README.org index c4ca256..0d28585 100644 --- a/README.org +++ b/README.org @@ -32,10 +32,11 @@ It adds the following features: | | mention booster in replies by default | | | autocompletion of mentions, via company-mode (must be installed to work) | | =C-c C-a= | media uploads | -| | media uploads appear in toot compose buffer to preview | +| | media uploads previews in toot compose buffer | | =C-c C-n= | and sensitive media/nsfw flag | | =C-c C-e= | add emoji (if =emojify= installed) | | | replies preserve visibility status/CW of original toot | +| | server's maximum toot length shown | | Search: | | | =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | | | | -- cgit v1.2.3 From 2ca3e65b147645c3278004571313437b8e85e9e5 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 18:28:30 +0200 Subject: handle caching of images we now store images ourselves for caching rather than relying on url-automatic-caching. --- lisp/mastodon-media.el | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index a401de5..28fbd19 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -135,7 +135,7 @@ fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") "The PNG data for a generic 200x200 'broken image' view.") (defun mastodon-media--process-image-response - (status-plist marker image-options region-length) + (status-plist marker image-options region-length url) "Callback function processing the url retrieve response for URL. STATUS-PLIST is the usual plist of status events as per `url-retrieve'. @@ -156,6 +156,8 @@ REGION-LENGTH is the length of the region that should be replaced with the image (when image-options 'imagemagick) nil) ; inbuilt scaling in 27.1 t image-options)))) + (unless (url-is-cached url) ; cache image if not already cached + (url-store-in-cache url-buffer)) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer (let ((inhibit-read-only t)) @@ -194,9 +196,17 @@ REGION-LENGTH is the range from start to propertize." (condition-case nil ;; catch any errors in url-retrieve so as to not abort ;; whatever called us - (url-retrieve url - #'mastodon-media--process-image-response - (list marker image-options region-length)) + (if (url-is-cached url) + ;; if image url is cached, decompress and use it + (with-current-buffer (url-fetch-from-cache url) + (set-buffer-multibyte nil) + (goto-char (point-min)) + (zlib-decompress-region (goto-char (search-forward "\n\n")) (point-max)) + (mastodon-media--process-image-response nil marker image-options region-length url)) + ;; else fetch as usual and process-image-response will cache it + (url-retrieve url + #'mastodon-media--process-image-response + (list marker image-options region-length url))) (error (with-current-buffer buffer ;; TODO: Consider adding retries (put-text-property marker -- cgit v1.2.3 From 5cd25e89696dc3aa5db5b4f36bae317547c69802 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 23:17:25 +0200 Subject: bookmark-toot keybinding --- lisp/mastodon.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 387e9eb..57f5721 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -158,6 +158,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) (define-key map (kbd "v") #'mastodon-tl--poll-vote) + (define-key map (kbd "k") #'mastodon-toot--bookmark-toot) (define-key map (kbd "K") #'mastodon-profile--view-bookmarks) map) -- cgit v1.2.3 From a131a846daaf82061cff37f42ed16445dcdbe36a Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 23:50:06 +0200 Subject: move defcustom attachment-height from media to toot - this makes the autoload fun mastodon-toot have access to the variable, so that it can be successfully called without mastodon-mode having been enabled previously. - maybe there is another work around for making variables available to autoloaded functions, but i failed to find it! --- lisp/mastodon-media.el | 5 ----- lisp/mastodon-toot.el | 11 +++++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index a401de5..1b6d054 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -51,11 +51,6 @@ :group 'mastodon-media :type 'integer) -(defcustom mastodon-media--attachment-height 80 - "Height of the attached images preview in the toot draft buffer." - :group 'mastodon-media - :type 'integer) - (defvar mastodon-media--generic-avatar-data (base64-decode-string "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 0153c9b..cfc5182 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -29,9 +29,6 @@ ;;; Code: -(defvar mastodon-instance-url) -(defvar mastodon-media--attachment-height) -(defvar mastodon-toot--enable-completion-for-mentions) (when (require 'emojify nil :noerror) (declare-function emojify-insert-emoji "emojify")) @@ -39,6 +36,7 @@ (require 'cl-lib) (require 'company nil :noerror) +(defvar mastodon-instance-url) (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") @@ -81,6 +79,11 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" :group 'mastodon-toot :type 'string) +(defcustom mastodon-toot--attachment-height 80 + "Height of the attached images preview in the toot draft buffer." + :group 'mastodon-media + :type 'integer) + (when (require 'company nil :noerror) (defcustom mastodon-toot--enable-completion-for-mentions "followers" "Whether to enable company completion for mentions in toot compose buffer." @@ -584,7 +587,7 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t (or (let ((counter 0) (image-options (when (or (image-type-available-p 'imagemagick) (image-transforms-p)) - `(:height ,mastodon-media--attachment-height)))) + `(:height ,mastodon-toot--attachment-height)))) (mapcan (lambda (attachment) (let* ((data (cdr (assoc :contents attachment))) (image (apply #'create-image data -- cgit v1.2.3 From 143dc33f576fe9a6a4bff38d6f732efa2aede654 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 22 Oct 2021 23:17:25 +0200 Subject: bookmark-toot keybinding --- lisp/mastodon.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 387e9eb..57f5721 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -158,6 +158,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) (define-key map (kbd "v") #'mastodon-tl--poll-vote) + (define-key map (kbd "k") #'mastodon-toot--bookmark-toot) (define-key map (kbd "K") #'mastodon-profile--view-bookmarks) map) -- cgit v1.2.3 From f892c5b28b829943619a0e810903c426308aa174 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 23 Oct 2021 11:31:52 +0200 Subject: rewrite bookmark-toot as toggle --- lisp/mastodon-toot.el | 37 +++++++++++++++++-------------------- lisp/mastodon.el | 3 ++- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index cfc5182..983515e 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -323,29 +323,26 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (setq mastodon-toot--content-warning-from-reply-or-redraft toot-cw)) (mastodon-toot--update-status-fields)))))))))) -(defun mastodon-toot--bookmark-toot () - "Bookmark toot at point synchronously." +(defun mastodon-toot--bookmark-toot-toggle () + "Bookmark or unbookmark toot at point synchronously." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s/bookmark" id)))) - (if (y-or-n-p (format "Bookmark this toot? ")) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "Toot bookmarked!"))))))) - -(defun mastodon-toot--unbookmark-toot () - "Bookmark toot at point synchronously." - (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s/unbookmark" id)))) - (if (y-or-n-p (format "Remove this toot from your bookmarks? ")) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "Toot unbookmarked!"))))))) + (bookmarked (cdr (assoc 'bookmarked toot))) + (url (mastodon-http--api (if (equal bookmarked t) + (format "statuses/%s/unbookmark" id) + (format "statuses/%s/bookmark" id)))) + (prompt (if (equal bookmarked t) + (format "Toot already bookmarked. Remove? ") + (format "Bookmark this toot? "))) + (message (if (equal bookmarked t) + "Bookmark removed!" + "Toot bookmarked!"))) + (when (y-or-n-p prompt) + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message message))))))) (defun mastodon-toot--kill () "Kill `mastodon-toot-mode' buffer and window." diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 57f5721..7f4b773 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -82,6 +82,7 @@ (autoload 'mastodon-tl--poll-vote "mastodon-http") (autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") (autoload 'mastodon-profile--view-bookmarks "mastodon-profile") +(autoload 'mastodon-toot--bookmark-toot-toggle "mastodon-toot") (defgroup mastodon nil "Interface with Mastodon." @@ -158,7 +159,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept-notifs) (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject-notifs) (define-key map (kbd "v") #'mastodon-tl--poll-vote) - (define-key map (kbd "k") #'mastodon-toot--bookmark-toot) + (define-key map (kbd "k") #'mastodon-toot--bookmark-toot-toggle) (define-key map (kbd "K") #'mastodon-profile--view-bookmarks) map) -- cgit v1.2.3 From 117e4f8675a6ac96534350fb3dfc97abf8a70c39 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 23 Oct 2021 11:53:01 +0200 Subject: stop shr-image-map taking over our 'u' binding - the shr-maybe-probe-and-copy-url function is already bound to 'w' as well, so we don't lose it by doing this --- lisp/mastodon-tl.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 904d850..7f9538b 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -149,6 +149,9 @@ types of mastodon links and not just shr.el-generated ones.") ;; browse-url loads the preview only, we want browse-image ;; on RET to browse full sized image URL (define-key map [remap shr-browse-url] 'shr-browse-image) + ;; remove shr's u binding, as it the maybe-probe-and-copy-url + ;; is already bound to w also + (define-key map (kbd "u") 'mastodon-tl--update) (keymap-canonicalize map)) "The keymap to be set for shr.el generated image links. -- cgit v1.2.3 From 21e22bea31da362e3673cbcc4a7ccd3fe67149ed Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 23 Oct 2021 12:21:12 +0200 Subject: remove wrongly set http--timeout - http--timeout was given as an 4th arg to url-retrieve, which has nothing to do with timeouts, but is whether to be silent or not. - timeout arg only exists for url-retrieve-synchronously --- lisp/mastodon-http.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index f092a2d..95e8bf5 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -223,7 +223,7 @@ Pass response buffer to CALLBACK function with args CBARGS." (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) - (url-retrieve url callback cbargs mastodon-http--timeout))) + (url-retrieve url callback cbargs))) (defun mastodon-http--get-json-async (url &optional callback &rest args) "Make GET request to URL. Call CALLBACK with json-vector and ARGS." @@ -251,7 +251,7 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (append `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))) headers))) (with-temp-buffer - (url-retrieve url callback cbargs mastodon-http--timeout)))) + (url-retrieve url callback cbargs)))) ;; TODO: test for curl first? (defun mastodon-http--post-media-attachment (url filename caption) -- cgit v1.2.3 From 67e515edbbaa660757ecdcf87bbdfe353eb652f2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 23 Oct 2021 12:22:39 +0200 Subject: move read-file-as-string --- lisp/mastodon-http.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 95e8bf5..4f4cc3f 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -90,6 +90,12 @@ Message status and JSON error from RESPONSE if unsuccessful." (let ((json-response (mastodon-http--process-json))) (message "Error %s: %s" status (cdr (assoc 'error json-response)))))))) +(defun mastodon-http--read-file-as-string (filename) + "Read a file FILENAME as a string. Used to generate image preview." + (with-temp-buffer + (insert-file-contents filename) + (string-to-unibyte (buffer-string)))) + (defun mastodon-http--post (url args headers &optional unauthenticed-p) "POST synchronously to URL with ARGS and HEADERS. @@ -113,12 +119,6 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (url-retrieve-synchronously url) (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) -(defun mastodon-http--read-file-as-string (filename) - "Read a file FILENAME as a string. Used to generate image preview." - (with-temp-buffer - (insert-file-contents filename) - (string-to-unibyte (buffer-string)))) - (defun mastodon-http--get (url) "Make synchronous GET request to URL. -- cgit v1.2.3 From f67558804e899306f6495c934bd25adff814d092 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 25 Oct 2021 11:37:08 +0200 Subject: restore original tl--init as tl--init-sync. - use it for eg notifications - this because i suspect sync is sometimes faster. - with async init*, i often have to press a key to trigger the request - perhaps good to have both in the code, and choose which to use when - cd also poss make this a customize. --- lisp/mastodon-notifications.el | 2 +- lisp/mastodon-tl.el | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index c917124..2e9aea3 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -252,7 +252,7 @@ ID is the notification's own id, which is attached as a property." "Display NOTIFICATIONS in buffer." (interactive) (message "Loading your notifications...") - (mastodon-tl--init + (mastodon-tl--init-sync "notifications" "notifications" 'mastodon-notifications--timeline)) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 7f9538b..a7767b8 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1314,5 +1314,36 @@ JSON is the data returned from the server." (current-buffer) nil))))) +(defun mastodon-tl--init-sync (buffer-name endpoint update-function) + "Initialize BUFFER-NAME with timeline targeted by ENDPOINT. + +UPDATE-FUNCTION is used to recieve more toots. +Runs synchronously." + (let* ((url (mastodon-http--api endpoint)) + (buffer (concat "*mastodon-" buffer-name "*")) + (json (mastodon-http--get-json url))) + (with-output-to-temp-buffer buffer + (switch-to-buffer buffer) + (setq + ;; Initialize with a minimal interval; we re-scan at least once + ;; every 5 minutes to catch any timestamps we may have missed + mastodon-tl--timestamp-next-update (time-add (current-time) + (seconds-to-time 300))) + (funcall update-function json)) + (mastodon-mode) + (with-current-buffer buffer + (setq mastodon-tl--buffer-spec + `(buffer-name ,buffer-name + endpoint ,endpoint update-function + ,update-function) + mastodon-tl--timestamp-update-timer + (when mastodon-tl--enable-relative-timestamps + (run-at-time mastodon-tl--timestamp-next-update + nil ;; don't repeat + #'mastodon-tl--update-timestamps-callback + (current-buffer) + nil)))) + buffer)) + (provide 'mastodon-tl) ;;; mastodon-tl.el ends here -- cgit v1.2.3 From f0c6f8a97280fa429c5e8b8a34a03fa887a44937 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 25 Oct 2021 12:28:23 +0200 Subject: echo faves, boosts, replies counts when in thread view --- lisp/mastodon-tl.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index a7767b8..b4e3ae2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -721,6 +721,14 @@ takes a single function. By default it is (mastodon-tl--byline toot author-byline action-byline)) 'toot-id (cdr (assoc 'id toot)) 'base-toot-id (mastodon-tl--toot-id toot) + 'help-echo (when (and mastodon-tl--buffer-spec + (string-match-p + "context" + (plist-get mastodon-tl--buffer-spec 'endpoint))) + (format "%s faves | %s boosts | %s replies" + (cdr (assoc 'favourites_count toot)) + (cdr (assoc 'reblogs_count toot)) + (cdr (assoc 'replies_count toot)))) 'toot-json toot) "\n") (when mastodon-tl--display-media-p -- cgit v1.2.3 From a79210d516d59d4603f243299cc0f313200d91f4 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 25 Oct 2021 16:37:03 +0200 Subject: declare company-mode functions --- 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 983515e..178df56 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -34,7 +34,11 @@ (declare-function emojify-insert-emoji "emojify")) (require 'cl-lib) -(require 'company nil :noerror) + +(when (require 'company nil :noerror) + (declare-function company-mode-on "company") + (declare-function company-begin-backend "company") + (declare-function company-grab-symbol "company")) (defvar mastodon-instance-url) (autoload 'mastodon-auth--user-acct "mastodon-auth") -- cgit v1.2.3 From 3a892a4caa8b77c7f634f192ea22620af6506877 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 25 Oct 2021 16:37:29 +0200 Subject: _args for update-status-fields --- 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 178df56..44b0b3b 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -731,7 +731,7 @@ REPLY-JSON is the full JSON of the toot being replied to." (setq mastodon-toot--content-warning t) (setq mastodon-toot--content-warning-from-reply-or-redraft reply-cw))))) -(defun mastodon-toot--update-status-fields (&rest args) +(defun mastodon-toot--update-status-fields (&rest _args) "Update the status fields in the header based on the current state." (ignore-errors ;; called from after-change-functions so let's not leak errors (let ((inhibit-read-only t) -- cgit v1.2.3 From 0dd83c5ada4bb4c0b73ebc43de4dcc58825b3f6f Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 25 Oct 2021 16:58:39 +0200 Subject: revert tl--thread to sync request for speed. --- lisp/mastodon-tl.el | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index b4e3ae2..4d30f51 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -915,23 +915,16 @@ webapp" (reblog (cdr (assoc 'reblog json)))) (if reblog (cdr (assoc 'id reblog)) id))) + (defun mastodon-tl--thread () - "Open thread buffer for toot under `point' asynchronously." + "Open thread buffer for toot under `point'." (interactive) (let* ((id (mastodon-tl--as-string (mastodon-tl--toot-id (mastodon-tl--property 'toot-json)))) - (toot (mastodon-tl--property 'toot-json)) + (url (mastodon-http--api (format "statuses/%s/context" id))) (buffer (format "*mastodon-thread-%s*" id)) - (url (mastodon-http--api (format "statuses/%s/context" id)))) - (mastodon-http--get-json-async url - 'mastodon-tl--thread* id toot buffer))) - -(defun mastodon-tl--thread* (context id toot buffer) - "Callback for async `mastodon-tl--thread'. - -Open thread buffer for TOOT with id ID under `point'asynchronously, -in new BUFFER. -CONTEXT is the previous and subsequent toots in the thread." + (toot (mastodon-tl--property 'toot-json)) + (context (mastodon-http--get-json url))) (when (member (cdr (assoc 'type toot)) '("reblog" "favourite")) (setq toot (cdr (assoc 'status toot)))) (if (> (+ (length (cdr (assoc 'ancestors context))) @@ -950,7 +943,7 @@ CONTEXT is the previous and subsequent toots in the thread." (cdr (assoc 'ancestors context)) `(,toot) (cdr (assoc 'descendants context)))))) - (message "No Thread!")));) + (message "No Thread!")))) (defun mastodon-tl--follow-user (user-handle) "Query for USER-HANDLE from current status and follow that user." -- cgit v1.2.3 From f6d3b20540600892e30415c79dad23ae088140b9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 25 Oct 2021 17:09:47 +0200 Subject: readme --- README.org | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.org b/README.org index 0d28585..756442d 100644 --- a/README.org +++ b/README.org @@ -1,3 +1,5 @@ +#+OPTIONS: toc:nil + * mastodon.el fork This is a fork of of the great but seemingly dormant https://github.com/jdenen/mastodon.el. @@ -24,10 +26,12 @@ It adds the following features: | =d= | delete your toot at point, and reload current timeline | | =D= | delete and redraft toot at point, preserving reply/CW/visibility | | =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | +| =k= | toggle bookmark of toot at point | | | display polls and vote on polls (pretty basic for now) | | | images are links to the full image, can be zoomed/rotated/saved (see image keymap) | | | images scale properly | | | toot visibility (direct, followers only) icon appears in toot bylines | +| | display a toot's favorites, boosts and replies count in thread view | | Toots: | | | | mention booster in replies by default | | | autocompletion of mentions, via company-mode (must be installed to work) | @@ -36,7 +40,7 @@ It adds the following features: | =C-c C-n= | and sensitive media/nsfw flag | | =C-c C-e= | add emoji (if =emojify= installed) | | | replies preserve visibility status/CW of original toot | -| | server's maximum toot length shown | +| | server's maximum toot length shown in toot compose buffer | | Search: | | | =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | | | | @@ -53,7 +57,9 @@ I did this for my own use and to learn more Elisp. Feel free to improve it. (code taken from https://github.com/alexjgriffith/mastodon-future.el.) -Works for federated, local, and home timelines and for notifications. It's pretty necro, sometimes it goes off the rails, so use at your own risk. Not a super high priority for me, but some people dig it. The command prefix is =mastodon-async--stream=. +Works for federated, local, and home timelines and for notifications. It's pretty necro, sometimes it goes off the rails, so use at your own risk. Not a super high priority for me, but some people dig it. + +To enable, run =mastodon-async-mode=. Then view a timeline with one of the commands that begin with =mastodon-async--stream=. ** NB: dependency @@ -80,9 +86,9 @@ I might add a few more features if the ones I added turn out to work ok. Possibl - [X] display post visibility status in timelines - [X] caching of images / avatars - better display of polls -- display number of boosts/faves in toot byline +- [X] display number of boosts/faves in toot byline - mention all thread participants in replies -- improve (or even partially disable) async. +- [X] improve (or even partially disable) async. It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. -- cgit v1.2.3 From b0d78e394ac70487d38257838d9b57b0677923f4 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 26 Oct 2021 11:49:52 +0200 Subject: switch followers-only and direct message icons to match web layout --- lisp/mastodon-tl.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 4d30f51..9bbc44f 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -406,11 +406,11 @@ By default it is `mastodon-tl--byline-boosted'" (funcall author-byline toot) (cond ((equal visibility "direct") (if (fontp (char-displayable-p #10r128274)) - " 🔒" + " ✉" " [direct]")) ((equal visibility "private") (if (fontp (char-displayable-p #10r9993)) - " ✉" + " 🔒" " [followers]"))) (funcall action-byline toot) " " -- cgit v1.2.3 From 64673e103233b238f936d78b4ca4182ce2304b26 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 26 Oct 2021 14:23:38 +0200 Subject: display status of locked accounts in profile view --- lisp/mastodon-profile.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index a374061..22120fe 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -296,6 +296,7 @@ Returns a list of lists." (buffer (concat "*mastodon-" acct "-" endpoint-type "*")) (note (mastodon-profile--account-field account 'note)) (json (mastodon-http--get-json url)) + (locked (mastodon-profile--account-field account 'locked)) (followers-count (mastodon-tl--as-string (mastodon-profile--account-field account 'followers_count))) @@ -338,8 +339,13 @@ Returns a list of lists." account 'display_name) 'face 'mastodon-display-name-face) "\n" - (propertize acct + (propertize (concat "@" acct) 'face 'default) + (if (equal locked t) + (if (fontp (char-displayable-p #10r9993)) + " 🔒" + " [locked]") + "") "\n ------------\n" (mastodon-tl--render-text note account) ;; account here to enable tab-stops in profile note -- cgit v1.2.3 From c82399d03e62bc258a7f9c89846f8552f2d2e52b Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 26 Oct 2021 16:46:20 +0200 Subject: readme --- README.org | 1 + 1 file changed, 1 insertion(+) diff --git a/README.org b/README.org index 756442d..7c9b18e 100644 --- a/README.org +++ b/README.org @@ -12,6 +12,7 @@ It adds the following features: | | display relationship (follows you/followed by you) on profiles | | | display toots/follows/followers counts on profiles | | | links/tags/mentions in profile bios are active links | +| | show a lock icon for locked accounts | | =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | | =V= | view your favorited toots | | =K= | view your bookmarked toots | -- cgit v1.2.3 From f9a4bab4a81f96407c38a1a45719d45827b9f585 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 26 Oct 2021 17:51:53 +0200 Subject: toot--enable-completion-for-mentions only if company noerror - from testing with 'emacs -Q' --- lisp/mastodon-toot.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 44b0b3b..3e60d2d 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -784,10 +784,11 @@ REPLY-JSON is the full JSON of the toot being replied to." (mastodon-toot-mode t) (unless mastodon-toot--max-toot-chars (mastodon-toot--get-max-toot-chars)) - (when mastodon-toot--enable-completion-for-mentions - (set (make-local-variable 'company-backends) - (add-to-list 'company-backends 'mastodon-toot--mentions-completion)) - (company-mode-on)) + (when (require 'company nil :noerror) + (when mastodon-toot--enable-completion-for-mentions + (set (make-local-variable 'company-backends) + (add-to-list 'company-backends 'mastodon-toot--mentions-completion)) + (company-mode-on))) (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) (mastodon-toot--refresh-attachments-display) -- cgit v1.2.3 From c60eb355232e57fec9fe97f366a3a2176f8c4110 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 26 Oct 2021 18:28:50 +0200 Subject: api/v2 for media attachment uploads --- 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 3e60d2d..14dcc29 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -567,7 +567,7 @@ It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used t (mapcar (lambda (attachment) (let* ((filename (cdr (assoc :filename attachment))) (caption (cdr (assoc :description attachment))) - (url (concat mastodon-instance-url "/api/v1/media"))) + (url (concat mastodon-instance-url "/api/v2/media"))) (message "Uploading %s..." (file-name-nondirectory filename)) (mastodon-http--post-media-attachment url filename caption))) mastodon-toot--media-attachments)) -- cgit v1.2.3 From 998bfd60ed0ad1c4de161dd9a32c7786ee34b48a Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 28 Oct 2021 17:50:19 +0200 Subject: mastodon-async readme --- README.org | 4 ++-- lisp/mastodon.el | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.org b/README.org index 7c9b18e..2455124 100644 --- a/README.org +++ b/README.org @@ -54,13 +54,13 @@ The minimum Emacs version is now 26.1. But if you are running an older version i I did this for my own use and to learn more Elisp. Feel free to improve it. -** live-updating timelines +** live-updating timelines: =mastodon-async-mode= (code taken from https://github.com/alexjgriffith/mastodon-future.el.) Works for federated, local, and home timelines and for notifications. It's pretty necro, sometimes it goes off the rails, so use at your own risk. Not a super high priority for me, but some people dig it. -To enable, run =mastodon-async-mode=. Then view a timeline with one of the commands that begin with =mastodon-async--stream=. +To enable, it, add =(require 'mastodon-async)= to your =init.el=. Then you can view a timeline with one of the commands that begin with =mastodon-async--stream-=. ** NB: dependency diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 7f4b773..25fb829 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -77,6 +77,7 @@ ;; (autoload 'mastodon-async--stream-local "mastodon-async") ;; (autoload 'mastodon-async--stream-home "mastodon-async") ;; (autoload 'mastodon-async--stream-notifications "mastodon-async") +;; (autoload 'mastodon-async-mode "mastodon-async") (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-tl--poll-vote "mastodon-http") -- cgit v1.2.3 From 14b3a95f431b789df17d39a6d7b52e1a4df2fb58 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 28 Oct 2021 18:17:23 +0200 Subject: fix group of mastodon-toot--attachment-height --- 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 14dcc29..70b95d3 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -85,7 +85,7 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" (defcustom mastodon-toot--attachment-height 80 "Height of the attached images preview in the toot draft buffer." - :group 'mastodon-media + :group 'mastodon-toot :type 'integer) (when (require 'company nil :noerror) -- cgit v1.2.3 From bceb7286a70dc90680bca4a9703db5d847b1e920 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 28 Oct 2021 19:01:42 +0200 Subject: require mastodon-toot in mastodon.el, for customize visibility - & no need for all other mastodon-toot autoloads --- lisp/mastodon.el | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 25fb829..159b9b2 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -31,6 +31,7 @@ ;;; Code: (require 'cl-lib) ; for `cl-some' call in mastodon +(require 'mastodon-toot) ; hack to make mastodon-toot customs visible (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") @@ -51,10 +52,10 @@ (autoload 'mastodon-profile--get-toot-author "mastodon-profile") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile") (autoload 'mastodon-profile--show-user "mastodon-profile") -(autoload 'mastodon-toot--compose-buffer "mastodon-toot") -(autoload 'mastodon-toot--reply "mastodon-toot") -(autoload 'mastodon-toot--toggle-boost "mastodon-toot") -(autoload 'mastodon-toot--toggle-favourite "mastodon-toot") +;; (autoload 'mastodon-toot--compose-buffer "mastodon-toot") +;; (autoload 'mastodon-toot--reply "mastodon-toot") +;; (autoload 'mastodon-toot--toggle-boost "mastodon-toot") +;; (autoload 'mastodon-toot--toggle-favourite "mastodon-toot") (autoload 'mastodon-discover "mastodon-discover") (autoload 'mastodon-tl--block-user "mastodon-tl") @@ -69,9 +70,9 @@ (autoload 'mastodon-notifications--follow-request-accept-notifs "mastodon-profile") (autoload 'mastodon-notifications--follow-request-reject-notifs "mastodon-profile") (autoload 'mastodon-search--search-query "mastodon-search") -(autoload 'mastodon-toot--delete-toot "mastodon-toot") -(autoload 'mastodon-toot--copy-toot-url "mastodon-toot") -(autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") +;; (autoload 'mastodon-toot--delete-toot "mastodon-toot") +;; (autoload 'mastodon-toot--copy-toot-url "mastodon-toot") +;; (autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") (autoload 'mastodon-auth--get-account-name "mastodon-auth") ;; (autoload 'mastodon-async--stream-federated "mastodon-async") ;; (autoload 'mastodon-async--stream-local "mastodon-async") @@ -81,9 +82,9 @@ (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-tl--poll-vote "mastodon-http") -(autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") +;; (autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") (autoload 'mastodon-profile--view-bookmarks "mastodon-profile") -(autoload 'mastodon-toot--bookmark-toot-toggle "mastodon-toot") +;; (autoload 'mastodon-toot--bookmark-toot-toggle "mastodon-toot") (defgroup mastodon nil "Interface with Mastodon." -- cgit v1.2.3 From cde76175ea2e0ceeedeb993fdf818a01c379ece9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 28 Oct 2021 18:17:23 +0200 Subject: fix group of mastodon-toot--attachment-height --- 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 14dcc29..70b95d3 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -85,7 +85,7 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" (defcustom mastodon-toot--attachment-height 80 "Height of the attached images preview in the toot draft buffer." - :group 'mastodon-media + :group 'mastodon-toot :type 'integer) (when (require 'company nil :noerror) -- cgit v1.2.3 From 39acda46f8597aaf45e664e97c8a39a9a4b2225e Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 28 Oct 2021 19:01:42 +0200 Subject: require mastodon-toot in mastodon.el, for customize visibility - & no need for all other mastodon-toot autoloads --- lisp/mastodon.el | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 25fb829..159b9b2 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -31,6 +31,7 @@ ;;; Code: (require 'cl-lib) ; for `cl-some' call in mastodon +(require 'mastodon-toot) ; hack to make mastodon-toot customs visible (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") @@ -51,10 +52,10 @@ (autoload 'mastodon-profile--get-toot-author "mastodon-profile") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile") (autoload 'mastodon-profile--show-user "mastodon-profile") -(autoload 'mastodon-toot--compose-buffer "mastodon-toot") -(autoload 'mastodon-toot--reply "mastodon-toot") -(autoload 'mastodon-toot--toggle-boost "mastodon-toot") -(autoload 'mastodon-toot--toggle-favourite "mastodon-toot") +;; (autoload 'mastodon-toot--compose-buffer "mastodon-toot") +;; (autoload 'mastodon-toot--reply "mastodon-toot") +;; (autoload 'mastodon-toot--toggle-boost "mastodon-toot") +;; (autoload 'mastodon-toot--toggle-favourite "mastodon-toot") (autoload 'mastodon-discover "mastodon-discover") (autoload 'mastodon-tl--block-user "mastodon-tl") @@ -69,9 +70,9 @@ (autoload 'mastodon-notifications--follow-request-accept-notifs "mastodon-profile") (autoload 'mastodon-notifications--follow-request-reject-notifs "mastodon-profile") (autoload 'mastodon-search--search-query "mastodon-search") -(autoload 'mastodon-toot--delete-toot "mastodon-toot") -(autoload 'mastodon-toot--copy-toot-url "mastodon-toot") -(autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") +;; (autoload 'mastodon-toot--delete-toot "mastodon-toot") +;; (autoload 'mastodon-toot--copy-toot-url "mastodon-toot") +;; (autoload 'mastodon-toot--pin-toot-toggle "mastodon-toot") (autoload 'mastodon-auth--get-account-name "mastodon-auth") ;; (autoload 'mastodon-async--stream-federated "mastodon-async") ;; (autoload 'mastodon-async--stream-local "mastodon-async") @@ -81,9 +82,9 @@ (autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-tl--poll-vote "mastodon-http") -(autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") +;; (autoload 'mastodon-toot--delete-and-redraft-toot "mastodon-toot") (autoload 'mastodon-profile--view-bookmarks "mastodon-profile") -(autoload 'mastodon-toot--bookmark-toot-toggle "mastodon-toot") +;; (autoload 'mastodon-toot--bookmark-toot-toggle "mastodon-toot") (defgroup mastodon nil "Interface with Mastodon." -- cgit v1.2.3 From fa00c8dd2d0cc65d58298667e18023e23980ed58 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 11:18:04 +0200 Subject: enable-image-caching customize option --- lisp/mastodon-media.el | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index fcef218..808a23d 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -51,6 +51,11 @@ :group 'mastodon-media :type 'integer) +(defcustom mastodon-media--enable-image-caching nil + "Whether images should be cached." + :group 'mastodon-media + :type 'boolean) + (defvar mastodon-media--generic-avatar-data (base64-decode-string "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA @@ -151,8 +156,9 @@ REGION-LENGTH is the length of the region that should be replaced with the image (when image-options 'imagemagick) nil) ; inbuilt scaling in 27.1 t image-options)))) - (unless (url-is-cached url) ; cache image if not already cached - (url-store-in-cache url-buffer)) + (when mastodon-media--enable-image-caching + (unless (url-is-cached url) ; cache if not already cached + (url-store-in-cache url-buffer))) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer (let ((inhibit-read-only t)) @@ -191,7 +197,8 @@ REGION-LENGTH is the range from start to propertize." (condition-case nil ;; catch any errors in url-retrieve so as to not abort ;; whatever called us - (if (url-is-cached url) + (if (and mastodon-media--enable-image-caching + (url-is-cached url)) ;; if image url is cached, decompress and use it (with-current-buffer (url-fetch-from-cache url) (set-buffer-multibyte nil) -- cgit v1.2.3 From 4c7c6f4f3cb832cecc67da23e4567e11a236adf7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 11:18:57 +0200 Subject: fix for image uploads error in 'emacs -Q': expand file name! --- lisp/mastodon-toot.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 70b95d3..309b64a 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -565,7 +565,8 @@ will be uploaded and attached to the toot upon sending." It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used to actually attach them to a toot after uploading." (interactive) (mapcar (lambda (attachment) - (let* ((filename (cdr (assoc :filename attachment))) + (let* ((filename (expand-file-name + (cdr (assoc :filename attachment)))) (caption (cdr (assoc :description attachment))) (url (concat mastodon-instance-url "/api/v2/media"))) (message "Uploading %s..." (file-name-nondirectory filename)) -- cgit v1.2.3 From 39a54a6aaf1a6f043bfe8769ef0c3484de917e7c Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 11:58:53 +0200 Subject: hopefully improve attachment upload error handling --- lisp/mastodon-http.el | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 4f4cc3f..b5437a3 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -285,15 +285,21 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' (mastodon-toot--update-status-fields))))) :error (cl-function (lambda (&key error-thrown &allow-other-keys) - (message "%s" (car (last error-thrown))) - (message "%s" (type-of (car (last error-thrown)))) - (cond ((= (car (last error-thrown)) 401) - (message "Got error: %s Unauthorized: The access token is invalid" error-thrown)) - ((= (car (last error-thrown)) 422) - (message "Got error: %s Unprocessable entity: file or file type is unsupported or invalid" error-thrown)) - (t - (message "Got error: %s Shit went south" - error-thrown)))))))) + (cond + ;; handle curl errors first (eg 26, can't read file/path) + ;; because the '=' test below fails for them + ;; they have the form (error . error message 24) + ((not (proper-list-p error-thrown)) ; not dotted list + (message "Got error: %s. Shit went south." (cdr error-thrown))) + ;; handle mastodon api errors + ;; they have the form (error http 401) + ((= (car (last error-thrown)) 401) + (message "Got error: %s Unauthorized: The access token is invalid" error-thrown)) + ((= (car (last error-thrown)) 422) + (message "Got error: %s Unprocessable entity: file or file type is unsupported or invalid" error-thrown)) + (t + (message "Got error: %s Shit went south" + error-thrown)))))))) (provide 'mastodon-http) ;;; mastodon-http.el ends here -- cgit v1.2.3 From 7e7b6c5c67af47c37d2a856dd72ccc040c967482 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 17:55:27 +0200 Subject: merge upload-media-attachments functionality into toot-send. this obviates the need for the user to upload files before posting their toot. - this commit makes http--post-media-attachment synchronous, so that toot-send has to wait for it. - in toot-send: if mastodon-toot--media-attachements is non-nil, the files it contains are uploaded synchronously, and their returned ids are added to toot-media-attachment-ids, which are parsed as args for the POST request to be attached to the toot. - then we send toot as usual. - clear-all-attachments also clears mastodon-toot--media-attachment-ids just in case. - we have no more need of media-attachments-filenames, as media-attachments is now a list and not a boolean value. --- lisp/mastodon-http.el | 7 +++--- lisp/mastodon-toot.el | 70 +++++++++++++++++++++++---------------------------- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index b5437a3..d6158eb 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -256,7 +256,9 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." ;; TODO: test for curl first? (defun mastodon-http--post-media-attachment (url filename caption) "Make POST request to upload FILENAME with CAPTION to the server's media URL. -The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, and `mastodon-toot--update-status-fields' is run." +The upload is asynchronous. On succeeding, +`mastodon-toot--media-attachment-ids' is set to the id(s) of the +item uploaded, and `mastodon-toot--update-status-fields' is run." (let* ((file (file-name-nondirectory filename)) (request-backend 'curl)) ;; (response @@ -269,14 +271,13 @@ The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' :parser 'json-read :headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))) - :sync nil + :sync t :success (cl-function (lambda (&key data &allow-other-keys) (when data (progn (push (cdr (assoc 'id data)) mastodon-toot--media-attachment-ids) ; add ID to list - (push file mastodon-toot--media-attachment-filenames) (message "%s file %s with id %S and caption '%s' uploaded!" (capitalize (cdr (assoc 'type data))) file diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 309b64a..063b346 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -116,25 +116,17 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (make-variable-buffer-local 'mastodon-toot--visibility) (defvar mastodon-toot--media-attachments nil - "A list of the media attachments of the toot being composed .") + "A list of the media attachments of the toot being composed.") (make-variable-buffer-local 'mastodon-toot--media-attachments) (defvar mastodon-toot--media-attachment-ids nil "A list of any media attachment ids of the toot being composed.") (make-variable-buffer-local 'mastodon-toot--media-attachment-ids) -(defvar mastodon-toot--media-attachment-filenames nil - "A list of any media attachment filenames of the toot being composed.") -(make-variable-buffer-local 'mastodon-toot--media-attachment-filenames) - (defvar mastodon-toot--reply-to-id nil "Buffer-local variable to hold the id of the toot being replied to.") (make-variable-buffer-local 'mastodon-toot--reply-to-id) -(defvar mastodon-toot--media-attachments nil - "Buffer-local variable to hold the list of media attachments.") -(make-variable-buffer-local 'mastodon-toot--media-attachments) - (defvar mastodon-toot--max-toot-chars nil "The maximum allowed characters count for a single toot.") @@ -378,9 +370,11 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (message "Visibility set to %s" visibility)) (defun mastodon-toot--send () - "Kill new-toot buffer/window and POST contents to the Mastodon instance. - -If media items have been uploaded with `mastodon-toot--add-media-attachment', attach them to the toot." + "POST contents of the new-toot buffer/window to the Mastodon instance and kill the buffer. +If media items have been attached with +`mastodon-toot--attach-media', upload them with +`mastodon-toot-upload-attached-media' and attach them to the +toot." (interactive) (let* ((toot (mastodon-toot--remove-docs)) (empty-toot-p (and (not mastodon-toot--media-attachments) @@ -389,31 +383,28 @@ If media items have been uploaded with `mastodon-toot--add-media-attachment', at (spoiler (when (and (not empty-toot-p) mastodon-toot--content-warning) (read-string "Warning: " mastodon-toot--content-warning-from-reply-or-redraft))) - (args-no-media `(("status" . ,toot) - ("in_reply_to_id" . ,mastodon-toot--reply-to-id) - ("visibility" . ,mastodon-toot--visibility) - ("sensitive" . ,(when mastodon-toot--content-nsfw - (symbol-name t))) - ("spoiler_text" . ,spoiler))) - (args-media - (when mastodon-toot--media-attachment-ids - (mapcar - (lambda (id) - (cons "media_ids[]" id)) - mastodon-toot--media-attachment-ids))) - (args (append args-no-media args-media))) - (if (and mastodon-toot--media-attachments - (equal mastodon-toot--media-attachment-ids nil)) - (message "Looks like your uploads are not up: C-c C-u to upload...") - (if (> (length toot) (string-to-number mastodon-toot--max-toot-chars)) - (message "Looks like your toot is longer than that maximum allowed length.") - (if empty-toot-p - (message "Empty toot. Cowardly refusing to post this.") - (let ((response (mastodon-http--post endpoint args nil))) - (mastodon-http--triage response - (lambda () - (mastodon-toot--kill) - (message "Toot toot!"))))))))) + (args `(("status" . ,toot) + ("in_reply_to_id" . ,mastodon-toot--reply-to-id) + ("visibility" . ,mastodon-toot--visibility) + ("sensitive" . ,(when mastodon-toot--content-nsfw + (symbol-name t))) + ("spoiler_text" . ,spoiler)))) + (when mastodon-toot--media-attachments + (mastodon-toot--upload-attached-media) ; sync upload so we wait (and pray) till done + (let* ((args-media (mapcar + (lambda (id) + (cons "media_ids[]" id)) + mastodon-toot--media-attachment-ids)) + (args (append args args-media))))) + (if (> (length toot) (string-to-number mastodon-toot--max-toot-chars)) + (message "Looks like your toot is longer than that maximum allowed length.") + (if empty-toot-p + (message "Empty toot. Cowardly refusing to post this.") + (let ((response (mastodon-http--post endpoint args nil))) + (mastodon-http--triage response + (lambda () + (mastodon-toot--kill) + (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) "Add domain to local ACCT and replace the curent user name with \"\". @@ -541,6 +532,7 @@ The prefix string is tested against both user handles and display names." "Remove all attachments from a toot draft." (interactive) (setq mastodon-toot--media-attachments nil) + (setq mastodon-toot--media-attachment-ids nil) (mastodon-toot--refresh-attachments-display) (mastodon-toot--update-status-fields)) @@ -562,7 +554,9 @@ will be uploaded and attached to the toot upon sending." (defun mastodon-toot--upload-attached-media () "Actually upload attachments using `mastodon-http--post-media-attachment'. -It adds the items' ids to `mastodon-toot--media-attachment-ids', which is used to actually attach them to a toot after uploading." +The files to be uploaded are in `mastodon-toot--media-attachments'. +The items' ids are added to `mastodon-toot--media-attachment-ids', +which are used to attach them to a toot after uploading." (interactive) (mapcar (lambda (attachment) (let* ((filename (expand-file-name -- cgit v1.2.3 From d74f462624b66040a78a3e4a13ccb0d3c681f509 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 18:12:31 +0200 Subject: docstrings --- lisp/mastodon-search.el | 2 +- lisp/mastodon-toot.el | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index ccac5e6..687b50c 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -52,7 +52,7 @@ (concat "@" (cdr (assoc 'acct account))))) (defun mastodon-search--search-accounts-query (query) - "Prompt for a search QUERY and return accounts. + "Prompt for a search QUERY and return accounts synchronously. Returns a nested list containing user handle, display name, and URL." (interactive "sSearch mastodon for: ") (let* ((url (format "%s/api/v1/accounts/search" mastodon-instance-url)) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 063b346..952ff58 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -444,7 +444,7 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (defun mastodon-toot--mentions-company-candidates (prefix) "Given a company PREFIX, build a list of candidates. -The prefix string is tested against both user handles and display names." +The prefix string can match against both user handles and display names." (let (res) (dolist (item (mastodon-search--search-accounts-query prefix)) (when (or (string-prefix-p prefix (cadr item)) -- cgit v1.2.3 From cf13db002b47f8e17267f48a0906be57d01eaf03 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 19:00:22 +0200 Subject: make get-max-toot-chars async --- lisp/mastodon-toot.el | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 952ff58..57e279f 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -146,12 +146,17 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p "Keymap for `mastodon-toot'.") (defun mastodon-toot--get-max-toot-chars () - "Fetch max_toot_chars from `mastodon-instance-url'." - (let ((instance-json (mastodon-http--get-json - (mastodon-http--api "instance")))) - (setq mastodon-toot--max-toot-chars - (number-to-string - (cdr (assoc 'max_toot_chars instance-json)))))) + "Fetch max_toot_chars from `mastodon-instance-url' asynchronously." + (mastodon-http--get-json-async + (mastodon-http--api "instance") 'mastodon-toot--get-max-toot-chars-callback)) + +(defun mastodon-toot--get-max-toot-chars-callback (json-response) + "Set max_toot_chars returned in JSON-RESPONSE." + (setq mastodon-toot--max-toot-chars + (number-to-string + (cdr (assoc 'max_toot_chars json-response)))) + (with-current-buffer "*new toot*" + (mastodon-toot--update-status-fields))) (defun mastodon-toot--action-success (marker byline-region remove) "Insert/remove the text MARKER with 'success face in byline. -- cgit v1.2.3 From 158bfd8785e46f134f699c5d6423e8c1785daf1c Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 19:00:22 +0200 Subject: make get-max-toot-chars async --- lisp/mastodon-toot.el | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 309b64a..3e3619c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -154,12 +154,17 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p "Keymap for `mastodon-toot'.") (defun mastodon-toot--get-max-toot-chars () - "Fetch max_toot_chars from `mastodon-instance-url'." - (let ((instance-json (mastodon-http--get-json - (mastodon-http--api "instance")))) - (setq mastodon-toot--max-toot-chars - (number-to-string - (cdr (assoc 'max_toot_chars instance-json)))))) + "Fetch max_toot_chars from `mastodon-instance-url' asynchronously." + (mastodon-http--get-json-async + (mastodon-http--api "instance") 'mastodon-toot--get-max-toot-chars-callback)) + +(defun mastodon-toot--get-max-toot-chars-callback (json-response) + "Set max_toot_chars returned in JSON-RESPONSE." + (setq mastodon-toot--max-toot-chars + (number-to-string + (cdr (assoc 'max_toot_chars json-response)))) + (with-current-buffer "*new toot*" + (mastodon-toot--update-status-fields))) (defun mastodon-toot--action-success (marker byline-region remove) "Insert/remove the text MARKER with 'success face in byline. -- cgit v1.2.3 From 5d226e03737240a763419d1753769b983b46a1a9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 29 Oct 2021 19:02:03 +0200 Subject: fix toot--send setting args/args-media --- lisp/mastodon-toot.el | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 57e279f..dd13251 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -139,7 +139,6 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (define-key map (kbd "C-c C-v") #'mastodon-toot--change-visibility) (when (require 'emojify nil :noerror) (define-key map (kbd "C-c C-e") #'mastodon-toot--insert-emoji)) - (define-key map (kbd "C-c C-u") #'mastodon-toot--upload-attached-media) (define-key map (kbd "C-c C-a") #'mastodon-toot--attach-media) (define-key map (kbd "C-c !") #'mastodon-toot--clear-all-attachments) map) @@ -375,7 +374,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (message "Visibility set to %s" visibility)) (defun mastodon-toot--send () - "POST contents of the new-toot buffer/window to the Mastodon instance and kill the buffer. + "POST contents of new-toot buffer to Mastodon instance and kill buffer. If media items have been attached with `mastodon-toot--attach-media', upload them with `mastodon-toot-upload-attached-media' and attach them to the @@ -388,19 +387,18 @@ toot." (spoiler (when (and (not empty-toot-p) mastodon-toot--content-warning) (read-string "Warning: " mastodon-toot--content-warning-from-reply-or-redraft))) - (args `(("status" . ,toot) - ("in_reply_to_id" . ,mastodon-toot--reply-to-id) - ("visibility" . ,mastodon-toot--visibility) - ("sensitive" . ,(when mastodon-toot--content-nsfw - (symbol-name t))) - ("spoiler_text" . ,spoiler)))) - (when mastodon-toot--media-attachments - (mastodon-toot--upload-attached-media) ; sync upload so we wait (and pray) till done - (let* ((args-media (mapcar - (lambda (id) - (cons "media_ids[]" id)) - mastodon-toot--media-attachment-ids)) - (args (append args args-media))))) + (args-no-media `(("status" . ,toot) + ("in_reply_to_id" . ,mastodon-toot--reply-to-id) + ("visibility" . ,mastodon-toot--visibility) + ("sensitive" . ,(when mastodon-toot--content-nsfw + (symbol-name t))) + ("spoiler_text" . ,spoiler))) + (args-media (when mastodon-toot--media-attachments + (mastodon-toot--upload-attached-media) ; sync upload so we wait (and pray) till done + (mapcar (lambda (id) + (cons "media_ids[]" id)) + mastodon-toot--media-attachment-ids))) + (args (append args-media args-no-media))) (if (> (length toot) (string-to-number mastodon-toot--max-toot-chars)) (message "Looks like your toot is longer than that maximum allowed length.") (if empty-toot-p @@ -562,7 +560,6 @@ will be uploaded and attached to the toot upon sending." The files to be uploaded are in `mastodon-toot--media-attachments'. The items' ids are added to `mastodon-toot--media-attachment-ids', which are used to attach them to a toot after uploading." - (interactive) (mapcar (lambda (attachment) (let* ((filename (expand-file-name (cdr (assoc :filename attachment)))) @@ -570,7 +567,7 @@ which are used to attach them to a toot after uploading." (url (concat mastodon-instance-url "/api/v2/media"))) (message "Uploading %s..." (file-name-nondirectory filename)) (mastodon-http--post-media-attachment url filename caption))) - mastodon-toot--media-attachments)) + mastodon-toot--media-attachments)) (defun mastodon-toot--refresh-attachments-display () "Update the display attachment previews in toot draft buffer." -- cgit v1.2.3 From 04465567450d6fc9cdec1a1ba0ef12557b0ab54b Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 1 Nov 2021 10:47:23 +0100 Subject: include user's profile URL in company mentions completion. also rename company mentions completion default value to "following" not "followers", which is what the actual search is called and what it returns. --- lisp/mastodon-search.el | 9 +++++---- lisp/mastodon-toot.el | 28 +++++++++++++++------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 687b50c..03301ce 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -46,10 +46,11 @@ ;; functions for company completion of mentions in mastodon-toot -(defun mastodon-search--get-user-info-no-url (account) +(defun mastodon-search--get-user-info (account) "Get user handle, display name and account URL from ACCOUNT." (list (cdr (assoc 'display_name account)) - (concat "@" (cdr (assoc 'acct account))))) + (concat "@" (cdr (assoc 'acct account))) + (cdr (assoc 'url account)))) (defun mastodon-search--search-accounts-query (query) "Prompt for a search QUERY and return accounts synchronously. @@ -57,10 +58,10 @@ Returns a nested list containing user handle, display name, and URL." (interactive "sSearch mastodon for: ") (let* ((url (format "%s/api/v1/accounts/search" mastodon-instance-url)) ;; (buffer (format "*mastodon-search-%s*" query)) - (response (if (equal mastodon-toot--enable-completion-for-mentions "followers") + (response (if (equal mastodon-toot--enable-completion-for-mentions "following") (mastodon-http--get-search-json url query "following=true") (mastodon-http--get-search-json url query)))) - (mapcar #'mastodon-search--get-user-info-no-url + (mapcar #'mastodon-search--get-user-info response))) ;; functions for mastodon search diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index dd13251..b0b7e13 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -89,12 +89,12 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" :type 'integer) (when (require 'company nil :noerror) - (defcustom mastodon-toot--enable-completion-for-mentions "followers" + (defcustom mastodon-toot--enable-completion-for-mentions "following" "Whether to enable company completion for mentions in toot compose buffer." :group 'mastodon-toot :type '(choice (const :tag "off" nil) - (const :tag "followers only" "followers") + (const :tag "following only" "following") (const :tag "all users" "all")))) (defvar mastodon-toot--content-warning nil @@ -436,18 +436,18 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (reverse (append mentions nil)) ""))) -;; (defun mastodon-toot--mentions-company-meta (candidate) -;; (format "meta %s of candidate %s" -;; (get-text-property 0 'meta candidate) -;; (substring-no-properties candidate))) +(defun mastodon-toot--mentions-company-meta (candidate) + "Format company completion CANDIDATE's meta field." + (format " %s" + (get-text-property 0 'meta candidate))) (defun mastodon-toot--mentions-company-annotation (candidate) - "Construct a company completion CANDIDATE's annotation for display." - (format " %s" (get-text-property 0 'meta candidate))) + "Format company completion CANDIDATE's annotation." + (format " %s" (get-text-property 0 'annot candidate))) (defun mastodon-toot--mentions-company-candidates (prefix) - "Given a company PREFIX, build a list of candidates. -The prefix string can match against both user handles and display names." + "Given a company PREFIX query, build a list of candidates. +The prefix can match against both user handles and display names." (let (res) (dolist (item (mastodon-search--search-accounts-query prefix)) (when (or (string-prefix-p prefix (cadr item)) @@ -458,8 +458,9 @@ The prefix string can match against both user handles and display names." (defun mastodon-toot--mentions-company-make-candidate (candidate) "Construct a company completion CANDIDATE for display." (let ((display-name (car candidate)) - (handle (cadr candidate))) - (propertize handle 'meta display-name))) + (handle (cadr candidate)) + (url (caddr candidate))) + (propertize handle 'annot display-name 'meta url))) (defun mastodon-toot--mentions-completion (command &optional arg &rest ignored) "A company completion backend for toot mentions." @@ -474,7 +475,8 @@ The prefix string can match against both user handles and display names." ;; @ + thing before point (concat "@" (company-grab-symbol)))) (candidates (mastodon-toot--mentions-company-candidates arg)) - (annotation (mastodon-toot--mentions-company-annotation arg)))) + (annotation (mastodon-toot--mentions-company-annotation arg)) + (meta (mastodon-toot--mentions-company-meta arg)))) (defun mastodon-toot--reply () "Reply to toot at `point'." -- cgit v1.2.3 From d7593a06912b7946d2fb318093ec7e27c64b3be7 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Mon, 1 Nov 2021 12:28:32 +0100 Subject: Fix compilation warnings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mostly reflowing / reworkding docstrings to keep within 80 characters limit and adding autoloads. There are two warning remaining that I don't understand: - mastodon-async.el:359:16: Warning: reference to free variable ‘url-http-end-of-headers’ - mastodon-http.el:139:8: Warning: value returned from (string-equal json-string "") is unused When adding autoloads this sorts them for better readability. --- lisp/mastodon-async.el | 14 ++++++++++++-- lisp/mastodon-auth.el | 13 ++++++++++--- lisp/mastodon-http.el | 2 +- lisp/mastodon-media.el | 5 ++++- lisp/mastodon-notifications.el | 15 ++++++++------- lisp/mastodon-search.el | 9 ++------- lisp/mastodon-tl.el | 7 +++++-- lisp/mastodon-toot.el | 41 +++++++++++++++++++++++------------------ 8 files changed, 65 insertions(+), 41 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 6a421d1..56dc230 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -30,8 +30,14 @@ ;;; Code: (require 'json) +(require 'url-http) +(autoload 'mastodon-auth--access-token "mastodon-auth") +(autoload 'mastodon-http--api "mastodon-http") +(autoload 'mastodon-http--get-json "mastodon-http") +(autoload 'mastodon-mode "mastodon") (autoload 'mastodon-notifications--timeline "mastodon-notifications") +(autoload 'mastodon-tl--timeline "mastodon-tl") (defgroup mastodon-async nil "An async module for mastodon streams." @@ -129,7 +135,9 @@ Then start an async stream at ENDPOINT filtering toots using FILTER. TIMELINE is a specific target, such as federated or home. -NAME is the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queue." +NAME is the center portion of the buffer name for +*mastodon-async-buffer and *mastodon-async-queue." + (ignore timeline) ;; TODO: figure out what this is meant to be used for (let ((buffer (mastodon-async--start-process endpoint filter name))) (with-current-buffer buffer @@ -238,7 +246,9 @@ Filter the toots using FILTER." (async-buffer (mastodon-async--setup-buffer "" (or name stream) endpoint)) (http-buffer (mastodon-async--get (mastodon-http--api stream) - (lambda (status) (message "HTTP SOURCE CLOSED"))))) + (lambda (status) + (ignore status) + (message "HTTP SOURCE CLOSED"))))) (mastodon-async--setup-http http-buffer (or name stream)) (mastodon-async--set-http-buffer async-buffer http-buffer) (mastodon-async--set-http-buffer async-queue http-buffer) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 0b0c703..b22b51e 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -63,7 +63,10 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defun mastodon-auth--generate-token () "Make POST to generate auth token. -If no auth-sources file, runs `mastodon-auth--generate-token-no-storing-credentials'. If auth-sources file exists, runs `mastodon-auth--generate-token-and-store'." +If no auth-sources file, runs +`mastodon-auth--generate-token-no-storing-credentials'. If +auth-sources file exists, runs +`mastodon-auth--generate-token-and-store'." (if (or (null mastodon-auth-source-file) (string= "" mastodon-auth-source-file)) (mastodon-auth--generate-token-no-storing-credentials) @@ -124,9 +127,13 @@ Reads and/or stores secrets in `MASTODON-AUTH-SOURCE-FILE'." (json-read-from-string json-string)))) (defun mastodon-auth--access-token () - "If an access token for `mastodon-instance-url' is in `mastodon-auth--token-alist', return it. + "Return exiting or generate new access token. -Otherwise, generate a token and pass it to `mastodon-auth--handle-token-reponse'." +If an access token for `mastodon-instance-url' is in +`mastodon-auth--token-alist', return it. + +Otherwise, generate a token and pass it to +`mastodon-auth--handle-token-reponse'." (if-let ((token (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) token diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index d6158eb..27f8ef0 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -145,7 +145,7 @@ Pass response buffer to CALLBACK function." (buffer-substring-no-properties (point) (point-max)) 'utf-8))) (kill-buffer) - (unless (or (string= "" json-string) (equal nil json-string))) + (unless (or (string-equal "" json-string) (null json-string))) (json-read-from-string json-string))) (defun mastodon-http--delete (url) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 808a23d..5f8f46c 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -32,6 +32,8 @@ ;; required by the server and client. ;;; Code: +(require 'url-cache) + (defvar url-show-status) (defvar mastodon-tl--shr-image-map-replacement) @@ -141,7 +143,8 @@ fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") STATUS-PLIST is the usual plist of status events as per `url-retrieve'. IMAGE-OPTIONS are the precomputed options to apply to the image. MARKER is the marker to where the response should be visible. -REGION-LENGTH is the length of the region that should be replaced with the image." +REGION-LENGTH is the length of the region that should be replaced +with the image." (when (marker-buffer marker) ; only if the buffer hasn't been kill in the meantime (let ((url-buffer (current-buffer)) (is-error-response-p (eq :error (car status-plist)))) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 2e9aea3..ad3d7b4 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -29,22 +29,23 @@ ;;; Code: +(autoload 'mastodon-http--api "mastodon-http.el") +(autoload 'mastodon-http--post "mastodon-http.el") +(autoload 'mastodon-http--triage "mastodon-http.el") (autoload 'mastodon-media--inline-images "mastodon-media.el") +(autoload 'mastodon-tl--byline "mastodon-tl.el") (autoload 'mastodon-tl--byline-author "mastodon-tl.el") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl.el") (autoload 'mastodon-tl--content "mastodon-tl.el") -(autoload 'mastodon-tl--byline "mastodon-tl.el") -(autoload 'mastodon-tl--toot-id "mastodon-tl.el") (autoload 'mastodon-tl--field "mastodon-tl.el") +(autoload 'mastodon-tl--find-property-range "mastodon-tl.el") (autoload 'mastodon-tl--has-spoiler "mastodon-tl.el") (autoload 'mastodon-tl--init "mastodon-tl.el") +(autoload 'mastodon-tl--init-sync "mastodon-tl.el") (autoload 'mastodon-tl--insert-status "mastodon-tl.el") -(autoload 'mastodon-tl--spoiler "mastodon-tl.el") (autoload 'mastodon-tl--property "mastodon-tl.el") -(autoload 'mastodon-tl--find-property-range "mastodon-tl.el") -(autoload 'mastodon-http--triage "mastodon-http.el") -(autoload 'mastodon-http--post "mastodon-http.el") -(autoload 'mastodon-http--api "mastodon-http.el") +(autoload 'mastodon-tl--spoiler "mastodon-tl.el") +(autoload 'mastodon-tl--toot-id "mastodon-tl.el") (defvar mastodon-tl--display-media-p) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 03301ce..2227d79 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -46,12 +46,6 @@ ;; functions for company completion of mentions in mastodon-toot -(defun mastodon-search--get-user-info (account) - "Get user handle, display name and account URL from ACCOUNT." - (list (cdr (assoc 'display_name account)) - (concat "@" (cdr (assoc 'acct account))) - (cdr (assoc 'url account)))) - (defun mastodon-search--search-accounts-query (query) "Prompt for a search QUERY and return accounts synchronously. Returns a nested list containing user handle, display name, and URL." @@ -161,7 +155,8 @@ We use this to fetch the complete status from the server." (defun mastodon-search--fetch-full-status-from-id (id) "Fetch the full status with id ID from the server. -This allows us to access the full account etc. details and to render them properly." +This allows us to access the full account etc. details and to +render them properly." (let* ((url (concat mastodon-instance-url "/api/v1/statuses/" (mastodon-tl--as-string id))) (json (mastodon-http--get-json url))) json)) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 9bbc44f..e5ded3f 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -67,7 +67,7 @@ :group 'mastodon) (defcustom mastodon-tl--enable-relative-timestamps t - "Nonnil to enable showing relative (to the current time) timestamps. + "Whether to show relative (to the current time) timestamps. This will require periodic updates of a timeline buffer to keep the timestamps current as time progresses." @@ -630,7 +630,10 @@ Used for a mouse-click EVENT on a link." (mastodon-tl--do-link-action-at-point (posn-point (event-end event)))) (defun mastodon-tl--has-spoiler (toot) - "Check if the given TOOT has a spoiler text that should initially be shown only while the main content should be hidden." + "Check if the given TOOT has a spoiler text. + +Spoiler text should initially be shown only while the main +content should be hidden." (let ((spoiler (mastodon-tl--field 'spoiler_text toot))) (and spoiler (> (length spoiler) 0)))) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index b0b7e13..7698226 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -43,24 +43,25 @@ (defvar mastodon-instance-url) (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") -(autoload 'mastodon-http--post "mastodon-http") -(autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") -(autoload 'mastodon-http--process-json "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") +(autoload 'mastodon-http--get-json-async "mastodon-htpp") +(autoload 'mastodon-http--post "mastodon-http") +(autoload 'mastodon-http--post-media-attachment "mastodon-http") +(autoload 'mastodon-http--process-json "mastodon-http") +(autoload 'mastodon-http--read-file-as-string "mastodon-http") +(autoload 'mastodon-http--triage "mastodon-http") +(autoload 'mastodon-search--search-accounts-query "mastodon-search") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") (autoload 'mastodon-tl--find-property-range "mastodon-tl") +(autoload 'mastodon-tl--find-property-range "mastodon-tl") (autoload 'mastodon-tl--goto-next-toot "mastodon-tl") (autoload 'mastodon-tl--property "mastodon-tl") -(autoload 'mastodon-tl--find-property-range "mastodon-tl") -(autoload 'mastodon-toot "mastodon") -(autoload 'mastodon-http--post-media-attachment "mastodon-http") -(autoload 'mastodon-http--read-file-as-string "mastodon-http") -(autoload 'mastodon-tl--toot-id "mastodon-tl") (autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl") -(autoload 'mastodon-search--search-accounts-query "mastodon-search") +(autoload 'mastodon-tl--toot-id "mastodon-tl") +(autoload 'mastodon-toot "mastodon") (defgroup mastodon-toot nil "Tooting in Mastodon." @@ -70,7 +71,8 @@ (defcustom mastodon-toot--default-visibility "public" "The default visibility for new toots. -Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \"direct\"." +Must be one of \"public\", \"unlisted\", \"private\" (for +followers-only), or \"direct\"." :group 'mastodon-toot :type '(choice (const :tag "public" "public") @@ -88,14 +90,17 @@ Must be one of \"public\", \"unlisted\", \"private\" (for followers-only), or \" :group 'mastodon-toot :type 'integer) -(when (require 'company nil :noerror) - (defcustom mastodon-toot--enable-completion-for-mentions "following" - "Whether to enable company completion for mentions in toot compose buffer." - :group 'mastodon-toot - :type '(choice - (const :tag "off" nil) - (const :tag "following only" "following") - (const :tag "all users" "all")))) +(defcustom mastodon-toot--enable-completion-for-mentions (if (require 'company nil :noerror) "following" "off") + "Whether to enable company completion for mentions. + +Used for completion in toot compose buffer. + +This is only used if company mode is installed." + :group 'mastodon-toot + :type '(choice + (const :tag "off" nil) + (const :tag "following only" "following") + (const :tag "all users" "all"))) (defvar mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") -- cgit v1.2.3 From e7c7da386c812f9452b072567e822077180f3dc5 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Mon, 1 Nov 2021 15:53:37 +0100 Subject: Fix tests. These needed a bit of tender love and care to get back into passing state. - Move the auth tests to the `test` directory. No idea what it was doing in `lisp`. - Image tests are mostly broken because with later Emacsen we no longer need the `imagemagic` option on create-image. - Some method signatures have changed and mocking calls needed to follow suit. --- Cask | 1 + lisp/mastodon-auth--test.el | 47 ------------------------------------- lisp/mastodon-http.el | 16 +++++++++---- lisp/mastodon-profile.el | 2 +- lisp/mastodon-tl.el | 2 +- lisp/mastodon.el | 2 +- test/ert-helper.el | 11 ++++++--- test/mastodon-auth-test.el | 47 +++++++++++++++++++++++++++++++++++++ test/mastodon-http-tests.el | 2 +- test/mastodon-media-tests.el | 34 ++++++++++++++++++--------- test/mastodon-notifications-test.el | 2 +- test/mastodon-tl-tests.el | 6 ++--- 12 files changed, 99 insertions(+), 73 deletions(-) delete mode 100644 lisp/mastodon-auth--test.el create mode 100644 test/mastodon-auth-test.el diff --git a/Cask b/Cask index ebb7669..60a064c 100644 --- a/Cask +++ b/Cask @@ -4,6 +4,7 @@ (package-file "lisp/mastodon.el") (files "lisp/*.el") +(depends-on "request") (depends-on "seq") (development diff --git a/lisp/mastodon-auth--test.el b/lisp/mastodon-auth--test.el deleted file mode 100644 index 9a765b9..0000000 --- a/lisp/mastodon-auth--test.el +++ /dev/null @@ -1,47 +0,0 @@ -;;; mastodon-auth--test.el --- Tests for mastodon-auth -*- lexical-binding: t; -*- - -;; Copyright (C) 2020 Ian Eure - -;; Author: Ian Eure -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "26.1")) - -;; This file is not part of GNU Emacs. - -;; This file is part of mastodon.el. - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: - -;; mastodon-auth--test.el provides ERT tests for mastodon-auth.el - -;;; Code: - -(require 'ert) - -(ert-deftest mastodon-auth--handle-token-response--good () - (should (string= "foo" (mastodon-auth--handle-token-response '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) - -(ert-deftest mastodon-auth--handle-token-response--unknown () - :expected-result :failed - (mastodon-auth--handle-token-response '(:herp "derp"))) - -(ert-deftest mastodon-auth--handle-token-response--failure () - :expected-result :failed - (mastodon-auth--handle-token-response '(:error "invalid_grant" :error_description "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."))) - -(provide 'mastodon-auth--test) -;;; mastodon-auth--test.el ends here diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 27f8ef0..875e9bf 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "26.1") (request "0.2.0")) +;; Package-Requires: ((emacs "27.1") (request "0.2.0")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. @@ -127,9 +127,17 @@ Pass response buffer to CALLBACK function." (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) - (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) - (url-retrieve-synchronously url) - (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + (mastodon-http--url-retrieve-synchronously url))) + +(defun mastodon-http--url-retrieve-synchronously (url) + "Retrieve URL asynchronously. + +This is a thin abstraction over the system +`url-retrieve-synchronously`. Depending on which version of this +is available we will call it with or without a timeout." + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout))) (defun mastodon-http--get-json (url) "Make synchronous GET request to URL. Return JSON response." diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 22120fe..018af21 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "26.1") (seq "1.8")) +;; Package-Requires: ((emacs "26.1") (seq "1.0")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index e5ded3f..3cb4ccb 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1321,7 +1321,7 @@ JSON is the data returned from the server." (defun mastodon-tl--init-sync (buffer-name endpoint update-function) "Initialize BUFFER-NAME with timeline targeted by ENDPOINT. -UPDATE-FUNCTION is used to recieve more toots. +UPDATE-FUNCTION is used to receive more toots. Runs synchronously." (let* ((url (mastodon-http--api endpoint)) (buffer (concat "*mastodon-" buffer-name "*")) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 159b9b2..d405bed 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.1 -;; Package-Requires: ((emacs "26.1") (request "0.2.0") (seq "1.8")) +;; Package-Requires: ((emacs "26.1") (request "0.3.2") (seq "1.0")) ;; Homepage: https://github.com/jdenen/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/test/ert-helper.el b/test/ert-helper.el index 6979837..d3e0016 100644 --- a/test/ert-helper.el +++ b/test/ert-helper.el @@ -1,8 +1,13 @@ +(load-file "lisp/mastodon-async.el") (load-file "lisp/mastodon-http.el") -(load-file "lisp/mastodon-client.el") (load-file "lisp/mastodon-auth.el") -(load-file "lisp/mastodon-toot.el") +(load-file "lisp/mastodon-client.el") +(load-file "lisp/mastodon-discover.el") +(load-file "lisp/mastodon-inspect.el") (load-file "lisp/mastodon-media.el") -(load-file "lisp/mastodon-tl.el") (load-file "lisp/mastodon-notifications.el") +(load-file "lisp/mastodon-profile.el") +(load-file "lisp/mastodon-search.el") +(load-file "lisp/mastodon-tl.el") +(load-file "lisp/mastodon-toot.el") (load-file "lisp/mastodon.el") diff --git a/test/mastodon-auth-test.el b/test/mastodon-auth-test.el new file mode 100644 index 0000000..9a765b9 --- /dev/null +++ b/test/mastodon-auth-test.el @@ -0,0 +1,47 @@ +;;; mastodon-auth--test.el --- Tests for mastodon-auth -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Ian Eure + +;; Author: Ian Eure +;; Version: 0.9.1 +;; Homepage: https://github.com/jdenen/mastodon.el +;; Package-Requires: ((emacs "26.1")) + +;; This file is not part of GNU Emacs. + +;; This file is part of mastodon.el. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; mastodon-auth--test.el provides ERT tests for mastodon-auth.el + +;;; Code: + +(require 'ert) + +(ert-deftest mastodon-auth--handle-token-response--good () + (should (string= "foo" (mastodon-auth--handle-token-response '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) + +(ert-deftest mastodon-auth--handle-token-response--unknown () + :expected-result :failed + (mastodon-auth--handle-token-response '(:herp "derp"))) + +(ert-deftest mastodon-auth--handle-token-response--failure () + :expected-result :failed + (mastodon-auth--handle-token-response '(:error "invalid_grant" :error_description "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."))) + +(provide 'mastodon-auth--test) +;;; mastodon-auth--test.el ends here diff --git a/test/mastodon-http-tests.el b/test/mastodon-http-tests.el index 972cedb..d0f715e 100644 --- a/test/mastodon-http-tests.el +++ b/test/mastodon-http-tests.el @@ -4,6 +4,6 @@ "Should make a `url-retrieve' of the given URL." (let ((callback-double (lambda () "double"))) (with-mock - (mock (url-retrieve-synchronously "https://foo.bar/baz")) + (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) (mock (mastodon-auth--access-token) => "test-token") (mastodon-http--get "https://foo.bar/baz")))) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index a586be9..20993f9 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -4,7 +4,7 @@ "Should return text with all expected properties." (with-mock (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * 'imagemagick t :height 123) => :mock-image) + (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => :mock-image) (let* ((mastodon-media--avatar-height 123) (result (mastodon-media--get-avatar-rendering "http://example.org/img.png")) @@ -37,12 +37,15 @@ (mastodon-media--avatar-height 123)) (with-mock (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * 'imagemagick t :height 123) => '(image foo)) + (mock (create-image + * + (when (version< emacs-version "27.1") 'imagemagick) + t :height 123) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve url #'mastodon-media--process-image-response - '(:my-marker (:height 123) 1)) + `(:my-marker (:height 123) 1 ,url)) => :called-as-expected) (with-temp-buffer @@ -62,7 +65,7 @@ (mock (url-retrieve url #'mastodon-media--process-image-response - '(:my-marker () 1)) + `(:my-marker () 1 ,url)) => :called-as-expected) (with-temp-buffer @@ -82,7 +85,7 @@ (mock (url-retrieve "http://example.org/image.png" #'mastodon-media--process-image-response - '(:my-marker (:max-height 321) 5)) + '(:my-marker (:max-height 321) 5 "http://example.org/image.png")) => :called-as-expected) (with-temp-buffer (insert (concat "Start:" @@ -101,7 +104,7 @@ (mock (url-retrieve "http://example.org/image.png" #'mastodon-media--process-image-response - '(:my-marker () 5)) + '(:my-marker () 5 "http://example.org/image.png")) => :called-as-expected) (with-temp-buffer @@ -117,7 +120,10 @@ (mastodon-media--avatar-height 123)) (with-mock (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * 'imagemagick t :height 123) => '(image foo)) + (mock (create-image + * + (when (version< emacs-version "27.1") 'imagemagick) + t :height 123) => '(image foo)) (stub url-retrieve => (error "url-retrieve failed")) (with-temp-buffer @@ -139,9 +145,11 @@ (insert "start:") (setq used-marker (copy-marker (point)) saved-marker (copy-marker (point))) - ;; Mock needed for the preliminary image created in mastodon-media--get-avatar-rendering + ;; Mock needed for the preliminary image created in + ;; mastodon-media--get-avatar-rendering (stub create-image => :fake-image) - (insert (mastodon-media--get-avatar-rendering "http://example.org/image.png") + (insert (mastodon-media--get-avatar-rendering + "http://example.org/image.png.") ":end") (with-temp-buffer (insert "some irrelevant\n" @@ -150,9 +158,13 @@ "fake\nimage\ndata") (goto-char (point-min)) - (mock (create-image "fake\nimage\ndata" 'imagemagick t ':image :option) => :fake-image) + (mock (create-image + "fake\nimage\ndata" + (when (version< emacs-version "27.1") 'imagemagick) + t ':image :option) => :fake-image) - (mastodon-media--process-image-response () used-marker '(:image :option) 1) + (mastodon-media--process-image-response + () used-marker '(:image :option) 1 "http://example.org/image.png") ;; the used marker has been unset: (should (null (marker-position used-marker))) diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el index 19b591d..778d350 100644 --- a/test/mastodon-notifications-test.el +++ b/test/mastodon-notifications-test.el @@ -185,7 +185,7 @@ "Ensure get request format for notifictions is accurate." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json-async "https://instance.url/api/v1/notifications" 'mastodon-tl--init* "*mastodon-notifications*" "notifications" 'mastodon-notifications--timeline)) + (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications" )) (mastodon-notifications--get)))) (defun mastodon-notifications--test-type (fun sample) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index c7dfc9a..24de5d0 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -285,7 +285,7 @@ a string or a numeric." (mastodon-tl--byline mastodon-tl-test-base-toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -395,8 +395,8 @@ a string or a numeric." (mastodon-tl--byline toot 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted)) - " Account 42 (@acct42@example.space) - Boosted Account 43 (@acct43@example.space) original time + "Account 42 (@acct42@example.space) + Boosted Account 43 (@acct43@example.space) original time ------------ "))))) -- cgit v1.2.3 From 18c146170a21dccd576228b1c6e3bcba9f0d50e9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 2 Nov 2021 15:24:28 +0100 Subject: add support for receiving notifications when a user posts - mastodon-tl--notify-user-posts - mastodon-tl--no-notify-user-posts - + some schtick in notifications.el to make sure the notifs display ok. --- lisp/mastodon-notifications.el | 26 +++++++++++++++++++++++-- lisp/mastodon-tl.el | 44 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 2e9aea3..19b2d3c 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -53,7 +53,8 @@ ("follow" . mastodon-notifications--follow) ("favourite" . mastodon-notifications--favourite) ("reblog" . mastodon-notifications--reblog) - ("follow_request" . mastodon-notifications--follow-request)) + ("follow_request" . mastodon-notifications--follow-request) + ("status" . mastodon-notifications--status)) "Alist of notification types and their corresponding function.") (defvar mastodon-notifications--response-alist @@ -61,7 +62,8 @@ ("Followed" . "you") ("Favourited" . "your status from") ("Boosted" . "your status from") - ("Requested to follow" . "you")) + ("Requested to follow" . "you") + ("Posted" . "a post")) "Alist of subjects for notification types.") (defun mastodon-notifications--byline-concat (message) @@ -204,6 +206,26 @@ "Boosted")) id))) +(defun mastodon-notifications--status (note) + "Format for a `status' NOTE. +Status notifications are given when +`mastodon-tl--notify-user-posts' has been set." + (let ((id (cdr (assoc 'id note))) + (status (mastodon-tl--field 'status note))) + (mastodon-notifications--insert-status + status + (mastodon-tl--clean-tabs-and-nl + (if (mastodon-tl--has-spoiler status) + (mastodon-tl--spoiler status) + (mastodon-tl--content status))) + (lambda (_status) + (mastodon-tl--byline-author + note)) + (lambda (_status) + (mastodon-notifications--byline-concat + "Posted")) + id))) + (defun mastodon-notifications--insert-status (toot body author-byline action-byline &optional id) "Display the content and byline of timeline element TOOT. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 9bbc44f..6cb5ab8 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -945,8 +945,10 @@ webapp" (cdr (assoc 'descendants context)))))) (message "No Thread!")))) -(defun mastodon-tl--follow-user (user-handle) - "Query for USER-HANDLE from current status and follow that user." +(defun mastodon-tl--follow-user (user-handle &optional notify) + "Query for USER-HANDLE from current status and follow that user. +If NOTIFY is \"true\", enable notifications when that user posts. +If NOTIFY is \"false\", disable notifications when that user posts." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles @@ -959,12 +961,22 @@ webapp" user-handle (mastodon-profile--toot-json))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/follow" user-id)))) + (url (mastodon-http--api + (if notify + (format "accounts/%s/follow?notify=%s" user-id notify) + (format "accounts/%s/follow" user-id))))) (if account (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response (lambda () - (message "User %s (@%s) followed!" name user-handle)))) + (cond ((string-equal notify "true") + (message "Receiving notifications for user %s (@%s)!" + name user-handle)) + ((string-equal notify "false") + (message "Not receiving notifications for user %s (@%s)!" + name user-handle)) + ((eq notify nil) + (message "User %s (@%s) followed!" name user-handle)))))) (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--unfollow-user (user-handle) @@ -990,6 +1002,30 @@ webapp" (message "User %s (@%s) unfollowed!" name user-handle))))) (message "Cannot find a user with handle %S" user-handle)))) +(defun mastodon-tl--notify-user-posts (user-handle) + "Query for USER-HANDLE from current status and enable notifications when they post." + (interactive + (list + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read "Receive notifications when user posts: " + user-handles + nil ; predicate + 'confirm)))) + (mastodon-tl--follow-user user-handle "true")) + +(defun mastodon-tl--no-notify-user-posts (user-handle) + "Query for USER-HANDLE from current status and disable notifications when they post." + (interactive + (list + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read "Disable notifications when user posts: " + user-handles + nil ; predicate + 'confirm)))) + (mastodon-tl--follow-user user-handle "false")) + (defun mastodon-tl--mute-user (user-handle) "Query for USER-HANDLE from current status and mute that user." (interactive -- cgit v1.2.3 From cba3982050c879fdebe10e9f6f64bd7721a8fb51 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 3 Nov 2021 09:22:04 +0100 Subject: fix broken completion, restore search--get-user-info{-@} we need this modified version of -get-user-info because it adds the @ prefix to the account handle, which our completion prefix also contains --- lisp/mastodon-search.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 2227d79..5f52bb7 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -46,6 +46,12 @@ ;; functions for company completion of mentions in mastodon-toot +(defun mastodon-search--get-user-info-@ (account) + "Get user handle, display name and account URL from ACCOUNT." + (list (cdr (assoc 'display_name account)) + (concat "@" (cdr (assoc 'acct account))) + (cdr (assoc 'url account)))) + (defun mastodon-search--search-accounts-query (query) "Prompt for a search QUERY and return accounts synchronously. Returns a nested list containing user handle, display name, and URL." @@ -55,7 +61,7 @@ Returns a nested list containing user handle, display name, and URL." (response (if (equal mastodon-toot--enable-completion-for-mentions "following") (mastodon-http--get-search-json url query "following=true") (mastodon-http--get-search-json url query)))) - (mapcar #'mastodon-search--get-user-info + (mapcar #'mastodon-search--get-user-info-@ response))) ;; functions for mastodon search -- cgit v1.2.3 From 681a39a2d1b8d88de37095ba5915ee55387dbc4f Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 5 Nov 2021 16:22:21 +0100 Subject: defvar company-backends for flycheck --- lisp/mastodon-toot.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 7698226..13d152a 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -38,7 +38,8 @@ (when (require 'company nil :noerror) (declare-function company-mode-on "company") (declare-function company-begin-backend "company") - (declare-function company-grab-symbol "company")) + (declare-function company-grab-symbol "company") + (defvar company-backends)) (defvar mastodon-instance-url) (autoload 'mastodon-auth--user-acct "mastodon-auth") -- cgit v1.2.3 From 7e1fd71a793a8d5844eb332ccc1e54e80ecb5223 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 5 Nov 2021 16:22:39 +0100 Subject: support downloading/using custom emoji with emojify. - adds functions to download custom emoji from mastodon-instance-url, collect them into a list formatted as needed by emojify-user-emojis, and to update that var with the mastodon custom emoji so that they can be used with emojify-insert-emoji. - for now the user has to enable these by calling -enable-custom-emoji themselves. --- lisp/mastodon-toot.el | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 13d152a..d0d3dfa 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -31,7 +31,10 @@ (when (require 'emojify nil :noerror) - (declare-function emojify-insert-emoji "emojify")) + (declare-function emojify-insert-emoji "emojify") + (declare-function emojify-set-emoji-data "emojify") + (defvar emojify-emojis-dir) + (defvar emojify-user-emojis)) (require 'cl-lib) @@ -363,6 +366,74 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." 'emojify-insert-emoji "Prompt to insert an emoji.") +(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 (concat (expand-file-name + emojify-emojis-dir) + "/mastodon-custom-emojis/"))) + (if (not (file-exists-p emojify-emojis-dir)) + (message "Looks like you need to set up emojify first.") + (progn + (unless (file-directory-p mastodon-custom-emoji-dir) + (make-directory mastodon-custom-emoji-dir nil)) ; no add parent + (mapc (lambda (x) + (url-copy-file (alist-get 'url x) + (concat + mastodon-custom-emoji-dir + (alist-get 'shortcode x) + "." + (file-name-extension (alist-get 'url x))) + t)) + custom-emoji) + (message "Custom emoji for %s downloaded to %s" + mastodon-instance-url + mastodon-custom-emoji-dir))))) + +(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/")) + (custom-emoji-files (directory-files mastodon-custom-emojis-dir + nil ; not full path + "^[^.]")) ; no dot files + (mastodon-emojify-user-emojis)) + (mapc (lambda (x) + (push + `(,(concat ":" + (file-name-base x) + ":") . (("name" . ,(file-name-base x)) + ("image" . ,(concat mastodon-custom-emojis-dir x)) + ("style" . "github"))) + mastodon-emojify-user-emojis)) + custom-emoji-files) + (reverse mastodon-emojify-user-emojis))) + +(defun mastodon-toot--enable-custom-emoji () + "Add `mastodon-instance-url's custom emoji to `emojify'. +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/")) + (when (y-or-n-p "Looks like you haven't downloaded your instance's custom emoji yet. Download now? ") + (mastodon-toot--download-custom-emoji))) + (setq emojify-user-emojis + (append (mastodon-toot--collect-custom-emoji) + emojify-user-emojis)) + ;; if already loaded, reload + (when (featurep 'emojify) + (emojify-set-emoji-data))) + + (defun mastodon-toot--remove-docs () "Get the body of a toot from the current compose buffer." (let ((header-region (mastodon-tl--find-property-range 'toot-post-header -- cgit v1.2.3 From 7718f0b3126407916447c66ac627114693513b04 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 6 Nov 2021 14:49:00 +0100 Subject: inspect functions for search.el --- lisp/mastodon-inspect.el | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 9559b21..2181ea2 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -69,7 +69,7 @@ (defun mastodon-inspect--view-single-toot (toot-id) "View the toot/status represented by TOOT-ID." (interactive "s Toot ID: ") - (let ((buffer (get-buffer-create(concat "*mastodon-status-" toot-id "*")))) + (let ((buffer (get-buffer-create (concat "*mastodon-status-" toot-id "*")))) (with-current-buffer buffer (let ((toot (mastodon-inspect--download-single-toot toot-id ))) (mastodon-tl--toot toot) @@ -87,5 +87,37 @@ (concat "*mastodon-status-raw-" toot-id "*") (mastodon-inspect--download-single-toot toot-id))) + +(defvar mastodon-inspect--search-query-accounts-result) +(defvar mastodon-inspect--single-account-json) + +(defvar mastodon-inspect--search-query-full-result) +(defvar mastodon-inspect--search-result-tags) + +(defun mastodon-inspect--get-search-result (query) + (interactive) + (setq mastodon-inspect--search-query-full-result + (append ; convert vector to list + (mastodon-http--get-search-json + (format "%s/api/v2/search" mastodon-instance-url) + query) + nil)) + (setq mastodon-inspect--search-result-tags + (append (cdr + (caddr mastodon-inspect--search-query-full-result)) + nil))) + +(defun mastodon-inspect--get-search-account (query) + (interactive) + (setq mastodon-inspect--search-query-accounts-result + (append ; convert vector to list + (mastodon-http--get-search-json + (format "%s/api/v1/accounts/search" mastodon-instance-url) + query) + nil)) + (setq mastodon-inspect--single-account-json + (car mastodon-inspect--search-query-accounts-result))) + + (provide 'mastodon-inspect) ;;; mastodon-inspect.el ends here -- cgit v1.2.3 From af72d4943ad942712ec74a387e79fb1d53e6bee8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 6 Nov 2021 15:06:25 +0100 Subject: update mastodon-notifications--test-byline-concat for post notify --- test/mastodon-notifications-test.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el index 19b591d..7b88de0 100644 --- a/test/mastodon-notifications-test.el +++ b/test/mastodon-notifications-test.el @@ -208,6 +208,8 @@ notification to be tested." (string= " Favourited your status from" (mastodon-notifications--byline-concat "Favourited")) (string= " Boosted your status from" - (mastodon-notifications--byline-concat "Boosted"))))) + (mastodon-notifications--byline-concat "Boosted")) + (string= " Posted a post" + (mastodon-notifications--byline-concat "Posted"))))) -- cgit v1.2.3 From 14476572dafe12454015189f67d8f29f50b25ccb Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 6 Nov 2021 14:53:24 +0100 Subject: add tests for -search.el --- test/ert-helper.el | 1 + test/mastodon-search-tests.el | 141 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 test/mastodon-search-tests.el diff --git a/test/ert-helper.el b/test/ert-helper.el index d3e0016..a6d6692 100644 --- a/test/ert-helper.el +++ b/test/ert-helper.el @@ -1,3 +1,4 @@ +(load-file "lisp/mastodon-search.el") (load-file "lisp/mastodon-async.el") (load-file "lisp/mastodon-http.el") (load-file "lisp/mastodon-auth.el") diff --git a/test/mastodon-search-tests.el b/test/mastodon-search-tests.el new file mode 100644 index 0000000..b8521f3 --- /dev/null +++ b/test/mastodon-search-tests.el @@ -0,0 +1,141 @@ + + +(defconst mastodon-search--single-account-query + '((id . "242971") + (username . "mousebot") + (acct . "mousebot") + (display_name . ": ( ) { : | : & } ; :") + (locked . t) + (bot . :json-false) + (discoverable . t) + (group . :json-false) + (created_at . "2020-04-14T00:00:00.000Z") + (note . "

poetry, writing, dmt, desertion, trash, black metal, translation, hegel, language, autonomia....

https://anarchive.mooo.com
https://pleasantlybabykid.tumblr.com/
IG: https://bibliogram.snopyta.org/u/martianhiatus
photos alt: @goosebot
git: https://git.blast.noho.st/mouse

want to trade chapbooks or zines? hmu!

he/him or they/them

") + (url . "https://todon.nl/@mousebot") + (avatar . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") + (avatar_static . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") + (header . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") + (header_static . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") + (followers_count . 226) + (following_count . 634) + (statuses_count . 3807) + (last_status_at . "2021-11-05") + (emojis . + []) + (fields . + [((name . "dark to") + (value . "themselves") + (verified_at)) + ((name . "its raining") + (value . "plastic") + (verified_at)) + ((name . "dis") + (value . "integration") + (verified_at)) + ((name . "ungleichzeitigkeit und") + (value . "gleichzeitigkeit, philosophisch") + (verified_at))])) + "A sample mastodon account search result (parsed json)") + +(defconst mastodon-search-test-single-tag + '((name . "TeamBringBackVisibleScrollbars") (url . "https://todon.nl/tags/TeamBringBackVisibleScrollbars") (history . [((day . "1636156800") (uses . "0") (accounts . "0")) ((day . "1636070400") (uses . "0") (accounts . "0")) ((day . "1635984000") (uses . "0") (accounts . "0")) ((day . "1635897600") (uses . "0") (accounts . "0")) ((day . "1635811200") (uses . "0") (accounts . "0")) ((day . "1635724800") (uses . "0") (accounts . "0")) ((day . "1635638400") (uses . "0") (accounts . "0"))]))) + +(defconst mastodon-search-test-single-status + '((id . "107230316503209282") + (created_at . "2021-11-06T13:19:40.628Z") + (in_reply_to_id) + (in_reply_to_account_id) + (sensitive . :json-false) + (spoiler_text . "") + (visibility . "direct") + (language . "en") + (uri . "https://todon.nl/users/mousebot/statuses/107230316503209282") + (url . "https://todon.nl/@mousebot/107230316503209282") + (replies_count . 0) + (reblogs_count . 0) + (favourites_count . 0) + (favourited . :json-false) + (reblogged . :json-false) + (muted . :json-false) + (bookmarked . :json-false) + (content . "

This is a nice test toot, for testing purposes. Thank you.

") + (reblog) + (application + (name . "mastodon.el") + (website . "https://github.com/jdenen/mastodon.el")) + (account + (id . "242971") + (username . "mousebot") + (acct . "mousebot") + (display_name . ": ( ) { : | : & } ; :") + (locked . t) + (bot . :json-false) + (discoverable . t) + (group . :json-false) + (created_at . "2020-04-14T00:00:00.000Z") + (note . "

poetry, writing, dmt, desertion, trash, black metal, translation, hegel, language, autonomia....

https://anarchive.mooo.com
https://pleasantlybabykid.tumblr.com/
IG: https://bibliogram.snopyta.org/u/martianhiatus
photos alt: @goosebot
git: https://git.blast.noho.st/mouse

want to trade chapbooks or zines? hmu!

he/him or they/them

") + (url . "https://todon.nl/@mousebot") + (avatar . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") + (avatar_static . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") + (header . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") + (header_static . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") + (followers_count . 226) + (following_count . 634) + (statuses_count . 3807) + (last_status_at . "2021-11-05") + (emojis . + []) + (fields . + [((name . "dark to") + (value . "themselves") + (verified_at)) + ((name . "its raining") + (value . "plastic") + (verified_at)) + ((name . "dis") + (value . "integration") + (verified_at)) + ((name . "ungleichzeitigkeit und") + (value . "gleichzeitigkeit, philosophisch") + (verified_at))])) + (media_attachments . + []) + (mentions . + [((id . "242971") + (username . "mousebot") + (url . "https://todon.nl/@mousebot") + (acct . "mousebot"))]) + (tags . + []) + (emojis . + []) + (card) + (poll))) + +(ert-deftest mastodon-search-test-get-user-info-@ () + "Should build a list from a single account for company completion." + (let ((account mastodon-search--single-account-query)) + (should (equal (mastodon-search--get-user-info-@ account) + '(": ( ) { : | : & } ; :" "@mousebot" "https://todon.nl/@mousebot"))))) + +(ert-deftest mastodon-search-test-get-user-info () + "Should build a list from a single account for company completion." + (let ((account mastodon-search--single-account-query)) + (should (equal (mastodon-search--get-user-info account) + '(": ( ) { : | : & } ; :" "mousebot" "https://todon.nl/@mousebot"))))) + +(ert-deftest mastodon-search-test-get-hashtag-info () + "Should build a list of hashtag name and URL." + (let ((tag mastodon-search-test-single-tag)) + (should (equal (mastodon-search--get-hashtag-info tag) + '("TeamBringBackVisibleScrollbars" + "https://todon.nl/tags/TeamBringBackVisibleScrollbars"))))) + +(ert-deftest mastodon-search-test-get-status-info () + "Should return a list of ID, timestamp, content, and spoiler." + (let ((status mastodon-search-test-single-status)) + (should (equal (mastodon-search--get-status-info status) + '("107230316503209282" + "2021-11-06T13:19:40.628Z" + "" + "

This is a nice test toot, for testing purposes. Thank you.

"))))) -- cgit v1.2.3 From 48f1193558c9655e2215615b5f6d0cf6ea4d4e08 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 6 Nov 2021 15:50:40 +0100 Subject: tiny cleanup --- README.org | 1 + lisp/mastodon-notifications.el | 1 - lisp/mastodon-toot.el | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.org b/README.org index 2455124..3a7a06e 100644 --- a/README.org +++ b/README.org @@ -40,6 +40,7 @@ It adds the following features: | | media uploads previews in toot compose buffer | | =C-c C-n= | and sensitive media/nsfw flag | | =C-c C-e= | add emoji (if =emojify= installed) | +| | download and use your instance's custom emoji | | | replies preserve visibility status/CW of original toot | | | server's maximum toot length shown in toot compose buffer | | Search: | | diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index ad3d7b4..36f9d4a 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -73,7 +73,6 @@ " " (cdr (assoc message mastodon-notifications--response-alist)))) - (defun mastodon-notifications--follow-request-accept-notifs () "Accept the follow request of user at point, in notifications view." (interactive) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d0d3dfa..deea2ef 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -159,7 +159,7 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p (mastodon-http--api "instance") 'mastodon-toot--get-max-toot-chars-callback)) (defun mastodon-toot--get-max-toot-chars-callback (json-response) - "Set max_toot_chars returned in JSON-RESPONSE." + "Set max_toot_chars returned in JSON-RESPONSE and display in new toot buffer." (setq mastodon-toot--max-toot-chars (number-to-string (cdr (assoc 'max_toot_chars json-response)))) -- cgit v1.2.3 From 027f24125fae4abc487207c8c81fdc0f20ec711d Mon Sep 17 00:00:00 2001 From: mousebot Date: Sat, 6 Nov 2021 15:50:54 +0100 Subject: display faves/boosts/replies in threads also for reblogs --- lisp/mastodon-tl.el | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 3cb4ccb..b1b7c68 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -726,12 +726,18 @@ takes a single function. By default it is 'base-toot-id (mastodon-tl--toot-id toot) 'help-echo (when (and mastodon-tl--buffer-spec (string-match-p - "context" + "context" ; when thread view (plist-get mastodon-tl--buffer-spec 'endpoint))) - (format "%s faves | %s boosts | %s replies" - (cdr (assoc 'favourites_count toot)) - (cdr (assoc 'reblogs_count toot)) - (cdr (assoc 'replies_count toot)))) + (if (alist-get 'reblog toot) + (let ((reblog (cdr (assoc 'reblog toot)))) + (format "%s faves | %s boosts | %s replies" + (alist-get 'favourites_count reblog) + (alist-get 'reblogs_count reblog) + (alist-get 'replies_count reblog))) + (format "%s faves | %s boosts | %s replies" + (alist-get 'favourites_count toot) + (alist-get 'reblogs_count toot) + (alist-get 'replies_count toot)))) 'toot-json toot) "\n") (when mastodon-tl--display-media-p -- cgit v1.2.3 From b9d5d2ee57855653c32fe2fe2a495e5a3a038acf Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Tue, 2 Nov 2021 18:35:38 +0100 Subject: Use `defvar-local` to create buffer-local vars. This is much cleaner than first using `defvar` immediately followed by `make-variable-buffer-local`. --- lisp/mastodon-async.el | 15 ++++++--------- lisp/mastodon-profile.el | 3 +-- lisp/mastodon-tl.el | 12 ++++-------- lisp/mastodon-toot.el | 24 ++++++++---------------- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 56dc230..f7bbdff 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -55,17 +55,14 @@ (defvar mastodon-tl--display-media-p) (defvar mastodon-tl--buffer-spec) -(make-variable-buffer-local - (defvar mastodon-async--queue "" ;;"*mastodon-async-queue*" - "The intermediate queue buffer name.")) +(defvar-local mastodon-async--queue "" ;;"*mastodon-async-queue*" + "The intermediate queue buffer name.") -(make-variable-buffer-local - (defvar mastodon-async--buffer "" ;;"*mastodon-async-buffer*" - "User facing output buffer name.")) +(defvar-local mastodon-async--buffer "" ;;"*mastodon-async-buffer*" + "User facing output buffer name.") -(make-variable-buffer-local - (defvar mastodon-async--http-buffer "" ;;"" - "Buffer variable bound to http output.")) +(defvar-local mastodon-async--http-buffer "" ;;"" + "Buffer variable bound to http output.") (defun mastodon-async--display-http () "Display the async HTTP input buffer." diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 018af21..31499ed 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -62,9 +62,8 @@ (defvar mastodon-tl--update-point) -(defvar mastodon-profile--account nil +(defvar-local mastodon-profile--account nil "The data for the account being described in the current profile buffer.") -(make-variable-buffer-local 'mastodon-profile--account) ;; this way you can update it with C-M-x: (defvar mastodon-profile-mode-map diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index b1b7c68..e4c179c 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -82,9 +82,8 @@ By default fixed width fonts are used." :type '(boolean :tag "Enable using proportional rather than fixed \ width fonts when rendering HTML text")) -(defvar mastodon-tl--buffer-spec nil +(defvar-local mastodon-tl--buffer-spec nil "A unique identifier and functions for each Mastodon buffer.") -(make-variable-buffer-local 'mastodon-tl--buffer-spec) (defcustom mastodon-tl--show-avatars nil "Whether to enable display of user avatars in timelines." @@ -97,22 +96,19 @@ width fonts when rendering HTML text")) ;; (image-transforms-p)) ;; "A boolean value stating whether to show avatars in timelines.") -(defvar mastodon-tl--update-point nil +(defvar-local mastodon-tl--update-point nil "When updating a mastodon buffer this is where new toots will be inserted. If nil `(point-min)' is used instead.") -(make-variable-buffer-local 'mastodon-tl--update-point) (defvar mastodon-tl--display-media-p t "A boolean value stating whether to show media in timelines.") -(defvar mastodon-tl--timestamp-next-update nil +(defvar-local mastodon-tl--timestamp-next-update nil "The timestamp when the buffer should next be scanned to update the timestamps.") -(make-variable-buffer-local 'mastodon-tl--timestamp-next-update) -(defvar mastodon-tl--timestamp-update-timer nil +(defvar-local mastodon-tl--timestamp-update-timer nil "The timer that, when set will scan the buffer to update the timestamps.") -(make-variable-buffer-local 'mastodon-tl--timestamp-update-timer) (defvar mastodon-tl--link-keymap (let ((map (make-sparse-keymap))) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index deea2ef..07b52e3 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -106,35 +106,28 @@ This is only used if company mode is installed." (const :tag "following only" "following") (const :tag "all users" "all"))) -(defvar mastodon-toot--content-warning nil +(defvar-local mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") -(make-variable-buffer-local 'mastodon-toot--content-warning) -(defvar mastodon-toot--content-warning-from-reply-or-redraft nil +(defvar-local mastodon-toot--content-warning-from-reply-or-redraft nil "The content warning of the toot being replied to.") -(make-variable-buffer-local 'mastodon-toot--content-warning) -(defvar mastodon-toot--content-nsfw nil +(defvar-local mastodon-toot--content-nsfw nil "A flag indicating whether the toot should be marked as NSFW.") -(make-variable-buffer-local 'mastodon-toot--content-nsfw) -(defvar mastodon-toot--visibility "public" +(defvar-local mastodon-toot--visibility "public" "A string indicating the visibility of the toot being composed. Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"public\".") -(make-variable-buffer-local 'mastodon-toot--visibility) -(defvar mastodon-toot--media-attachments nil +(defvar-local mastodon-toot--media-attachments nil "A list of the media attachments of the toot being composed.") -(make-variable-buffer-local 'mastodon-toot--media-attachments) -(defvar mastodon-toot--media-attachment-ids nil +(defvar-local mastodon-toot--media-attachment-ids nil "A list of any media attachment ids of the toot being composed.") -(make-variable-buffer-local 'mastodon-toot--media-attachment-ids) -(defvar mastodon-toot--reply-to-id nil +(defvar-local mastodon-toot--reply-to-id nil "Buffer-local variable to hold the id of the toot being replied to.") -(make-variable-buffer-local 'mastodon-toot--reply-to-id) (defvar mastodon-toot--max-toot-chars nil "The maximum allowed characters count for a single toot.") @@ -714,9 +707,8 @@ e.g. mastodon-toot--send -> Send." "Format a list of keybindings, KBINDS, for display in documentation." (mapcar #'mastodon-toot--format-kbind kbinds)) -(defvar mastodon-toot--kbinds-pairs nil +(defvar-local mastodon-toot--kbinds-pairs nil "Contains a list of paired toot compose buffer keybindings for inserting.") -(make-variable-buffer-local 'mastodon-toot--kbinds-pairs) (defun mastodon-toot--formatted-kbinds-pairs (kbinds-list longest) "Return a list of strings each containing two formatted kbinds. -- cgit v1.2.3 From 93950dbee4165c733fd8e0a4938fd7d0f462d908 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Tue, 2 Nov 2021 20:30:27 +0100 Subject: Reformat all code. Basically, in Emacs for each file: select all text and `indent-region`. - This also removes one redundant comment, and - fixes an error with json decoding where the `json-read-from-string` was actually not within the intended `unless` clause (which explains the warning about "result of (string-equal "" json-string) will be ignored" which I never understood. --- lisp/mastodon-async.el | 22 +- lisp/mastodon-http.el | 87 ++++---- lisp/mastodon-inspect.el | 2 +- lisp/mastodon-media.el | 4 +- lisp/mastodon-notifications.el | 68 +++--- lisp/mastodon-profile.el | 24 +-- lisp/mastodon-search.el | 78 +++---- lisp/mastodon-tl.el | 54 ++--- lisp/mastodon-toot.el | 106 ++++----- lisp/mastodon.el | 4 +- test/mastodon-auth-tests.el | 14 +- test/mastodon-client-tests.el | 64 +++--- test/mastodon-http-tests.el | 6 +- test/mastodon-media-tests.el | 266 +++++++++++------------ test/mastodon-notifications-test.el | 4 +- test/mastodon-tl-tests.el | 420 ++++++++++++++++++------------------ test/mastodon-toot-tests.el | 6 +- 17 files changed, 614 insertions(+), 615 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index f7bbdff..1fabee2 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -59,10 +59,10 @@ "The intermediate queue buffer name.") (defvar-local mastodon-async--buffer "" ;;"*mastodon-async-buffer*" - "User facing output buffer name.") + "User facing output buffer name.") (defvar-local mastodon-async--http-buffer "" ;;"" - "Buffer variable bound to http output.") + "Buffer variable bound to http output.") (defun mastodon-async--display-http () "Display the async HTTP input buffer." @@ -177,16 +177,16 @@ is not known when `mastodon-async--setup-buffer' is called." NAME is used to generate the display buffer and the queue." (let ((queue-name (concat " *mastodon-async-queue-" name "-" - mastodon-instance-url "*")) + mastodon-instance-url "*")) (buffer-name (concat "*mastodon-async-display-" name "-" - mastodon-instance-url "*"))) + mastodon-instance-url "*"))) (mastodon-async--set-local-variables http-buffer http-buffer buffer-name queue-name))) (defun mastodon-async--setup-queue (http-buffer name) "Sets up the buffer for the async queue." (let ((queue-name (concat " *mastodon-async-queue-" name "-" - mastodon-instance-url "*")) + mastodon-instance-url "*")) (buffer-name(concat "*mastodon-async-display-" name "-" mastodon-instance-url "*"))) (mastodon-async--set-local-variables queue-name http-buffer @@ -203,8 +203,8 @@ ENPOINT is the endpoint for the stream and timeline." mastodon-instance-url "*")) (buffer-name (concat "*mastodon-async-display-" name "-" mastodon-instance-url "*")) - ;; if user stream, we need "timelines/home" not "timelines/user" - ;; if notifs, we need "notifications" not "timelines/notifications" + ;; if user stream, we need "timelines/home" not "timelines/user" + ;; if notifs, we need "notifications" not "timelines/notifications" (endpoint (if (equal name "notifications") "notifications" (if (equal name "home") "timelines/home" (format "timelines/%s" endpoint))))) @@ -285,8 +285,8 @@ Filter the toots using FILTER." ;; NB notification events in streams include follow requests (let* ((split-strings (split-string string "\n" t)) (event-type (replace-regexp-in-string - "^event: " "" - (car split-strings))) + "^event: " "" + (car split-strings))) (data (replace-regexp-in-string "^data: " "" (cadr split-strings)))) (when (equal "notification" event-type) @@ -304,8 +304,8 @@ Filter the toots using FILTER." (defun mastodon-async--account-local-p (json) "Test JSON to see if account is local." (not (string-match-p - "@" - (cdr (assoc 'acct (cdr (assoc 'account json))))))) + "@" + (cdr (assoc 'acct (cdr (assoc 'account json))))))) (defun mastodon-async--output-toot (toot) "Process TOOT and prepend it to the async user-facing buffer." diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 875e9bf..a183ed7 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -153,8 +153,8 @@ is available we will call it with or without a timeout." (buffer-substring-no-properties (point) (point-max)) 'utf-8))) (kill-buffer) - (unless (or (string-equal "" json-string) (null json-string))) - (json-read-from-string json-string))) + (unless (or (string-equal "" json-string) (null json-string)) + (json-read-from-string json-string)))) (defun mastodon-http--delete (url) "Make DELETE request to URL." @@ -256,8 +256,8 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." args "&"))) (url-request-extra-headers - (append `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))) - headers))) + (append `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))) + headers))) (with-temp-buffer (url-retrieve url callback cbargs)))) @@ -269,46 +269,45 @@ The upload is asynchronous. On succeeding, item uploaded, and `mastodon-toot--update-status-fields' is run." (let* ((file (file-name-nondirectory filename)) (request-backend 'curl)) - ;; (response - (request - url - :type "POST" - :params `(("description" . ,caption)) - :files `(("file" . (,file :file ,filename - :mime-type "multipart/form-data"))) - :parser 'json-read - :headers `(("Authorization" . ,(concat "Bearer " - (mastodon-auth--access-token)))) - :sync t - :success (cl-function - (lambda (&key data &allow-other-keys) - (when data - (progn - (push (cdr (assoc 'id data)) - mastodon-toot--media-attachment-ids) ; add ID to list - (message "%s file %s with id %S and caption '%s' uploaded!" - (capitalize (cdr (assoc 'type data))) - file - (cdr (assoc 'id data)) - (cdr (assoc 'description data))) - (mastodon-toot--update-status-fields))))) - :error (cl-function - (lambda (&key error-thrown &allow-other-keys) - (cond - ;; handle curl errors first (eg 26, can't read file/path) - ;; because the '=' test below fails for them - ;; they have the form (error . error message 24) - ((not (proper-list-p error-thrown)) ; not dotted list - (message "Got error: %s. Shit went south." (cdr error-thrown))) - ;; handle mastodon api errors - ;; they have the form (error http 401) - ((= (car (last error-thrown)) 401) - (message "Got error: %s Unauthorized: The access token is invalid" error-thrown)) - ((= (car (last error-thrown)) 422) - (message "Got error: %s Unprocessable entity: file or file type is unsupported or invalid" error-thrown)) - (t - (message "Got error: %s Shit went south" - error-thrown)))))))) + (request + url + :type "POST" + :params `(("description" . ,caption)) + :files `(("file" . (,file :file ,filename + :mime-type "multipart/form-data"))) + :parser 'json-read + :headers `(("Authorization" . ,(concat "Bearer " + (mastodon-auth--access-token)))) + :sync t + :success (cl-function + (lambda (&key data &allow-other-keys) + (when data + (progn + (push (cdr (assoc 'id data)) + mastodon-toot--media-attachment-ids) ; add ID to list + (message "%s file %s with id %S and caption '%s' uploaded!" + (capitalize (cdr (assoc 'type data))) + file + (cdr (assoc 'id data)) + (cdr (assoc 'description data))) + (mastodon-toot--update-status-fields))))) + :error (cl-function + (lambda (&key error-thrown &allow-other-keys) + (cond + ;; handle curl errors first (eg 26, can't read file/path) + ;; because the '=' test below fails for them + ;; they have the form (error . error message 24) + ((not (proper-list-p error-thrown)) ; not dotted list + (message "Got error: %s. Shit went south." (cdr error-thrown))) + ;; handle mastodon api errors + ;; they have the form (error http 401) + ((= (car (last error-thrown)) 401) + (message "Got error: %s Unauthorized: The access token is invalid" error-thrown)) + ((= (car (last error-thrown)) 422) + (message "Got error: %s Unprocessable entity: file or file type is unsupported or invalid" error-thrown)) + (t + (message "Got error: %s Shit went south" + error-thrown)))))))) (provide 'mastodon-http) ;;; mastodon-http.el ends here diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 2181ea2..4647335 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -59,7 +59,7 @@ (concat "*mastodon-inspect-toot-" (mastodon-tl--as-string (mastodon-tl--property 'toot-id)) "*") - (mastodon-tl--property 'toot-json))) + (mastodon-tl--property 'toot-json))) (defun mastodon-inspect--download-single-toot (toot-id) "Download the toot/status represented by TOOT-ID." diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 5f8f46c..f7386c6 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -161,7 +161,7 @@ with the image." t image-options)))) (when mastodon-media--enable-image-caching (unless (url-is-cached url) ; cache if not already cached - (url-store-in-cache url-buffer))) + (url-store-in-cache url-buffer))) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer (let ((inhibit-read-only t)) @@ -239,7 +239,7 @@ found." ;; Avatars are just one character in the buffer ((eq media-type 'avatar) (list next-pos (+ next-pos 1) 'avatar)) - ;; Media links are 5 character ("[img]") + ;; Media links are 5 character ("[img]") ((eq media-type 'media-link) (list next-pos (+ next-pos 5) 'media-link))))))) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 36f9d4a..2430bcc 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -80,23 +80,23 @@ (let* ((toot-json (mastodon-tl--property 'toot-json)) (f-req-p (string= "follow_request" (cdr (assoc 'type toot-json))))) (if f-req-p - (let* ((account (cdr (assoc 'account toot-json))) - (id (cdr (assoc 'id account))) - (handle (cdr (assoc 'acct account))) - (name (cdr (assoc 'username account)))) - (if id - (let ((response - (mastodon-http--post - (concat - (mastodon-http--api "follow_requests") - (format "/%s/authorize" id)) - nil nil))) - (mastodon-http--triage response - (lambda () - (mastodon-notifications--get) - (message "Follow request of %s (@%s) accepted!" - name handle)))) - (message "No account result at point?"))) + (let* ((account (cdr (assoc 'account toot-json))) + (id (cdr (assoc 'id account))) + (handle (cdr (assoc 'acct account))) + (name (cdr (assoc 'username account)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/authorize" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (mastodon-notifications--get) + (message "Follow request of %s (@%s) accepted!" + name handle)))) + (message "No account result at point?"))) (message "No follow request at point?"))))) (defun mastodon-notifications--follow-request-reject-notifs () @@ -106,23 +106,23 @@ (let* ((toot-json (mastodon-tl--property 'toot-json)) (f-req-p (string= "follow_request" (cdr (assoc 'type toot-json))))) (if f-req-p - (let* ((account (cdr (assoc 'account toot-json))) - (id (cdr (assoc 'id account))) - (handle (cdr (assoc 'acct account))) - (name (cdr (assoc 'username account)))) - (if id - (let ((response - (mastodon-http--post - (concat - (mastodon-http--api "follow_requests") - (format "/%s/reject" id)) - nil nil))) - (mastodon-http--triage response - (lambda () - (mastodon-notifications--get) - (message "Follow request of %s (@%s) rejected!" - name handle)))) - (message "No account result at point?"))) + (let* ((account (cdr (assoc 'account toot-json))) + (id (cdr (assoc 'id account))) + (handle (cdr (assoc 'acct account))) + (name (cdr (assoc 'username account)))) + (if id + (let ((response + (mastodon-http--post + (concat + (mastodon-http--api "follow_requests") + (format "/%s/reject" id)) + nil nil))) + (mastodon-http--triage response + (lambda () + (mastodon-notifications--get) + (message "Follow request of %s (@%s) rejected!" + name handle)))) + (message "No account result at point?"))) (message "No follow request at point?"))))) (defun mastodon-notifications--mention (note) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 31499ed..b68be6f 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -256,20 +256,20 @@ Returns a list of lists." (let* ((car-fields (mapcar 'car fields)) ;; (cdr-fields (mapcar 'cadr fields)) ;; (cdr-fields-rendered - ;; (list - ;; (mapcar (lambda (x) - ;; (mastodon-tl--render-text x nil)) - ;; cdr-fields))) + ;; (list + ;; (mapcar (lambda (x) + ;; (mastodon-tl--render-text x nil)) + ;; cdr-fields))) (left-width (car (sort (mapcar 'length car-fields) '>)))) - ;; (right-width (car (sort (mapcar 'length cdr-fields) '>)))) + ;; (right-width (car (sort (mapcar 'length cdr-fields) '>)))) (mapconcat (lambda (field) (mastodon-tl--render-text (concat (format "_ %s " (car field)) (make-string (- (+ 1 left-width) (length (car field))) ?_) (format " :: %s" (cadr field))) - ;; (make-string (- (+ 1 right-width) (length (cdr field))) ?_) - ;; " |") + ;; (make-string (- (+ 1 right-width) (length (cdr field))) ?_) + ;; " |") field)) ; nil)) ; hack to make links tabstops fields ""))) @@ -307,7 +307,7 @@ Returns a list of lists." account 'statuses_count))) (relationships (mastodon-profile--relationships-get id)) (followed-by-you (cdr (assoc 'following - (aref relationships 0)))) + (aref relationships 0)))) (follows-you (cdr (assoc 'followed_by (aref relationships 0)))) (followsp (or (equal follows-you 't) (equal followed-by-you 't))) @@ -327,9 +327,9 @@ Returns a list of lists." (is-followers (string= endpoint-type "followers")) (is-following (string= endpoint-type "following")) (endpoint-name (cond - (is-statuses " TOOTS ") - (is-followers " FOLLOWERS ") - (is-following " FOLLOWING ")))) + (is-statuses " TOOTS ") + (is-followers " FOLLOWERS ") + (is-following " FOLLOWING ")))) (insert "\n" (mastodon-profile--image-from-account account) @@ -382,7 +382,7 @@ Returns a list of lists." 'success)) (setq mastodon-tl--update-point (point)) (mastodon-media--inline-images (point-min) (point)) - ;; insert pinned toots first + ;; insert pinned toots first (when (and pinned (equal endpoint-type "statuses")) (mastodon-profile--insert-statuses-pinned pinned) (setq mastodon-tl--update-point (point))) ;updates to follow pinned toots diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 5f52bb7..cbb452d 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -80,7 +80,7 @@ Returns a nested list containing user handle, display name, and URL." (tags-list (mapcar #'mastodon-search--get-hashtag-info tags)) ;; (status-list (mapcar #'mastodon-search--get-status-info - ;; statuses)) + ;; statuses)) (status-ids-list (mapcar 'mastodon-search--get-id-from-status statuses)) (toots-list-json (mapcar #'mastodon-search--fetch-full-status-from-id @@ -97,42 +97,42 @@ Returns a nested list containing user handle, display name, and URL." " ------------\n\n") 'success)) (mapc (lambda (el) - (insert (propertize (car el) 'face 'mastodon-display-name-face) - " : \n : " - (propertize (concat "@" (car (cdr el))) - 'face 'mastodon-handle-face - 'mouse-face 'highlight - 'mastodon-tab-stop 'user-handle - 'keymap mastodon-tl--link-keymap - 'mastodon-handle (concat "@" (car (cdr el))) - 'help-echo (concat "Browse user profile of @" (car (cdr el)))) - " : \n" - "\n")) - user-ids) - ;; hashtag results: - (insert (mastodon-tl--set-face - (concat "\n ------------\n" - " HASHTAGS\n" - " ------------\n\n") - 'success)) - (mapc (lambda (el) - (insert " : #" - (propertize (car el) - 'mouse-face 'highlight - 'mastodon-tag (car el) - 'mastodon-tab-stop 'hashtag - 'help-echo (concat "Browse tag #" (car el)) - 'keymap mastodon-tl--link-keymap) - " : \n\n")) - tags-list) - ;; status results: - (insert (mastodon-tl--set-face - (concat "\n ------------\n" - " STATUSES\n" - " ------------\n") - 'success)) - (mapc 'mastodon-tl--toot toots-list-json) - (goto-char (point-min)))))) + (insert (propertize (car el) 'face 'mastodon-display-name-face) + " : \n : " + (propertize (concat "@" (car (cdr el))) + 'face 'mastodon-handle-face + 'mouse-face 'highlight + 'mastodon-tab-stop 'user-handle + 'keymap mastodon-tl--link-keymap + 'mastodon-handle (concat "@" (car (cdr el))) + 'help-echo (concat "Browse user profile of @" (car (cdr el)))) + " : \n" + "\n")) + user-ids) + ;; hashtag results: + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " HASHTAGS\n" + " ------------\n\n") + 'success)) + (mapc (lambda (el) + (insert " : #" + (propertize (car el) + 'mouse-face 'highlight + 'mastodon-tag (car el) + 'mastodon-tab-stop 'hashtag + 'help-echo (concat "Browse tag #" (car el)) + 'keymap mastodon-tl--link-keymap) + " : \n\n")) + tags-list) + ;; status results: + (insert (mastodon-tl--set-face + (concat "\n ------------\n" + " STATUSES\n" + " ------------\n") + 'success)) + (mapc 'mastodon-tl--toot toots-list-json) + (goto-char (point-min)))))) (defun mastodon-search--get-user-info (account) "Get user handle, display name and account URL from ACCOUNT." @@ -153,7 +153,7 @@ Returns a nested list containing user handle, display name, and URL." (cdr (assoc 'content status)))) (defun mastodon-search--get-id-from-status (status) - "Fetch the id from a STATUS returned by a search call to the server. + "Fetch the id from a STATUS returned by a search call to the server. We use this to fetch the complete status from the server." (cdr (assoc 'id status))) @@ -164,7 +164,7 @@ We use this to fetch the complete status from the server." This allows us to access the full account etc. details and to render them properly." (let* ((url (concat mastodon-instance-url "/api/v1/statuses/" (mastodon-tl--as-string id))) - (json (mastodon-http--get-json url))) + (json (mastodon-http--get-json url))) json)) (provide 'mastodon-search) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index e4c179c..d300a09 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -91,10 +91,10 @@ width fonts when rendering HTML text")) :type '(boolean :tag "Whether to display user avatars in timelines")) ;; (defvar mastodon-tl--show-avatars nil - ;; (if (version< emacs-version "27.1") - ;; (image-type-available-p 'imagemagick) - ;; (image-transforms-p)) - ;; "A boolean value stating whether to show avatars in timelines.") +;; (if (version< emacs-version "27.1") +;; (image-type-available-p 'imagemagick) +;; (image-transforms-p)) +;; "A boolean value stating whether to show avatars in timelines.") (defvar-local mastodon-tl--update-point nil "When updating a mastodon buffer this is where new toots will be inserted. @@ -463,7 +463,7 @@ START and END are the boundaries of the link in the toot." (url-instance (concat "https://" (url-host (url-generic-parse-url url)))) (maybe-userhandle (if (string= mastodon-instance-url url-instance) - ; if handle is local, then no instance suffix: + ; if handle is local, then no instance suffix: (buffer-substring-no-properties start end) (mastodon-tl--extract-userhandle-from-url url (buffer-substring-no-properties start end))))) @@ -652,12 +652,12 @@ message is a link which unhides/hides the main body." (mastodon-tl--render-text spoiler toot)) 'default)) (message (concat ;"\n" - " ---------------\n" - " " (mastodon-tl--make-link - (concat "CW: " string) - 'content-warning) - "\n" - " ---------------\n")) + " ---------------\n" + " " (mastodon-tl--make-link + (concat "CW: " string) + 'content-warning) + "\n" + " ---------------\n")) (cw (mastodon-tl--set-face message 'mastodon-cw-face))) (concat cw @@ -747,10 +747,10 @@ takes a single function. By default it is (concat "Poll: \n\n" (mapconcat (lambda (option) (progn - (format "Option %s: %s, %s votes.\n" - (setq option-counter (1+ option-counter)) - (cdr (assoc 'title option)) - (cdr (assoc 'votes_count option))))) + (format "Option %s: %s, %s votes.\n" + (setq option-counter (1+ option-counter)) + (cdr (assoc 'title option)) + (cdr (assoc 'votes_count option))))) options "\n") "\n"))) @@ -764,8 +764,8 @@ takes a single function. By default it is (mastodon-tl--field 'poll toot))) (options (mastodon-tl--field 'options poll)) (options-titles (mapcar (lambda (x) - (cdr (assoc 'title x))) - options)) + (cdr (assoc 'title x))) + options)) (options-number-seq (number-sequence 1 (length options))) (options-numbers (mapcar (lambda(x) (number-to-string x)) @@ -775,16 +775,16 @@ takes a single function. By default it is ;; but also store both as cons cell as cdr, as we need it below (candidates (mapcar (lambda (cell) (cons (format "%s | %s" (car cell) (cdr cell)) - cell)) + cell)) options-alist))) (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) (message "No poll here.") ;; var "option" = just the cdr, a cons of option number and desc (cdr (assoc (completing-read "Poll option to vote for: " - candidates - nil ; (predicate) - t) ; require match + candidates + nil ; (predicate) + t) ; require match candidates)))))) (if (null (mastodon-tl--field 'poll (mastodon-tl--property 'toot-json))) (message "No poll here.") @@ -961,7 +961,7 @@ webapp" nil ; predicate 'confirm)))) (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) + user-handle (mastodon-profile--toot-json))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) (url (mastodon-http--api (format "accounts/%s/follow" user-id)))) @@ -983,7 +983,7 @@ webapp" nil ; predicate 'confirm)))) (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) + user-handle (mastodon-profile--toot-json))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) (url (mastodon-http--api (format "accounts/%s/unfollow" user-id)))) @@ -1006,7 +1006,7 @@ webapp" nil ; predicate 'confirm)))) (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) + user-handle (mastodon-profile--toot-json))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) (url (mastodon-http--api (format "accounts/%s/mute" user-id)))) @@ -1026,7 +1026,7 @@ webapp" (mutes-json (mastodon-http--get-json mutes-url)) (muted-accts (mapcar (lambda (muted) (cdr (assoc 'acct muted))) - mutes-json))) + mutes-json))) (completing-read "Handle of user to unmute: " muted-accts nil ; predicate @@ -1055,7 +1055,7 @@ webapp" nil ; predicate 'confirm)))) (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) + user-handle (mastodon-profile--toot-json))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) (url (mastodon-http--api (format "accounts/%s/block" user-id)))) @@ -1074,7 +1074,7 @@ webapp" (let* ((blocks-url (mastodon-http--api (format "blocks"))) (blocks-json (mastodon-http--get-json blocks-url)) (blocked-accts (mapcar (lambda (blocked) - (cdr (assoc 'acct blocked))) + (cdr (assoc 'acct blocked))) blocks-json))) (completing-read "Handle of user to unblock: " blocked-accts diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 07b52e3..22eb626 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -184,9 +184,9 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." "Take ACTION on toot at point, then execute CALLBACK." (let* ((id (mastodon-tl--property 'base-toot-id)) (url (mastodon-http--api (concat "statuses/" - (mastodon-tl--as-string id) - "/" - action)))) + (mastodon-tl--as-string id) + "/" + action)))) (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response callback)))) @@ -312,7 +312,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (with-current-buffer response (let* ((json-response (mastodon-http--process-json)) (content (cdr (assoc 'text json-response)))) - ;; (media (cdr (assoc 'media_attachments json-response)))) + ;; (media (cdr (assoc 'media_attachments json-response)))) (mastodon-toot--compose-buffer nil nil) (goto-char (point-max)) (insert content) @@ -338,8 +338,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (format "Toot already bookmarked. Remove? ") (format "Bookmark this toot? "))) (message (if (equal bookmarked t) - "Bookmark removed!" - "Toot bookmarked!"))) + "Bookmark removed!" + "Toot bookmarked!"))) (when (y-or-n-p prompt) (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response @@ -496,10 +496,10 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." "Extract mentions from STATUS and process them into a string." (interactive) (let* ((boosted (mastodon-tl--field 'reblog status)) - (mentions - (if boosted - (cdr (assoc 'mentions (cdr (assoc 'reblog status)))) - (cdr (assoc 'mentions status))))) + (mentions + (if boosted + (cdr (assoc 'mentions (cdr (assoc 'reblog status)))) + (cdr (assoc 'mentions status))))) (mapconcat (lambda(x) (mastodon-toot--process-local (cdr (assoc 'acct x)))) ;; reverse does not work on vectors in 24.5 @@ -534,19 +534,19 @@ The prefix can match against both user handles and display names." (defun mastodon-toot--mentions-completion (command &optional arg &rest ignored) "A company completion backend for toot mentions." - (interactive (list 'interactive)) - (cl-case command - (interactive (company-begin-backend 'mastodon-toot--mentions-completion)) - (prefix (when (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode - (save-excursion - (forward-whitespace -1) - (forward-whitespace 1) - (looking-at "@"))) - ;; @ + thing before point - (concat "@" (company-grab-symbol)))) - (candidates (mastodon-toot--mentions-company-candidates arg)) - (annotation (mastodon-toot--mentions-company-annotation arg)) - (meta (mastodon-toot--mentions-company-meta arg)))) + (interactive (list 'interactive)) + (cl-case command + (interactive (company-begin-backend 'mastodon-toot--mentions-completion)) + (prefix (when (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode + (save-excursion + (forward-whitespace -1) + (forward-whitespace 1) + (looking-at "@"))) + ;; @ + thing before point + (concat "@" (company-grab-symbol)))) + (candidates (mastodon-toot--mentions-company-candidates arg)) + (annotation (mastodon-toot--mentions-company-annotation arg)) + (meta (mastodon-toot--mentions-company-meta arg)))) (defun mastodon-toot--reply () "Reply to toot at `point'." @@ -803,38 +803,38 @@ REPLY-JSON is the full JSON of the toot being replied to." "Update the status fields in the header based on the current state." (ignore-errors ;; called from after-change-functions so let's not leak errors (let ((inhibit-read-only t) - (header-region (mastodon-tl--find-property-range 'toot-post-header + (header-region (mastodon-tl--find-property-range 'toot-post-header + (point-min))) + (count-region (mastodon-tl--find-property-range 'toot-post-counter (point-min))) - (count-region (mastodon-tl--find-property-range 'toot-post-counter + (visibility-region (mastodon-tl--find-property-range + 'toot-post-visibility (point-min))) + (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag (point-min))) - (visibility-region (mastodon-tl--find-property-range - 'toot-post-visibility (point-min))) - (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag - (point-min))) - (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag - (point-min)))) - (add-text-properties (car count-region) (cdr count-region) - (list 'display - (format "%s/%s characters" - (- (point-max) (cdr header-region)) - mastodon-toot--max-toot-chars))) - (add-text-properties (car visibility-region) (cdr visibility-region) - (list 'display - (format "Visibility: %s" - (if (equal - mastodon-toot--visibility - "private") - "followers-only" - mastodon-toot--visibility)))) - (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)") - "") - 'face 'mastodon-cw-face)) - (add-text-properties (car cw-region) (cdr cw-region) - (list 'invisible (not mastodon-toot--content-warning) - 'face 'mastodon-cw-face))))) + (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag + (point-min)))) + (add-text-properties (car count-region) (cdr count-region) + (list 'display + (format "%s/%s characters" + (- (point-max) (cdr header-region)) + mastodon-toot--max-toot-chars))) + (add-text-properties (car visibility-region) (cdr visibility-region) + (list 'display + (format "Visibility: %s" + (if (equal + mastodon-toot--visibility + "private") + "followers-only" + mastodon-toot--visibility)))) + (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)") + "") + 'face 'mastodon-cw-face)) + (add-text-properties (car cw-region) (cdr cw-region) + (list 'invisible (not mastodon-toot--content-warning) + 'face 'mastodon-cw-face))))) (defun mastodon-toot--compose-buffer (reply-to-user reply-to-id &optional reply-json) "Create a new buffer to capture text for a new toot. diff --git a/lisp/mastodon.el b/lisp/mastodon.el index d405bed..826787a 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -204,8 +204,8 @@ Use. e.g. \"%c\" for your locale's date and time format." "favourites" "search")) (buffer (cl-some (lambda (el) - (get-buffer (concat "*mastodon-" el "*"))) - tls))) ; return first buff that exists + (get-buffer (concat "*mastodon-" el "*"))) + tls))) ; return first buff that exists (if buffer (switch-to-buffer buffer) (mastodon-tl--get-home-timeline) diff --git a/test/mastodon-auth-tests.el b/test/mastodon-auth-tests.el index 7daa4db..69c34a4 100644 --- a/test/mastodon-auth-tests.el +++ b/test/mastodon-auth-tests.el @@ -45,10 +45,10 @@ "Should generate token and return JSON response." (with-temp-buffer (with-mock - (mock (mastodon-auth--generate-token) => (progn - (insert "\n\n{\"access_token\":\"abcdefg\"}") - (current-buffer))) - (should (equal (mastodon-auth--get-token) '(:access_token "abcdefg")))))) + (mock (mastodon-auth--generate-token) => (progn + (insert "\n\n{\"access_token\":\"abcdefg\"}") + (current-buffer))) + (should (equal (mastodon-auth--get-token) '(:access_token "abcdefg")))))) (ert-deftest access-token-found () "Should return value in `mastodon-auth--token-alist' if found." @@ -61,6 +61,6 @@ (let ((mastodon-instance-url "https://instance.url") (mastodon-auth--token nil)) (with-mock - (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) - (should (string= (mastodon-auth--access-token) "foobaz")) - (should (equal mastodon-auth--token-alist '(("https://instance.url" . "foobaz"))))))) + (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) + (should (string= (mastodon-auth--access-token) "foobaz")) + (should (equal mastodon-auth--token-alist '(("https://instance.url" . "foobaz"))))))) diff --git a/test/mastodon-client-tests.el b/test/mastodon-client-tests.el index dfe175b..d7f750d 100644 --- a/test/mastodon-client-tests.el +++ b/test/mastodon-client-tests.el @@ -17,30 +17,30 @@ "Should return client registration JSON." (with-temp-buffer (with-mock - (mock (mastodon-client--register) => (progn - (insert "\n\n{\"foo\":\"bar\"}") - (current-buffer))) - (should (equal (mastodon-client--fetch) '(:foo "bar")))))) + (mock (mastodon-client--register) => (progn + (insert "\n\n{\"foo\":\"bar\"}") + (current-buffer))) + (should (equal (mastodon-client--fetch) '(:foo "bar")))))) (ert-deftest store-1 () "Should return the client plist." (let ((mastodon-instance-url "http://mastodon.example") (plist '(:client_id "id" :client_secret "secret"))) (with-mock - (mock (mastodon-client--token-file) => "stubfile.plstore") - (mock (mastodon-client--fetch) => '(:client_id "id" :client_secret "secret")) - (let* ((plstore (plstore-open "stubfile.plstore")) - (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) - (should (equal (mastodon-client--store) plist)))))) + (mock (mastodon-client--token-file) => "stubfile.plstore") + (mock (mastodon-client--fetch) => '(:client_id "id" :client_secret "secret")) + (let* ((plstore (plstore-open "stubfile.plstore")) + (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) + (should (equal (mastodon-client--store) plist)))))) (ert-deftest store-2 () - "Should store client in `mastodon-client--token-file'." - (let* ((mastodon-instance-url "http://mastodon.example") - (plstore (plstore-open "stubfile.plstore")) - (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) - (plstore-close plstore) - (should (string= (plist-get client :client_id) "id")) - (should (string= (plist-get client :client_secret) "secret")))) + "Should store client in `mastodon-client--token-file'." + (let* ((mastodon-instance-url "http://mastodon.example") + (plstore (plstore-open "stubfile.plstore")) + (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) + (plstore-close plstore) + (should (string= (plist-get client :client_id) "id")) + (should (string= (plist-get client :client_secret) "secret")))) (ert-deftest read-finds-match () "Should return mastodon client from `mastodon-token-file' if it exists." @@ -60,8 +60,8 @@ (ert-deftest read-empty-store () "Should return nil if mastodon client is not present in the plstore." (with-mock - (mock (mastodon-client--token-file) => "fixture/empty.plstore") - (should (equal (mastodon-client--read) nil)))) + (mock (mastodon-client--token-file) => "fixture/empty.plstore") + (should (equal (mastodon-client--read) nil)))) (ert-deftest client-set-and-matching () "Should return `mastondon-client' if `mastodon-client--client-details-alist' is non-nil and instance url is included." @@ -75,29 +75,29 @@ (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist '(("http://other.example" :wrong)))) (with-mock - (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) - (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) - (should (equal mastodon-client--client-details-alist - '(("http://mastodon.example" :client_id "foo" :client_secret "bar") - ("http://other.example" :wrong))))))) + (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) + (should (equal mastodon-client--client-details-alist + '(("http://mastodon.example" :client_id "foo" :client_secret "bar") + ("http://other.example" :wrong))))))) (ert-deftest client-unset () "Should read from `mastodon-token-file' if available." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) (with-mock - (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) - (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) - (should (equal mastodon-client--client-details-alist - '(("http://mastodon.example" :client_id "foo" :client_secret "bar"))))))) + (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) + (should (equal mastodon-client--client-details-alist + '(("http://mastodon.example" :client_id "foo" :client_secret "bar"))))))) (ert-deftest client-unset-and-not-in-storage () "Should store client data in plstore if it can't be read." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) (with-mock - (mock (mastodon-client--read)) - (mock (mastodon-client--store) => '(:client_id "foo" :client_secret "baz")) - (should (equal (mastodon-client) '(:client_id "foo" :client_secret "baz"))) - (should (equal mastodon-client--client-details-alist - '(("http://mastodon.example" :client_id "foo" :client_secret "baz"))))))) + (mock (mastodon-client--read)) + (mock (mastodon-client--store) => '(:client_id "foo" :client_secret "baz")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "baz"))) + (should (equal mastodon-client--client-details-alist + '(("http://mastodon.example" :client_id "foo" :client_secret "baz"))))))) diff --git a/test/mastodon-http-tests.el b/test/mastodon-http-tests.el index d0f715e..03d4f94 100644 --- a/test/mastodon-http-tests.el +++ b/test/mastodon-http-tests.el @@ -4,6 +4,6 @@ "Should make a `url-retrieve' of the given URL." (let ((callback-double (lambda () "double"))) (with-mock - (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) - (mock (mastodon-auth--access-token) => "test-token") - (mastodon-http--get "https://foo.bar/baz")))) + (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) + (mock (mastodon-auth--access-token) => "test-token") + (mastodon-http--get "https://foo.bar/baz")))) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index 20993f9..b537dfe 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -3,143 +3,143 @@ (ert-deftest mastodon-media:get-avatar-rendering () "Should return text with all expected properties." (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => :mock-image) - - (let* ((mastodon-media--avatar-height 123) - (result (mastodon-media--get-avatar-rendering "http://example.org/img.png")) - (result-no-properties (substring-no-properties result)) - (properties (text-properties-at 0 result))) - (should (string= " " result-no-properties)) - (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) - (should (eq 'needs-loading (plist-get properties 'media-state))) - (should (eq 'avatar (plist-get properties 'media-type))) - (should (eq :mock-image (plist-get properties 'display)))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => :mock-image) + + (let* ((mastodon-media--avatar-height 123) + (result (mastodon-media--get-avatar-rendering "http://example.org/img.png")) + (result-no-properties (substring-no-properties result)) + (properties (text-properties-at 0 result))) + (should (string= " " result-no-properties)) + (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) + (should (eq 'needs-loading (plist-get properties 'media-state))) + (should (eq 'avatar (plist-get properties 'media-type))) + (should (eq :mock-image (plist-get properties 'display)))))) (ert-deftest mastodon-media:get-media-link-rendering () "Should return text with all expected properties." (with-mock - (mock (create-image * nil t) => :mock-image) - - (let* ((mastodon-media--preview-max-height 123) - (result (mastodon-media--get-media-link-rendering "http://example.org/img.png")) - (result-no-properties (substring-no-properties result)) - (properties (text-properties-at 0 result))) - (should (string= "[img] " result-no-properties)) - (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) - (should (eq 'needs-loading (plist-get properties 'media-state))) - (should (eq 'media-link (plist-get properties 'media-type))) - (should (eq :mock-image (plist-get properties 'display)))))) + (mock (create-image * nil t) => :mock-image) + + (let* ((mastodon-media--preview-max-height 123) + (result (mastodon-media--get-media-link-rendering "http://example.org/img.png")) + (result-no-properties (substring-no-properties result)) + (properties (text-properties-at 0 result))) + (should (string= "[img] " result-no-properties)) + (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) + (should (eq 'needs-loading (plist-get properties 'media-state))) + (should (eq 'media-link (plist-get properties 'media-type))) + (should (eq :mock-image (plist-get properties 'display)))))) (ert-deftest mastodon-media:load-image-from-url:avatar-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image - * - (when (version< emacs-version "27.1") 'imagemagick) - t :height 123) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - url - #'mastodon-media--process-image-response - `(:my-marker (:height 123) 1 ,url)) - => :called-as-expected) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering "http://example.org/img.png") - ":rest")) - - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image + * + (when (version< emacs-version "27.1") 'imagemagick) + t :height 123) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + url + #'mastodon-media--process-image-response + `(:my-marker (:height 123) 1 ,url)) + => :called-as-expected) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering "http://example.org/img.png") + ":rest")) + + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) (ert-deftest mastodon-media:load-image-from-url:avatar-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock - (mock (image-type-available-p 'imagemagick) => nil) - (mock (create-image * nil t) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - url - #'mastodon-media--process-image-response - `(:my-marker () 1 ,url)) - => :called-as-expected) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering "http://example.org/img.png") - ":rest")) - - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) + (mock (image-type-available-p 'imagemagick) => nil) + (mock (create-image * nil t) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + url + #'mastodon-media--process-image-response + `(:my-marker () 1 ,url)) + => :called-as-expected) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering "http://example.org/img.png") + ":rest")) + + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) (ert-deftest mastodon-media:load-image-from-url:media-link-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * nil t) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - "http://example.org/image.png" - #'mastodon-media--process-image-response - '(:my-marker (:max-height 321) 5 "http://example.org/image.png")) - => :called-as-expected) - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-media-link-rendering url) - ":rest")) - (let ((mastodon-media--preview-max-height 321)) - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image * nil t) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + "http://example.org/image.png" + #'mastodon-media--process-image-response + '(:my-marker (:max-height 321) 5 "http://example.org/image.png")) + => :called-as-expected) + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-media-link-rendering url) + ":rest")) + (let ((mastodon-media--preview-max-height 321)) + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) (ert-deftest mastodon-media:load-image-from-url:media-link-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock - (mock (image-type-available-p 'imagemagick) => nil) - (mock (create-image * nil t) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - "http://example.org/image.png" - #'mastodon-media--process-image-response - '(:my-marker () 5 "http://example.org/image.png")) - => :called-as-expected) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering url) - ":rest")) - (let ((mastodon-media--preview-max-height 321)) - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) + (mock (image-type-available-p 'imagemagick) => nil) + (mock (create-image * nil t) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + "http://example.org/image.png" + #'mastodon-media--process-image-response + '(:my-marker () 5 "http://example.org/image.png")) + => :called-as-expected) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering url) + ":rest")) + (let ((mastodon-media--preview-max-height 321)) + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) (ert-deftest mastodon-media:load-image-from-url:url-fetching-fails () "Should cope with failures in url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image - * - (when (version< emacs-version "27.1") 'imagemagick) - t :height 123) => '(image foo)) - (stub url-retrieve => (error "url-retrieve failed")) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering "http://example.org/img.png") - ":rest")) - - (should (eq :loading-failed (mastodon-media--load-image-from-url url 'avatar 7 1))) - ;; the media state was updated so we won't load this again: - (should (eq 'loading-failed (get-text-property 7 'media-state))))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image + * + (when (version< emacs-version "27.1") 'imagemagick) + t :height 123) => '(image foo)) + (stub url-retrieve => (error "url-retrieve failed")) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering "http://example.org/img.png") + ":rest")) + + (should (eq :loading-failed (mastodon-media--load-image-from-url url 'avatar 7 1))) + ;; the media state was updated so we won't load this again: + (should (eq 'loading-failed (get-text-property 7 'media-state))))))) (ert-deftest mastodon-media:process-image-response () "Should process the HTTP response and adjust the source buffer." (with-temp-buffer (with-mock - (let ((source-buffer (current-buffer)) + (let ((source-buffer (current-buffer)) used-marker saved-marker) (insert "start:") @@ -175,35 +175,35 @@ (ert-deftest mastodon-media:inline-images () "Should process all media in buffer." (with-mock - ;; Stub needed for the test setup: - (stub create-image => '(image ignored)) - - (let (marker-media-link marker-media-link-bad-url marker-false-media marker-avatar) - (with-temp-buffer - (insert "Some text before\n") - (setq marker-media-link (copy-marker (point))) - (insert (mastodon-media--get-media-link-rendering "http://example.org/i.jpg") - " some more text ") - (setq marker-media-link-bad-url (copy-marker (point))) - (insert (mastodon-media--get-media-link-rendering "/files/small/missing.png") - " some more text ") - (setq marker-false-media (copy-marker (point))) - (insert - ;; text that looks almost like an avatar but lacks the media-url property - (propertize "this won't be processed" - 'media-state 'needs-loading - 'media-type 'avatar) - "even more text ") - (setq marker-avatar (copy-marker (point))) - (insert (mastodon-media--get-avatar-rendering "http://example.org/avatar.png") - " end of text") - (goto-char (point-min)) - - ;; stub for the actual test: - (stub mastodon-media--load-image-from-url) - (mastodon-media--inline-images (point-min) (point-max)) - - (should (eq 'loading (get-text-property marker-media-link 'media-state))) - (should (eq 'invalid-url (get-text-property marker-media-link-bad-url 'media-state))) - (should (eq 'loading (get-text-property marker-avatar 'media-state))) - (should (eq 'needs-loading (get-text-property marker-false-media 'media-state))))))) + ;; Stub needed for the test setup: + (stub create-image => '(image ignored)) + + (let (marker-media-link marker-media-link-bad-url marker-false-media marker-avatar) + (with-temp-buffer + (insert "Some text before\n") + (setq marker-media-link (copy-marker (point))) + (insert (mastodon-media--get-media-link-rendering "http://example.org/i.jpg") + " some more text ") + (setq marker-media-link-bad-url (copy-marker (point))) + (insert (mastodon-media--get-media-link-rendering "/files/small/missing.png") + " some more text ") + (setq marker-false-media (copy-marker (point))) + (insert + ;; text that looks almost like an avatar but lacks the media-url property + (propertize "this won't be processed" + 'media-state 'needs-loading + 'media-type 'avatar) + "even more text ") + (setq marker-avatar (copy-marker (point))) + (insert (mastodon-media--get-avatar-rendering "http://example.org/avatar.png") + " end of text") + (goto-char (point-min)) + + ;; stub for the actual test: + (stub mastodon-media--load-image-from-url) + (mastodon-media--inline-images (point-min) (point-max)) + + (should (eq 'loading (get-text-property marker-media-link 'media-state))) + (should (eq 'invalid-url (get-text-property marker-media-link-bad-url 'media-state))) + (should (eq 'loading (get-text-property marker-avatar 'media-state))) + (should (eq 'needs-loading (get-text-property marker-false-media 'media-state))))))) diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el index 778d350..3047ae6 100644 --- a/test/mastodon-notifications-test.el +++ b/test/mastodon-notifications-test.el @@ -185,8 +185,8 @@ "Ensure get request format for notifictions is accurate." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications" )) - (mastodon-notifications--get)))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications" )) + (mastodon-notifications--get)))) (defun mastodon-notifications--test-type (fun sample) "Test notification draw functions. diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index 24de5d0..4edf5d5 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -114,19 +114,19 @@ (ert-deftest as-string-1 () "Should accept a string or number and return a string." (let ((id "1000")) - (should (string= (mastodon-tl--as-string id) id)))) + (should (string= (mastodon-tl--as-string id) id)))) (ert-deftest as-string-2 () "Should accept a string or number and return a string." (let ((id 1000)) - (should (string= (mastodon-tl--as-string id) (number-to-string id))))) + (should (string= (mastodon-tl--as-string id) (number-to-string id))))) (ert-deftest more-json () "Should request toots older than max_id." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) - (mastodon-tl--more-json "timelines/foo" 12345)))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) + (mastodon-tl--more-json "timelines/foo" 12345)))) (ert-deftest more-json-id-string () "Should request toots older than max_id. @@ -135,8 +135,8 @@ a string or a numeric." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) - (mastodon-tl--more-json "timelines/foo" "12345")))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) + (mastodon-tl--more-json "timelines/foo" "12345")))) (ert-deftest update-json-id-string () "Should request toots more recent than since_id. @@ -145,8 +145,8 @@ a string or a numeric." a string or a numeric." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?since_id=12345")) - (mastodon-tl--updated-json "timelines/foo" "12345")))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?since_id=12345")) + (mastodon-tl--updated-json "timelines/foo" "12345")))) (ert-deftest mastodon-tl--relative-time-description () "Should format relative time as expected" @@ -156,10 +156,10 @@ a string or a numeric." (weeks (n) (* n (days 7))) (years (n) (* n (days 365))) (format-seconds-since (seconds) - (let ((timestamp (time-subtract (current-time) (seconds-to-time seconds)))) - (mastodon-tl--relative-time-description timestamp))) + (let ((timestamp (time-subtract (current-time) (seconds-to-time seconds)))) + (mastodon-tl--relative-time-description timestamp))) (check (seconds expected) - (should (string= (format-seconds-since 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") @@ -195,33 +195,33 @@ a string or a numeric." (weeks (n) (* n (days 7))) (years (n) (* n (days 365.25))) (next-update (seconds-ago) - (let* ((timestamp (time-subtract current-time - (seconds-to-time seconds-ago)))) - (cdr (mastodon-tl--relative-time-details timestamp current-time)))) + (let* ((timestamp (time-subtract current-time + (seconds-to-time seconds-ago)))) + (cdr (mastodon-tl--relative-time-details timestamp current-time)))) (check (seconds-ago) - (let* ((timestamp (time-subtract current-time (seconds-to-time seconds-ago))) - (at-now (mastodon-tl--relative-time-description timestamp current-time)) - (at-one-second-before (mastodon-tl--relative-time-description - timestamp - (time-subtract (next-update seconds-ago) - (seconds-to-time 1)))) - (at-result (mastodon-tl--relative-time-description - timestamp - (next-update seconds-ago)))) - (when nil ;; change to t to debug test failures - (prin1 (format "\nFor %s: %s / %s" - seconds-ago - (time-to-seconds - (time-subtract (next-update seconds-ago) - timestamp)) - (round - (time-to-seconds - (time-subtract (next-update seconds-ago) - current-time)))))) - ;; a second earlier the description is the same as at current time - (should (string= at-now at-one-second-before)) - ;; but at the result time it is different - (should-not (string= at-one-second-before at-result))))) + (let* ((timestamp (time-subtract current-time (seconds-to-time seconds-ago))) + (at-now (mastodon-tl--relative-time-description timestamp current-time)) + (at-one-second-before (mastodon-tl--relative-time-description + timestamp + (time-subtract (next-update seconds-ago) + (seconds-to-time 1)))) + (at-result (mastodon-tl--relative-time-description + timestamp + (next-update seconds-ago)))) + (when nil ;; change to t to debug test failures + (prin1 (format "\nFor %s: %s / %s" + seconds-ago + (time-to-seconds + (time-subtract (next-update seconds-ago) + timestamp)) + (round + (time-to-seconds + (time-subtract (next-update seconds-ago) + current-time)))))) + ;; a second earlier the description is the same as at current time + (should (string= at-now at-one-second-before)) + ;; but at the result time it is different + (should-not (string= at-one-second-before at-result))))) (check 0) (check 1) (check 59) @@ -253,39 +253,39 @@ a string or a numeric." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (let ((byline (mastodon-tl--byline mastodon-tl-test-base-toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - (handle-location 20)) - (should (string= (substring-no-properties - byline) - "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (let ((byline (mastodon-tl--byline mastodon-tl-test-base-toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + (handle-location 20)) + (should (string= (substring-no-properties + byline) + "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ ")) - (should (eq (get-text-property handle-location 'mastodon-tab-stop byline) - 'user-handle)) - (should (string= (get-text-property handle-location 'mastodon-handle byline) - "@acct42@example.space")) - (should (equal (get-text-property handle-location 'help-echo byline) - "Browse user profile of @acct42@example.space")))))) + (should (eq (get-text-property handle-location 'mastodon-tab-stop byline) + 'user-handle)) + (should (string= (get-text-property handle-location 'mastodon-handle byline) + "@acct42@example.space")) + (should (equal (get-text-property handle-location 'help-echo byline) + "Browse user profile of @acct42@example.space")))))) (ert-deftest mastodon-tl--byline-regular-with-avatar () "Should format the regular toot correctly." (let ((mastodon-tl--show-avatars-p t) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock - (stub create-image => '(image "fake data")) - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline mastodon-tl-test-base-toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (stub create-image => '(image "fake data")) + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline mastodon-tl-test-base-toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -295,14 +295,14 @@ a string or a numeric." (toot (cons '(reblogged . t) mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -312,14 +312,14 @@ a string or a numeric." (toot (cons '(favourited . t) mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -330,14 +330,14 @@ a string or a numeric." (toot `((favourited . t) (reblogged . t) ,@mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(B) (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(B) (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -349,31 +349,31 @@ a string or a numeric." (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock - ;; We don't expect to use the toot's timestamp but the timestamp of the - ;; reblogged toot: - (mock (date-to-time timestamp) => '(1 2)) - (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") - (mock (date-to-time original-timestamp) => '(3 4)) - (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") - - (let ((byline (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - (handle1-location 20) - (handle2-location 65)) - (should (string= (substring-no-properties byline) - "Account 42 (@acct42@example.space) + ;; We don't expect to use the toot's timestamp but the timestamp of the + ;; reblogged toot: + (mock (date-to-time timestamp) => '(1 2)) + (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") + (mock (date-to-time original-timestamp) => '(3 4)) + (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") + + (let ((byline (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + (handle1-location 20) + (handle2-location 65)) + (should (string= (substring-no-properties byline) + "Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time ------------ ")) - (should (eq (get-text-property handle1-location 'mastodon-tab-stop byline) - 'user-handle)) - (should (equal (get-text-property handle1-location 'help-echo byline) - "Browse user profile of @acct42@example.space")) - (should (eq (get-text-property handle2-location 'mastodon-tab-stop byline) - 'user-handle)) - (should (equal (get-text-property handle2-location 'help-echo byline) - "Browse user profile of @acct43@example.space")))))) + (should (eq (get-text-property handle1-location 'mastodon-tab-stop byline) + 'user-handle)) + (should (equal (get-text-property handle1-location 'help-echo byline) + "Browse user profile of @acct42@example.space")) + (should (eq (get-text-property handle2-location 'mastodon-tab-stop byline) + 'user-handle)) + (should (equal (get-text-property handle2-location 'help-echo byline) + "Browse user profile of @acct43@example.space")))))) (ert-deftest mastodon-tl--byline-reblogged-with-avatars () "Should format the reblogged toot correctly." @@ -383,19 +383,19 @@ a string or a numeric." (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock - ;; We don't expect to use the toot's timestamp but the timestamp of the - ;; reblogged toot: - (stub create-image => '(image "fake data")) - (mock (date-to-time timestamp) => '(1 2)) - (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") - (mock (date-to-time original-timestamp) => '(3 4)) - (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "Account 42 (@acct42@example.space) + ;; We don't expect to use the toot's timestamp but the timestamp of the + ;; reblogged toot: + (stub create-image => '(image "fake data")) + (mock (date-to-time timestamp) => '(1 2)) + (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") + (mock (date-to-time original-timestamp) => '(3 4)) + (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time ------------ "))))) @@ -408,17 +408,17 @@ a string or a numeric." (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock - ;; We don't expect to use the toot's timestamp but the timestamp of the - ;; reblogged toot: - (mock (date-to-time timestamp) => '(1 2)) - (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") - (mock (date-to-time original-timestamp) => '(3 4)) - (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) + ;; We don't expect to use the toot's timestamp but the timestamp of the + ;; reblogged toot: + (mock (date-to-time timestamp) => '(1 2)) + (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") + (mock (date-to-time original-timestamp) => '(3 4)) + (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) "(B) (F) Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time ------------ @@ -429,17 +429,17 @@ a string or a numeric." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (current-time) => '(22782 22000)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (let* ((formatted-string (mastodon-tl--byline mastodon-tl-test-base-toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - (timestamp-start (string-match "2999-99-99" formatted-string)) - (properties (text-properties-at timestamp-start formatted-string))) - (should (equal '(22782 21551) (plist-get properties 'timestamp))) - (should (string-equal "7 minutes ago" (plist-get properties 'display))))))) + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (current-time) => '(22782 22000)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (let* ((formatted-string (mastodon-tl--byline mastodon-tl-test-base-toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + (timestamp-start (string-match "2999-99-99" formatted-string)) + (properties (text-properties-at timestamp-start formatted-string))) + (should (equal '(22782 21551) (plist-get properties 'timestamp))) + (should (string-equal "7 minutes ago" (plist-get properties 'display))))))) (ert-deftest mastodon-tl--consider-timestamp-for-updates-no-active-callback () "Should update the timestamp update variables as expected." @@ -454,33 +454,33 @@ a string or a numeric." ;; something a later update doesn't update: (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (null mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) + (should (null mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something only shortly sooner doesn't update: (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" (time-subtract long-in-the-future (seconds-to-time 9)))) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" (time-subtract long-in-the-future (seconds-to-time 9)))) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (null mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) + (should (null mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something much sooner, does update (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" soon-in-the-future)) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" soon-in-the-future)) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (null mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) + (should (null mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) ))) (ert-deftest mastodon-tl--consider-timestamp-for-updates-with-active-callback () @@ -496,27 +496,27 @@ a string or a numeric." ;; something a later update doesn't update: (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (eq 'initial-timer mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) + (should (eq 'initial-timer mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something much sooner, does update (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" soon-in-the-future)) - (mock (cancel-timer 'initial-timer)) - (mock (run-at-time soon-in-the-future nil - #'mastodon-tl--update-timestamps-callback - (current-buffer) nil) => 'new-timer) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" soon-in-the-future)) + (mock (cancel-timer 'initial-timer)) + (mock (run-at-time soon-in-the-future nil + #'mastodon-tl--update-timestamps-callback + (current-buffer) nil) => 'new-timer) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (eq 'new-timer mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) + (should (eq 'new-timer mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) ))) (ert-deftest mastodon-tl--find-property-range--no-tag () @@ -769,45 +769,45 @@ constant." (let ((now (current-time)) markers) (cl-labels ((insert-timestamp (n) - (insert (format "\nSome text before timestamp %s:" n)) - (insert (propertize - (format "timestamp #%s" n) - 'timestamp (time-subtract now (seconds-to-time (* 60 n))) - 'display (format "unset %s" n))) - (push (copy-marker (point)) markers) - (insert " some more text."))) + (insert (format "\nSome text before timestamp %s:" n)) + (insert (propertize + (format "timestamp #%s" n) + 'timestamp (time-subtract now (seconds-to-time (* 60 n))) + 'display (format "unset %s" n))) + (push (copy-marker (point)) markers) + (insert " some more text."))) (with-temp-buffer (cl-dotimes (n 12) (insert-timestamp (+ n 2))) (setq markers (nreverse markers)) (with-mock - (mock (current-time) => now) - (stub run-at-time => 'fake-timer) - - ;; make the initial call - (mastodon-tl--update-timestamps-callback (current-buffer) nil) - (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" - "unset 7" "unset 8" "unset 9" "unset 10" "unset 11" "unset 12" "unset 13") - (tl-tests--property-values-at 'display - (tl-tests--all-regions-with-property 'timestamp)))) - - ;; fake the follow-up call - (mastodon-tl--update-timestamps-callback (current-buffer) (nth 4 markers)) - (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" - "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" - "unset 12" "unset 13") - (tl-tests--property-values-at 'display - (tl-tests--all-regions-with-property 'timestamp)))) - (should (null (marker-position (nth 4 markers)))) - - ;; fake the follow-up call - (mastodon-tl--update-timestamps-callback (current-buffer) (nth 9 markers)) - (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" - "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" - "12 minutes ago" "13 minutes ago") - (tl-tests--property-values-at 'display - (tl-tests--all-regions-with-property 'timestamp)))) - (should (null (marker-position (nth 9 markers))))))))) + (mock (current-time) => now) + (stub run-at-time => 'fake-timer) + + ;; make the initial call + (mastodon-tl--update-timestamps-callback (current-buffer) nil) + (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" + "unset 7" "unset 8" "unset 9" "unset 10" "unset 11" "unset 12" "unset 13") + (tl-tests--property-values-at 'display + (tl-tests--all-regions-with-property 'timestamp)))) + + ;; fake the follow-up call + (mastodon-tl--update-timestamps-callback (current-buffer) (nth 4 markers)) + (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" + "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" + "unset 12" "unset 13") + (tl-tests--property-values-at 'display + (tl-tests--all-regions-with-property 'timestamp)))) + (should (null (marker-position (nth 4 markers)))) + + ;; fake the follow-up call + (mastodon-tl--update-timestamps-callback (current-buffer) (nth 9 markers)) + (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" + "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" + "12 minutes ago" "13 minutes ago") + (tl-tests--property-values-at 'display + (tl-tests--all-regions-with-property 'timestamp)))) + (should (null (marker-position (nth 9 markers))))))))) (ert-deftest mastodon-tl--has-spoiler () "Should be able to detect toots with spoiler text as expected" @@ -925,13 +925,13 @@ constant." (ert-deftest mastodon-tl--extract-hashtag-from-url-wrong-instance () (should (null (mastodon-tl--extract-hashtag-from-url - "https://example.org/tags/foo" - "https://other.example.org")))) + "https://example.org/tags/foo" + "https://other.example.org")))) (ert-deftest mastodon-tl--extract-hashtag-from-url-not-tag () (should (null (mastodon-tl--extract-hashtag-from-url - "https://example.org/@userid" - "https://example.org")))) + "https://example.org/@userid" + "https://example.org")))) (ert-deftest mastodon-tl--userhandles () "Should recognise iserhandles in a toot and add the required properties to it." diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index 06da870..abc66d0 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -41,6 +41,6 @@ (ert-deftest cancel () (with-mock - (mock (kill-buffer-and-window)) - (mastodon-toot--cancel) - (mock-verify))) + (mock (kill-buffer-and-window)) + (mastodon-toot--cancel) + (mock-verify))) -- cgit v1.2.3 From 64bfd211fd48b674c1fa4d65d5b61ac86331d8e5 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Tue, 2 Nov 2021 20:43:11 +0100 Subject: Clean up uses of `url-retrieve-synchronously`. We recently introduced a new thin abstraction `mastodon-http--url-retrieve-synchronously` but did not make use of it everywhere. This also moves its definition to the top above its first use. This also removes some dead, commented-out code. --- lisp/mastodon-http.el | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index a183ed7..3e27e13 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -67,15 +67,15 @@ (string-match "[0-9][0-9][0-9]" status-line) (match-string 0 status-line))) -;; (defun mastodon-http--triage (response success) -;; "Determine if RESPONSE was successful. Call SUCCESS if successful. +(defun mastodon-http--url-retrieve-synchronously (url) + "Retrieve URL asynchronously. -;; Open RESPONSE buffer if unsuccessful." -;; (let ((status (with-current-buffer response -;; (mastodon-http--status)))) -;; (if (string-prefix-p "2" status) -;; (funcall success) -;; (switch-to-buffer response)))) +This is a thin abstraction over the system +`url-retrieve-synchronously`. Depending on which version of this +is available we will call it with or without a timeout." + (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) + (url-retrieve-synchronously url) + (url-retrieve-synchronously url nil nil mastodon-http--timeout))) (defun mastodon-http--triage (response success) "Determine if RESPONSE was successful. Call SUCCESS if successful. @@ -115,9 +115,7 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token))))) headers))) (with-temp-buffer - (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) - (url-retrieve-synchronously url) - (url-retrieve-synchronously url nil nil mastodon-http--timeout))))) + (mastodon-http--url-retrieve-synchronously url)))) (defun mastodon-http--get (url) "Make synchronous GET request to URL. @@ -129,16 +127,6 @@ Pass response buffer to CALLBACK function." (mastodon-auth--access-token)))))) (mastodon-http--url-retrieve-synchronously url))) -(defun mastodon-http--url-retrieve-synchronously (url) - "Retrieve URL asynchronously. - -This is a thin abstraction over the system -`url-retrieve-synchronously`. Depending on which version of this -is available we will call it with or without a timeout." - (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) - (url-retrieve-synchronously url) - (url-retrieve-synchronously url nil nil mastodon-http--timeout))) - (defun mastodon-http--get-json (url) "Make synchronous GET request to URL. Return JSON response." (with-current-buffer (mastodon-http--get url) @@ -163,7 +151,7 @@ is available we will call it with or without a timeout." `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) (with-temp-buffer - (url-retrieve-synchronously url)))) + (mastodon-http--url-retrieve-synchronously url)))) ;; search functions: (defun mastodon-http--process-json-search () @@ -195,9 +183,7 @@ PARAM is a formatted request parameter, eg 'following=true'." (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) - (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) - (url-retrieve-synchronously url) - (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + (mastodon-http--url-retrieve-synchronously url))) ;; profile update functions @@ -218,9 +204,7 @@ Pass response buffer to CALLBACK function." (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) - (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) - (url-retrieve-synchronously url) - (url-retrieve-synchronously url nil nil mastodon-http--timeout)))) + (mastodon-http--url-retrieve-synchronously url))) ;; Asynchronous functions -- cgit v1.2.3 From d0bf4f196a9a30ea4e19b0b6fa5f9c5bfaf695b3 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Tue, 2 Nov 2021 21:25:18 +0100 Subject: Convert most uses of `(cdr (assoc ))` to `(alist-get )` This is more readable and actually more efficient (maybe) since it uses `eq` rather than `equal` as a test. --- lisp/mastodon-async.el | 2 +- lisp/mastodon-auth.el | 10 ++--- lisp/mastodon-http.el | 10 ++--- lisp/mastodon-notifications.el | 30 +++++++-------- lisp/mastodon-profile.el | 62 +++++++++++++++--------------- lisp/mastodon-search.el | 26 ++++++------- lisp/mastodon-tl.el | 87 +++++++++++++++++++++--------------------- lisp/mastodon-toot.el | 64 +++++++++++++++---------------- 8 files changed, 145 insertions(+), 146 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 1fabee2..1fee9ef 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -305,7 +305,7 @@ Filter the toots using FILTER." "Test JSON to see if account is local." (not (string-match-p "@" - (cdr (assoc 'acct (cdr (assoc 'account json))))))) + (alist-get 'acct (alist-get 'account json))))) (defun mastodon-async--output-toot (toot) "Process TOOT and prepend it to the async user-facing buffer." diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index b22b51e..e5767f1 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -158,11 +158,11 @@ Handle any errors from the server." (defun mastodon-auth--get-account-name () "Request user credentials and return an account name." - (cdr (assoc - 'acct - (mastodon-http--get-json - (mastodon-http--api - "accounts/verify_credentials"))))) + (alist-get + 'acct + (mastodon-http--get-json + (mastodon-http--api + "accounts/verify_credentials")))) (defun mastodon-auth--user-acct () "Return a mastodon user acct name." diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 3e27e13..a45b4ed 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -88,7 +88,7 @@ Message status and JSON error from RESPONSE if unsuccessful." (progn (switch-to-buffer response) (let ((json-response (mastodon-http--process-json))) - (message "Error %s: %s" status (cdr (assoc 'error json-response)))))))) + (message "Error %s: %s" status (alist-get 'error json-response))))))) (defun mastodon-http--read-file-as-string (filename) "Read a file FILENAME as a string. Used to generate image preview." @@ -267,13 +267,13 @@ item uploaded, and `mastodon-toot--update-status-fields' is run." (lambda (&key data &allow-other-keys) (when data (progn - (push (cdr (assoc 'id data)) + (push (alist-get 'id data) mastodon-toot--media-attachment-ids) ; add ID to list (message "%s file %s with id %S and caption '%s' uploaded!" - (capitalize (cdr (assoc 'type data))) + (capitalize (alist-get 'type data)) file - (cdr (assoc 'id data)) - (cdr (assoc 'description data))) + (alist-get 'id data) + (alist-get 'description data)) (mastodon-toot--update-status-fields))))) :error (cl-function (lambda (&key error-thrown &allow-other-keys) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 2430bcc..4437635 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -78,12 +78,12 @@ (interactive) (when (mastodon-tl--find-property-range 'toot-json (point)) (let* ((toot-json (mastodon-tl--property 'toot-json)) - (f-req-p (string= "follow_request" (cdr (assoc 'type toot-json))))) + (f-req-p (string= "follow_request" (alist-get 'type toot-json)))) (if f-req-p - (let* ((account (cdr (assoc 'account toot-json))) - (id (cdr (assoc 'id account))) - (handle (cdr (assoc 'acct account))) - (name (cdr (assoc 'username account)))) + (let* ((account (alist-get 'account toot-json)) + (id (alist-get 'id account)) + (handle (alist-get 'acct account)) + (name (alist-get 'username account))) (if id (let ((response (mastodon-http--post @@ -104,12 +104,12 @@ (interactive) (when (mastodon-tl--find-property-range 'toot-json (point)) (let* ((toot-json (mastodon-tl--property 'toot-json)) - (f-req-p (string= "follow_request" (cdr (assoc 'type toot-json))))) + (f-req-p (string= "follow_request" (alist-get 'type toot-json)))) (if f-req-p - (let* ((account (cdr (assoc 'account toot-json))) - (id (cdr (assoc 'id account))) - (handle (cdr (assoc 'acct account))) - (name (cdr (assoc 'username account)))) + (let* ((account (alist-get 'account toot-json)) + (id (alist-get 'id account)) + (handle (alist-get 'acct account)) + (name (alist-get 'username account))) (if id (let ((response (mastodon-http--post @@ -127,7 +127,7 @@ (defun mastodon-notifications--mention (note) "Format for a `mention' NOTE." - (let ((id (cdr (assoc 'id note))) + (let ((id (alist-get 'id note)) (status (mastodon-tl--field 'status note))) (mastodon-notifications--insert-status status @@ -156,8 +156,8 @@ (defun mastodon-notifications--follow-request (note) "Format for a `follow-request' NOTE." - (let ((id (cdr (assoc 'id note))) - (follower (cdr (assoc 'username (cdr (assoc 'account note)))))) + (let ((id (alist-get 'id note)) + (follower (alist-get 'username (alist-get 'account note)))) (mastodon-notifications--insert-status (cons '(reblog (id . nil)) note) (propertize (format "You have a follow request from... %s" follower) @@ -170,7 +170,7 @@ (defun mastodon-notifications--favourite (note) "Format for a `favourite' NOTE." - (let ((id (cdr (assoc 'id note))) + (let ((id (alist-get 'id note)) (status (mastodon-tl--field 'status note))) (mastodon-notifications--insert-status status @@ -188,7 +188,7 @@ (defun mastodon-notifications--reblog (note) "Format for a `boost' NOTE." - (let ((id (cdr (assoc 'id note))) + (let ((id (alist-get 'id note)) (status (mastodon-tl--field 'status note))) (mastodon-notifications--insert-status status diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index b68be6f..c4bec38 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -163,9 +163,9 @@ extra keybindings." (interactive) (if (mastodon-tl--find-property-range 'toot-json (point)) (let* ((acct-json (mastodon-profile--toot-json)) - (id (cdr (assoc 'id acct-json))) - (handle (cdr (assoc 'acct acct-json))) - (name (cdr (assoc 'username acct-json)))) + (id (alist-get 'id acct-json)) + (handle (alist-get 'acct acct-json)) + (name (alist-get 'username acct-json))) (if id (let ((response (mastodon-http--post @@ -185,9 +185,9 @@ extra keybindings." (interactive) (if (mastodon-tl--find-property-range 'toot-json (point)) (let* ((acct-json (mastodon-profile--toot-json)) - (id (cdr (assoc 'id acct-json))) - (handle (cdr (assoc 'acct acct-json))) - (name (cdr (assoc 'username acct-json)))) + (id (alist-get 'id acct-json)) + (handle (alist-get 'acct acct-json)) + (name (alist-get 'username acct-json))) (if id (let ((response (mastodon-http--post @@ -209,8 +209,8 @@ extra keybindings." "/api/v1/accounts/update_credentials")) ;; (buffer (mastodon-http--patch url)) (json (mastodon-http--patch-json url)) - (source (cdr (assoc 'source json))) - (note (cdr (assoc 'note source))) + (source (alist-get 'source json)) + (note (alist-get 'note source)) (buffer (get-buffer-create "*mastodon-update-profile*")) (inhibit-read-only t)) (switch-to-buffer-other-window buffer) @@ -247,8 +247,8 @@ Returns a list of lists." (mapcar (lambda (el) (list - (cdr (assoc 'name el)) - (cdr (assoc 'value el)))) + (alist-get 'name el) + (alist-get 'value el))) fields)))) (defun mastodon-profile--fields-insert (fields) @@ -306,10 +306,10 @@ Returns a list of lists." (mastodon-profile--account-field account 'statuses_count))) (relationships (mastodon-profile--relationships-get id)) - (followed-by-you (cdr (assoc 'following - (aref relationships 0)))) - (follows-you (cdr (assoc 'followed_by - (aref relationships 0)))) + (followed-by-you (alist-get 'following + (aref relationships 0))) + (follows-you (alist-get 'followed_by + (aref relationships 0))) (followsp (or (equal follows-you 't) (equal followed-by-you 't))) (fields (mastodon-profile--fields-get account)) (pinned (mastodon-profile--get-statuses-pinned account))) @@ -396,11 +396,11 @@ Returns a list of lists." If toot is a boost, opens the profile of the booster." (interactive) (mastodon-profile--make-author-buffer - (cdr (assoc 'account (mastodon-profile--toot-json))))) + (alist-get 'account (mastodon-profile--toot-json)))) (defun mastodon-profile--image-from-account (status) "Generate an image from a STATUS." - (let ((url (cdr (assoc 'avatar_static status)))) + (let ((url (alist-get 'avatar_static status))) (unless (equal url "/avatars/original/missing.png") (mastodon-media--get-media-link-rendering url)))) @@ -443,12 +443,12 @@ FIELD is used to identify regions under 'account" (propertize (mastodon-tl--byline-author `((account . ,toot))) 'byline 't - 'toot-id (cdr (assoc 'id toot)) + 'toot-id (alist-get 'id toot) 'base-toot-id (mastodon-tl--toot-id toot) 'toot-json toot)) (mastodon-media--inline-images start-pos (point)) (insert "\n" - (mastodon-tl--render-text (cdr (assoc 'note toot)) nil) + (mastodon-tl--render-text (alist-get 'note toot) nil) "\n"))) tootv))) @@ -461,7 +461,7 @@ If the handle does not match a search return then retun NIL." handle)) (matching-account (seq-remove - (lambda(x) (not (string= (cdr (assoc 'acct x)) handle))) + (lambda(x) (not (string= (alist-get 'acct x) handle))) (mastodon-http--get-json (mastodon-http--api (format "accounts/search?q=%s" handle)))))) (when (equal 1 (length matching-account)) @@ -477,35 +477,35 @@ If the handle does not match a search return then retun NIL." These include the author, author of reblogged entries and any user mentioned." (when status - (let ((this-account (cdr (assoc 'account status))) - (mentions (cdr (assoc 'mentions status))) - (reblog (cdr (assoc 'reblog status)))) + (let ((this-account (alist-get 'account status)) + (mentions (alist-get 'mentions status)) + (reblog (alist-get 'reblog status))) (seq-filter 'stringp (seq-uniq (seq-concatenate 'list - (list (cdr (assoc 'acct this-account))) + (list (alist-get 'acct this-account)) (mastodon-profile--extract-users-handles reblog) (mapcar (lambda (mention) - (cdr (assoc 'acct mention))) + (alist-get 'acct mention)) mentions))))))) (defun mastodon-profile--lookup-account-in-status (handle status) "Return account for HANDLE using hints in STATUS if possible." - (let* ((this-account (cdr (assoc 'account status))) - (reblog-account (cdr (assoc 'account (cdr (assoc 'reblog status))))) + (let* ((this-account (alist-get 'account status)) + (reblog-account (alist-get 'account (alist-get 'reblog status))) (mention-id (seq-some (lambda (mention) (when (string= handle - (cdr (assoc 'acct mention))) - (cdr (assoc 'id mention)))) - (cdr (assoc 'mentions status))))) + (alist-get 'acct mention)) + (alist-get 'id mention))) + (alist-get 'mentions status)))) (cond ((string= handle - (cdr (assoc 'acct this-account))) + (alist-get 'acct this-account)) this-account) ((string= handle - (cdr (assoc 'acct reblog-account))) + (alist-get 'acct reblog-account)) reblog-account) (mention-id (mastodon-profile--account-from-id mention-id)) diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index cbb452d..fcfaec9 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -72,9 +72,9 @@ Returns a nested list containing user handle, display name, and URL." (let* ((url (format "%s/api/v2/search" mastodon-instance-url)) (buffer (format "*mastodon-search-%s*" query)) (response (mastodon-http--get-search-json url query)) - (accts (cdr (assoc 'accounts response))) - (tags (cdr (assoc 'hashtags response))) - (statuses (cdr (assoc 'statuses response))) + (accts (alist-get 'accounts response)) + (tags (alist-get 'hashtags response)) + (statuses (alist-get 'statuses response)) (user-ids (mapcar #'mastodon-search--get-user-info accts)) ; returns a list of three-item lists (tags-list (mapcar #'mastodon-search--get-hashtag-info @@ -136,27 +136,27 @@ Returns a nested list containing user handle, display name, and URL." (defun mastodon-search--get-user-info (account) "Get user handle, display name and account URL from ACCOUNT." - (list (cdr (assoc 'display_name account)) - (cdr (assoc 'acct account)) - (cdr (assoc 'url account)))) + (list (alist-get 'display_name account) + (alist-get 'acct account) + (alist-get 'url account))) (defun mastodon-search--get-hashtag-info (tag) "Get hashtag name and URL from TAG." - (list (cdr (assoc 'name tag)) - (cdr (assoc 'url tag)))) + (list (alist-get 'name tag) + (alist-get 'url tag))) (defun mastodon-search--get-status-info (status) "Get ID, timestamp, content, and spoiler from STATUS." - (list (cdr (assoc 'id status)) - (cdr (assoc 'created_at status)) - (cdr (assoc 'spoiler_text status)) - (cdr (assoc 'content status)))) + (list (alist-get 'id status) + (alist-get 'created_at status) + (alist-get 'spoiler_text status) + (alist-get 'content status))) (defun mastodon-search--get-id-from-status (status) "Fetch the id from a STATUS returned by a search call to the server. We use this to fetch the complete status from the server." - (cdr (assoc 'id status))) + (alist-get 'id status)) (defun mastodon-search--fetch-full-status-from-id (id) "Fetch the full status with id ID from the server. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index d300a09..cf1c326 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -266,13 +266,13 @@ Optionally start from POS." (defun mastodon-tl--byline-author (toot) "Propertize author of TOOT." - (let* ((account (cdr (assoc 'account toot))) - (handle (cdr (assoc 'acct account))) - (name (if (not (string= "" (cdr (assoc 'display_name account)))) - (cdr (assoc 'display_name account)) - (cdr (assoc 'username account)))) - (profile-url (cdr (assoc 'url account))) - (avatar-url (cdr (assoc 'avatar account)))) + (let* ((account (alist-get 'account toot)) + (handle (alist-get 'acct account)) + (name (if (not (string= "" (alist-get 'display_name account))) + (alist-get 'display_name account) + (alist-get 'username account))) + (profile-url (alist-get 'url account)) + (avatar-url (alist-get 'avatar account))) ;; TODO: Once we have a view for a user (e.g. their posts ;; timeline) make this a tab-stop and attach an action (concat @@ -298,7 +298,7 @@ Optionally start from POS." (defun mastodon-tl--byline-boosted (toot) "Add byline for boosted data from TOOT." - (let ((reblog (cdr (assoc 'reblog toot)))) + (let ((reblog (alist-get 'reblog toot))) (when reblog (concat "\n " @@ -310,8 +310,8 @@ Optionally start from POS." "Return FIELD from TOOT. Return value from boosted content if available." - (or (cdr (assoc field (cdr (assoc 'reblog toot)))) - (cdr (assoc field toot)))) + (or (alist-get field (alist-get 'reblog toot)) + (alist-get field toot))) (defun mastodon-tl--relative-time-details (timestamp &optional current-time) "Return cons of (descriptive string . next change) for the TIMESTAMP. @@ -502,14 +502,14 @@ START and END are the boundaries of the link in the toot." (defun mastodon-tl--extract-userid-toot (toot acct) "Extract a user id for an ACCT from mentions in a TOOT." - (let* ((mentions (append (cdr (assoc 'mentions toot)) nil)) + (let* ((mentions (append (alist-get 'mentions toot) nil)) (mention (pop mentions)) (short-acct (substring acct 1 (length acct))) return) (while mention - (when (string= (cdr (assoc 'acct mention)) + (when (string= (alist-get 'acct mention) short-acct) - (setq return (cdr (assoc 'id mention)))) + (setq return (alist-get 'id mention))) (setq mention (pop mentions))) return)) @@ -671,12 +671,12 @@ message is a link which unhides/hides the main body." (media-string (mapconcat (lambda (media-attachement) (let ((preview-url - (cdr (assoc 'preview_url media-attachement))) + (alist-get 'preview_url media-attachement)) (remote-url - (if (cdr (assoc 'remote_url media-attachement)) - (cdr (assoc 'remote_url media-attachement)) + (if (alist-get 'remote_url media-attachement) + (alist-get 'remote_url media-attachement) ;; fallback b/c notifications don't have remote_url - (cdr (assoc 'url media-attachement))))) + (alist-get 'url media-attachement)))) (if mastodon-tl--display-media-p (mastodon-media--get-media-link-rendering preview-url remote-url) ; 2nd arg for shr-browse-url @@ -690,10 +690,10 @@ message is a link which unhides/hides the main body." (defun mastodon-tl--content (toot) "Retrieve text content from TOOT." (let* ((content (mastodon-tl--field 'content toot)) - (reblog (cdr (assoc 'reblog toot))) + (reblog (alist-get 'reblog toot)) (poll-p (if reblog - (cdr (assoc 'poll reblog)) - (cdr (assoc 'poll toot))))) + (alist-get 'poll reblog) + (alist-get 'poll toot)))) (concat (when poll-p (mastodon-tl--get-poll toot)) @@ -718,18 +718,17 @@ takes a single function. By default it is body " \n" (mastodon-tl--byline toot author-byline action-byline)) - 'toot-id (cdr (assoc 'id toot)) + 'toot-id (alist-get 'id toot) 'base-toot-id (mastodon-tl--toot-id toot) 'help-echo (when (and mastodon-tl--buffer-spec (string-match-p "context" ; when thread view (plist-get mastodon-tl--buffer-spec 'endpoint))) - (if (alist-get 'reblog toot) - (let ((reblog (cdr (assoc 'reblog toot)))) - (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count reblog) - (alist-get 'reblogs_count reblog) - (alist-get 'replies_count reblog))) + (if-let ((reblog (alist-get 'reblog toot))) + (format "%s faves | %s boosts | %s replies" + (alist-get 'favourites_count reblog) + (alist-get 'reblogs_count reblog) + (alist-get 'replies_count reblog)) (format "%s faves | %s boosts | %s replies" (alist-get 'favourites_count toot) (alist-get 'reblogs_count toot) @@ -749,8 +748,8 @@ takes a single function. By default it is (progn (format "Option %s: %s, %s votes.\n" (setq option-counter (1+ option-counter)) - (cdr (assoc 'title option)) - (cdr (assoc 'votes_count option))))) + (alist-get 'title option) + (alist-get 'votes_count option)))) options "\n") "\n"))) @@ -759,12 +758,12 @@ takes a single function. By default it is (interactive (list (let* ((toot (mastodon-tl--property 'toot-json)) - (reblog (cdr (assoc 'reblog toot))) - (poll (or (cdr (assoc 'poll reblog)) + (reblog (alist-get 'reblog toot)) + (poll (or (alist-get 'poll reblog) (mastodon-tl--field 'poll toot))) (options (mastodon-tl--field 'options poll)) (options-titles (mapcar (lambda (x) - (cdr (assoc 'title x))) + (alist-get 'title x)) options)) (options-number-seq (number-sequence 1 (length options))) (options-numbers (mapcar (lambda(x) @@ -790,7 +789,7 @@ takes a single function. By default it is (message "No poll here.") (let* ((toot (mastodon-tl--property 'toot-json)) (poll (mastodon-tl--field 'poll toot)) - (poll-id (cdr (assoc 'id poll))) + (poll-id (alist-get 'id poll)) (url (mastodon-http--api (format "polls/%s/votes" poll-id))) ;; need to zero-index our option: (option-as-arg (number-to-string (1- (string-to-number (car option))))) @@ -916,9 +915,9 @@ If the toot has been boosted use the id found in the reblog portion of the toot. Otherwise, use the body of the toot. This is the same behaviour as the mastodon.social webapp" - (let ((id (cdr (assoc 'id json))) - (reblog (cdr (assoc 'reblog json)))) - (if reblog (cdr (assoc 'id reblog)) id))) + (let ((id (alist-get 'id json)) + (reblog (alist-get 'reblog json))) + (if reblog (alist-get 'id reblog) id))) (defun mastodon-tl--thread () @@ -930,10 +929,10 @@ webapp" (buffer (format "*mastodon-thread-%s*" id)) (toot (mastodon-tl--property 'toot-json)) (context (mastodon-http--get-json url))) - (when (member (cdr (assoc 'type toot)) '("reblog" "favourite")) - (setq toot (cdr (assoc 'status toot)))) - (if (> (+ (length (cdr (assoc 'ancestors context))) - (length (cdr (assoc 'descendants context)))) + (when (member (alist-get 'type toot) '("reblog" "favourite")) + (setq toot (alist-get 'status toot))) + (if (> (+ (length (alist-get 'ancestors context)) + (length (alist-get 'descendants context))) 0) (with-output-to-temp-buffer buffer (switch-to-buffer buffer) @@ -945,9 +944,9 @@ webapp" (lambda(toot) (message "END of thread.")))) (let ((inhibit-read-only t)) (mastodon-tl--timeline (vconcat - (cdr (assoc 'ancestors context)) + (alist-get 'ancestors context) `(,toot) - (cdr (assoc 'descendants context)))))) + (alist-get 'descendants context))))) (message "No Thread!")))) (defun mastodon-tl--follow-user (user-handle) @@ -1025,7 +1024,7 @@ webapp" (let* ((mutes-url (mastodon-http--api (format "mutes"))) (mutes-json (mastodon-http--get-json mutes-url)) (muted-accts (mapcar (lambda (muted) - (cdr (assoc 'acct muted))) + (alist-get 'acct muted)) mutes-json))) (completing-read "Handle of user to unmute: " muted-accts @@ -1074,7 +1073,7 @@ webapp" (let* ((blocks-url (mastodon-http--api (format "blocks"))) (blocks-json (mastodon-http--get-json blocks-url)) (blocked-accts (mapcar (lambda (blocked) - (cdr (assoc 'acct blocked))) + (alist-get 'acct blocked)) blocks-json))) (completing-read "Handle of user to unblock: " blocked-accts diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 22eb626..9acdb2a 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -155,7 +155,7 @@ Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"p "Set max_toot_chars returned in JSON-RESPONSE and display in new toot buffer." (setq mastodon-toot--max-toot-chars (number-to-string - (cdr (assoc 'max_toot_chars json-response)))) + (alist-get 'max_toot_chars json-response))) (with-current-buffer "*new toot*" (mastodon-toot--update-status-fields))) @@ -246,11 +246,11 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) (pinnable-p (and - (not (cdr (assoc 'reblog toot))) - (equal (cdr (assoc 'acct - (cdr (assoc 'account toot)))) + (not (alist-get 'reblog toot)) + (equal (alist-get 'acct + (alist-get 'account toot)) (mastodon-auth--user-acct)))) - (pinned-p (equal (cdr (assoc 'pinned toot)) t)) + (pinned-p (equal (alist-get 'pinned toot) t)) (action (if pinned-p "unpin" "pin")) (msg (if pinned-p "unpinned" "pinned")) (msg-y-or-n (if pinned-p "Unpin" "Pin"))) @@ -266,8 +266,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) (url (if (mastodon-tl--field 'reblog toot) - (cdr (assoc 'url (cdr (assoc 'reblog toot)))) - (cdr (assoc 'url toot))))) + (alist-get 'url (alist-get 'reblog toot)) + (alist-get 'url toot)))) (kill-new url) (message "Toot URL copied to the clipboard."))) @@ -277,9 +277,9 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) (url (mastodon-http--api (format "statuses/%s" id)))) - (if (or (cdr (assoc 'reblog toot)) - (not (equal (cdr (assoc 'acct - (cdr (assoc 'account toot)))) + (if (or (alist-get 'reblog toot) + (not (equal (alist-get 'acct + (alist-get 'account toot)) (mastodon-auth--user-acct)))) (message "You can only delete your own toots.") (if (y-or-n-p (format "Delete this toot? ")) @@ -296,12 +296,12 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) (url (mastodon-http--api (format "statuses/%s" id))) - (toot-cw (cdr (assoc 'spoiler_text toot))) - (toot-visibility (cdr (assoc 'visibility toot))) - (reply-id (cdr (assoc 'in_reply_to_id toot)))) - (if (or (cdr (assoc 'reblog toot)) - (not (equal (cdr (assoc 'acct - (cdr (assoc 'account toot)))) + (toot-cw (alist-get 'spoiler_text toot)) + (toot-visibility (alist-get 'visibility toot)) + (reply-id (alist-get 'in_reply_to_id toot))) + (if (or (alist-get 'reblog toot) + (not (equal (alist-get 'acct + (alist-get 'account toot)) (mastodon-auth--user-acct)))) (message "You can only delete and redraft your own toots.") (if (y-or-n-p (format "Delete and redraft this toot? ")) @@ -311,8 +311,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (lambda () (with-current-buffer response (let* ((json-response (mastodon-http--process-json)) - (content (cdr (assoc 'text json-response)))) - ;; (media (cdr (assoc 'media_attachments json-response)))) + (content (alist-get 'text json-response))) + ;; (media (alist-get 'media_attachments json-response))) (mastodon-toot--compose-buffer nil nil) (goto-char (point-max)) (insert content) @@ -330,7 +330,7 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (bookmarked (cdr (assoc 'bookmarked toot))) + (bookmarked (alist-get 'bookmarked toot)) (url (mastodon-http--api (if (equal bookmarked t) (format "statuses/%s/unbookmark" id) (format "statuses/%s/bookmark" id)))) @@ -498,10 +498,10 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (let* ((boosted (mastodon-tl--field 'reblog status)) (mentions (if boosted - (cdr (assoc 'mentions (cdr (assoc 'reblog status)))) - (cdr (assoc 'mentions status))))) + (alist-get 'mentions (alist-get 'reblog status)) + (alist-get 'mentions status)))) (mapconcat (lambda(x) (mastodon-toot--process-local - (cdr (assoc 'acct x)))) + (alist-get 'acct x))) ;; reverse does not work on vectors in 24.5 (reverse (append mentions nil)) ""))) @@ -554,12 +554,12 @@ The prefix can match against both user handles and display names." (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--field 'id toot))) (account (mastodon-tl--field 'account toot)) - (user (cdr (assoc 'acct account))) + (user (alist-get 'acct account)) (mentions (mastodon-toot--mentions toot)) (boosted (mastodon-tl--field 'reblog toot)) (booster (when boosted - (cdr (assoc 'acct - (cdr (assoc 'account toot))))))) + (alist-get 'acct + (alist-get 'account toot))))) (mastodon-toot (when user (if booster (if (and @@ -634,8 +634,8 @@ The items' ids are added to `mastodon-toot--media-attachment-ids', which are used to attach them to a toot after uploading." (mapcar (lambda (attachment) (let* ((filename (expand-file-name - (cdr (assoc :filename attachment)))) - (caption (cdr (assoc :description attachment))) + (alist-get :filename attachment))) + (caption (alist-get :description attachment)) (url (concat mastodon-instance-url "/api/v2/media"))) (message "Uploading %s..." (file-name-nondirectory filename)) (mastodon-http--post-media-attachment url filename caption))) @@ -659,14 +659,14 @@ which are used to attach them to a toot after uploading." (image-transforms-p)) `(:height ,mastodon-toot--attachment-height)))) (mapcan (lambda (attachment) - (let* ((data (cdr (assoc :contents attachment))) + (let* ((data (alist-get :contents attachment)) (image (apply #'create-image data (if (version< emacs-version "27.1") (when image-options 'imagemagick) nil) ; inbuilt scaling in 27.1 t image-options)) - (type (cdr (assoc :content-type attachment))) - (description (cdr (assoc :description attachment)))) + (type (alist-get :content-type attachment)) + (description (alist-get :description attachment))) (setq counter (1+ counter)) (list (format "\n %d: " counter) image @@ -787,8 +787,8 @@ on the status of NSFW, content warning flags, media attachments, etc." "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 (cdr (assoc 'visibility reply-json))) - (reply-cw (cdr (assoc 'spoiler_text reply-json)))) + (let ((reply-visibility (alist-get 'visibility reply-json)) + (reply-cw (alist-get 'spoiler_text reply-json))) (when reply-to-user (insert (format "%s " reply-to-user)) (setq mastodon-toot--reply-to-id reply-to-id) -- cgit v1.2.3 From f67114cc6c5c167db7327b6b965839236e0466aa Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Fri, 5 Nov 2021 17:57:55 +0100 Subject: Use portable filename component functions. Apparently one should not rely on "/" being the directory separator and use the funtions from https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Name-Components.html#File-Name-Components instead. The new version seems strictly better in that it won't create paths with double slashes when `emojify-emojis-dir` already ends in a slash. This also refines the test for `emojify-emojis-dir` to actually check it is an existing directoy and not just an existing file, dir, or symlink. --- lisp/mastodon-toot.el | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9acdb2a..d5f4d78 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -366,23 +366,25 @@ 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 (concat (expand-file-name - emojify-emojis-dir) - "/mastodon-custom-emojis/"))) - (if (not (file-exists-p emojify-emojis-dir)) + (mastodon-custom-emoji-dir (file-name-as-directory + (concat (file-name-as-directory + (expand-file-name + emojify-emojis-dir)) + "mastodon-custom-emojis")))) + (if (not (file-directory-p emojify-emojis-dir)) (message "Looks like you need to set up emojify first.") (progn (unless (file-directory-p mastodon-custom-emoji-dir) (make-directory mastodon-custom-emoji-dir nil)) ; no add parent (mapc (lambda (x) - (url-copy-file (alist-get 'url x) - (concat - mastodon-custom-emoji-dir - (alist-get 'shortcode x) - "." - (file-name-extension (alist-get 'url x))) - t)) - custom-emoji) + (url-copy-file (alist-get 'url x) + (concat + mastodon-custom-emoji-dir + (alist-get 'shortcode x) + "." + (file-name-extension (alist-get 'url x))) + t)) + custom-emoji) (message "Custom emoji for %s downloaded to %s" mastodon-instance-url mastodon-custom-emoji-dir))))) -- cgit v1.2.3 From 65f80fd810793638beb6f146b25919bca5c21cfc Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Fri, 5 Nov 2021 18:33:16 +0100 Subject: Do a bit if `if` and `progn` sanitizing. - A `progn` with a single form is redundant - `when` doesn't need a `progn` body - `if` has an implicit `progn` for the consequences - I converted one cascade of `if`s into a `cond`. --- lisp/mastodon-async.el | 7 ++++--- lisp/mastodon-auth.el | 1 - lisp/mastodon-http.el | 24 +++++++++++------------- lisp/mastodon-profile.el | 11 +++++------ lisp/mastodon-toot.el | 29 ++++++++++++++--------------- 5 files changed, 34 insertions(+), 38 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 1fee9ef..524e13d 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -205,9 +205,10 @@ ENPOINT is the endpoint for the stream and timeline." mastodon-instance-url "*")) ;; if user stream, we need "timelines/home" not "timelines/user" ;; if notifs, we need "notifications" not "timelines/notifications" - (endpoint (if (equal name "notifications") "notifications" - (if (equal name "home") "timelines/home" - (format "timelines/%s" endpoint))))) + (endpoint (cond + ((equal name "notifications") "notifications") + ((equal name "home") "timelines/home") + (t (format "timelines/%s" endpoint))))) (mastodon-async--set-local-variables buffer-name http-buffer buffer-name queue-name) ;; Similar to timeline init. diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index e5767f1..8d0d7c6 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -136,7 +136,6 @@ Otherwise, generate a token and pass it to `mastodon-auth--handle-token-reponse'." (if-let ((token (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) token - (mastodon-auth--handle-token-response (mastodon-auth--get-token)))) (defun mastodon-auth--handle-token-response (response) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index a45b4ed..1ec0dc0 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -85,10 +85,9 @@ Message status and JSON error from RESPONSE if unsuccessful." (mastodon-http--status)))) (if (string-prefix-p "2" status) (funcall success) - (progn - (switch-to-buffer response) - (let ((json-response (mastodon-http--process-json))) - (message "Error %s: %s" status (alist-get 'error json-response))))))) + (switch-to-buffer response) + (let ((json-response (mastodon-http--process-json))) + (message "Error %s: %s" status (alist-get 'error json-response)))))) (defun mastodon-http--read-file-as-string (filename) "Read a file FILENAME as a string. Used to generate image preview." @@ -266,15 +265,14 @@ item uploaded, and `mastodon-toot--update-status-fields' is run." :success (cl-function (lambda (&key data &allow-other-keys) (when data - (progn - (push (alist-get 'id data) - mastodon-toot--media-attachment-ids) ; add ID to list - (message "%s file %s with id %S and caption '%s' uploaded!" - (capitalize (alist-get 'type data)) - file - (alist-get 'id data) - (alist-get 'description data)) - (mastodon-toot--update-status-fields))))) + (push (alist-get 'id data) + mastodon-toot--media-attachment-ids) ; add ID to list + (message "%s file %s with id %S and caption '%s' uploaded!" + (capitalize (alist-get 'type data)) + file + (alist-get 'id data) + (alist-get 'description data)) + (mastodon-toot--update-status-fields)))) :error (cl-function (lambda (&key error-thrown &allow-other-keys) (cond diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index c4bec38..81ab837 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -349,12 +349,11 @@ Returns a list of lists." (mastodon-tl--render-text note account) ;; account here to enable tab-stops in profile note (if fields - (progn - (concat "\n" - (mastodon-tl--set-face - (mastodon-profile--fields-insert fields) - 'success) - "\n")) + (concat "\n" + (mastodon-tl--set-face + (mastodon-profile--fields-insert fields) + 'success) + "\n") "") ;; insert counts (mastodon-tl--set-face diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index d5f4d78..885db1d 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -373,21 +373,20 @@ To use the downloaded emoji, run `mastodon-toot--enable-custom-emoji'." "mastodon-custom-emojis")))) (if (not (file-directory-p emojify-emojis-dir)) (message "Looks like you need to set up emojify first.") - (progn - (unless (file-directory-p mastodon-custom-emoji-dir) - (make-directory mastodon-custom-emoji-dir nil)) ; no add parent - (mapc (lambda (x) - (url-copy-file (alist-get 'url x) - (concat - mastodon-custom-emoji-dir - (alist-get 'shortcode x) - "." - (file-name-extension (alist-get 'url x))) - t)) - custom-emoji) - (message "Custom emoji for %s downloaded to %s" - mastodon-instance-url - mastodon-custom-emoji-dir))))) + (unless (file-directory-p mastodon-custom-emoji-dir) + (make-directory mastodon-custom-emoji-dir nil)) ; no add parent + (mapc (lambda (x) + (url-copy-file (alist-get 'url x) + (concat + mastodon-custom-emoji-dir + (alist-get 'shortcode x) + "." + (file-name-extension (alist-get 'url x))) + t)) + custom-emoji) + (message "Custom emoji for %s downloaded to %s" + mastodon-instance-url + mastodon-custom-emoji-dir)))) (defun mastodon-toot--collect-custom-emoji () "Return a list of `mastodon-instance-url's custom emoji. -- cgit v1.2.3 From 6f0afbb8b46f3d5efa02f4f6ecd4d2a216d9bb21 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Sat, 6 Nov 2021 16:23:02 +0100 Subject: Fix new warnings in `mastodon-inspect.el`. Just some autoload and defvar needed to keep the compiler quiet. --- lisp/mastodon-inspect.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 4647335..57240f3 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -30,12 +30,15 @@ ;;; Code: (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") +(autoload 'mastodon-http--get-search-json "mastodon-http") (autoload 'mastodon-media--inline-images "mastodon-media") (autoload 'mastodon-mode "mastodon") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--property "mastodon-tl") (autoload 'mastodon-tl--toot "mastodon-tl") +(defvar mastodon-instance-url) + (defgroup mastodon-inspect nil "Tools to help inspect toots." :prefix "mastodon-inspect-" -- cgit v1.2.3 From d5bab484a7f8593e095ff0fc97e903a38c62c951 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Sat, 6 Nov 2021 16:31:01 +0100 Subject: Simplify the logic in `mastodon-tl--insert-status`. Just a small simplification of the recent change from commit 027f24125f: the formatting is actually the same no matter if showing infos about the toot itself or the reblogged toot, so let's just first pick which toot to use and have the formatting just once. --- lisp/mastodon-tl.el | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index cf1c326..62d283b 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -724,15 +724,12 @@ takes a single function. By default it is (string-match-p "context" ; when thread view (plist-get mastodon-tl--buffer-spec 'endpoint))) - (if-let ((reblog (alist-get 'reblog toot))) - (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count reblog) - (alist-get 'reblogs_count reblog) - (alist-get 'replies_count reblog)) + ;; prefer the reblog toot if present: + (let ((toot-to-use (or (alist-get 'reblog toot) toot))) (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count toot) - (alist-get 'reblogs_count toot) - (alist-get 'replies_count toot)))) + (alist-get 'favourites_count toot-to-use) + (alist-get 'reblogs_count toot-to-use) + (alist-get 'replies_count toot-to-use)))) 'toot-json toot) "\n") (when mastodon-tl--display-media-p -- cgit v1.2.3 From 8d543a03694e575cd0352275b60b2d232bfeaeb5 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 9 Nov 2021 10:02:24 +0100 Subject: remove help-echo for faves/boosts/replies, it breaks img echo keymap --- lisp/mastodon-tl.el | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 62d283b..5418374 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -720,16 +720,6 @@ takes a single function. By default it is (mastodon-tl--byline toot author-byline action-byline)) 'toot-id (alist-get 'id toot) 'base-toot-id (mastodon-tl--toot-id toot) - 'help-echo (when (and mastodon-tl--buffer-spec - (string-match-p - "context" ; when thread view - (plist-get mastodon-tl--buffer-spec 'endpoint))) - ;; prefer the reblog toot if present: - (let ((toot-to-use (or (alist-get 'reblog toot) toot))) - (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count toot-to-use) - (alist-get 'reblogs_count toot-to-use) - (alist-get 'replies_count toot-to-use)))) 'toot-json toot) "\n") (when mastodon-tl--display-media-p -- cgit v1.2.3 From dd9ef80d940655bb24958d3c48a86aad45cefa43 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 9 Nov 2021 10:06:03 +0100 Subject: fixme insert-status/get-media-link-rendering --- lisp/mastodon-tl.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 62d283b..112b59f 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -720,6 +720,7 @@ takes a single function. By default it is (mastodon-tl--byline toot author-byline action-byline)) 'toot-id (alist-get 'id toot) 'base-toot-id (mastodon-tl--toot-id toot) + ;; FIXME this breaks help property of `mastodon-media--get-media-link-rendering'. 'help-echo (when (and mastodon-tl--buffer-spec (string-match-p "context" ; when thread view -- cgit v1.2.3 From b02782226b34507508020179e3100c307738eeee Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 9 Nov 2021 10:37:57 +0100 Subject: update test mastodon-media:get-media-link-rendering with extra props --- test/mastodon-media-tests.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index b537dfe..7124672 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -22,14 +22,22 @@ (mock (create-image * nil t) => :mock-image) (let* ((mastodon-media--preview-max-height 123) - (result (mastodon-media--get-media-link-rendering "http://example.org/img.png")) + (result + (mastodon-media--get-media-link-rendering "http://example.org/img.png" + "http://example.org/remote/img.png")) (result-no-properties (substring-no-properties result)) (properties (text-properties-at 0 result))) (should (string= "[img] " result-no-properties)) (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) (should (eq 'needs-loading (plist-get properties 'media-state))) (should (eq 'media-link (plist-get properties 'media-type))) - (should (eq :mock-image (plist-get properties 'display)))))) + (should (eq :mock-image (plist-get properties 'display))) + (should (eq 'highlight (plist-get properties 'mouse-face))) + (should (eq 'image (plist-get properties 'mastodon-tab-stop))) + (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) + (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) + (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview" + (plist-get properties 'help-echo)))))) (ert-deftest mastodon-media:load-image-from-url:avatar-with-imagemagic () "Should make the right call to url-retrieve." -- cgit v1.2.3 From 6485f236ce9bab609a606d6f5896b1d39b3c114d Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 9 Nov 2021 10:12:56 +0100 Subject: fetch media_attachments' "type" from server and store as property - if the type is not "image", it is displayed in`'help-echo' property. - the idea is to use this to handle gifs/videos differently to images. but for now i'm not sure how to actually render such media. but this way, at least the item could be viewed externally if the user wants to see it, or at least they know they're missing out on something. - NB: EWW can't handle content type "video/mp4". --- lisp/mastodon-media.el | 34 ++++++++++++++++++++-------------- lisp/mastodon-tl.el | 5 +++-- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index f7386c6..457628f 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -292,21 +292,27 @@ Replace them with the referenced image." t image-options)) " "))) -(defun mastodon-media--get-media-link-rendering (media-url &optional full-remote-url) +(defun mastodon-media--get-media-link-rendering (media-url &optional full-remote-url type) "Return the string to be written that renders the image at MEDIA-URL. -FULL-REMOTE-URL is used for `shr-browse-image'." - (concat - (propertize "[img]" - 'media-url media-url - 'media-state 'needs-loading - 'media-type 'media-link - 'display (create-image mastodon-media--generic-broken-image-data nil t) - 'mouse-face 'highlight - 'mastodon-tab-stop 'image ; for do-link-action-at-point - 'image-url full-remote-url ; for shr-browse-image - 'keymap mastodon-tl--shr-image-map-replacement - 'help-echo (concat "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview")) - " ")) +FULL-REMOTE-URL is used for `shr-browse-image'. +TYPE is the attachment's type field on the server." + (let ((help-echo + "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview")) + (concat + (propertize "[img]" + 'media-url media-url + 'media-state 'needs-loading + 'media-type 'media-link + 'mastodon-media-type type + 'display (create-image mastodon-media--generic-broken-image-data nil t) + 'mouse-face 'highlight + 'mastodon-tab-stop 'image ; for do-link-action-at-point + 'image-url full-remote-url ; for shr-browse-image + 'keymap mastodon-tl--shr-image-map-replacement + 'help-echo (if (string= type "image") + help-echo + (concat help-echo "\ntype: " type))) + " "))) (provide 'mastodon-media) ;;; mastodon-media.el ends here diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 5418374..9bc7cf2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -676,10 +676,11 @@ message is a link which unhides/hides the main body." (if (alist-get 'remote_url media-attachement) (alist-get 'remote_url media-attachement) ;; fallback b/c notifications don't have remote_url - (alist-get 'url media-attachement)))) + (alist-get 'url media-attachement))) + (type (alist-get 'type media-attachement))) (if mastodon-tl--display-media-p (mastodon-media--get-media-link-rendering - preview-url remote-url) ; 2nd arg for shr-browse-url + preview-url remote-url type) ; 2nd arg for shr-browse-url (concat "Media::" preview-url "\n")))) media-attachements ""))) (if (not (and mastodon-tl--display-media-p -- cgit v1.2.3 From 3014e10ec268250a130ac490b5f32b3d263ad21b Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 9 Nov 2021 11:35:57 +0100 Subject: update mastodon-media:get-media-link-rendering{-gif} to handle adding property "type" to media, and to display in help-echo if not an image. --- test/mastodon-media-tests.el | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index 7124672..252c819 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -24,7 +24,8 @@ (let* ((mastodon-media--preview-max-height 123) (result (mastodon-media--get-media-link-rendering "http://example.org/img.png" - "http://example.org/remote/img.png")) + "http://example.org/remote/img.png" + "image")) (result-no-properties (substring-no-properties result)) (properties (text-properties-at 0 result))) (should (string= "[img] " result-no-properties)) @@ -36,7 +37,33 @@ (should (eq 'image (plist-get properties 'mastodon-tab-stop))) (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) + (should (string= "image" (plist-get properties 'mastodon-media-type))) (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview" + (plist-get properties 'help-echo)))))) + +(ert-deftest mastodon-media:get-media-link-rendering-gif () + "Should return text with all expected properties." + (with-mock + (mock (create-image * nil t) => :mock-image) + + (let* ((mastodon-media--preview-max-height 123) + (result + (mastodon-media--get-media-link-rendering "http://example.org/img.png" + "http://example.org/remote/img.png" + "gifv")) + (result-no-properties (substring-no-properties result)) + (properties (text-properties-at 0 result))) + (should (string= "[img] " result-no-properties)) + (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) + (should (eq 'needs-loading (plist-get properties 'media-state))) + (should (eq 'media-link (plist-get properties 'media-type))) + (should (eq :mock-image (plist-get properties 'display))) + (should (eq 'highlight (plist-get properties 'mouse-face))) + (should (eq 'image (plist-get properties 'mastodon-tab-stop))) + (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) + (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) + (should (string= "gifv" (plist-get properties 'mastodon-media-type))) + (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview\ntype: gifv" (plist-get properties 'help-echo)))))) (ert-deftest mastodon-media:load-image-from-url:avatar-with-imagemagic () -- cgit v1.2.3 From 4885cb1f3a564584eb90153051c0277c46f77ca4 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 9 Nov 2021 11:43:01 +0100 Subject: autocompletion ignores case of handles/display names --- 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 885db1d..753a659 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -521,8 +521,8 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." The prefix can match against both user handles and display names." (let (res) (dolist (item (mastodon-search--search-accounts-query prefix)) - (when (or (string-prefix-p prefix (cadr item)) - (string-prefix-p prefix (car item))) + (when (or (string-prefix-p prefix (cadr item) t) + (string-prefix-p prefix (car item) t)) (push (mastodon-toot--mentions-company-make-candidate item) res))) res)) -- cgit v1.2.3 From 3dd4fea29835702a9664d7dd36014066edd1e49a Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 10 Nov 2021 08:38:28 +0100 Subject: move profile--my-profile binding to 'O' to avoid using C-S- bindings, which don't always work for others. --- lisp/mastodon.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 826787a..f9c18a0 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -145,7 +145,7 @@ Use. e.g. \"%c\" for your locale's date and time format." (define-key map (kbd "C-S-B") #'mastodon-tl--unblock-user) (define-key map (kbd "M") #'mastodon-tl--mute-user) (define-key map (kbd "C-S-M") #'mastodon-tl--unmute-user) - (define-key map (kbd "C-S-P") #'mastodon-profile--my-profile) + (define-key map (kbd "O") #'mastodon-profile--my-profile) (define-key map (kbd "S") #'mastodon-search--search-query) (define-key map (kbd "d") #'mastodon-toot--delete-toot) (define-key map (kbd "D") #'mastodon-toot--delete-and-redraft-toot) -- cgit v1.2.3 From 1892014062229f3b68136495e53e90a51dfa58a1 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 10 Nov 2021 10:21:42 +0100 Subject: move profile view followers/following bindings to 's'/'g'. because 'O' is no longer available, being used for --my-profile. the actual solution is to just have one binding that cycles through the profile views. --- lisp/mastodon-profile.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 81ab837..7a9edc3 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -68,8 +68,8 @@ ;; this way you can update it with C-M-x: (defvar mastodon-profile-mode-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "O") #'mastodon-profile--open-followers) - (define-key map (kbd "o") #'mastodon-profile--open-following) + (define-key map (kbd "s") #'mastodon-profile--open-followers) + (define-key map (kbd "g") #'mastodon-profile--open-following) (define-key map (kbd "a") #'mastodon-profile--follow-request-accept) (define-key map (kbd "j") #'mastodon-profile--follow-request-reject) map) -- cgit v1.2.3 From 6b4a47290bf32f5be670d6aa92c3e7780e667ff3 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Mon, 8 Nov 2021 20:17:23 +0100 Subject: Change `mastodon-auth-test.el` to not expect errors. Instead let's catch the error and then assert the correct error text. This is more specific and also looks nicer on a test run as there are no `F` symbols for the (expected) failures. --- test/mastodon-auth-test.el | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/mastodon-auth-test.el b/test/mastodon-auth-test.el index 9a765b9..4372047 100644 --- a/test/mastodon-auth-test.el +++ b/test/mastodon-auth-test.el @@ -36,12 +36,24 @@ (should (string= "foo" (mastodon-auth--handle-token-response '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) (ert-deftest mastodon-auth--handle-token-response--unknown () - :expected-result :failed - (mastodon-auth--handle-token-response '(:herp "derp"))) + (should + (equal + '(error "Unknown response from mastodon-auth--get-token!") + (condition-case error + (progn + (mastodon-auth--handle-token-response '(:herp "derp")) + nil) + (t error))))) (ert-deftest mastodon-auth--handle-token-response--failure () - :expected-result :failed - (mastodon-auth--handle-token-response '(:error "invalid_grant" :error_description "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."))) + (let ((error-message "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.")) + (should + (equal + `(error ,(format "Mastodon-auth--access-token: invalid_grant: %s" error-message)) + (condition-case error + (mastodon-auth--handle-token-response + `(:error "invalid_grant" :error_description ,error-message)) + (t error)))))) (provide 'mastodon-auth--test) ;;; mastodon-auth--test.el ends here -- cgit v1.2.3 From 5df05d94926ada6843cbc65aea4b64c18429fdf1 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Mon, 8 Nov 2021 20:28:25 +0100 Subject: Reformatting `mastodon-search-tests.el`. - Remove redundant let binding of vars - Re-indent various things to better fit reasonably on a screen. --- test/mastodon-auth-tests.el | 80 +++---- test/mastodon-client-tests.el | 78 +++---- test/mastodon-http-tests.el | 6 +- test/mastodon-media-tests.el | 344 ++++++++++++++--------------- test/mastodon-notifications-test.el | 4 +- test/mastodon-search-tests.el | 92 ++++---- test/mastodon-tl-tests.el | 418 ++++++++++++++++++------------------ test/mastodon-toot-tests.el | 6 +- 8 files changed, 517 insertions(+), 511 deletions(-) diff --git a/test/mastodon-auth-tests.el b/test/mastodon-auth-tests.el index 69c34a4..fda04eb 100644 --- a/test/mastodon-auth-tests.el +++ b/test/mastodon-auth-tests.el @@ -3,52 +3,52 @@ (ert-deftest generate-token--no-storing-credentials () "Should make `mastdon-http--post' request to generate auth token." (with-mock - (let ((mastodon-auth-source-file "") - (mastodon-instance-url "https://instance.url")) - (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) - (mock (read-string "Email: " user-mail-address) => "foo@bar.com") - (mock (read-passwd "Password: ") => "password") - (mock (mastodon-http--post "https://instance.url/oauth/token" - '(("client_id" . "id") - ("client_secret" . "secret") - ("grant_type" . "password") - ("username" . "foo@bar.com") - ("password" . "password") - ("scope" . "read write follow")) - nil - :unauthenticated)) - (mastodon-auth--generate-token)))) + (let ((mastodon-auth-source-file "") + (mastodon-instance-url "https://instance.url")) + (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) + (mock (read-string "Email: " user-mail-address) => "foo@bar.com") + (mock (read-passwd "Password: ") => "password") + (mock (mastodon-http--post "https://instance.url/oauth/token" + '(("client_id" . "id") + ("client_secret" . "secret") + ("grant_type" . "password") + ("username" . "foo@bar.com") + ("password" . "password") + ("scope" . "read write follow")) + nil + :unauthenticated)) + (mastodon-auth--generate-token)))) (ert-deftest generate-token--storing-credentials () "Should make `mastdon-http--post' request to generate auth token." (with-mock - (let ((mastodon-auth-source-file "~/.authinfo") - (mastodon-instance-url "https://instance.url")) - (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) - (mock (auth-source-search :create t - :host "https://instance.url" - :port 443 - :require '(:user :secret)) - => '((:user "foo@bar.com" :secret (lambda () "password")))) - (mock (mastodon-http--post "https://instance.url/oauth/token" - '(("client_id" . "id") - ("client_secret" . "secret") - ("grant_type" . "password") - ("username" . "foo@bar.com") - ("password" . "password") - ("scope" . "read write follow")) - nil - :unauthenticated)) - (mastodon-auth--generate-token)))) + (let ((mastodon-auth-source-file "~/.authinfo") + (mastodon-instance-url "https://instance.url")) + (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) + (mock (auth-source-search :create t + :host "https://instance.url" + :port 443 + :require '(:user :secret)) + => '((:user "foo@bar.com" :secret (lambda () "password")))) + (mock (mastodon-http--post "https://instance.url/oauth/token" + '(("client_id" . "id") + ("client_secret" . "secret") + ("grant_type" . "password") + ("username" . "foo@bar.com") + ("password" . "password") + ("scope" . "read write follow")) + nil + :unauthenticated)) + (mastodon-auth--generate-token)))) (ert-deftest get-token () "Should generate token and return JSON response." (with-temp-buffer (with-mock - (mock (mastodon-auth--generate-token) => (progn - (insert "\n\n{\"access_token\":\"abcdefg\"}") - (current-buffer))) - (should (equal (mastodon-auth--get-token) '(:access_token "abcdefg")))))) + (mock (mastodon-auth--generate-token) => (progn + (insert "\n\n{\"access_token\":\"abcdefg\"}") + (current-buffer))) + (should (equal (mastodon-auth--get-token) '(:access_token "abcdefg")))))) (ert-deftest access-token-found () "Should return value in `mastodon-auth--token-alist' if found." @@ -61,6 +61,6 @@ (let ((mastodon-instance-url "https://instance.url") (mastodon-auth--token nil)) (with-mock - (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) - (should (string= (mastodon-auth--access-token) "foobaz")) - (should (equal mastodon-auth--token-alist '(("https://instance.url" . "foobaz"))))))) + (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) + (should (string= (mastodon-auth--access-token) "foobaz")) + (should (equal mastodon-auth--token-alist '(("https://instance.url" . "foobaz"))))))) diff --git a/test/mastodon-client-tests.el b/test/mastodon-client-tests.el index d7f750d..12d2350 100644 --- a/test/mastodon-client-tests.el +++ b/test/mastodon-client-tests.el @@ -3,35 +3,35 @@ (ert-deftest register () "Should POST to /apps." (with-mock - (mock (mastodon-http--api "apps") => "https://instance.url/api/v1/apps") - (mock (mastodon-http--post "https://instance.url/api/v1/apps" - '(("client_name" . "mastodon.el") - ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") - ("scopes" . "read write follow") - ("website" . "https://github.com/jdenen/mastodon.el")) - nil - :unauthenticated)) - (mastodon-client--register))) + (mock (mastodon-http--api "apps") => "https://instance.url/api/v1/apps") + (mock (mastodon-http--post "https://instance.url/api/v1/apps" + '(("client_name" . "mastodon.el") + ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") + ("scopes" . "read write follow") + ("website" . "https://github.com/jdenen/mastodon.el")) + nil + :unauthenticated)) + (mastodon-client--register))) (ert-deftest fetch () "Should return client registration JSON." (with-temp-buffer (with-mock - (mock (mastodon-client--register) => (progn - (insert "\n\n{\"foo\":\"bar\"}") - (current-buffer))) - (should (equal (mastodon-client--fetch) '(:foo "bar")))))) + (mock (mastodon-client--register) => (progn + (insert "\n\n{\"foo\":\"bar\"}") + (current-buffer))) + (should (equal (mastodon-client--fetch) '(:foo "bar")))))) (ert-deftest store-1 () "Should return the client plist." (let ((mastodon-instance-url "http://mastodon.example") (plist '(:client_id "id" :client_secret "secret"))) (with-mock - (mock (mastodon-client--token-file) => "stubfile.plstore") - (mock (mastodon-client--fetch) => '(:client_id "id" :client_secret "secret")) - (let* ((plstore (plstore-open "stubfile.plstore")) - (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) - (should (equal (mastodon-client--store) plist)))))) + (mock (mastodon-client--token-file) => "stubfile.plstore") + (mock (mastodon-client--fetch) => '(:client_id "id" :client_secret "secret")) + (let* ((plstore (plstore-open "stubfile.plstore")) + (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) + (should (equal (mastodon-client--store) plist)))))) (ert-deftest store-2 () "Should store client in `mastodon-client--token-file'." @@ -46,22 +46,22 @@ "Should return mastodon client from `mastodon-token-file' if it exists." (let ((mastodon-instance-url "http://mastodon.example")) (with-mock - (mock (mastodon-client--token-file) => "fixture/client.plstore") - (should (equal (mastodon-client--read) - '(:client_id "id2" :client_secret "secret2")))))) + (mock (mastodon-client--token-file) => "fixture/client.plstore") + (should (equal (mastodon-client--read) + '(:client_id "id2" :client_secret "secret2")))))) (ert-deftest read-finds-no-match () "Should return mastodon client from `mastodon-token-file' if it exists." (let ((mastodon-instance-url "http://mastodon.social")) (with-mock - (mock (mastodon-client--token-file) => "fixture/client.plstore") - (should (equal (mastodon-client--read) nil))))) + (mock (mastodon-client--token-file) => "fixture/client.plstore") + (should (equal (mastodon-client--read) nil))))) (ert-deftest read-empty-store () "Should return nil if mastodon client is not present in the plstore." (with-mock - (mock (mastodon-client--token-file) => "fixture/empty.plstore") - (should (equal (mastodon-client--read) nil)))) + (mock (mastodon-client--token-file) => "fixture/empty.plstore") + (should (equal (mastodon-client--read) nil)))) (ert-deftest client-set-and-matching () "Should return `mastondon-client' if `mastodon-client--client-details-alist' is non-nil and instance url is included." @@ -75,29 +75,29 @@ (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist '(("http://other.example" :wrong)))) (with-mock - (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) - (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) - (should (equal mastodon-client--client-details-alist - '(("http://mastodon.example" :client_id "foo" :client_secret "bar") - ("http://other.example" :wrong))))))) + (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) + (should (equal mastodon-client--client-details-alist + '(("http://mastodon.example" :client_id "foo" :client_secret "bar") + ("http://other.example" :wrong))))))) (ert-deftest client-unset () "Should read from `mastodon-token-file' if available." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) (with-mock - (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) - (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) - (should (equal mastodon-client--client-details-alist - '(("http://mastodon.example" :client_id "foo" :client_secret "bar"))))))) + (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) + (should (equal mastodon-client--client-details-alist + '(("http://mastodon.example" :client_id "foo" :client_secret "bar"))))))) (ert-deftest client-unset-and-not-in-storage () "Should store client data in plstore if it can't be read." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) (with-mock - (mock (mastodon-client--read)) - (mock (mastodon-client--store) => '(:client_id "foo" :client_secret "baz")) - (should (equal (mastodon-client) '(:client_id "foo" :client_secret "baz"))) - (should (equal mastodon-client--client-details-alist - '(("http://mastodon.example" :client_id "foo" :client_secret "baz"))))))) + (mock (mastodon-client--read)) + (mock (mastodon-client--store) => '(:client_id "foo" :client_secret "baz")) + (should (equal (mastodon-client) '(:client_id "foo" :client_secret "baz"))) + (should (equal mastodon-client--client-details-alist + '(("http://mastodon.example" :client_id "foo" :client_secret "baz"))))))) diff --git a/test/mastodon-http-tests.el b/test/mastodon-http-tests.el index 03d4f94..d0f715e 100644 --- a/test/mastodon-http-tests.el +++ b/test/mastodon-http-tests.el @@ -4,6 +4,6 @@ "Should make a `url-retrieve' of the given URL." (let ((callback-double (lambda () "double"))) (with-mock - (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) - (mock (mastodon-auth--access-token) => "test-token") - (mastodon-http--get "https://foo.bar/baz")))) + (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) + (mock (mastodon-auth--access-token) => "test-token") + (mastodon-http--get "https://foo.bar/baz")))) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index 7124672..3345e74 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -3,215 +3,215 @@ (ert-deftest mastodon-media:get-avatar-rendering () "Should return text with all expected properties." (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => :mock-image) - - (let* ((mastodon-media--avatar-height 123) - (result (mastodon-media--get-avatar-rendering "http://example.org/img.png")) - (result-no-properties (substring-no-properties result)) - (properties (text-properties-at 0 result))) - (should (string= " " result-no-properties)) - (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) - (should (eq 'needs-loading (plist-get properties 'media-state))) - (should (eq 'avatar (plist-get properties 'media-type))) - (should (eq :mock-image (plist-get properties 'display)))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => :mock-image) + + (let* ((mastodon-media--avatar-height 123) + (result (mastodon-media--get-avatar-rendering "http://example.org/img.png")) + (result-no-properties (substring-no-properties result)) + (properties (text-properties-at 0 result))) + (should (string= " " result-no-properties)) + (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) + (should (eq 'needs-loading (plist-get properties 'media-state))) + (should (eq 'avatar (plist-get properties 'media-type))) + (should (eq :mock-image (plist-get properties 'display)))))) (ert-deftest mastodon-media:get-media-link-rendering () "Should return text with all expected properties." (with-mock - (mock (create-image * nil t) => :mock-image) - - (let* ((mastodon-media--preview-max-height 123) - (result - (mastodon-media--get-media-link-rendering "http://example.org/img.png" - "http://example.org/remote/img.png")) - (result-no-properties (substring-no-properties result)) - (properties (text-properties-at 0 result))) - (should (string= "[img] " result-no-properties)) - (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) - (should (eq 'needs-loading (plist-get properties 'media-state))) - (should (eq 'media-link (plist-get properties 'media-type))) - (should (eq :mock-image (plist-get properties 'display))) - (should (eq 'highlight (plist-get properties 'mouse-face))) - (should (eq 'image (plist-get properties 'mastodon-tab-stop))) - (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) - (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) - (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview" - (plist-get properties 'help-echo)))))) + (mock (create-image * nil t) => :mock-image) + + (let* ((mastodon-media--preview-max-height 123) + (result + (mastodon-media--get-media-link-rendering "http://example.org/img.png" + "http://example.org/remote/img.png")) + (result-no-properties (substring-no-properties result)) + (properties (text-properties-at 0 result))) + (should (string= "[img] " result-no-properties)) + (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) + (should (eq 'needs-loading (plist-get properties 'media-state))) + (should (eq 'media-link (plist-get properties 'media-type))) + (should (eq :mock-image (plist-get properties 'display))) + (should (eq 'highlight (plist-get properties 'mouse-face))) + (should (eq 'image (plist-get properties 'mastodon-tab-stop))) + (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) + (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) + (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview" + (plist-get properties 'help-echo)))))) (ert-deftest mastodon-media:load-image-from-url:avatar-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image - * - (when (version< emacs-version "27.1") 'imagemagick) - t :height 123) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - url - #'mastodon-media--process-image-response - `(:my-marker (:height 123) 1 ,url)) - => :called-as-expected) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering "http://example.org/img.png") - ":rest")) - - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image + * + (when (version< emacs-version "27.1") 'imagemagick) + t :height 123) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + url + #'mastodon-media--process-image-response + `(:my-marker (:height 123) 1 ,url)) + => :called-as-expected) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering "http://example.org/img.png") + ":rest")) + + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) (ert-deftest mastodon-media:load-image-from-url:avatar-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock - (mock (image-type-available-p 'imagemagick) => nil) - (mock (create-image * nil t) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - url - #'mastodon-media--process-image-response - `(:my-marker () 1 ,url)) - => :called-as-expected) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering "http://example.org/img.png") - ":rest")) - - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) + (mock (image-type-available-p 'imagemagick) => nil) + (mock (create-image * nil t) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + url + #'mastodon-media--process-image-response + `(:my-marker () 1 ,url)) + => :called-as-expected) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering "http://example.org/img.png") + ":rest")) + + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) (ert-deftest mastodon-media:load-image-from-url:media-link-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image * nil t) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - "http://example.org/image.png" - #'mastodon-media--process-image-response - '(:my-marker (:max-height 321) 5 "http://example.org/image.png")) - => :called-as-expected) - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-media-link-rendering url) - ":rest")) - (let ((mastodon-media--preview-max-height 321)) - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image * nil t) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + "http://example.org/image.png" + #'mastodon-media--process-image-response + '(:my-marker (:max-height 321) 5 "http://example.org/image.png")) + => :called-as-expected) + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-media-link-rendering url) + ":rest")) + (let ((mastodon-media--preview-max-height 321)) + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) (ert-deftest mastodon-media:load-image-from-url:media-link-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock - (mock (image-type-available-p 'imagemagick) => nil) - (mock (create-image * nil t) => '(image foo)) - (mock (copy-marker 7) => :my-marker ) - (mock (url-retrieve - "http://example.org/image.png" - #'mastodon-media--process-image-response - '(:my-marker () 5 "http://example.org/image.png")) - => :called-as-expected) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering url) - ":rest")) - (let ((mastodon-media--preview-max-height 321)) - (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) + (mock (image-type-available-p 'imagemagick) => nil) + (mock (create-image * nil t) => '(image foo)) + (mock (copy-marker 7) => :my-marker ) + (mock (url-retrieve + "http://example.org/image.png" + #'mastodon-media--process-image-response + '(:my-marker () 5 "http://example.org/image.png")) + => :called-as-expected) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering url) + ":rest")) + (let ((mastodon-media--preview-max-height 321)) + (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) (ert-deftest mastodon-media:load-image-from-url:url-fetching-fails () "Should cope with failures in url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) (with-mock - (mock (image-type-available-p 'imagemagick) => t) - (mock (create-image - * - (when (version< emacs-version "27.1") 'imagemagick) - t :height 123) => '(image foo)) - (stub url-retrieve => (error "url-retrieve failed")) - - (with-temp-buffer - (insert (concat "Start:" - (mastodon-media--get-avatar-rendering "http://example.org/img.png") - ":rest")) - - (should (eq :loading-failed (mastodon-media--load-image-from-url url 'avatar 7 1))) - ;; the media state was updated so we won't load this again: - (should (eq 'loading-failed (get-text-property 7 'media-state))))))) + (mock (image-type-available-p 'imagemagick) => t) + (mock (create-image + * + (when (version< emacs-version "27.1") 'imagemagick) + t :height 123) => '(image foo)) + (stub url-retrieve => (error "url-retrieve failed")) + + (with-temp-buffer + (insert (concat "Start:" + (mastodon-media--get-avatar-rendering "http://example.org/img.png") + ":rest")) + + (should (eq :loading-failed (mastodon-media--load-image-from-url url 'avatar 7 1))) + ;; the media state was updated so we won't load this again: + (should (eq 'loading-failed (get-text-property 7 'media-state))))))) (ert-deftest mastodon-media:process-image-response () "Should process the HTTP response and adjust the source buffer." (with-temp-buffer (with-mock - (let ((source-buffer (current-buffer)) - used-marker - saved-marker) - (insert "start:") - (setq used-marker (copy-marker (point)) - saved-marker (copy-marker (point))) - ;; Mock needed for the preliminary image created in - ;; mastodon-media--get-avatar-rendering - (stub create-image => :fake-image) - (insert (mastodon-media--get-avatar-rendering - "http://example.org/image.png.") - ":end") - (with-temp-buffer - (insert "some irrelevant\n" - "http headers\n" - "which will be ignored\n\n" - "fake\nimage\ndata") - (goto-char (point-min)) - - (mock (create-image - "fake\nimage\ndata" - (when (version< emacs-version "27.1") 'imagemagick) - t ':image :option) => :fake-image) - - (mastodon-media--process-image-response - () used-marker '(:image :option) 1 "http://example.org/image.png") - - ;; the used marker has been unset: - (should (null (marker-position used-marker))) - ;; the media-state has been set to loaded and the image is being displayed - (should (eq 'loaded (get-text-property saved-marker 'media-state source-buffer))) - (should (eq ':fake-image (get-text-property saved-marker 'display source-buffer)))))))) + (let ((source-buffer (current-buffer)) + used-marker + saved-marker) + (insert "start:") + (setq used-marker (copy-marker (point)) + saved-marker (copy-marker (point))) + ;; Mock needed for the preliminary image created in + ;; mastodon-media--get-avatar-rendering + (stub create-image => :fake-image) + (insert (mastodon-media--get-avatar-rendering + "http://example.org/image.png.") + ":end") + (with-temp-buffer + (insert "some irrelevant\n" + "http headers\n" + "which will be ignored\n\n" + "fake\nimage\ndata") + (goto-char (point-min)) + + (mock (create-image + "fake\nimage\ndata" + (when (version< emacs-version "27.1") 'imagemagick) + t ':image :option) => :fake-image) + + (mastodon-media--process-image-response + () used-marker '(:image :option) 1 "http://example.org/image.png") + + ;; the used marker has been unset: + (should (null (marker-position used-marker))) + ;; the media-state has been set to loaded and the image is being displayed + (should (eq 'loaded (get-text-property saved-marker 'media-state source-buffer))) + (should (eq ':fake-image (get-text-property saved-marker 'display source-buffer)))))))) (ert-deftest mastodon-media:inline-images () "Should process all media in buffer." (with-mock - ;; Stub needed for the test setup: - (stub create-image => '(image ignored)) - - (let (marker-media-link marker-media-link-bad-url marker-false-media marker-avatar) - (with-temp-buffer - (insert "Some text before\n") - (setq marker-media-link (copy-marker (point))) - (insert (mastodon-media--get-media-link-rendering "http://example.org/i.jpg") - " some more text ") - (setq marker-media-link-bad-url (copy-marker (point))) - (insert (mastodon-media--get-media-link-rendering "/files/small/missing.png") - " some more text ") - (setq marker-false-media (copy-marker (point))) - (insert - ;; text that looks almost like an avatar but lacks the media-url property - (propertize "this won't be processed" - 'media-state 'needs-loading - 'media-type 'avatar) - "even more text ") - (setq marker-avatar (copy-marker (point))) - (insert (mastodon-media--get-avatar-rendering "http://example.org/avatar.png") - " end of text") - (goto-char (point-min)) - - ;; stub for the actual test: - (stub mastodon-media--load-image-from-url) - (mastodon-media--inline-images (point-min) (point-max)) - - (should (eq 'loading (get-text-property marker-media-link 'media-state))) - (should (eq 'invalid-url (get-text-property marker-media-link-bad-url 'media-state))) - (should (eq 'loading (get-text-property marker-avatar 'media-state))) - (should (eq 'needs-loading (get-text-property marker-false-media 'media-state))))))) + ;; Stub needed for the test setup: + (stub create-image => '(image ignored)) + + (let (marker-media-link marker-media-link-bad-url marker-false-media marker-avatar) + (with-temp-buffer + (insert "Some text before\n") + (setq marker-media-link (copy-marker (point))) + (insert (mastodon-media--get-media-link-rendering "http://example.org/i.jpg") + " some more text ") + (setq marker-media-link-bad-url (copy-marker (point))) + (insert (mastodon-media--get-media-link-rendering "/files/small/missing.png") + " some more text ") + (setq marker-false-media (copy-marker (point))) + (insert + ;; text that looks almost like an avatar but lacks the media-url property + (propertize "this won't be processed" + 'media-state 'needs-loading + 'media-type 'avatar) + "even more text ") + (setq marker-avatar (copy-marker (point))) + (insert (mastodon-media--get-avatar-rendering "http://example.org/avatar.png") + " end of text") + (goto-char (point-min)) + + ;; stub for the actual test: + (stub mastodon-media--load-image-from-url) + (mastodon-media--inline-images (point-min) (point-max)) + + (should (eq 'loading (get-text-property marker-media-link 'media-state))) + (should (eq 'invalid-url (get-text-property marker-media-link-bad-url 'media-state))) + (should (eq 'loading (get-text-property marker-avatar 'media-state))) + (should (eq 'needs-loading (get-text-property marker-false-media 'media-state))))))) diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el index 3047ae6..778d350 100644 --- a/test/mastodon-notifications-test.el +++ b/test/mastodon-notifications-test.el @@ -185,8 +185,8 @@ "Ensure get request format for notifictions is accurate." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications" )) - (mastodon-notifications--get)))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications" )) + (mastodon-notifications--get)))) (defun mastodon-notifications--test-type (fun sample) "Test notification draw functions. diff --git a/test/mastodon-search-tests.el b/test/mastodon-search-tests.el index b8521f3..552f467 100644 --- a/test/mastodon-search-tests.el +++ b/test/mastodon-search-tests.el @@ -38,7 +38,15 @@ "A sample mastodon account search result (parsed json)") (defconst mastodon-search-test-single-tag - '((name . "TeamBringBackVisibleScrollbars") (url . "https://todon.nl/tags/TeamBringBackVisibleScrollbars") (history . [((day . "1636156800") (uses . "0") (accounts . "0")) ((day . "1636070400") (uses . "0") (accounts . "0")) ((day . "1635984000") (uses . "0") (accounts . "0")) ((day . "1635897600") (uses . "0") (accounts . "0")) ((day . "1635811200") (uses . "0") (accounts . "0")) ((day . "1635724800") (uses . "0") (accounts . "0")) ((day . "1635638400") (uses . "0") (accounts . "0"))]))) + '((name . "TeamBringBackVisibleScrollbars") + (url . "https://todon.nl/tags/TeamBringBackVisibleScrollbars") + (history . [((day . "1636156800") (uses . "0") (accounts . "0")) + ((day . "1636070400") (uses . "0") (accounts . "0")) + ((day . "1635984000") (uses . "0") (accounts . "0")) + ((day . "1635897600") (uses . "0") (accounts . "0")) + ((day . "1635811200") (uses . "0") (accounts . "0")) + ((day . "1635724800") (uses . "0") (accounts . "0")) + ((day . "1635638400") (uses . "0") (accounts . "0"))]))) (defconst mastodon-search-test-single-status '((id . "107230316503209282") @@ -83,59 +91,57 @@ (following_count . 634) (statuses_count . 3807) (last_status_at . "2021-11-05") - (emojis . - []) - (fields . - [((name . "dark to") - (value . "themselves") - (verified_at)) - ((name . "its raining") - (value . "plastic") - (verified_at)) - ((name . "dis") - (value . "integration") - (verified_at)) - ((name . "ungleichzeitigkeit und") - (value . "gleichzeitigkeit, philosophisch") - (verified_at))])) - (media_attachments . - []) - (mentions . - [((id . "242971") - (username . "mousebot") - (url . "https://todon.nl/@mousebot") - (acct . "mousebot"))]) - (tags . - []) - (emojis . - []) + (emojis . []) + (fields . [((name . "dark to") + (value . "themselves") + (verified_at)) + ((name . "its raining") + (value . "plastic") + (verified_at)) + ((name . "dis") + (value . "integration") + (verified_at)) + ((name . "ungleichzeitigkeit und") + (value . "gleichzeitigkeit, philosophisch") + (verified_at))])) + (media_attachments . []) + (mentions . [((id . "242971") + (username . "mousebot") + (url . "https://todon.nl/@mousebot") + (acct . "mousebot"))]) + (tags . []) + (emojis . []) (card) (poll))) (ert-deftest mastodon-search-test-get-user-info-@ () "Should build a list from a single account for company completion." - (let ((account mastodon-search--single-account-query)) - (should (equal (mastodon-search--get-user-info-@ account) - '(": ( ) { : | : & } ; :" "@mousebot" "https://todon.nl/@mousebot"))))) + (should + (equal + (mastodon-search--get-user-info-@ mastodon-search--single-account-query) + '(": ( ) { : | : & } ; :" "@mousebot" "https://todon.nl/@mousebot")))) (ert-deftest mastodon-search-test-get-user-info () "Should build a list from a single account for company completion." - (let ((account mastodon-search--single-account-query)) - (should (equal (mastodon-search--get-user-info account) - '(": ( ) { : | : & } ; :" "mousebot" "https://todon.nl/@mousebot"))))) + (should + (equal + (mastodon-search--get-user-info mastodon-search--single-account-query) + '(": ( ) { : | : & } ; :" "mousebot" "https://todon.nl/@mousebot")))) (ert-deftest mastodon-search-test-get-hashtag-info () "Should build a list of hashtag name and URL." - (let ((tag mastodon-search-test-single-tag)) - (should (equal (mastodon-search--get-hashtag-info tag) - '("TeamBringBackVisibleScrollbars" - "https://todon.nl/tags/TeamBringBackVisibleScrollbars"))))) + (should + (equal + (mastodon-search--get-hashtag-info mastodon-search-test-single-tag) + '("TeamBringBackVisibleScrollbars" + "https://todon.nl/tags/TeamBringBackVisibleScrollbars")))) (ert-deftest mastodon-search-test-get-status-info () "Should return a list of ID, timestamp, content, and spoiler." - (let ((status mastodon-search-test-single-status)) - (should (equal (mastodon-search--get-status-info status) - '("107230316503209282" - "2021-11-06T13:19:40.628Z" - "" - "

This is a nice test toot, for testing purposes. Thank you.

"))))) + (should + (equal + (mastodon-search--get-status-info mastodon-search-test-single-status) + '("107230316503209282" + "2021-11-06T13:19:40.628Z" + "" + "

This is a nice test toot, for testing purposes. Thank you.

")))) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index 4edf5d5..e4606cc 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -125,8 +125,8 @@ "Should request toots older than max_id." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) - (mastodon-tl--more-json "timelines/foo" 12345)))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) + (mastodon-tl--more-json "timelines/foo" 12345)))) (ert-deftest more-json-id-string () "Should request toots older than max_id. @@ -135,8 +135,8 @@ a string or a numeric." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) - (mastodon-tl--more-json "timelines/foo" "12345")))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) + (mastodon-tl--more-json "timelines/foo" "12345")))) (ert-deftest update-json-id-string () "Should request toots more recent than since_id. @@ -145,8 +145,8 @@ a string or a numeric." a string or a numeric." (let ((mastodon-instance-url "https://instance.url")) (with-mock - (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?since_id=12345")) - (mastodon-tl--updated-json "timelines/foo" "12345")))) + (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?since_id=12345")) + (mastodon-tl--updated-json "timelines/foo" "12345")))) (ert-deftest mastodon-tl--relative-time-description () "Should format relative time as expected" @@ -253,39 +253,39 @@ a string or a numeric." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (let ((byline (mastodon-tl--byline mastodon-tl-test-base-toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - (handle-location 20)) - (should (string= (substring-no-properties - byline) - "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (let ((byline (mastodon-tl--byline mastodon-tl-test-base-toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + (handle-location 20)) + (should (string= (substring-no-properties + byline) + "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ ")) - (should (eq (get-text-property handle-location 'mastodon-tab-stop byline) - 'user-handle)) - (should (string= (get-text-property handle-location 'mastodon-handle byline) - "@acct42@example.space")) - (should (equal (get-text-property handle-location 'help-echo byline) - "Browse user profile of @acct42@example.space")))))) + (should (eq (get-text-property handle-location 'mastodon-tab-stop byline) + 'user-handle)) + (should (string= (get-text-property handle-location 'mastodon-handle byline) + "@acct42@example.space")) + (should (equal (get-text-property handle-location 'help-echo byline) + "Browse user profile of @acct42@example.space")))))) (ert-deftest mastodon-tl--byline-regular-with-avatar () "Should format the regular toot correctly." (let ((mastodon-tl--show-avatars-p t) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock - (stub create-image => '(image "fake data")) - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline mastodon-tl-test-base-toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (stub create-image => '(image "fake data")) + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline mastodon-tl-test-base-toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -295,14 +295,14 @@ a string or a numeric." (toot (cons '(reblogged . t) mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -312,14 +312,14 @@ a string or a numeric." (toot (cons '(favourited . t) mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -330,14 +330,14 @@ a string or a numeric." (toot `((favourited . t) (reblogged . t) ,@mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(B) (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(B) (F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 ------------ "))))) @@ -349,31 +349,31 @@ a string or a numeric." (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock - ;; We don't expect to use the toot's timestamp but the timestamp of the - ;; reblogged toot: - (mock (date-to-time timestamp) => '(1 2)) - (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") - (mock (date-to-time original-timestamp) => '(3 4)) - (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") - - (let ((byline (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - (handle1-location 20) - (handle2-location 65)) - (should (string= (substring-no-properties byline) - "Account 42 (@acct42@example.space) + ;; We don't expect to use the toot's timestamp but the timestamp of the + ;; reblogged toot: + (mock (date-to-time timestamp) => '(1 2)) + (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") + (mock (date-to-time original-timestamp) => '(3 4)) + (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") + + (let ((byline (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + (handle1-location 20) + (handle2-location 65)) + (should (string= (substring-no-properties byline) + "Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time ------------ ")) - (should (eq (get-text-property handle1-location 'mastodon-tab-stop byline) - 'user-handle)) - (should (equal (get-text-property handle1-location 'help-echo byline) - "Browse user profile of @acct42@example.space")) - (should (eq (get-text-property handle2-location 'mastodon-tab-stop byline) - 'user-handle)) - (should (equal (get-text-property handle2-location 'help-echo byline) - "Browse user profile of @acct43@example.space")))))) + (should (eq (get-text-property handle1-location 'mastodon-tab-stop byline) + 'user-handle)) + (should (equal (get-text-property handle1-location 'help-echo byline) + "Browse user profile of @acct42@example.space")) + (should (eq (get-text-property handle2-location 'mastodon-tab-stop byline) + 'user-handle)) + (should (equal (get-text-property handle2-location 'help-echo byline) + "Browse user profile of @acct43@example.space")))))) (ert-deftest mastodon-tl--byline-reblogged-with-avatars () "Should format the reblogged toot correctly." @@ -383,19 +383,19 @@ a string or a numeric." (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock - ;; We don't expect to use the toot's timestamp but the timestamp of the - ;; reblogged toot: - (stub create-image => '(image "fake data")) - (mock (date-to-time timestamp) => '(1 2)) - (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") - (mock (date-to-time original-timestamp) => '(3 4)) - (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "Account 42 (@acct42@example.space) + ;; We don't expect to use the toot's timestamp but the timestamp of the + ;; reblogged toot: + (stub create-image => '(image "fake data")) + (mock (date-to-time timestamp) => '(1 2)) + (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") + (mock (date-to-time original-timestamp) => '(3 4)) + (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time ------------ "))))) @@ -408,18 +408,18 @@ a string or a numeric." (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock - ;; We don't expect to use the toot's timestamp but the timestamp of the - ;; reblogged toot: - (mock (date-to-time timestamp) => '(1 2)) - (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") - (mock (date-to-time original-timestamp) => '(3 4)) - (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") - - (should (string= (substring-no-properties - (mastodon-tl--byline toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - "(B) (F) Account 42 (@acct42@example.space) + ;; We don't expect to use the toot's timestamp but the timestamp of the + ;; reblogged toot: + (mock (date-to-time timestamp) => '(1 2)) + (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") + (mock (date-to-time original-timestamp) => '(3 4)) + (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") + + (should (string= (substring-no-properties + (mastodon-tl--byline toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + "(B) (F) Account 42 (@acct42@example.space) Boosted Account 43 (@acct43@example.space) original time ------------ "))))) @@ -429,17 +429,17 @@ a string or a numeric." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock - (mock (date-to-time timestamp) => '(22782 21551)) - (mock (current-time) => '(22782 22000)) - (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") - - (let* ((formatted-string (mastodon-tl--byline mastodon-tl-test-base-toot - 'mastodon-tl--byline-author - 'mastodon-tl--byline-boosted)) - (timestamp-start (string-match "2999-99-99" formatted-string)) - (properties (text-properties-at timestamp-start formatted-string))) - (should (equal '(22782 21551) (plist-get properties 'timestamp))) - (should (string-equal "7 minutes ago" (plist-get properties 'display))))))) + (mock (date-to-time timestamp) => '(22782 21551)) + (mock (current-time) => '(22782 22000)) + (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") + + (let* ((formatted-string (mastodon-tl--byline mastodon-tl-test-base-toot + 'mastodon-tl--byline-author + 'mastodon-tl--byline-boosted)) + (timestamp-start (string-match "2999-99-99" formatted-string)) + (properties (text-properties-at timestamp-start formatted-string))) + (should (equal '(22782 21551) (plist-get properties 'timestamp))) + (should (string-equal "7 minutes ago" (plist-get properties 'display))))))) (ert-deftest mastodon-tl--consider-timestamp-for-updates-no-active-callback () "Should update the timestamp update variables as expected." @@ -454,33 +454,33 @@ a string or a numeric." ;; something a later update doesn't update: (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (null mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) + (should (null mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something only shortly sooner doesn't update: (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" (time-subtract long-in-the-future (seconds-to-time 9)))) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" (time-subtract long-in-the-future (seconds-to-time 9)))) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (null mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) + (should (null mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something much sooner, does update (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" soon-in-the-future)) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" soon-in-the-future)) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (null mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) + (should (null mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) ))) (ert-deftest mastodon-tl--consider-timestamp-for-updates-with-active-callback () @@ -496,27 +496,27 @@ a string or a numeric." ;; something a later update doesn't update: (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (eq 'initial-timer mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) + (should (eq 'initial-timer mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something much sooner, does update (with-mock - (mock (mastodon-tl--relative-time-details 'fake-timestamp) => - (cons "xxx ago" soon-in-the-future)) - (mock (cancel-timer 'initial-timer)) - (mock (run-at-time soon-in-the-future nil - #'mastodon-tl--update-timestamps-callback - (current-buffer) nil) => 'new-timer) + (mock (mastodon-tl--relative-time-details 'fake-timestamp) => + (cons "xxx ago" soon-in-the-future)) + (mock (cancel-timer 'initial-timer)) + (mock (run-at-time soon-in-the-future nil + #'mastodon-tl--update-timestamps-callback + (current-buffer) nil) => 'new-timer) - (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) + (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) - (should (eq 'new-timer mastodon-tl--timestamp-update-timer)) - (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) + (should (eq 'new-timer mastodon-tl--timestamp-update-timer)) + (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) ))) (ert-deftest mastodon-tl--find-property-range--no-tag () @@ -691,20 +691,20 @@ a string or a numeric." (list 'r3 r3 r2 r3) (list 'end end r3 end)))) (with-mock - (stub message => nil) ;; don't mess up our test output with the function's messages - (cl-dolist (test test-cases) - (let ((test-name (cl-first test)) - (test-start (cl-second test)) - (expected-prev (cl-third test)) - (expected-next (cl-fourth test))) - (goto-char test-start) - (mastodon-tl--previous-tab-item) - (should (equal (list 'prev test-name expected-prev) - (list 'prev test-name (point)))) - (goto-char test-start) - (mastodon-tl--next-tab-item) - (should (equal (list 'next test-name expected-next) - (list 'next test-name (point))))))))))) + (stub message => nil) ;; don't mess up our test output with the function's messages + (cl-dolist (test test-cases) + (let ((test-name (cl-first test)) + (test-start (cl-second test)) + (expected-prev (cl-third test)) + (expected-next (cl-fourth test))) + (goto-char test-start) + (mastodon-tl--previous-tab-item) + (should (equal (list 'prev test-name expected-prev) + (list 'prev test-name (point)))) + (goto-char test-start) + (mastodon-tl--next-tab-item) + (should (equal (list 'next test-name expected-next) + (list 'next test-name (point))))))))))) (ert-deftest mastodon-tl--next-tab-item--no-spaces-at-ends () "Should do the correct tab actions even with regions right at buffer ends." @@ -739,20 +739,20 @@ a string or a numeric." (list 'gap2 gap2 r3 r4) (list 'r4 r4 r3 r4)))) (with-mock - (stub message => nil) ;; don't mess up our test output with the function's messages - (cl-dolist (test test-cases) - (let ((test-name (cl-first test)) - (test-start (cl-second test)) - (expected-prev (cl-third test)) - (expected-next (cl-fourth test))) - (goto-char test-start) - (mastodon-tl--previous-tab-item) - (should (equal (list 'prev test-name expected-prev) - (list 'prev test-name (point)))) - (goto-char test-start) - (mastodon-tl--next-tab-item) - (should (equal (list 'next test-name expected-next) - (list 'next test-name (point))))))))))) + (stub message => nil) ;; don't mess up our test output with the function's messages + (cl-dolist (test test-cases) + (let ((test-name (cl-first test)) + (test-start (cl-second test)) + (expected-prev (cl-third test)) + (expected-next (cl-fourth test))) + (goto-char test-start) + (mastodon-tl--previous-tab-item) + (should (equal (list 'prev test-name expected-prev) + (list 'prev test-name (point)))) + (goto-char test-start) + (mastodon-tl--next-tab-item) + (should (equal (list 'next test-name expected-next) + (list 'next test-name (point))))))))))) (defun tl-tests--property-values-at (property ranges) @@ -781,33 +781,33 @@ constant." (setq markers (nreverse markers)) (with-mock - (mock (current-time) => now) - (stub run-at-time => 'fake-timer) - - ;; make the initial call - (mastodon-tl--update-timestamps-callback (current-buffer) nil) - (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" - "unset 7" "unset 8" "unset 9" "unset 10" "unset 11" "unset 12" "unset 13") - (tl-tests--property-values-at 'display - (tl-tests--all-regions-with-property 'timestamp)))) - - ;; fake the follow-up call - (mastodon-tl--update-timestamps-callback (current-buffer) (nth 4 markers)) - (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" - "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" - "unset 12" "unset 13") - (tl-tests--property-values-at 'display - (tl-tests--all-regions-with-property 'timestamp)))) - (should (null (marker-position (nth 4 markers)))) - - ;; fake the follow-up call - (mastodon-tl--update-timestamps-callback (current-buffer) (nth 9 markers)) - (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" - "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" - "12 minutes ago" "13 minutes ago") - (tl-tests--property-values-at 'display - (tl-tests--all-regions-with-property 'timestamp)))) - (should (null (marker-position (nth 9 markers))))))))) + (mock (current-time) => now) + (stub run-at-time => 'fake-timer) + + ;; make the initial call + (mastodon-tl--update-timestamps-callback (current-buffer) nil) + (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" + "unset 7" "unset 8" "unset 9" "unset 10" "unset 11" "unset 12" "unset 13") + (tl-tests--property-values-at 'display + (tl-tests--all-regions-with-property 'timestamp)))) + + ;; fake the follow-up call + (mastodon-tl--update-timestamps-callback (current-buffer) (nth 4 markers)) + (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" + "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" + "unset 12" "unset 13") + (tl-tests--property-values-at 'display + (tl-tests--all-regions-with-property 'timestamp)))) + (should (null (marker-position (nth 4 markers)))) + + ;; fake the follow-up call + (mastodon-tl--update-timestamps-callback (current-buffer) (nth 9 markers)) + (should (equal '("2 minutes ago" "3 minutes ago" "4 minutes ago" "5 minutes ago" "6 minutes ago" + "7 minutes ago" "8 minutes ago" "9 minutes ago" "10 minutes ago" "11 minutes ago" + "12 minutes ago" "13 minutes ago") + (tl-tests--property-values-at 'display + (tl-tests--all-regions-with-property 'timestamp)))) + (should (null (marker-position (nth 9 markers))))))))) (ert-deftest mastodon-tl--has-spoiler () "Should be able to detect toots with spoiler text as expected" @@ -833,10 +833,10 @@ constant." (insert "some text before\n") (setq toot-start (point)) (with-mock - (stub create-image => '(image "fake data")) - (stub shr-render-region => nil) ;; Travis's Emacs doesn't have libxml - (insert - (mastodon-tl--spoiler normal-toot-with-spoiler))) + (stub create-image => '(image "fake data")) + (stub shr-render-region => nil) ;; Travis's Emacs doesn't have libxml + (insert + (mastodon-tl--spoiler normal-toot-with-spoiler))) (setq toot-end (point)) (insert "\nsome more text.") (add-text-properties @@ -899,10 +899,10 @@ constant." 'help-echo "https://example.space/tags/sampletag") " some text after")) (rendered (with-mock - (stub shr-render-region => nil) - (mastodon-tl--render-text - fake-input-text - mastodon-tl-test-base-toot))) + (stub shr-render-region => nil) + (mastodon-tl--render-text + fake-input-text + mastodon-tl-test-base-toot))) (tag-location 7)) (should (eq (get-text-property tag-location 'mastodon-tab-stop rendered) 'hashtag)) @@ -946,10 +946,10 @@ constant." 'help-echo "https://bar.example/@foo") " some text after")) (rendered (with-mock - (stub shr-render-region => nil) - (mastodon-tl--render-text - fake-input-text - mastodon-tl-test-base-toot))) + (stub shr-render-region => nil) + (mastodon-tl--render-text + fake-input-text + mastodon-tl-test-base-toot))) (mention-location 11)) (should (eq (get-text-property mention-location 'mastodon-tab-stop rendered) 'user-handle)) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index abc66d0..06da870 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -41,6 +41,6 @@ (ert-deftest cancel () (with-mock - (mock (kill-buffer-and-window)) - (mastodon-toot--cancel) - (mock-verify))) + (mock (kill-buffer-and-window)) + (mastodon-toot--cancel) + (mock-verify))) -- cgit v1.2.3 From 522926bcca0caf45516da3dcd00c944066641965 Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Tue, 9 Nov 2021 18:24:54 +0100 Subject: Hamonize tests. - Add a header comment explicitly switching off lexical binding - Harmonize naming (always start with module and double hyphen) - Ensure all tests have at least a minimal doc string. - Move tests from `mastodon-auth-test.el` to `mastodon-auth-tests.el` --- test/mastodon-auth-test.el | 59 ------------------------------------- test/mastodon-auth-tests.el | 59 ++++++++++++++++++++++++++++++------- test/mastodon-client-tests.el | 26 ++++++++-------- test/mastodon-http-tests.el | 13 ++++---- test/mastodon-media-tests.el | 20 +++++++------ test/mastodon-notifications-test.el | 14 +++++---- test/mastodon-search-tests.el | 18 +++++------ test/mastodon-tl-tests.el | 27 +++++++++++------ test/mastodon-toot-tests.el | 25 +++++++++++----- 9 files changed, 134 insertions(+), 127 deletions(-) delete mode 100644 test/mastodon-auth-test.el diff --git a/test/mastodon-auth-test.el b/test/mastodon-auth-test.el deleted file mode 100644 index 4372047..0000000 --- a/test/mastodon-auth-test.el +++ /dev/null @@ -1,59 +0,0 @@ -;;; mastodon-auth--test.el --- Tests for mastodon-auth -*- lexical-binding: t; -*- - -;; Copyright (C) 2020 Ian Eure - -;; Author: Ian Eure -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el -;; Package-Requires: ((emacs "26.1")) - -;; This file is not part of GNU Emacs. - -;; This file is part of mastodon.el. - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: - -;; mastodon-auth--test.el provides ERT tests for mastodon-auth.el - -;;; Code: - -(require 'ert) - -(ert-deftest mastodon-auth--handle-token-response--good () - (should (string= "foo" (mastodon-auth--handle-token-response '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) - -(ert-deftest mastodon-auth--handle-token-response--unknown () - (should - (equal - '(error "Unknown response from mastodon-auth--get-token!") - (condition-case error - (progn - (mastodon-auth--handle-token-response '(:herp "derp")) - nil) - (t error))))) - -(ert-deftest mastodon-auth--handle-token-response--failure () - (let ((error-message "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.")) - (should - (equal - `(error ,(format "Mastodon-auth--access-token: invalid_grant: %s" error-message)) - (condition-case error - (mastodon-auth--handle-token-response - `(:error "invalid_grant" :error_description ,error-message)) - (t error)))))) - -(provide 'mastodon-auth--test) -;;; mastodon-auth--test.el ends here diff --git a/test/mastodon-auth-tests.el b/test/mastodon-auth-tests.el index fda04eb..6a090b7 100644 --- a/test/mastodon-auth-tests.el +++ b/test/mastodon-auth-tests.el @@ -1,6 +1,38 @@ +;;; mastodon-auth-test.el --- Tests for mastodon-auth.el -*- lexical-binding: nil -*- + (require 'el-mock) -(ert-deftest generate-token--no-storing-credentials () +(ert-deftest mastodon-auth--handle-token-response--good () + "Should extract the access token from a good response." + (should + (string= + "foo" + (mastodon-auth--handle-token-response + '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) + +(ert-deftest mastodon-auth--handle-token-response--unknown () + "Should throw an error when the response is unparsable." + (should + (equal + '(error "Unknown response from mastodon-auth--get-token!") + (condition-case error + (progn + (mastodon-auth--handle-token-response '(:herp "derp")) + nil) + (t error))))) + +(ert-deftest mastodon-auth--handle-token-response--failure () + "Should throw an error when the response indicates an error." + (let ((error-message "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.")) + (should + (equal + `(error ,(format "Mastodon-auth--access-token: invalid_grant: %s" error-message)) + (condition-case error + (mastodon-auth--handle-token-response + `(:error "invalid_grant" :error_description ,error-message)) + (t error)))))) + +(ert-deftest mastodon-auth--generate-token--no-storing-credentials () "Should make `mastdon-http--post' request to generate auth token." (with-mock (let ((mastodon-auth-source-file "") @@ -19,7 +51,7 @@ :unauthenticated)) (mastodon-auth--generate-token)))) -(ert-deftest generate-token--storing-credentials () +(ert-deftest mastodon-auth--generate-token--storing-credentials () "Should make `mastdon-http--post' request to generate auth token." (with-mock (let ((mastodon-auth-source-file "~/.authinfo") @@ -41,26 +73,33 @@ :unauthenticated)) (mastodon-auth--generate-token)))) -(ert-deftest get-token () +(ert-deftest mastodon-auth--get-token () "Should generate token and return JSON response." (with-temp-buffer (with-mock (mock (mastodon-auth--generate-token) => (progn (insert "\n\n{\"access_token\":\"abcdefg\"}") (current-buffer))) - (should (equal (mastodon-auth--get-token) '(:access_token "abcdefg")))))) + (should + (equal (mastodon-auth--get-token) + '(:access_token "abcdefg")))))) -(ert-deftest access-token-found () +(ert-deftest mastodon-auth--access-token-found () "Should return value in `mastodon-auth--token-alist' if found." (let ((mastodon-instance-url "https://instance.url") (mastodon-auth--token-alist '(("https://instance.url" . "foobar")) )) - (should (string= (mastodon-auth--access-token) "foobar")))) + (should + (string= (mastodon-auth--access-token) "foobar")))) -(ert-deftest access-token-2 () +(ert-deftest mastodon-auth--access-token-not-found () "Should set and return `mastodon-auth--token' if nil." (let ((mastodon-instance-url "https://instance.url") - (mastodon-auth--token nil)) + (mastodon-auth--token-alist nil)) (with-mock (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) - (should (string= (mastodon-auth--access-token) "foobaz")) - (should (equal mastodon-auth--token-alist '(("https://instance.url" . "foobaz"))))))) + (should + (string= (mastodon-auth--access-token) + "foobaz")) + (should + (equal mastodon-auth--token-alist + '(("https://instance.url" . "foobaz"))))))) diff --git a/test/mastodon-client-tests.el b/test/mastodon-client-tests.el index 12d2350..b112729 100644 --- a/test/mastodon-client-tests.el +++ b/test/mastodon-client-tests.el @@ -1,6 +1,8 @@ +;;; mastodon-client-test.el --- Tests for mastodon-client.el -*- lexical-binding: nil -*- + (require 'el-mock) -(ert-deftest register () +(ert-deftest mastodon-client--register () "Should POST to /apps." (with-mock (mock (mastodon-http--api "apps") => "https://instance.url/api/v1/apps") @@ -13,7 +15,7 @@ :unauthenticated)) (mastodon-client--register))) -(ert-deftest fetch () +(ert-deftest mastodon-client--fetch () "Should return client registration JSON." (with-temp-buffer (with-mock @@ -22,7 +24,7 @@ (current-buffer))) (should (equal (mastodon-client--fetch) '(:foo "bar")))))) -(ert-deftest store-1 () +(ert-deftest mastodon-client--store-1 () "Should return the client plist." (let ((mastodon-instance-url "http://mastodon.example") (plist '(:client_id "id" :client_secret "secret"))) @@ -33,8 +35,8 @@ (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) (should (equal (mastodon-client--store) plist)))))) -(ert-deftest store-2 () - "Should store client in `mastodon-client--token-file'." +(ert-deftest mastodon-client--store-2 () + "Should store client in `mastodon-client--token-file'." (let* ((mastodon-instance-url "http://mastodon.example") (plstore (plstore-open "stubfile.plstore")) (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) @@ -42,7 +44,7 @@ (should (string= (plist-get client :client_id) "id")) (should (string= (plist-get client :client_secret) "secret")))) -(ert-deftest read-finds-match () +(ert-deftest mastodon-client--read-finds-match () "Should return mastodon client from `mastodon-token-file' if it exists." (let ((mastodon-instance-url "http://mastodon.example")) (with-mock @@ -50,27 +52,27 @@ (should (equal (mastodon-client--read) '(:client_id "id2" :client_secret "secret2")))))) -(ert-deftest read-finds-no-match () +(ert-deftest mastodon-client--read-finds-no-match () "Should return mastodon client from `mastodon-token-file' if it exists." (let ((mastodon-instance-url "http://mastodon.social")) (with-mock (mock (mastodon-client--token-file) => "fixture/client.plstore") (should (equal (mastodon-client--read) nil))))) -(ert-deftest read-empty-store () +(ert-deftest mastodon-client--read-empty-store () "Should return nil if mastodon client is not present in the plstore." (with-mock (mock (mastodon-client--token-file) => "fixture/empty.plstore") (should (equal (mastodon-client--read) nil)))) -(ert-deftest client-set-and-matching () +(ert-deftest mastodon-client--client-set-and-matching () "Should return `mastondon-client' if `mastodon-client--client-details-alist' is non-nil and instance url is included." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist '(("https://other.example" . :no-match) ("http://mastodon.example" . :matches)))) (should (eq (mastodon-client) :matches)))) -(ert-deftest client-set-but-not-matching () +(ert-deftest mastodon-client--client-set-but-not-matching () "Should read from `mastodon-token-file' if wrong data is cached." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist '(("http://other.example" :wrong)))) @@ -81,7 +83,7 @@ '(("http://mastodon.example" :client_id "foo" :client_secret "bar") ("http://other.example" :wrong))))))) -(ert-deftest client-unset () +(ert-deftest mastodon-client--client-unset () "Should read from `mastodon-token-file' if available." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) @@ -91,7 +93,7 @@ (should (equal mastodon-client--client-details-alist '(("http://mastodon.example" :client_id "foo" :client_secret "bar"))))))) -(ert-deftest client-unset-and-not-in-storage () +(ert-deftest mastodon-client--client-unset-and-not-in-storage () "Should store client data in plstore if it can't be read." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) diff --git a/test/mastodon-http-tests.el b/test/mastodon-http-tests.el index d0f715e..00e1f41 100644 --- a/test/mastodon-http-tests.el +++ b/test/mastodon-http-tests.el @@ -1,9 +1,10 @@ +;;; mastodon-http-test.el --- Tests for mastodon-http.el -*- lexical-binding: nil -*- + (require 'el-mock) -(ert-deftest mastodon-http:get:retrieves-endpoint () +(ert-deftest mastodon-http--get-retrieves-endpoint () "Should make a `url-retrieve' of the given URL." - (let ((callback-double (lambda () "double"))) - (with-mock - (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) - (mock (mastodon-auth--access-token) => "test-token") - (mastodon-http--get "https://foo.bar/baz")))) + (with-mock + (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) + (mock (mastodon-auth--access-token) => "test-token") + (mastodon-http--get "https://foo.bar/baz"))) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index 3345e74..886c7b0 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -1,6 +1,8 @@ +;;; mastodon-media-test.el --- Tests for mastodon-media.el -*- lexical-binding: nil -*- + (require 'el-mock) -(ert-deftest mastodon-media:get-avatar-rendering () +(ert-deftest mastodon-media--get-avatar-rendering () "Should return text with all expected properties." (with-mock (mock (image-type-available-p 'imagemagick) => t) @@ -16,7 +18,7 @@ (should (eq 'avatar (plist-get properties 'media-type))) (should (eq :mock-image (plist-get properties 'display)))))) -(ert-deftest mastodon-media:get-media-link-rendering () +(ert-deftest mastodon-media--get-media-link-rendering () "Should return text with all expected properties." (with-mock (mock (create-image * nil t) => :mock-image) @@ -39,7 +41,7 @@ (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview" (plist-get properties 'help-echo)))))) -(ert-deftest mastodon-media:load-image-from-url:avatar-with-imagemagic () +(ert-deftest mastodon-media--load-image-from-url-avatar-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) @@ -63,7 +65,7 @@ (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) -(ert-deftest mastodon-media:load-image-from-url:avatar-without-imagemagic () +(ert-deftest mastodon-media--load-image-from-url-avatar-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock @@ -83,7 +85,7 @@ (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) -(ert-deftest mastodon-media:load-image-from-url:media-link-with-imagemagic () +(ert-deftest mastodon-media--load-image-from-url-media-link-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock @@ -102,7 +104,7 @@ (let ((mastodon-media--preview-max-height 321)) (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) -(ert-deftest mastodon-media:load-image-from-url:media-link-without-imagemagic () +(ert-deftest mastodon-media--load-image-from-url-media-link-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock @@ -122,7 +124,7 @@ (let ((mastodon-media--preview-max-height 321)) (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) -(ert-deftest mastodon-media:load-image-from-url:url-fetching-fails () +(ert-deftest mastodon-media--load-image-from-url-url-fetching-fails () "Should cope with failures in url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) @@ -143,7 +145,7 @@ ;; the media state was updated so we won't load this again: (should (eq 'loading-failed (get-text-property 7 'media-state))))))) -(ert-deftest mastodon-media:process-image-response () +(ert-deftest mastodon-media--process-image-response () "Should process the HTTP response and adjust the source buffer." (with-temp-buffer (with-mock @@ -180,7 +182,7 @@ (should (eq 'loaded (get-text-property saved-marker 'media-state source-buffer))) (should (eq ':fake-image (get-text-property saved-marker 'display source-buffer)))))))) -(ert-deftest mastodon-media:inline-images () +(ert-deftest mastodon-media--inline-images () "Should process all media in buffer." (with-mock ;; Stub needed for the test setup: diff --git a/test/mastodon-notifications-test.el b/test/mastodon-notifications-test.el index 778d350..ee6748a 100644 --- a/test/mastodon-notifications-test.el +++ b/test/mastodon-notifications-test.el @@ -1,8 +1,10 @@ +;;; mastodon-notifications-test.el --- Tests for mastodon-notifications.el -*- lexical-binding: nil -*- + (require 'cl-lib) (require 'cl-macs) (require 'el-mock) -(defconst mastodon-notifications-test-base-mentioned +(defconst mastodon-notifications--test-base-mentioned '((id . "1234") (type . "mention") (created_at . "2018-03-06T04:27:21.288Z" ) @@ -43,7 +45,7 @@ (favourites_count . 0) (reblog)))) -(defconst mastodon-notifications-test-base-favourite +(defconst mastodon-notifications--test-base-favourite '((id . "1234") (type . "favourite") (created_at . "2018-03-06T04:27:21.288Z" ) @@ -84,7 +86,7 @@ (favourites_count . 0) (reblog)))) -(defconst mastodon-notifications-test-base-boosted +(defconst mastodon-notifications--test-base-boosted '((id . "1234") (type . "reblog") (created_at . "2018-03-06T04:27:21.288Z" ) @@ -125,7 +127,7 @@ (favourites_count . 0) (reblog)))) -(defconst mastodon-notifications-test-base-followed +(defconst mastodon-notifications--test-base-followed '((id . "1234") (type . "follow") (created_at . "2018-03-06T04:27:21.288Z" ) @@ -166,7 +168,7 @@ (favourites_count . 0) (reblog)))) -(defconst mastodon-notifications-test-base-favourite +(defconst mastodon-notifications--test-base-favourite '((id . "1234") (type . "mention") (created_at . "2018-03-06T04:27:21.288Z" ) @@ -181,7 +183,7 @@ (statuses_count . 101) (note . "E")))) -(ert-deftest notification-get () +(ert-deftest mastodon-notifications--notification-get () "Ensure get request format for notifictions is accurate." (let ((mastodon-instance-url "https://instance.url")) (with-mock diff --git a/test/mastodon-search-tests.el b/test/mastodon-search-tests.el index 552f467..996f786 100644 --- a/test/mastodon-search-tests.el +++ b/test/mastodon-search-tests.el @@ -1,4 +1,4 @@ - +;;; mastodon-search-test.el --- Tests for mastodon-search.el -*- lexical-binding: nil -*- (defconst mastodon-search--single-account-query '((id . "242971") @@ -37,7 +37,7 @@ (verified_at))])) "A sample mastodon account search result (parsed json)") -(defconst mastodon-search-test-single-tag +(defconst mastodon-search--test-single-tag '((name . "TeamBringBackVisibleScrollbars") (url . "https://todon.nl/tags/TeamBringBackVisibleScrollbars") (history . [((day . "1636156800") (uses . "0") (accounts . "0")) @@ -48,7 +48,7 @@ ((day . "1635724800") (uses . "0") (accounts . "0")) ((day . "1635638400") (uses . "0") (accounts . "0"))]))) -(defconst mastodon-search-test-single-status +(defconst mastodon-search--test-single-status '((id . "107230316503209282") (created_at . "2021-11-06T13:19:40.628Z") (in_reply_to_id) @@ -114,33 +114,33 @@ (card) (poll))) -(ert-deftest mastodon-search-test-get-user-info-@ () +(ert-deftest mastodon-search--get-user-info-@ () "Should build a list from a single account for company completion." (should (equal (mastodon-search--get-user-info-@ mastodon-search--single-account-query) '(": ( ) { : | : & } ; :" "@mousebot" "https://todon.nl/@mousebot")))) -(ert-deftest mastodon-search-test-get-user-info () +(ert-deftest mastodon-search--get-user-info () "Should build a list from a single account for company completion." (should (equal (mastodon-search--get-user-info mastodon-search--single-account-query) '(": ( ) { : | : & } ; :" "mousebot" "https://todon.nl/@mousebot")))) -(ert-deftest mastodon-search-test-get-hashtag-info () +(ert-deftest mastodon-search--get-hashtag-info () "Should build a list of hashtag name and URL." (should (equal - (mastodon-search--get-hashtag-info mastodon-search-test-single-tag) + (mastodon-search--get-hashtag-info mastodon-search--test-single-tag) '("TeamBringBackVisibleScrollbars" "https://todon.nl/tags/TeamBringBackVisibleScrollbars")))) -(ert-deftest mastodon-search-test-get-status-info () +(ert-deftest mastodon-search--get-status-info () "Should return a list of ID, timestamp, content, and spoiler." (should (equal - (mastodon-search--get-status-info mastodon-search-test-single-status) + (mastodon-search--get-status-info mastodon-search--test-single-status) '("107230316503209282" "2021-11-06T13:19:40.628Z" "" diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index e4606cc..da3b315 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -1,3 +1,5 @@ +;;; mastodon-tl-test.el --- Tests for mastodon-tl.el -*- lexical-binding: nil -*- + (require 'cl-lib) (require 'cl-macs) (require 'el-mock) @@ -89,46 +91,46 @@ (reblogged))) "A sample reblogged/boosted toot (parsed json)") -(ert-deftest remove-html-1 () +(ert-deftest mastodon-tl--remove-html-1 () "Should remove all tags." (let ((input "foobar foobaz")) (should (string= (mastodon-tl--remove-html input) "foobar foobaz")))) -(ert-deftest remove-html-2 () +(ert-deftest mastodon-tl--remove-html-2 () "Should replace <\p> tags with two new lines." (let ((input "foobar

")) (should (string= (mastodon-tl--remove-html input) "foobar\n\n")))) -(ert-deftest toot-id-boosted () +(ert-deftest mastodon-tl--toot-id-boosted () "If a toot is boostedm, return the reblog id." (should (string= (mastodon-tl--as-string (mastodon-tl--toot-id mastodon-tl-test-base-boosted-toot)) "4543919"))) -(ert-deftest toot-id () +(ert-deftest mastodon-tl--toot-id () "If a toot is boostedm, return the reblog id." (should (string= (mastodon-tl--as-string (mastodon-tl--toot-id mastodon-tl-test-base-toot)) "61208"))) -(ert-deftest as-string-1 () +(ert-deftest mastodon-tl--as-string-1 () "Should accept a string or number and return a string." (let ((id "1000")) (should (string= (mastodon-tl--as-string id) id)))) -(ert-deftest as-string-2 () +(ert-deftest mastodon-tl--as-string-2 () "Should accept a string or number and return a string." (let ((id 1000)) (should (string= (mastodon-tl--as-string id) (number-to-string id))))) -(ert-deftest more-json () +(ert-deftest mastodon-tl--more-json () "Should request toots older than max_id." (let ((mastodon-instance-url "https://instance.url")) (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) (mastodon-tl--more-json "timelines/foo" 12345)))) -(ert-deftest more-json-id-string () +(ert-deftest mastodon-tl--more-json-id-string () "Should request toots older than max_id. `mastodon-tl--more-json' should accept and id that is either @@ -138,7 +140,7 @@ a string or a numeric." (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo?max_id=12345")) (mastodon-tl--more-json "timelines/foo" "12345")))) -(ert-deftest update-json-id-string () +(ert-deftest mastodon-tl--update-json-id-string () "Should request toots more recent than since_id. `mastodon-tl--updated-json' should accept and id that is either @@ -912,23 +914,27 @@ constant." "Browse tag #sampletag")))) (ert-deftest mastodon-tl--extract-hashtag-from-url-mastodon-link () + "Should extract the hashtag from a tags url." (should (equal (mastodon-tl--extract-hashtag-from-url "https://example.org/tags/foo" "https://example.org") "foo"))) (ert-deftest mastodon-tl--extract-hashtag-from-url-other-link () + "Should extract the hashtag from a tag url." (should (equal (mastodon-tl--extract-hashtag-from-url "https://example.org/tag/foo" "https://example.org") "foo"))) (ert-deftest mastodon-tl--extract-hashtag-from-url-wrong-instance () + "Should not find a tag when the instance doesn't match." (should (null (mastodon-tl--extract-hashtag-from-url "https://example.org/tags/foo" "https://other.example.org")))) (ert-deftest mastodon-tl--extract-hashtag-from-url-not-tag () + "Should not find a hashtag when not a tag url" (should (null (mastodon-tl--extract-hashtag-from-url "https://example.org/@userid" "https://example.org")))) @@ -957,17 +963,20 @@ constant." "Browse user profile of @foo@bar.example")))) (ert-deftest mastodon-tl--extract-userhandle-from-url-correct-case () + "Should extract the user handle from url." (should (equal (mastodon-tl--extract-userhandle-from-url "https://example.org/@someuser" "@SomeUser") "@SomeUser@example.org"))) (ert-deftest mastodon-tl--extract-userhandle-from-url-missing-at-in-text () + "Should not extract a user handle from url if the text is wrong." (should (null (mastodon-tl--extract-userhandle-from-url "https://example.org/@someuser" "SomeUser")))) (ert-deftest mastodon-tl--extract-userhandle-from-url-query-in-url () + "Should not extract a user handle from url if there is a query param." (should (null (mastodon-tl--extract-userhandle-from-url "https://example.org/@someuser?shouldnot=behere" "SomeUser")))) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index 06da870..804c55a 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -1,6 +1,8 @@ +;;; mastodon-toot-test.el --- Tests for mastodon-toot.el -*- lexical-binding: nil -*- + (require 'el-mock) -(defconst mastodon-toot-multi-mention +(defconst mastodon-toot--multi-mention '((mentions . [((id . "1") (username . "federated") @@ -18,28 +20,37 @@ (defconst mastodon-toot-no-mention '((mentions . []))) -(ert-deftest toot-multi-mentions () +(ert-deftest mastodon-toot--multi-mentions () + "Should build a correct mention string from the test toot data. + +Even the local name \"local\" gets a domain name added." (let ((mastodon-auth--acct-alist '(("https://local.social". "null"))) (mastodon-instance-url "https://local.social")) (should (string= - (mastodon-toot--mentions mastodon-toot-multi-mention) + (mastodon-toot--mentions mastodon-toot--multi-mention) "@local@local.social @federated@federated.social @federated@federated.cafe ")))) -(ert-deftest toot-multi-mentions-with-name () +(ert-deftest mastodon-toot--multi-mentions-with-name () + "Should build a correct mention string omitting self. + +Here \"local\" is the user themselves and gets omitted from the +mention string." (let ((mastodon-auth--acct-alist '(("https://local.social". "local"))) (mastodon-instance-url "https://local.social")) (should (string= - (mastodon-toot--mentions mastodon-toot-multi-mention) + (mastodon-toot--mentions mastodon-toot--multi-mention) "@federated@federated.social @federated@federated.cafe ")))) -(ert-deftest toot-no-mention () +(ert-deftest mastodon-toot--no-mention () + "Should construct an empty mention string without mentions." (let ((mastodon-auth--acct-alist '(("https://local.social". "null"))) (mastodon-instance-url "https://local.social")) (should (string= (mastodon-toot--mentions mastodon-toot-no-mention) "")))) -(ert-deftest cancel () +(ert-deftest mastodon-toot--cancel () + "Should kill the buffer when cancelling the toot." (with-mock (mock (kill-buffer-and-window)) (mastodon-toot--cancel) -- cgit v1.2.3 From eb922191259721d6b1b232de41bbd43ebdb10d2f Mon Sep 17 00:00:00 2001 From: Holger Dürer Date: Tue, 9 Nov 2021 21:06:04 +0100 Subject: Make the local ert runner pass. When just loading the lisp and test files one can run `M-x ert` but because things are subtly different we need to tweak a few more things to make things pass in that mode. --- test/fixture | 1 + test/mastodon-client-tests.el | 2 +- test/mastodon-media-tests.el | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) create mode 120000 test/fixture diff --git a/test/fixture b/test/fixture new file mode 120000 index 0000000..f418013 --- /dev/null +++ b/test/fixture @@ -0,0 +1 @@ +../fixture \ No newline at end of file diff --git a/test/mastodon-client-tests.el b/test/mastodon-client-tests.el index b112729..9123286 100644 --- a/test/mastodon-client-tests.el +++ b/test/mastodon-client-tests.el @@ -36,7 +36,7 @@ (should (equal (mastodon-client--store) plist)))))) (ert-deftest mastodon-client--store-2 () - "Should store client in `mastodon-client--token-file'." + "Should store client in `mastodon-client--token-file'." (let* ((mastodon-instance-url "http://mastodon.example") (plstore (plstore-open "stubfile.plstore")) (client (cdr (plstore-get plstore "mastodon-http://mastodon.example")))) diff --git a/test/mastodon-media-tests.el b/test/mastodon-media-tests.el index 886c7b0..6168aaf 100644 --- a/test/mastodon-media-tests.el +++ b/test/mastodon-media-tests.el @@ -70,6 +70,7 @@ (let ((url "http://example.org/image.png")) (with-mock (mock (image-type-available-p 'imagemagick) => nil) + (mock (image-transforms-p) => nil) (mock (create-image * nil t) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve @@ -109,6 +110,7 @@ (let ((url "http://example.org/image.png")) (with-mock (mock (image-type-available-p 'imagemagick) => nil) + (mock (image-transforms-p) => nil) (mock (create-image * nil t) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve -- cgit v1.2.3 From f22cfa60d301a1b834cb86f6f9b75b57d9dab6e8 Mon Sep 17 00:00:00 2001 From: mousebot Date: Sun, 12 Dec 2021 10:41:35 +0100 Subject: rename company mentions to 'mastodon-toot-mentions' and fix matching for both user handle and user display name. --- lisp/mastodon-toot.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 753a659..9112fc9 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -519,9 +519,10 @@ eg. \"feduser@fed.social\" -> \"feduser@fed.social\"." (defun mastodon-toot--mentions-company-candidates (prefix) "Given a company PREFIX query, build a list of candidates. The prefix can match against both user handles and display names." - (let (res) + (let ((prefix (substring prefix 1)) ;remove @ for search + (res)) (dolist (item (mastodon-search--search-accounts-query prefix)) - (when (or (string-prefix-p prefix (cadr item) t) + (when (or (string-prefix-p prefix (substring (cadr item) 1) t) (string-prefix-p prefix (car item) t)) (push (mastodon-toot--mentions-company-make-candidate item) res))) res)) @@ -533,11 +534,11 @@ The prefix can match against both user handles and display names." (url (caddr candidate))) (propertize handle 'annot display-name 'meta url))) -(defun mastodon-toot--mentions-completion (command &optional arg &rest ignored) +(defun mastodon-toot-mentions (command &optional arg &rest ignored) "A company completion backend for toot mentions." (interactive (list 'interactive)) (cl-case command - (interactive (company-begin-backend 'mastodon-toot--mentions-completion)) + (interactive (company-begin-backend 'mastodon-toot-mentions)) (prefix (when (and (bound-and-true-p mastodon-toot-mode) ; if masto toot minor mode (save-excursion (forward-whitespace -1) @@ -856,7 +857,7 @@ REPLY-JSON is the full JSON of the toot being replied to." (when (require 'company nil :noerror) (when mastodon-toot--enable-completion-for-mentions (set (make-local-variable 'company-backends) - (add-to-list 'company-backends 'mastodon-toot--mentions-completion)) + (add-to-list 'company-backends 'mastodon-toot-mentions)) (company-mode-on))) (make-local-variable 'after-change-functions) (push #'mastodon-toot--update-status-fields after-change-functions) -- cgit v1.2.3 From 2259577b8616005fd0265e211ae63188f4b32a3d Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 15 Dec 2021 10:39:20 +0100 Subject: a first hack to make media uploads immediate and async. this commit moves the call to -upload-attached-media into -attach-media. upload-attached-media now uploads a single item only, whichever file has just been selected at the prompt. but we still use the list of attached-media to handle preview displays. --- lisp/mastodon-http.el | 2 +- lisp/mastodon-toot.el | 45 ++++++++++++++++++++++----------------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 1ec0dc0..a4f126f 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -261,7 +261,7 @@ item uploaded, and `mastodon-toot--update-status-fields' is run." :parser 'json-read :headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))) - :sync t + :sync nil :success (cl-function (lambda (&key data &allow-other-keys) (when data diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9112fc9..6eac981 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -446,10 +446,8 @@ to `emojify-user-emojis', and the emoji data is updated." (defun mastodon-toot--send () "POST contents of new-toot buffer to Mastodon instance and kill buffer. -If media items have been attached with -`mastodon-toot--attach-media', upload them with -`mastodon-toot-upload-attached-media' and attach them to the -toot." +If media items have been attached and uploaded with +`mastodon-toot--attach-media', they are attached to the toot." (interactive) (let* ((toot (mastodon-toot--remove-docs)) (empty-toot-p (and (not mastodon-toot--media-attachments) @@ -465,7 +463,8 @@ toot." (symbol-name t))) ("spoiler_text" . ,spoiler))) (args-media (when mastodon-toot--media-attachments - (mastodon-toot--upload-attached-media) ; sync upload so we wait (and pray) till done + ;; (mastodon-toot--upload-attached-media) + ;; moved upload to mastodon-toot--attach-media (mapcar (lambda (id) (cons "media_ids[]" id)) mastodon-toot--media-attachment-ids))) @@ -614,9 +613,10 @@ The prefix can match against both user handles and display names." (mastodon-toot--update-status-fields)) (defun mastodon-toot--attach-media (file content-type description) - "Prompt for a attachment FILE of CONTENT-TYPE with DESCRIPTION. -A preview is displayed in the toot create buffer, and the file -will be uploaded and attached to the toot upon sending." + "Prompt for an attachment FILE of CONTENT-TYPE with DESCRIPTION. +A preview is displayed in the new toot buffer, and the file +is uploaded asynchronously using `mastodon-toot--upload-attached-media'. +File is actually attached to the toot upon posting." (interactive "fFilename: \nsContent type: \nsDescription: ") (when (>= (length mastodon-toot--media-attachments) 4) ;; Only a max. of 4 attachments are allowed, so pop the oldest one. @@ -627,21 +627,20 @@ will be uploaded and attached to the toot upon sending." (:content-type . ,content-type) (:description . ,description) (:filename . ,file))))) - (mastodon-toot--refresh-attachments-display)) - -(defun mastodon-toot--upload-attached-media () - "Actually upload attachments using `mastodon-http--post-media-attachment'. -The files to be uploaded are in `mastodon-toot--media-attachments'. -The items' ids are added to `mastodon-toot--media-attachment-ids', -which are used to attach them to a toot after uploading." - (mapcar (lambda (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..." (file-name-nondirectory filename)) - (mastodon-http--post-media-attachment url filename caption))) - mastodon-toot--media-attachments)) + (mastodon-toot--refresh-attachments-display) + ;; upload only most recent attachment: + (mastodon-toot--upload-attached-media (car (last mastodon-toot--media-attachments)))) + +(defun mastodon-toot--upload-attached-media (attachment) + "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))) + (caption (alist-get :description attachment)) + (url (concat mastodon-instance-url "/api/v2/media"))) + (message "Uploading %s..." (file-name-nondirectory filename)) + (mastodon-http--post-media-attachment url filename caption))) (defun mastodon-toot--refresh-attachments-display () "Update the display attachment previews in toot draft buffer." -- cgit v1.2.3 From f2af3a64967c403145c9b32aefd08ea8932a4770 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 15 Dec 2021 12:54:58 +0100 Subject: attach media test before post just test that length of --media-attachments == length of --media-attachment-ids. --- lisp/mastodon-toot.el | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 6eac981..9a88bd5 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -463,11 +463,14 @@ If media items have been attached and uploaded with (symbol-name t))) ("spoiler_text" . ,spoiler))) (args-media (when mastodon-toot--media-attachments + (if (= (length mastodon-toot--media-attachments) + (length mastodon-toot--media-attachment-ids)) ;; (mastodon-toot--upload-attached-media) ;; moved upload to mastodon-toot--attach-media - (mapcar (lambda (id) - (cons "media_ids[]" id)) - mastodon-toot--media-attachment-ids))) + (mapcar (lambda (id) + (cons "media_ids[]" id)) + mastodon-toot--media-attachment-ids) + (message "Looks like something went wrong with your uploads. Maybe you want to try again.")))) (args (append args-media args-no-media))) (if (> (length toot) (string-to-number mastodon-toot--max-toot-chars)) (message "Looks like your toot is longer than that maximum allowed length.") -- cgit v1.2.3 From 0fd7f354e9474ca9eb63049558c3a44514228ba5 Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 15 Dec 2021 21:00:18 +0100 Subject: refactor un/follow, un/block, un/mute functions --- lisp/mastodon-tl.el | 188 ++++++++++++++++++++-------------------------------- 1 file changed, 72 insertions(+), 116 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 5418374..742b247 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -940,145 +940,101 @@ webapp" "Query for USER-HANDLE from current status and follow that user." (interactive (list - (let ((user-handles (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json)))) - (completing-read "Handle of user to follow: " - user-handles - nil ; predicate - 'confirm)))) - (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) - (user-id (mastodon-profile--account-field account 'id)) - (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/follow" user-id)))) - (if account - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User %s (@%s) followed!" name user-handle)))) - (message "Cannot find a user with handle %S" user-handle)))) + (mastodon-tl--interactive-user-handles-get "follow"))) + (mastodon-tl--do-user-action-and-response user-handle "follow")) (defun mastodon-tl--unfollow-user (user-handle) "Query for USER-HANDLE from current status and unfollow that user." (interactive (list - (let ((user-handles (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json)))) - (completing-read "Handle of user to unfollow: " - user-handles - nil ; predicate - 'confirm)))) - (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) - (user-id (mastodon-profile--account-field account 'id)) - (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/unfollow" user-id)))) - (if account - (when (y-or-n-p (format "Unfollow user %s? " name)) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User %s (@%s) unfollowed!" name user-handle))))) - (message "Cannot find a user with handle %S" user-handle)))) + (mastodon-tl--interactive-user-handles-get "unfollow"))) + (mastodon-tl--do-user-action-and-response user-handle "unfollow" t)) -(defun mastodon-tl--mute-user (user-handle) - "Query for USER-HANDLE from current status and mute that user." +(defun mastodon-tl--block-user (user-handle) + "Query for USER-HANDLE from current status and block that user." (interactive (list - (let ((user-handles (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json)))) - (completing-read "Handle of user to mute: " - user-handles - nil ; predicate - 'confirm)))) - (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) - (user-id (mastodon-profile--account-field account 'id)) - (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/mute" user-id)))) - (if account - (when (y-or-n-p (format "Mute user %s? " name)) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User %s (@%s) muted!" name user-handle))))) - (message "Cannot find a user with handle %S" user-handle)))) + (mastodon-tl--interactive-user-handles-get "block"))) + (mastodon-tl--do-user-action-and-response user-handle "block")) -(defun mastodon-tl--unmute-user (user-handle) - "Query for USER-HANDLE from list of muted users and unmute that user." +(defun mastodon-tl--unblock-user (user-handle) + "Query for USER-HANDLE from list of blocked users and unblock that user." (interactive (list - (let* ((mutes-url (mastodon-http--api (format "mutes"))) - (mutes-json (mastodon-http--get-json mutes-url)) - (muted-accts (mapcar (lambda (muted) - (alist-get 'acct muted)) - mutes-json))) - (completing-read "Handle of user to unmute: " - muted-accts - nil ; predicate - t)))) - (let* ((account (mastodon-profile--search-account-by-handle - user-handle)) - (user-id (mastodon-profile--account-field account 'id)) - (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/unmute" user-id)))) - (if account - (when (y-or-n-p (format "Unmute user %s? " name)) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User %s (@%s) unmuted!" name user-handle))))) - (message "Cannot find a user with handle %S" user-handle)))) + (mastodon-tl--interactive-blocks-or-mutes-list-get "unblock"))) + (if (not user-handle) + (message "Looks like you have no blocks to unblock!") + (mastodon-tl--do-user-action-and-response user-handle "unblock" t))) -(defun mastodon-tl--block-user (user-handle) - "Query for USER-HANDLE from current status and block that user." +(defun mastodon-tl--mute-user (user-handle) + "Query for USER-HANDLE from current status and mute that user." (interactive (list - (let ((user-handles (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json)))) - (completing-read "Handle of user to block: " - user-handles - nil ; predicate - 'confirm)))) - (let* ((account (mastodon-profile--lookup-account-in-status - user-handle (mastodon-profile--toot-json))) - (user-id (mastodon-profile--account-field account 'id)) - (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/block" user-id)))) - (if account - (when (y-or-n-p (format "Block user %s? " name)) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User %s (@%s) blocked!" name user-handle))))) - (message "Cannot find a user with handle %S" user-handle)))) + (mastodon-tl--interactive-user-handles-get "mute"))) + (mastodon-tl--do-user-action-and-response user-handle "mute")) -(defun mastodon-tl--unblock-user (user-handle) - "Query for USER-HANDLE from list of blocked users and unblock that user." +(defun mastodon-tl--unmute-user (user-handle) + "Query for USER-HANDLE from list of muted users and unmute that user." (interactive (list - (let* ((blocks-url (mastodon-http--api (format "blocks"))) - (blocks-json (mastodon-http--get-json blocks-url)) - (blocked-accts (mapcar (lambda (blocked) - (alist-get 'acct blocked)) - blocks-json))) - (completing-read "Handle of user to unblock: " - blocked-accts + (mastodon-tl--interactive-blocks-or-mutes-list-get "unmute"))) + (if (not user-handle) + (message "Looks like you have no mutes to unmute!") + (mastodon-tl--do-user-action-and-response user-handle "unmute" t))) + +(defun mastodon-tl--interactive-user-handles-get (action) + "Get the list of user-handles for ACTION from the current toot." + (let ((user-handles (mastodon-profile--extract-users-handles + (mastodon-profile--toot-json)))) + (completing-read (format "Handle of user to %s: " action) + user-handles nil ; predicate - t)))) - (let* ((account (mastodon-profile--search-account-by-handle - user-handle)) + 'confirm))) + +(defun mastodon-tl--interactive-blocks-or-mutes-list-get (action) + "Fetch the list of accounts for ACTION from the server. +Action must be either \"unblock\" or \"mute\"." + (let* ((endpoint (cond ((equal action "unblock") + "blocks") + ((equal action "unmute") + "mutes"))) + (url (mastodon-http--api endpoint)) + (json (mastodon-http--get-json url)) + (accts (mapcar (lambda (user) + (alist-get 'acct user)) + json))) + (when accts + (completing-read (format "Handle of user to %s: " action) + accts + nil ; predicate + t)))) + +(defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp) + "Do ACTION on user NAME/USER-HANDLE. +NEGP is whether the action involves un-doing something." + (let* ((account (if negp + ;; TODO check if both are actually needed + (mastodon-profile--search-account-by-handle + user-handle) + (mastodon-profile--lookup-account-in-status + user-handle (mastodon-profile--toot-json)))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/unblock" user-id)))) + (url (mastodon-http--api (format "accounts/%s/%s" user-id action)))) (if account - (when (y-or-n-p (format "Unblock user %s? " name)) - (let ((response (mastodon-http--post url nil nil))) - (mastodon-http--triage response - (lambda () - (message "User %s (@%s) unblocked!" name user-handle))))) + (if (equal action "follow") ; y-or-n for all but follow + (mastodon-tl--do-user-action-function url name user-handle action) + (when (y-or-n-p (format "%s user %s? " action name)) + (mastodon-tl--do-user-action-function url name user-handle action))) (message "Cannot find a user with handle %S" user-handle)))) +(defun mastodon-tl--do-user-action-function (url name user-handle action) +"Post ACTION on user NAME/USER-HANDLE to URL." + (let ((response (mastodon-http--post url nil nil))) + (mastodon-http--triage response + (lambda () + (message "User %s (@%s) %sed!" name user-handle action))))) + ;; TODO: add this to new posts in some cases, e.g. in thread view. (defun mastodon-tl--reload-timeline-or-profile () "Reload the current timeline or profile page. -- cgit v1.2.3 From 834dabcb9147e45633166b3f3b35b2b1d6fc64cc Mon Sep 17 00:00:00 2001 From: mousebot Date: Wed, 15 Dec 2021 21:16:24 +0100 Subject: customize option to enable custom emoji by default. --- lisp/mastodon-toot.el | 5 +++++ lisp/mastodon.el | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9112fc9..cb3cd44 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -106,6 +106,11 @@ This is only used if company mode is installed." (const :tag "following only" "following") (const :tag "all users" "all"))) +(defcustom mastodon-toot--enable-custom-instance-emoji nil + "Whether to enable your instance's custom emoji by default." + :group 'mastodon-toot + :type 'boolean) + (defvar-local mastodon-toot--content-warning nil "A flag whether the toot should be marked with a content warning.") diff --git a/lisp/mastodon.el b/lisp/mastodon.el index f9c18a0..662b691 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -223,7 +223,9 @@ If REPLY-JSON is the json of the toot being replied to." ;;;###autoload (add-hook 'mastodon-mode-hook (lambda () (when (require 'emojify nil :noerror) - (emojify-mode t)))) + (emojify-mode t) + (when mastodon-toot--enable-custom-instance-emoji + (mastodon-toot--enable-custom-emoji))))) (define-derived-mode mastodon-mode special-mode "Mastodon" "Major mode for Mastodon, the federated microblogging network." -- cgit v1.2.3 From 663993bdac18f3c5dea4bc5d928f3c71d22b4824 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 16 Dec 2021 12:18:49 +0100 Subject: improve display of polls: place them after toot content and add padding for vote count display. --- lisp/mastodon-tl.el | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 5418374..c57a9b1 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -695,9 +695,9 @@ message is a link which unhides/hides the main body." (alist-get 'poll reblog) (alist-get 'poll toot)))) (concat + (mastodon-tl--render-text content toot) (when poll-p (mastodon-tl--get-poll toot)) - (mastodon-tl--render-text content toot) (mastodon-tl--media toot)))) (defun mastodon-tl--insert-status (toot body author-byline action-byline) @@ -729,16 +729,30 @@ takes a single function. By default it is "If post TOOT is a poll, return a formatted string of poll." (let* ((poll (mastodon-tl--field 'poll toot)) (options (mastodon-tl--field 'options poll)) + (option-titles (mapcar (lambda (x) + (alist-get 'title x)) + options)) + (longest-option (car (sort option-titles + (lambda (x y) + (> (length x) + (length y)))))) (option-counter 0)) - (concat "Poll: \n\n" + (concat "\nPoll: \n\n" (mapconcat (lambda (option) (progn - (format "Option %s: %s, %s votes.\n" + (format "Option %s: %s%s [%s votes].\n" (setq option-counter (1+ option-counter)) (alist-get 'title option) + (make-string + (1+ + (- (length longest-option) + (length (alist-get 'title + option)))) + ?\ ) (alist-get 'votes_count option)))) options - "\n") "\n"))) + "\n") + "\n"))) (defun mastodon-tl--poll-vote (option) "If there is a poll at point, prompt user for OPTION to vote on it." -- cgit v1.2.3 From 29fc628c128b82a91c87de226ebcb66db248fd4d Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 16 Dec 2021 14:12:52 +0100 Subject: indent-buffer on -tl.el --- lisp/mastodon-tl.el | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 742b247..46d999f 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -287,13 +287,13 @@ Optionally start from POS." (propertize (concat "@" handle) 'face 'mastodon-handle-face 'mouse-face 'highlight - ;; TODO: Replace url browsing with native profile viewing - 'mastodon-tab-stop 'user-handle + ;; TODO: Replace url browsing with native profile viewing + 'mastodon-tab-stop 'user-handle 'account account - 'shr-url profile-url - 'keymap mastodon-tl--link-keymap + 'shr-url profile-url + 'keymap mastodon-tl--link-keymap 'mastodon-handle (concat "@" handle) - 'help-echo (concat "Browse user profile of @" handle)) + 'help-echo (concat "Browse user profile of @" handle)) ")"))) (defun mastodon-tl--byline-boosted (toot) @@ -986,10 +986,10 @@ webapp" "Get the list of user-handles for ACTION from the current toot." (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read (format "Handle of user to %s: " action) - user-handles - nil ; predicate - 'confirm))) + (completing-read (format "Handle of user to %s: " action) + user-handles + nil ; predicate + 'confirm))) (defun mastodon-tl--interactive-blocks-or-mutes-list-get (action) "Fetch the list of accounts for ACTION from the server. @@ -1004,10 +1004,10 @@ Action must be either \"unblock\" or \"mute\"." (alist-get 'acct user)) json))) (when accts - (completing-read (format "Handle of user to %s: " action) - accts - nil ; predicate - t)))) + (completing-read (format "Handle of user to %s: " action) + accts + nil ; predicate + t)))) (defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp) "Do ACTION on user NAME/USER-HANDLE. @@ -1029,7 +1029,7 @@ NEGP is whether the action involves un-doing something." (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--do-user-action-function (url name user-handle action) -"Post ACTION on user NAME/USER-HANDLE to URL." + "Post ACTION on user NAME/USER-HANDLE to URL." (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response (lambda () -- cgit v1.2.3 From adfcd9bb45e3a59e8dbc5968708084e3dbf96b68 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 16 Dec 2021 15:52:22 +0100 Subject: refactor notify-user-posts functions this updates the functions to toggle receiving notifications when a user posts to work with the newly refactored follow-user function and associated functions. --- lisp/mastodon-tl.el | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 9305bea..46cd1d6 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -954,34 +954,25 @@ webapp" (defun mastodon-tl--follow-user (user-handle &optional notify) "Query for USER-HANDLE from current status and follow that user. If NOTIFY is \"true\", enable notifications when that user posts. -If NOTIFY is \"false\", disable notifications when that user posts." +If NOTIFY is \"false\", disable notifications when that user posts. +This can be called to toggle NOTIFY on users already being followed." (interactive (list (mastodon-tl--interactive-user-handles-get "follow"))) - (mastodon-tl--do-user-action-and-response user-handle "follow" notify)) + (mastodon-tl--do-user-action-and-response user-handle "follow" nil notify)) -(defun mastodon-tl--notify-user-posts (user-handle) - "Query for USER-HANDLE from current status and enable notifications when they post." +(defun mastodon-tl--enable-notify-user-posts (user-handle) + "Query for USER-HANDLE and enable notifications when they post." (interactive (list - (let ((user-handles (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json)))) - (completing-read "Receive notifications when user posts: " - user-handles - nil ; predicate - 'confirm)))) + (mastodon-tl--interactive-user-handles-get "enable"))) (mastodon-tl--follow-user user-handle "true")) -(defun mastodon-tl--no-notify-user-posts (user-handle) - "Query for USER-HANDLE from current status and disable notifications when they post." +(defun mastodon-tl--disable-notify-user-posts (user-handle) + "Query for USER-HANDLE and disable notifications when they post." (interactive (list - (let ((user-handles (mastodon-profile--extract-users-handles - (mastodon-profile--toot-json)))) - (completing-read "Disable notifications when user posts: " - user-handles - nil ; predicate - 'confirm)))) + (mastodon-tl--interactive-user-handles-get "disable"))) (mastodon-tl--follow-user user-handle "false")) (defun mastodon-tl--unfollow-user (user-handle) @@ -1027,7 +1018,10 @@ If NOTIFY is \"false\", disable notifications when that user posts." "Get the list of user-handles for ACTION from the current toot." (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--toot-json)))) - (completing-read (format "Handle of user to %s: " action) + (completing-read (if (or (equal action "disable") + (equal action "enable")) + (format "%s notifications when user posts: " action) + (format "Handle of user to %s: " action)) user-handles nil ; predicate 'confirm))) @@ -1050,9 +1044,12 @@ Action must be either \"unblock\" or \"mute\"." nil ; predicate t)))) -(defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp) +(defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp notify) "Do ACTION on user NAME/USER-HANDLE. -NEGP is whether the action involves un-doing something." +NEGP is whether the action involves un-doing something. +If NOTIFY is \"true\", enable notifications when that user posts. +If NOTIFY is \"false\", disable notifications when that user posts. +NOTIFY is only non-nil when called by `mastodon-tl--follow-user'." (let* ((account (if negp ;; TODO check if both are actually needed (mastodon-profile--search-account-by-handle @@ -1061,20 +1058,30 @@ NEGP is whether the action involves un-doing something." user-handle (mastodon-profile--toot-json)))) (user-id (mastodon-profile--account-field account 'id)) (name (mastodon-profile--account-field account 'display_name)) - (url (mastodon-http--api (format "accounts/%s/%s" user-id action)))) + (url (mastodon-http--api + (if notify + (format "accounts/%s/%s?notify=%s" user-id action notify) + (format "accounts/%s/%s" user-id action))))) (if account (if (equal action "follow") ; y-or-n for all but follow - (mastodon-tl--do-user-action-function url name user-handle action) + (mastodon-tl--do-user-action-function url name user-handle action notify) (when (y-or-n-p (format "%s user %s? " action name)) (mastodon-tl--do-user-action-function url name user-handle action))) (message "Cannot find a user with handle %S" user-handle)))) -(defun mastodon-tl--do-user-action-function (url name user-handle action) +(defun mastodon-tl--do-user-action-function (url name user-handle action &optional notify) "Post ACTION on user NAME/USER-HANDLE to URL." (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response (lambda () - (message "User %s (@%s) %sed!" name user-handle action))))) + (cond ((string-equal notify "true") + (message "Receiving notifications for user %s (@%s)!" + name user-handle)) + ((string-equal notify "false") + (message "Not receiving notifications for user %s (@%s)!" + name user-handle)) + ((eq notify nil) + (message "User %s (@%s) %sed!" name user-handle action))))))) ;; TODO: add this to new posts in some cases, e.g. in thread view. (defun mastodon-tl--reload-timeline-or-profile () -- cgit v1.2.3 From 2cc25a13872581eea9fc36b1ddc809f34cd3747a Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 16 Dec 2021 17:31:56 +0100 Subject: readme update --- README.org | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/README.org b/README.org index 3a7a06e..ab2dbff 100644 --- a/README.org +++ b/README.org @@ -15,33 +15,34 @@ It adds the following features: | | show a lock icon for locked accounts | | =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | | =V= | view your favorited toots | -| =K= | view your bookmarked toots | | =i= | toggle pinning of toots | | =S-C-P= | jump to your profile | | =U= | update your profile bio note | | Notifications: | | | | follow requests now also appear in notifications | | =a=, =r= | accept/reject follow requests | +| | notifications for when a user posts (optional) | | Timelines: | | | =C= | copy url of toot at point | | =d= | delete your toot at point, and reload current timeline | | =D= | delete and redraft toot at point, preserving reply/CW/visibility | | =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | -| =k= | toggle bookmark of toot at point | -| | display polls and vote on polls (pretty basic for now) | +| =k=, =K= | toggle bookmark of toot at point, view bookmarked toots | +| | display polls and vote on them | | | images are links to the full image, can be zoomed/rotated/saved (see image keymap) | | | images scale properly | | | toot visibility (direct, followers only) icon appears in toot bylines | | | display a toot's favorites, boosts and replies count in thread view | +| | customize option to cache images | | Toots: | | | | mention booster in replies by default | -| | autocompletion of mentions, via company-mode (must be installed to work) | -| =C-c C-a= | media uploads | -| | media uploads previews in toot compose buffer | +| | replies preserve visibility status/CW of original toot | +| | autocompletion of user mentions, via =company-mode= (must be installed to work) | +| =C-c C-a= | media uploads, asynchronous | +| | media upload previews displayed in toot compose buffer | | =C-c C-n= | and sensitive media/nsfw flag | | =C-c C-e= | add emoji (if =emojify= installed) | | | download and use your instance's custom emoji | -| | replies preserve visibility status/CW of original toot | | | server's maximum toot length shown in toot compose buffer | | Search: | | | =S= | search (posts, users, tags) (NB: only posts you have interacted with are searched) | @@ -73,27 +74,16 @@ This repo also incorporates fixes for two bugs that were never merged into the u - https://github.com/jdenen/mastodon.el/issues/227 (and https://github.com/jdenen/mastodon.el/issues/234) - https://github.com/jdenen/mastodon.el/issues/228 -** roadmap-ish - -I might add a few more features if the ones I added turn out to work ok. Possible additions/amendments: - -- [X] update profile note. -- [X] fix loading more notifications re-loads the same ones -- [X] view/accept/reject follow requests in notifications view. -- [X] fix sometimes usernames don't appear in timelines -- [X] voting on polls -- [X] delete and redraft toots -- [X] prevent loss of draft toots by the toot-send bug -- [X] fix scaling of images -- [X] display post visibility status in timelines -- [X] caching of images / avatars -- better display of polls -- [X] display number of boosts/faves in toot byline -- mention all thread participants in replies -- [X] improve (or even partially disable) async. +** 2FA It looks like 2-factor auth was never completed in the original repo. It's not a priority for me, auth ain't my thing. If you want to hack on it, its on the develop branch in the original repo. +** contributing + +Contributions are welcome. Registration is disabled by default on the gitea instance, but if you are interested, get in touch with me on mastodon: + +[[https://todon.nl/@mousebot][@mousebot@todon.nl]] + * Original README ** Installation -- cgit v1.2.3 From 5288ffc54c50d41cddcd432a258ada3f7f882a93 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 12:58:33 +0100 Subject: fix media attachments test before posting if --media-attachments is non-nil, make sure we have non-nil media-args, and that we have same num of -ids to attach as attachments uploaded. --- lisp/mastodon-toot.el | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 9a88bd5..8953ee6 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -463,24 +463,27 @@ If media items have been attached and uploaded with (symbol-name t))) ("spoiler_text" . ,spoiler))) (args-media (when mastodon-toot--media-attachments - (if (= (length mastodon-toot--media-attachments) - (length mastodon-toot--media-attachment-ids)) - ;; (mastodon-toot--upload-attached-media) - ;; moved upload to mastodon-toot--attach-media (mapcar (lambda (id) (cons "media_ids[]" id)) - mastodon-toot--media-attachment-ids) - (message "Looks like something went wrong with your uploads. Maybe you want to try again.")))) + mastodon-toot--media-attachment-ids))) (args (append args-media args-no-media))) - (if (> (length toot) (string-to-number mastodon-toot--max-toot-chars)) - (message "Looks like your toot is longer than that maximum allowed length.") - (if empty-toot-p - (message "Empty toot. Cowardly refusing to post this.") - (let ((response (mastodon-http--post endpoint args nil))) - (mastodon-http--triage response - (lambda () - (mastodon-toot--kill) - (message "Toot toot!")))))))) + (cond ((and mastodon-toot--media-attachments + ;; make sure we have media args + ;; and the same num of ids as attachments + (or (not args-media) + (not (= (length mastodon-toot--media-attachments) + (length mastodon-toot--media-attachment-ids))))) + (message "Something is wrong with your uploads. Wait for them to complete or try again.")) + ((> (length toot) (string-to-number mastodon-toot--max-toot-chars)) + (message "Looks like your toot is longer than that maximum allowed length.")) + (empty-toot-p + (message "Empty toot. Cowardly refusing to post this.")) + (t + (let ((response (mastodon-http--post endpoint args nil))) + (mastodon-http--triage response + (lambda () + (mastodon-toot--kill) + (message "Toot toot!")))))))) (defun mastodon-toot--process-local (acct) "Add domain to local ACCT and replace the curent user name with \"\". -- cgit v1.2.3 From 469974fa74e1661ea0a60cb5249ee0d3c6f640fd Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 13:10:42 +0100 Subject: ensure media-attachment is not a dir --- lisp/mastodon-toot.el | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 71bd3ad..2ff7f83 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -632,15 +632,17 @@ File is actually attached to the toot upon posting." (when (>= (length mastodon-toot--media-attachments) 4) ;; Only a max. of 4 attachments are allowed, so pop the oldest one. (pop mastodon-toot--media-attachments)) - (setq mastodon-toot--media-attachments - (nconc mastodon-toot--media-attachments - `(((:contents . ,(mastodon-http--read-file-as-string file)) - (:content-type . ,content-type) - (:description . ,description) - (:filename . ,file))))) - (mastodon-toot--refresh-attachments-display) - ;; upload only most recent attachment: - (mastodon-toot--upload-attached-media (car (last mastodon-toot--media-attachments)))) + (if (file-directory-p file) + (message "Looks like you chose a directory not a file.") + (setq mastodon-toot--media-attachments + (nconc mastodon-toot--media-attachments + `(((:contents . ,(mastodon-http--read-file-as-string file)) + (:content-type . ,content-type) + (:description . ,description) + (:filename . ,file))))) + (mastodon-toot--refresh-attachments-display) + ;; upload only most recent attachment: + (mastodon-toot--upload-attached-media (car (last mastodon-toot--media-attachments))))) (defun mastodon-toot--upload-attached-media (attachment) "Upload a single attachment using `mastodon-http--post-media-attachment'. -- cgit v1.2.3 From 439d87ecfa8684a5f218ccb3e7c6e1d4566f378b Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 14:00:52 +0100 Subject: FIX echo faves in thread view clashing with media help-echo move help-echo propertizing to author name of byline, in `mastodon-tl--byline-author'. so when we use `goto-next-toot' point is on author and we get the help echo and add the same help-echo to `mastodon-tl--content', but only when in thread view. this ensures the propertizing occurs prior to any image propertizing, when will then only replace the faves propertizing for the image part of the given toot. that way we have help echo for images when we want, and faves count otherwise. --- lisp/mastodon-tl.el | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 1cb9863..ff066f4 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -282,7 +282,17 @@ Optionally start from POS." (image-type-available-p 'imagemagick) (image-transforms-p))) (mastodon-media--get-avatar-rendering avatar-url)) - (propertize name 'face 'mastodon-display-name-face) + (propertize name + 'face 'mastodon-display-name-face + 'help-echo + ;; echo faves count when point on post author name: + ;; which is where --goto-next-toot puts point. + ;; prefer the reblog toot if present: + (let ((toot-to-use (or (alist-get 'reblog toot) toot))) + (format "%s faves | %s boosts | %s replies" + (alist-get 'favourites_count toot-to-use) + (alist-get 'reblogs_count toot-to-use) + (alist-get 'replies_count toot-to-use)))) " (" (propertize (concat "@" handle) 'face 'mastodon-handle-face @@ -689,17 +699,30 @@ message is a link which unhides/hides the main body." ""))) (defun mastodon-tl--content (toot) - "Retrieve text content from TOOT." + "Retrieve text content from TOOT. +If we are in thread view, the toot content is propertized with +faves/boosts/replies counts." (let* ((content (mastodon-tl--field 'content toot)) (reblog (alist-get 'reblog toot)) (poll-p (if reblog (alist-get 'poll reblog) (alist-get 'poll toot)))) (concat + (propertize (mastodon-tl--render-text content toot) - (when poll-p - (mastodon-tl--get-poll toot)) - (mastodon-tl--media toot)))) + 'help-echo (when (and mastodon-tl--buffer-spec + (string-match-p + "context" ; only when thread view + (plist-get mastodon-tl--buffer-spec 'endpoint))) + ;; prefer the reblog toot if present: + (let ((toot-to-use (or (alist-get 'reblog toot) toot))) + (format "%s faves | %s boosts | %s replies" + (alist-get 'favourites_count toot-to-use) + (alist-get 'reblogs_count toot-to-use) + (alist-get 'replies_count toot-to-use))))) + (when poll-p + (mastodon-tl--get-poll toot)) + (mastodon-tl--media toot)))) (defun mastodon-tl--insert-status (toot body author-byline action-byline) "Display the content and byline of timeline element TOOT. @@ -721,17 +744,6 @@ takes a single function. By default it is (mastodon-tl--byline toot author-byline action-byline)) 'toot-id (alist-get 'id toot) 'base-toot-id (mastodon-tl--toot-id toot) - ;; FIXME this breaks help property of `mastodon-media--get-media-link-rendering'. - 'help-echo (when (and mastodon-tl--buffer-spec - (string-match-p - "context" ; when thread view - (plist-get mastodon-tl--buffer-spec 'endpoint))) - ;; prefer the reblog toot if present: - (let ((toot-to-use (or (alist-get 'reblog toot) toot))) - (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count toot-to-use) - (alist-get 'reblogs_count toot-to-use) - (alist-get 'replies_count toot-to-use)))) 'toot-json toot) "\n") (when mastodon-tl--display-media-p -- cgit v1.2.3 From c65c6231f29929b6e39ebcc9b866d492519ae19b Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 14:15:38 +0100 Subject: keep "O"/my-profile binding when point on image. --- lisp/mastodon-tl.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index ff066f4..67ce4eb 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -148,6 +148,8 @@ types of mastodon links and not just shr.el-generated ones.") ;; remove shr's u binding, as it the maybe-probe-and-copy-url ;; is already bound to w also (define-key map (kbd "u") 'mastodon-tl--update) + ;; keep new my-profile binding; shr 'O' doesn't work here anyway + (define-key map (kbd "O") 'mastodon-profile--my-profile) (keymap-canonicalize map)) "The keymap to be set for shr.el generated image links. -- cgit v1.2.3 From 9329ce1674333a8bc67ee5f53178f27bac14991b Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 14:36:23 +0100 Subject: revert echo faves on toot text in thread view because it breaks propertizing of links/handles. so echo faves is now only on byline author name. --- lisp/mastodon-tl.el | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 67ce4eb..9355480 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -710,18 +710,7 @@ faves/boosts/replies counts." (alist-get 'poll reblog) (alist-get 'poll toot)))) (concat - (propertize - (mastodon-tl--render-text content toot) - 'help-echo (when (and mastodon-tl--buffer-spec - (string-match-p - "context" ; only when thread view - (plist-get mastodon-tl--buffer-spec 'endpoint))) - ;; prefer the reblog toot if present: - (let ((toot-to-use (or (alist-get 'reblog toot) toot))) - (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count toot-to-use) - (alist-get 'reblogs_count toot-to-use) - (alist-get 'replies_count toot-to-use))))) + (mastodon-tl--render-text content toot) (when poll-p (mastodon-tl--get-poll toot)) (mastodon-tl--media toot)))) -- cgit v1.2.3 From fc8005c8fe3c5466c7e2d2b510e24f6eba661431 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 15:03:00 +0100 Subject: bump version, change homepage link, readme --- README.org | 2 +- lisp/mastodon-async.el | 4 ++-- lisp/mastodon-auth.el | 4 ++-- lisp/mastodon-client.el | 4 ++-- lisp/mastodon-discover.el | 4 ++-- lisp/mastodon-http.el | 4 ++-- lisp/mastodon-inspect.el | 4 ++-- lisp/mastodon-media.el | 4 ++-- lisp/mastodon-notifications.el | 4 ++-- lisp/mastodon-profile.el | 4 ++-- lisp/mastodon-search.el | 4 ++-- lisp/mastodon-tl.el | 4 ++-- lisp/mastodon-toot.el | 4 ++-- lisp/mastodon.el | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/README.org b/README.org index ab2dbff..fff4bc8 100644 --- a/README.org +++ b/README.org @@ -32,7 +32,7 @@ It adds the following features: | | images are links to the full image, can be zoomed/rotated/saved (see image keymap) | | | images scale properly | | | toot visibility (direct, followers only) icon appears in toot bylines | -| | display a toot's favorites, boosts and replies count in thread view | +| | display toot's number of favorites, boosts and replies | | | customize option to cache images | | Toots: | | | | mention booster in replies by default | diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 524e13d..3651bd5 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.7.1 +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) -;; Homepage: https://github.com/jdenen/mastodon.el +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 8d0d7c6..8355200 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index bdfbca9..cb8eb26 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 33ce3d5..6b2eadf 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) -;; Homepage: https://github.com/jdenen/mastodon.el +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index a4f126f..00a0718 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 +;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1") (request "0.2.0")) -;; Homepage: https://github.com/jdenen/mastodon.el +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 57240f3..4d91948 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) -;; Homepage: https://github.com/jdenen/mastodon.el +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 457628f..bbab816 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 15633be..5efb7d4 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 7a9edc3..d21f5c0 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1") (seq "1.0")) -;; Homepage: https://github.com/jdenen/mastodon.el +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index fcfaec9..a7dcda9 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen , martyhiatt -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 9355480..89604b5 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 2ff7f83..c89acc7 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 -;; Homepage: https://github.com/jdenen/mastodon.el +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1")) +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 662b691..2411e20 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -2,9 +2,9 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen -;; Version: 0.9.1 +;; Version: 0.9.2 ;; Package-Requires: ((emacs "26.1") (request "0.3.2") (seq "1.0")) -;; Homepage: https://github.com/jdenen/mastodon.el +;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. -- cgit v1.2.3 From 3a87f6caa62cbd0e925c765d2ac2840ba55f8db1 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 16:22:46 +0100 Subject: depend on emacs 27.1, flychecks, docstrings, etc. strictly, the 27.1 dependency is only for proper-list-p in -http.el. --- lisp/mastodon-async.el | 25 +++++++++++++++---------- lisp/mastodon-auth.el | 2 +- lisp/mastodon-client.el | 2 +- lisp/mastodon-discover.el | 2 +- lisp/mastodon-http.el | 2 +- lisp/mastodon-inspect.el | 4 +++- lisp/mastodon-media.el | 2 +- lisp/mastodon-notifications.el | 2 +- lisp/mastodon-profile.el | 2 +- lisp/mastodon-search.el | 2 +- lisp/mastodon-tl.el | 2 +- lisp/mastodon-toot.el | 10 +++++++--- lisp/mastodon.el | 5 +++-- 13 files changed, 37 insertions(+), 25 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 3651bd5..77fdb8e 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. @@ -32,6 +32,8 @@ (require 'json) (require 'url-http) +(defvar url-http-end-of-headers) + (autoload 'mastodon-auth--access-token "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") @@ -153,10 +155,10 @@ NAME is the center portion of the buffer name for (url-retrieve url callback))) (defun mastodon-async--set-http-buffer (buffer http-buffer) - "Initializes for BUFFER a local variable `mastodon-async--http-buffer'. + "Initialize for BUFFER a local variable `mastodon-async--http-buffer'. HTTP-BUFFER is the initializing value. Use this funcion if HTTP-BUFFER -is not known when `mastodon-async--setup-buffer' is called." +is not known when `mastodon-async--setup-buffer' is called." (with-current-buffer (get-buffer-create buffer) (setq mastodon-async--http-buffer http-buffer))) @@ -164,6 +166,7 @@ is not known when `mastodon-async--setup-buffer' is called." http-buffer buffer-name queue-name) + "Set local variables for BUFFER, HTTP-BUFFER, BUFFER-NAME, and QUEUE-NAME." (with-current-buffer (get-buffer-create buffer) (let ((value mastodon-instance-url)) (make-local-variable 'mastodon-instance-url) @@ -173,7 +176,7 @@ is not known when `mastodon-async--setup-buffer' is called." (setq mastodon-async--queue queue-name))) (defun mastodon-async--setup-http (http-buffer name) - "Adds local variables to HTTP-BUFFER. + "Add local variables to HTTP-BUFFER. NAME is used to generate the display buffer and the queue." (let ((queue-name (concat " *mastodon-async-queue-" name "-" @@ -184,7 +187,8 @@ NAME is used to generate the display buffer and the queue." buffer-name queue-name))) (defun mastodon-async--setup-queue (http-buffer name) - "Sets up the buffer for the async queue." + "Set up HTTP-BUFFER buffer for the async queue. +NAME is used to generate the display buffer and the queue." (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name(concat "*mastodon-async-display-" name "-" @@ -194,11 +198,11 @@ NAME is used to generate the display buffer and the queue." queue-name)) (defun mastodon-async--setup-buffer (http-buffer name endpoint) - "Sets up the buffer timeline like `mastodon-tl--init'. + "Set up the buffer timeline like `mastodon-tl--init'. HTTP-BUFFER the name of the http-buffer, if unknown, set to... NAME is the name of the stream for the buffer name. -ENPOINT is the endpoint for the stream and timeline." +ENDPOINT is the endpoint for the stream and timeline." (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name (concat "*mastodon-async-display-" name "-" @@ -211,7 +215,7 @@ ENPOINT is the endpoint for the stream and timeline." (t (format "timelines/%s" endpoint))))) (mastodon-async--set-local-variables buffer-name http-buffer buffer-name queue-name) - ;; Similar to timeline init. + ;; Similar to timeline init. (with-current-buffer (get-buffer-create buffer-name) (setq inhibit-read-only t) ; for home timeline? (make-local-variable 'mastodon-tl--enable-relative-timestamps) @@ -238,7 +242,8 @@ ENPOINT is the endpoint for the stream and timeline." (defun mastodon-async--start-process (endpoint filter &optional name) "Start an async mastodon stream at ENDPOINT. -Filter the toots using FILTER." +Filter the toots using FILTER. +NAME is used for the queue and display buffer." (let* ((stream (concat "streaming/" endpoint)) (async-queue (mastodon-async--setup-queue "" (or name stream))) (async-buffer (mastodon-async--setup-buffer "" (or name stream) endpoint)) @@ -249,7 +254,7 @@ Filter the toots using FILTER." (message "HTTP SOURCE CLOSED"))))) (mastodon-async--setup-http http-buffer (or name stream)) (mastodon-async--set-http-buffer async-buffer http-buffer) - (mastodon-async--set-http-buffer async-queue http-buffer) + (mastodon-async--set-http-buffer async-queue http-buffer) (set-process-filter (get-buffer-process http-buffer) (mastodon-async--http-hook filter)) http-buffer)) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 8355200..31df2ae 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index cb8eb26..a03d035 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 6b2eadf..21a0f95 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 00a0718..4461ea2 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "27.1") (request "0.2.0")) +;; Package-Requires: ((emacs "27.1") (request "0.3.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 4d91948..c9a9277 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. @@ -98,6 +98,7 @@ (defvar mastodon-inspect--search-result-tags) (defun mastodon-inspect--get-search-result (query) + "Inspect function for a search result for QUERY." (interactive) (setq mastodon-inspect--search-query-full-result (append ; convert vector to list @@ -111,6 +112,7 @@ nil))) (defun mastodon-inspect--get-search-account (query) + "Return JSON for a single account after search QUERY." (interactive) (setq mastodon-inspect--search-query-accounts-result (append ; convert vector to list diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index bbab816..6e02ebb 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 5efb7d4..ebf98ba 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index d21f5c0..dbe5686 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1") (seq "1.0")) +;; Package-Requires: ((emacs "27.1") (seq "1.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index a7dcda9..6317895 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen , martyhiatt ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 89604b5..71e08de 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index c89acc7..6cf337a 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. @@ -545,7 +545,11 @@ The prefix can match against both user handles and display names." (propertize handle 'annot display-name 'meta url))) (defun mastodon-toot-mentions (command &optional arg &rest ignored) - "A company completion backend for toot mentions." + "A company completion backend for toot mentions. +COMMAND is either prefix, to fetch a prefix query, candidates, to +build a list of candidates with query ARG, annotation, to format +an annotation for candidate ARG, or meta, to format meta info for +candidate ARG. IGNORED remains a mystery." (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'mastodon-toot-mentions)) @@ -645,7 +649,7 @@ File is actually attached to the toot upon posting." (mastodon-toot--upload-attached-media (car (last mastodon-toot--media-attachments))))) (defun mastodon-toot--upload-attached-media (attachment) - "Upload a single attachment using `mastodon-http--post-media-attachment'. + "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 diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 2411e20..adc1ac8 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Version: 0.9.2 -;; Package-Requires: ((emacs "26.1") (request "0.3.2") (seq "1.0")) +;; Package-Requires: ((emacs "27.1") (request "0.3.2") (seq "1.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el ;; This file is not part of GNU Emacs. @@ -31,7 +31,8 @@ ;;; Code: (require 'cl-lib) ; for `cl-some' call in mastodon -(require 'mastodon-toot) ; hack to make mastodon-toot customs visible +;; hack to make mastodon-toot customizes visible prior to running mastodon-toot: +(require 'mastodon-toot) (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") -- cgit v1.2.3 From 242628c090adad5e6f6292b108c6626bd78bf11a Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 18:06:41 +0100 Subject: boilerplate maintainer contact --- lisp/mastodon-async.el | 2 ++ lisp/mastodon-auth.el | 1 + lisp/mastodon-client.el | 1 + lisp/mastodon-discover.el | 1 + lisp/mastodon-http.el | 1 + lisp/mastodon-inspect.el | 1 + lisp/mastodon-media.el | 1 + lisp/mastodon-notifications.el | 1 + lisp/mastodon-profile.el | 1 + lisp/mastodon-search.el | 4 +++- lisp/mastodon-tl.el | 1 + lisp/mastodon-toot.el | 1 + lisp/mastodon.el | 1 + 13 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index 77fdb8e..bda6a4d 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -2,6 +2,8 @@ ;; Copyright (C) 2017 Johnson Denen ;; Author: Johnson Denen +;; Alex J. Griffith +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 31df2ae..0b9a0dd 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index a03d035..2ecfff4 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index 21a0f95..c8e3fd0 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 4461ea2..0447e22 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1") (request "0.3.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index c9a9277..209e8dd 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 6e02ebb..5e2699a 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index ebf98ba..ac0d339 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index dbe5686..0ed4d04 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1") (seq "1.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 6317895..04b3e23 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -1,7 +1,9 @@ ;;; mastodon-search.el --- Search functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen -;; Author: Johnson Denen , martyhiatt +;; Author: Johnson Denen +;; Marty Hiatt +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 71e08de..45b905d 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 6cf337a..5b46f5e 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon.el b/lisp/mastodon.el index adc1ac8..9a0fe37 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -2,6 +2,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen +;; Maintainer: Marty Hiatt ;; Version: 0.9.2 ;; Package-Requires: ((emacs "27.1") (request "0.3.2") (seq "1.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el -- cgit v1.2.3 From 34105df90e67562bb3736177085baffdca66b23a Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 18:16:58 +0100 Subject: cl-lib not cl for mapcar* in -tl --- lisp/mastodon-tl.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 45b905d..67cdf82 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -31,7 +31,7 @@ ;;; Code: (require 'shr) -(require 'thingatpt) ;; for word-at-point +(require 'thingatpt) ; for word-at-point (require 'time-date) (autoload 'mastodon-auth--get-account-name "mastodon-auth") @@ -60,7 +60,7 @@ (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this -(declare-function mapcar* "cl") +(declare-function mapcar* "cl-lib") (defgroup mastodon-tl nil "Timelines in Mastodon." -- cgit v1.2.3 From c1aa61bb361cca5d107896a83b1b729315c4d79a Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 18:18:28 +0100 Subject: bump version to a round number --- lisp/mastodon-async.el | 2 +- lisp/mastodon-auth.el | 2 +- lisp/mastodon-client.el | 2 +- 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-search.el | 2 +- lisp/mastodon-tl.el | 2 +- lisp/mastodon-toot.el | 2 +- lisp/mastodon.el | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lisp/mastodon-async.el b/lisp/mastodon-async.el index bda6a4d..6ff09e3 100644 --- a/lisp/mastodon-async.el +++ b/lisp/mastodon-async.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Alex J. Griffith ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 0b9a0dd..e4f5934 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 2ecfff4..b27d434 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-discover.el b/lisp/mastodon-discover.el index c8e3fd0..10abc59 100644 --- a/lisp/mastodon-discover.el +++ b/lisp/mastodon-discover.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 0447e22..33182ff 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1") (request "0.3.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-inspect.el b/lisp/mastodon-inspect.el index 209e8dd..b0270ee 100644 --- a/lisp/mastodon-inspect.el +++ b/lisp/mastodon-inspect.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el index 5e2699a..acce473 100644 --- a/lisp/mastodon-media.el +++ b/lisp/mastodon-media.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index ac0d339..6d48681 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index 0ed4d04..e8025ed 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1") (seq "1.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-search.el b/lisp/mastodon-search.el index 04b3e23..78c2ab4 100644 --- a/lisp/mastodon-search.el +++ b/lisp/mastodon-search.el @@ -4,7 +4,7 @@ ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 67cdf82..62550cd 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 5b46f5e..e813b33 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 9a0fe37..d5f9b6e 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2017-2019 Johnson Denen ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt -;; Version: 0.9.2 +;; Version: 0.10.0 ;; Package-Requires: ((emacs "27.1") (request "0.3.2") (seq "1.0")) ;; Homepage: https://git.blast.noho.st/mouse/mastodon.el -- cgit v1.2.3 From b693dc24e6bbabab2cbdea0cf19542d130973b02 Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 18:24:06 +0100 Subject: mapcar* -> cl-mapcar in -tl.el --- lisp/mastodon-tl.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 62550cd..fe8f7c8 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -33,6 +33,7 @@ (require 'shr) (require 'thingatpt) ; for word-at-point (require 'time-date) +(require 'cl-lib) ; for cl-mapcar (autoload 'mastodon-auth--get-account-name "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") @@ -60,8 +61,6 @@ (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this -(declare-function mapcar* "cl-lib") - (defgroup mastodon-tl nil "Timelines in Mastodon." :prefix "mastodon-tl-" @@ -786,7 +785,7 @@ takes a single function. By default it is (options-numbers (mapcar (lambda(x) (number-to-string x)) options-number-seq)) - (options-alist (mapcar* 'cons options-numbers options-titles)) + (options-alist (cl-mapcar 'cons options-numbers options-titles)) ;; we display both option number and the option title ;; but also store both as cons cell as cdr, as we need it below (candidates (mapcar (lambda (cell) -- cgit v1.2.3 From 9f5b56b4003f4ff5b2c3e6183de228d22c94574c Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 19:18:46 +0100 Subject: y-or-n-p before cancelling a toot. --- lisp/mastodon-toot.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index e813b33..230f7d2 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -359,7 +359,13 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (defun mastodon-toot--cancel () "Kill new-toot buffer/window. Does not POST content to Mastodon." (interactive) - (mastodon-toot--kill)) + (let* ((toot (mastodon-toot--remove-docs)) + (empty-toot-p (and (not mastodon-toot--media-attachments) + (string= "" (mastodon-tl--clean-tabs-and-nl toot))))) + (if empty-toot-p + (mastodon-toot--kill) + (when (y-or-n-p "Discard draft toot? ") + (mastodon-toot--kill))))) (defalias 'mastodon-toot--insert-emoji 'emojify-insert-emoji -- cgit v1.2.3 From 9a44a97b751855529647ead629bc300bc7e045ce Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 19:30:12 +0100 Subject: readme --- README.org | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.org b/README.org index fff4bc8..88e8c41 100644 --- a/README.org +++ b/README.org @@ -8,9 +8,9 @@ It adds the following features: | Profiles: | | | | display profile metadata fields | -| | display pinned toots on profiles | -| | display relationship (follows you/followed by you) on profiles | -| | display toots/follows/followers counts on profiles | +| | display pinned toots first | +| | display relationship (follows you/followed by you) | +| | display toots/follows/followers counts | | | links/tags/mentions in profile bios are active links | | | show a lock icon for locked accounts | | =R=, =C-c a=, =C-c r= | view/accept/reject follow requests | @@ -18,10 +18,11 @@ It adds the following features: | =i= | toggle pinning of toots | | =S-C-P= | jump to your profile | | =U= | update your profile bio note | +| =O= | jump to own profile | | Notifications: | | | | follow requests now also appear in notifications | -| =a=, =r= | accept/reject follow requests | -| | notifications for when a user posts (optional) | +| =a=, =r= | accept/reject follow request | +| | notifications for when a user posts (=mastodon-tl--enable-notify-user-posts=) | | Timelines: | | | =C= | copy url of toot at point | | =d= | delete your toot at point, and reload current timeline | -- cgit v1.2.3 From 03bf9741f77b2c1292ab72148a4d60bb6fcfe3cc Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 21:47:01 +0100 Subject: improve faves count help-echo propertizing - add `mastodon-tl--format-faves-count function - handle notifications formatting (get 'status field of toot) - apply to author-byline formatting - apply to the (F) and (B) formatting for faves/boosts - ensures where point lands after `mastodon-tl--goto-next-toot is always propertized --- lisp/mastodon-tl.el | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index fe8f7c8..c2cfdb2 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -287,14 +287,11 @@ Optionally start from POS." (propertize name 'face 'mastodon-display-name-face 'help-echo + (mastodon-tl--format-faves-count toot)) + ;; 'help-echo ;; echo faves count when point on post author name: ;; which is where --goto-next-toot puts point. - ;; prefer the reblog toot if present: - (let ((toot-to-use (or (alist-get 'reblog toot) toot))) - (format "%s faves | %s boosts | %s replies" - (alist-get 'favourites_count toot-to-use) - (alist-get 'reblogs_count toot-to-use) - (alist-get 'replies_count toot-to-use)))) + ;; (mastodon-tl--format-faves-count toot)) " (" (propertize (concat "@" handle) 'face 'mastodon-handle-face @@ -308,6 +305,21 @@ Optionally start from POS." 'help-echo (concat "Browse user profile of @" handle)) ")"))) +(defun mastodon-tl--format-faves-count (toot) + "Format a favorites, boosts, replies count for a TOOT. +Used to help-echo when point is at the start of a byline, +i.e. where `mastodon-tl--goto-next-toot' leaves point." + (let ((toot-to-count + (or + ;; simply praying this order works + (alist-get 'status toot) ; notifications timeline + (alist-get 'reblog toot) ; boosts + toot))) ; everything else + (format "%s faves | %s boosts | %s replies" + (alist-get 'favourites_count toot-to-count) + (alist-get 'reblogs_count toot-to-count) + (alist-get 'replies_count toot-to-count)))) + (defun mastodon-tl--byline-boosted (toot) "Add byline for boosted data from TOOT." (let ((reblog (alist-get 'reblog toot))) @@ -406,11 +418,19 @@ By default it is `mastodon-tl--byline-boosted'" ;; (propertize "\n | " 'face 'default) (propertize (concat (when boosted - (format "(%s) " - (propertize "B" 'face 'mastodon-boost-fave-face))) + (format + (propertize "(%s) " + 'help-echo + (mastodon-tl--format-faves-count toot)) + (propertize "B" 'face 'mastodon-boost-fave-face))) (when faved - (format "(%s) " - (propertize "F" 'face 'mastodon-boost-fave-face))) + (format + (propertize "(%s) " + 'help-echo + (mastodon-tl--format-faves-count toot)) + (propertize "F" 'face 'mastodon-boost-fave-face))) + ;; we propertize help-echo format faves for author name + ;; in `mastodon-tl--byline-author' (funcall author-byline toot) (cond ((equal visibility "direct") (if (fontp (char-displayable-p #10r128274)) -- cgit v1.2.3 From 5c894196298f8f5dfdddefeccb1e4694c0fc1a6f Mon Sep 17 00:00:00 2001 From: mousebot Date: Fri, 17 Dec 2021 22:43:48 +0100 Subject: autoload typo --- 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 230f7d2..31613d0 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -50,7 +50,7 @@ (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") -(autoload 'mastodon-http--get-json-async "mastodon-htpp") +(autoload 'mastodon-http--get-json-async "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--post-media-attachment "mastodon-http") (autoload 'mastodon-http--process-json "mastodon-http") -- cgit v1.2.3 From 199ced2730b172538adb26684cd5b4bc25819718 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 17:01:50 +0100 Subject: test mastodon-http--triage --- test/mastodon-http-tests.el | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/test/mastodon-http-tests.el b/test/mastodon-http-tests.el index 00e1f41..dc4aa76 100644 --- a/test/mastodon-http-tests.el +++ b/test/mastodon-http-tests.el @@ -2,9 +2,84 @@ (require 'el-mock) +(defconst mastodon-http--example-200 + "HTTP/1.1 200 OK +Date: Mon, 20 Dec 2021 13:42:29 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: Mastodon +X-Frame-Options: DENY +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Permissions-Policy: interest-cohort=() +X-RateLimit-Limit: 300 +X-RateLimit-Remaining: 298 +X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z +Cache-Control: no-store +Vary: Accept, Accept-Encoding, Origin +ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" +X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 +X-Runtime: 0.371914 +Strict-Transport-Security: max-age=63072000; includeSubDomains +Strict-Transport-Security: max-age=31536000 + +{\"id\":\"18173\",\"following\":true,\"showing_reblogs\":true,\"notifying\":true,\"followed_by\":true,\"blocking\":false,\"blocked_by\":false,\"muting\":false,\"muting_notifications\":false,\"requested\":false,\"domain_blocking\":false,\"endorsed\":false,\"note\":\"\"}") + +(defconst mastodon-http--example-400 + "HTTP/1.1 444 OK +Date: Mon, 20 Dec 2021 13:42:29 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: Mastodon +X-Frame-Options: DENY +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Permissions-Policy: interest-cohort=() +X-RateLimit-Limit: 300 +X-RateLimit-Remaining: 298 +X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z +Cache-Control: no-store +Vary: Accept, Accept-Encoding, Origin +ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" +X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 +X-Runtime: 0.371914 +Strict-Transport-Security: max-age=63072000; includeSubDomains +Strict-Transport-Security: max-age=31536000 + +{\"error\":\"some unhappy complaint\"}") + (ert-deftest mastodon-http--get-retrieves-endpoint () "Should make a `url-retrieve' of the given URL." (with-mock (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz")) (mock (mastodon-auth--access-token) => "test-token") (mastodon-http--get "https://foo.bar/baz"))) + +(ert-deftest mastodon-http--triage-success () + "Should run success function for 200 HTML response." + (let ((response-buffer + (get-buffer-create "mastodon-http--triage-buffer"))) + (with-current-buffer response-buffer + (erase-buffer) + (insert mastodon-http--example-200)) + (should (equal (mastodon-http--triage + response-buffer + (lambda () + (message "success call"))) + "success call")))) + +(ert-deftest mastodon-http--triage-failure () + "Should return formatted JSON error from bad HTML response buffer. + Should not run success function." + (let ((response-buffer + (get-buffer-create "mastodon-http--triage-buffer"))) + (with-current-buffer response-buffer + (erase-buffer) + (insert mastodon-http--example-400)) + (should (equal (mastodon-http--triage + response-buffer + (lambda () + (message "success call"))) + "Error 444: some unhappy complaint")))) -- cgit v1.2.3 From 2e84df005202acbab6d9d1f8ccbb13010e0823cc Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 17:02:41 +0100 Subject: typos and docstrings --- lisp/mastodon-auth.el | 2 +- lisp/mastodon-profile.el | 7 ++++--- lisp/mastodon-tl.el | 13 ++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index e4f5934..74d4404 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -166,7 +166,7 @@ Handle any errors from the server." (defun mastodon-auth--user-acct () "Return a mastodon user acct name." - (or (cdr (assoc mastodon-instance-url mastodon-auth--acct-alist)) + (or (cdr (assoc mastodon-instance-url mastodon-auth--acct-alist)) (let ((acct (mastodon-auth--get-account-name))) (push (cons mastodon-instance-url acct) mastodon-auth--acct-alist) acct))) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index e8025ed..d98d24c 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -405,7 +405,7 @@ If toot is a boost, opens the profile of the booster." (mastodon-media--get-media-link-rendering url)))) (defun mastodon-profile--show-user (user-handle) - "Query user for USER-HANDLE from current status and show that user's profile." + "Query for USER-HANDLE from current status and show that user's profile." (interactive (list (let ((user-handles (mastodon-profile--extract-users-handles @@ -453,7 +453,7 @@ FIELD is used to identify regions under 'account" tootv))) (defun mastodon-profile--search-account-by-handle (handle) - "Return an account based on a users HANDLE. + "Return an account based on a user's HANDLE. If the handle does not match a search return then retun NIL." (let* ((handle (if (string= "@" (substring handle 0 1)) @@ -461,7 +461,8 @@ If the handle does not match a search return then retun NIL." handle)) (matching-account (seq-remove - (lambda(x) (not (string= (alist-get 'acct x) handle))) + (lambda (x) + (not (string= (alist-get 'acct x) handle))) (mastodon-http--get-json (mastodon-http--api (format "accounts/search?q=%s" handle)))))) (when (equal 1 (length matching-account)) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index c2cfdb2..e3cd5c7 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -223,7 +223,7 @@ text, i.e. hidden spoiler text." "Prompts for tag and opens its timeline." (interactive) (let* ((word (or (word-at-point) "")) - (input (read-string (format "Load timeline for tag(%s): " word))) + (input (read-string (format "Load timeline for tag (%s): " word))) (tag (if (equal input "") word input))) (message "Loading timeline for #%s..." tag) (mastodon-tl--show-tag-timeline tag))) @@ -989,7 +989,7 @@ webapp" "Query for USER-HANDLE from current status and follow that user. If NOTIFY is \"true\", enable notifications when that user posts. If NOTIFY is \"false\", disable notifications when that user posts. -This can be called to toggle NOTIFY on users already being followed." +Can be called to toggle NOTIFY on users already being followed." (interactive (list (mastodon-tl--interactive-user-handles-get "follow"))) @@ -1079,15 +1079,16 @@ Action must be either \"unblock\" or \"mute\"." t)))) (defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp notify) - "Do ACTION on user NAME/USER-HANDLE. + "Do ACTION on user USER-HANDLE. NEGP is whether the action involves un-doing something. If NOTIFY is \"true\", enable notifications when that user posts. If NOTIFY is \"false\", disable notifications when that user posts. NOTIFY is only non-nil when called by `mastodon-tl--follow-user'." (let* ((account (if negp - ;; TODO check if both are actually needed + ;; if unmuting/unblocking, we got handle from mute/block list (mastodon-profile--search-account-by-handle user-handle) + ;; if muting/blocking, we select from handles in current status (mastodon-profile--lookup-account-in-status user-handle (mastodon-profile--toot-json)))) (user-id (mastodon-profile--account-field account 'id)) @@ -1104,7 +1105,9 @@ NOTIFY is only non-nil when called by `mastodon-tl--follow-user'." (message "Cannot find a user with handle %S" user-handle)))) (defun mastodon-tl--do-user-action-function (url name user-handle action &optional notify) - "Post ACTION on user NAME/USER-HANDLE to URL." + "Post ACTION on user NAME/USER-HANDLE to URL. +NOTIFY is either \"true\" or \"false\", and used when we have been called +by `mastodon-tl--follow-user' to enable or disable notifications." (let ((response (mastodon-http--post url nil nil))) (mastodon-http--triage response (lambda () -- cgit v1.2.3 From 083ef8500bff15f2fc35add26e9afd3b6b961811 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 17:03:12 +0100 Subject: test mastodon-tl--do-user-action-function --- test/mastodon-tl-tests.el | 96 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index da3b315..748d98e 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -91,6 +91,54 @@ (reblogged))) "A sample reblogged/boosted toot (parsed json)") +(defconst mastodon-tl--follow-notify-true-response + "HTTP/1.1 200 OK +Date: Mon, 20 Dec 2021 13:42:29 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: Mastodon +X-Frame-Options: DENY +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Permissions-Policy: interest-cohort=() +X-RateLimit-Limit: 300 +X-RateLimit-Remaining: 298 +X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z +Cache-Control: no-store +Vary: Accept, Accept-Encoding, Origin +ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" +X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 +X-Runtime: 0.371914 +Strict-Transport-Security: max-age=63072000; includeSubDomains +Strict-Transport-Security: max-age=31536000 + +{\"id\":\"123456789\",\"following\":true,\"showing_reblogs\":true,\"notifying\":true,\"followed_by\":true,\"blocking\":false,\"blocked_by\":false,\"muting\":false,\"muting_notifications\":false,\"requested\":false,\"domain_blocking\":false,\"endorsed\":false,\"note\":\"\"}") + +(defconst mastodon-tl--follow-notify-false-response + "HTTP/1.1 200 OK +Date: Mon, 20 Dec 2021 13:42:29 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: Mastodon +X-Frame-Options: DENY +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Permissions-Policy: interest-cohort=() +X-RateLimit-Limit: 300 +X-RateLimit-Remaining: 298 +X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z +Cache-Control: no-store +Vary: Accept, Accept-Encoding, Origin +ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" +X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 +X-Runtime: 0.371914 +Strict-Transport-Security: max-age=63072000; includeSubDomains +Strict-Transport-Security: max-age=31536000 + +{\"id\":\"123456789\",\"following\":true,\"showing_reblogs\":true,\"notifying\":false,\"followed_by\":true,\"blocking\":false,\"blocked_by\":false,\"muting\":false,\"muting_notifications\":false,\"requested\":false,\"domain_blocking\":false,\"endorsed\":false,\"note\":\"\"}") + (ert-deftest mastodon-tl--remove-html-1 () "Should remove all tags." (let ((input "foobar foobaz")) @@ -940,7 +988,7 @@ constant." "https://example.org")))) (ert-deftest mastodon-tl--userhandles () - "Should recognise iserhandles in a toot and add the required properties to it." + "Should recognise userhandles in a toot and add the required properties to it." ;; Travis's Emacs doesn't have libxml so we fake things by inputting ;; propertized text and stubbing shr-render-region (let* ((fake-input-text @@ -980,3 +1028,49 @@ constant." (should (null (mastodon-tl--extract-userhandle-from-url "https://example.org/@someuser?shouldnot=behere" "SomeUser")))) + +(ert-deftest mastodon-tl--do-user-action-function-follow-and-notify () + "Should triage a follow request response buffer and return +correct value for following, as well as notifications enabled or disabled." + (let* ((user-handle "some-user@instance.url") + (user-name "some-user") + (user-id "123456789") + (url-follow-only "https://instance.url/accounts/123456789/follow") + (url-true "https://instance.url/accounts/123456789/follow?notify=true") + (url-false "https://instance.url/accounts/123456789/follow?notify=false")) + (with-temp-buffer + (let ((response-buffer-true (current-buffer))) + (insert mastodon-tl--follow-notify-true-response) + (with-mock + (mock (mastodon-http--post url-follow-only nil nil) + => response-buffer-true) + (should + (equal + (mastodon-tl--do-user-action-function url-follow-only + user-name + user-handle + "follow") + "User some-user (@some-user@instance.url) followed!"))) + (with-mock + (mock (mastodon-http--post url-true nil nil) => response-buffer-true) + (should + (equal + (mastodon-tl--do-user-action-function url-true + user-name + user-handle + "follow" + "true") + "Receiving notifications for user some-user (@some-user@instance.url)!"))))) + (with-temp-buffer + (let ((response-buffer-false (current-buffer))) + (insert mastodon-tl--follow-notify-false-response) + (with-mock + (mock (mastodon-http--post url-false nil nil) => response-buffer-false) + (should + (equal + (mastodon-tl--do-user-action-function url-false + user-name + user-handle + "follow" + "false") + "Not receiving notifications for user some-user (@some-user@instance.url)!"))))))) -- cgit v1.2.3 From 6bb40ba89f0d5097028c1f949e14b0f1b576abe9 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 17:10:02 +0100 Subject: add block/mute calls to test do user action function --- test/mastodon-tl-tests.el | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index 748d98e..c36b95a 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -1029,13 +1029,15 @@ constant." "https://example.org/@someuser?shouldnot=behere" "SomeUser")))) -(ert-deftest mastodon-tl--do-user-action-function-follow-and-notify () +(ert-deftest mastodon-tl--do-user-action-function-follow-notify-block-mute () "Should triage a follow request response buffer and return correct value for following, as well as notifications enabled or disabled." (let* ((user-handle "some-user@instance.url") (user-name "some-user") (user-id "123456789") (url-follow-only "https://instance.url/accounts/123456789/follow") + (url-mute "https://instance.url/accounts/123456789/mute") + (url-block "https://instance.url/accounts/123456789/block") (url-true "https://instance.url/accounts/123456789/follow?notify=true") (url-false "https://instance.url/accounts/123456789/follow?notify=false")) (with-temp-buffer @@ -1050,7 +1052,25 @@ correct value for following, as well as notifications enabled or disabled." user-name user-handle "follow") - "User some-user (@some-user@instance.url) followed!"))) + "User some-user (@some-user@instance.url) followed!")) + (mock (mastodon-http--post url-mute nil nil) + => response-buffer-true) + (should + (equal + (mastodon-tl--do-user-action-function url-mute + user-name + user-handle + "mute") + "User some-user (@some-user@instance.url) muted!")) + (mock (mastodon-http--post url-block nil nil) + => response-buffer-true) + (should + (equal + (mastodon-tl--do-user-action-function url-block + user-name + user-handle + "blocked") + "User some-user (@some-user@instance.url) blocked!"))) (with-mock (mock (mastodon-http--post url-true nil nil) => response-buffer-true) (should -- cgit v1.2.3 From a7a6f0115f63a5ab324b93bdcb2820354765acea Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 19:15:09 +0100 Subject: hack attempts to test delete toot functions --- test/mastodon-toot-tests.el | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index 804c55a..31f95df 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -1,6 +1,17 @@ ;;; mastodon-toot-test.el --- Tests for mastodon-toot.el -*- lexical-binding: nil -*- (require 'el-mock) +(require 'mastodon-http) + +(defconst mastodon-toot--200-html + "HTTP/1.1 200 OK +Date: Mon, 20 Dec 2021 13:42:29 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked") + +(defconst mastodon-toot--mock-toot + (propertize "here is a mock toot text." + 'toot-json mastodon-tl-test-base-toot)) (defconst mastodon-toot--multi-mention '((mentions . @@ -49,9 +60,35 @@ mention string." (mastodon-instance-url "https://local.social")) (should (string= (mastodon-toot--mentions mastodon-toot-no-mention) "")))) -(ert-deftest mastodon-toot--cancel () +;; TODO: test y-or-no-p with matodon-toot--cancel +(ert-deftest mastodon-toot--kill () "Should kill the buffer when cancelling the toot." (with-mock (mock (kill-buffer-and-window)) - (mastodon-toot--cancel) + (mastodon-toot--kill) (mock-verify))) + +(ert-deftest mastodon-toot--delete-toot-fail () + "Should refuse to delete toot." + (with-temp-buffer + (insert mastodon-toot--mock-toot) + (goto-char (point-min)) + (should (equal (mastodon-toot--delete-toot) + "You can only delete (and redraft) your own toots.")))) + +(ert-deftest mastodon-toot--delete-toot () + "Should return correct triaged response to a DELETE request." + (let ((delete-response (get-buffer-create "delete-200"))) + (with-current-buffer delete-response + (insert mastodon-toot--200-html)) + (let ((toot mastodon-tl-test-base-toot)) + (with-mock + (mock (mastodon-tl--property 'toot-json) => mastodon-tl-test-base-toot) + (mock (mastodon-toot--own-toot-p toot) => t) + (mock (mastodon-http--api (format "statuses/61208")) + => "https://local.social/statuses/61208") + (mock (y-or-n-p "Delete this toot? ") => t) + (mock (mastodon-http--delete "https://local.social/statuses/61208") + => delete-response) + (should (equal (mastodon-toot--delete-toot) + "Toot deleted!")))))) -- cgit v1.2.3 From 4cec0aa24f717489be5d1959682d0c14b349d5af Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 19:29:34 +0100 Subject: refactoring delete/redraft functions --- lisp/mastodon-toot.el | 80 +++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index 31613d0..f49b35c 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -46,6 +46,7 @@ (defvar company-backends)) (defvar mastodon-instance-url) +(defvar mastodon-tl--buffer-spec) (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") @@ -277,27 +278,21 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (kill-new url) (message "Toot URL copied to the clipboard."))) +(defun mastodon-toot--own-toot-p (toot) + "Check if TOOT is user's own, e.g. for deleting it." + (and (not (alist-get 'reblog toot)) + (equal (alist-get 'acct (alist-get 'account toot)) + (mastodon-auth--user-acct)))) + (defun mastodon-toot--delete-toot () "Delete user's toot at point synchronously." (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) - (url (mastodon-http--api (format "statuses/%s" id)))) - (if (or (alist-get 'reblog toot) - (not (equal (alist-get 'acct - (alist-get 'account toot)) - (mastodon-auth--user-acct)))) - (message "You can only delete your own toots.") - (if (y-or-n-p (format "Delete this toot? ")) - (let ((response (mastodon-http--delete url))) - (mastodon-http--triage response - (lambda () - (mastodon-tl--reload-timeline-or-profile) - (message "Toot deleted!")))))))) + (mastodon-toot--delete-and-redraft-toot t)) ;; TODO: handle media/poll for redrafting toots -(defun mastodon-toot--delete-and-redraft-toot () - "Delete and redraft user's toot at point synchronously." +(defun mastodon-toot--delete-and-redraft-toot (&optional no-redraft) + "Delete and redraft user's toot at point synchronously. +NO-REDRAFT means delete toot only." (interactive) (let* ((toot (mastodon-tl--property 'toot-json)) (id (mastodon-tl--as-string (mastodon-tl--toot-id toot))) @@ -305,31 +300,42 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (toot-cw (alist-get 'spoiler_text toot)) (toot-visibility (alist-get 'visibility toot)) (reply-id (alist-get 'in_reply_to_id toot))) - (if (or (alist-get 'reblog toot) - (not (equal (alist-get 'acct - (alist-get 'account toot)) - (mastodon-auth--user-acct)))) - (message "You can only delete and redraft your own toots.") - (if (y-or-n-p (format "Delete and redraft this toot? ")) + (if (not (mastodon-toot--own-toot-p toot)) + (message "You can only delete (and redraft) your own toots.") + (if (y-or-n-p (if no-redraft + (format "Delete this toot? ") + (format "Delete and redraft this toot? "))) (let* ((response (mastodon-http--delete url))) (mastodon-http--triage response (lambda () - (with-current-buffer response - (let* ((json-response (mastodon-http--process-json)) - (content (alist-get 'text json-response))) - ;; (media (alist-get 'media_attachments json-response))) - (mastodon-toot--compose-buffer nil nil) - (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) - (when (not (equal toot-cw "")) - (setq mastodon-toot--content-warning t) - (setq mastodon-toot--content-warning-from-reply-or-redraft toot-cw)) - (mastodon-toot--update-status-fields)))))))))) + (if no-redraft + (progn + (when mastodon-tl--buffer-spec + (mastodon-tl--reload-timeline-or-profile)) + (message "Toot deleted!")) + (mastodon-toot--redraft response + reply-id + toot-visibility + toot-cw))))))))) + +(defun mastodon-toot--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." + (with-current-buffer response + (let* ((json-response (mastodon-http--process-json)) + (content (alist-get 'text json-response))) + (mastodon-toot--compose-buffer nil nil) + (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) + (when (not (equal toot-cw "")) + (setq mastodon-toot--content-warning t) + (setq mastodon-toot--content-warning-from-reply-or-redraft toot-cw)) + (mastodon-toot--update-status-fields)))) (defun mastodon-toot--bookmark-toot-toggle () "Bookmark or unbookmark toot at point synchronously." -- cgit v1.2.3 From fff33fa9206864f3bfc80f7725d76eecf074aaaa Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 20:25:43 +0100 Subject: delete toot test use temp buffer --- test/mastodon-toot-tests.el | 59 +++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index 31f95df..1ad2558 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -9,9 +9,38 @@ Date: Mon, 20 Dec 2021 13:42:29 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked") +(defconst mastodon-toot-test-base-toot + '((id . 61208) + (created_at . "2017-04-24T19:01:02.000Z") + (in_reply_to_id) + (in_reply_to_account_id) + (sensitive . :json-false) + (spoiler_text . "") + (visibility . "public") + (account (id . 42) + (username . "acct42") + (acct . "acct42@example.space") + (display_name . "Account 42") + (locked . :json-false) + (created_at . "2017-04-01T00:00:00.000Z") + (followers_count . 99) + (following_count . 13) + (statuses_count . 101) + (note . "E")) + (media_attachments . []) + (mentions . []) + (tags . []) + (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") + (url . "https://example.space/users/acct42/updates/123456789") + (content . "

Just some text

") + (reblogs_count . 0) + (favourites_count . 0) + (reblog)) + "A sample toot (parsed json)") + (defconst mastodon-toot--mock-toot (propertize "here is a mock toot text." - 'toot-json mastodon-tl-test-base-toot)) + 'toot-json mastodon-toot-test-base-toot)) (defconst mastodon-toot--multi-mention '((mentions . @@ -78,17 +107,17 @@ mention string." (ert-deftest mastodon-toot--delete-toot () "Should return correct triaged response to a DELETE request." - (let ((delete-response (get-buffer-create "delete-200"))) - (with-current-buffer delete-response - (insert mastodon-toot--200-html)) - (let ((toot mastodon-tl-test-base-toot)) - (with-mock - (mock (mastodon-tl--property 'toot-json) => mastodon-tl-test-base-toot) - (mock (mastodon-toot--own-toot-p toot) => t) - (mock (mastodon-http--api (format "statuses/61208")) - => "https://local.social/statuses/61208") - (mock (y-or-n-p "Delete this toot? ") => t) - (mock (mastodon-http--delete "https://local.social/statuses/61208") - => delete-response) - (should (equal (mastodon-toot--delete-toot) - "Toot deleted!")))))) + (with-temp-buffer + (insert mastodon-toot--200-html) + (let ((delete-response (current-buffer)) + (toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) + (mock (mastodon-toot--own-toot-p toot) => t) + (mock (mastodon-http--api (format "statuses/61208")) + => "https://local.social/statuses/61208") + (mock (y-or-n-p "Delete this toot? ") => t) + (mock (mastodon-http--delete "https://local.social/statuses/61208") + => delete-response) + (should (equal (mastodon-toot--delete-toot) + "Toot deleted!")))))) -- cgit v1.2.3 From cb920113ac0cd7b8b57b7936432e7d0805401441 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 20:28:13 +0100 Subject: remove old comments --- lisp/mastodon-profile.el | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index d98d24c..ec9adaa 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -66,7 +66,6 @@ (defvar-local mastodon-profile--account nil "The data for the account being described in the current profile buffer.") -;; this way you can update it with C-M-x: (defvar mastodon-profile-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "s") #'mastodon-profile--open-followers) @@ -82,13 +81,9 @@ This minor mode is used for mastodon profile pages and adds a couple of extra keybindings." :init-value nil - ;; The mode line indicator. + ;; modeline indicator: :lighter " Profile" :keymap mastodon-profile-mode-map - ;; :keymap '(((kbd "O") . mastodon-profile--open-followers) - ;; ((kbd "o") . mastodon-profile--open-following) - ;; ((kbd "a") . mastodon-profile--follow-request-accept) - ;; ((kbd "r") . mastodon-profile--follow-request-reject) :group 'mastodon :global nil) -- cgit v1.2.3 From 7e3269835aace403d6462655dfa79d9a3060b02a Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 21:24:02 +0100 Subject: improve delete toot tests --- lisp/mastodon-tl.el | 2 ++ test/mastodon-tl-tests.el | 2 +- test/mastodon-toot-tests.el | 14 ++++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index e3cd5c7..61b2885 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -1117,6 +1117,8 @@ by `mastodon-tl--follow-user' to enable or disable notifications." ((string-equal notify "false") (message "Not receiving notifications for user %s (@%s)!" name user-handle)) + ((string-equal action "mute") + (message "User %s (@%s) %sd!" name user-handle action)) ((eq notify nil) (message "User %s (@%s) %sed!" name user-handle action))))))) diff --git a/test/mastodon-tl-tests.el b/test/mastodon-tl-tests.el index c36b95a..dd07416 100644 --- a/test/mastodon-tl-tests.el +++ b/test/mastodon-tl-tests.el @@ -1069,7 +1069,7 @@ correct value for following, as well as notifications enabled or disabled." (mastodon-tl--do-user-action-function url-block user-name user-handle - "blocked") + "block") "User some-user (@some-user@instance.url) blocked!"))) (with-mock (mock (mastodon-http--post url-true nil nil) => response-buffer-true) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index 1ad2558..f2c7b8f 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -99,14 +99,16 @@ mention string." (ert-deftest mastodon-toot--delete-toot-fail () "Should refuse to delete toot." - (with-temp-buffer - (insert mastodon-toot--mock-toot) - (goto-char (point-min)) - (should (equal (mastodon-toot--delete-toot) - "You can only delete (and redraft) your own toots.")))) + (let ((toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-auth--user-acct) => "joebogus") + ;; (mock (mastodon-toot--own-toot-p toot) => nil) + (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) + (should (equal (mastodon-toot--delete-toot) + "You can only delete (and redraft) your own toots."))))) (ert-deftest mastodon-toot--delete-toot () - "Should return correct triaged response to a DELETE request." + "Should return correct triaged response to a legitimate DELETE request." (with-temp-buffer (insert mastodon-toot--200-html) (let ((delete-response (current-buffer)) -- cgit v1.2.3 From 9620244cb4ece4e5503a3f5a6c73b948afa5ff74 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 21:30:22 +0100 Subject: tests for own-toot-p --- test/mastodon-toot-tests.el | 57 ++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index f2c7b8f..ac56015 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -97,29 +97,44 @@ mention string." (mastodon-toot--kill) (mock-verify))) +(ert-deftest mastodon-toot--own-toot-p-fail () + (let ((toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-auth--user-acct) => "joebogus@bogus.space") + (should (not (equal (mastodon-toot--own-toot-p toot) + t)))))) + +(ert-deftest mastodon-toot--own-toot-p () + (let ((toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-auth--user-acct) => "acct42@example.space") + (should (equal (mastodon-toot--own-toot-p toot) + t))))) + (ert-deftest mastodon-toot--delete-toot-fail () "Should refuse to delete toot." - (let ((toot mastodon-toot-test-base-toot)) - (with-mock - (mock (mastodon-auth--user-acct) => "joebogus") - ;; (mock (mastodon-toot--own-toot-p toot) => nil) - (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) - (should (equal (mastodon-toot--delete-toot) - "You can only delete (and redraft) your own toots."))))) + (let ((toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-auth--user-acct) => "joebogus") + ;; (mock (mastodon-toot--own-toot-p toot) => nil) + (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) + (should (equal (mastodon-toot--delete-toot) + "You can only delete (and redraft) your own toots."))))) (ert-deftest mastodon-toot--delete-toot () "Should return correct triaged response to a legitimate DELETE request." - (with-temp-buffer - (insert mastodon-toot--200-html) - (let ((delete-response (current-buffer)) - (toot mastodon-toot-test-base-toot)) - (with-mock - (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) - (mock (mastodon-toot--own-toot-p toot) => t) - (mock (mastodon-http--api (format "statuses/61208")) - => "https://local.social/statuses/61208") - (mock (y-or-n-p "Delete this toot? ") => t) - (mock (mastodon-http--delete "https://local.social/statuses/61208") - => delete-response) - (should (equal (mastodon-toot--delete-toot) - "Toot deleted!")))))) + (with-temp-buffer + (insert mastodon-toot--200-html) + (let ((delete-response (current-buffer)) + (toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) + ;; (mock (mastodon-toot--own-toot-p toot) => t) + (mock (mastodon-auth--user-acct) => "acct42@example.space") + (mock (mastodon-http--api (format "statuses/61208")) + => "https://example.space/statuses/61208") + (mock (y-or-n-p "Delete this toot? ") => t) + (mock (mastodon-http--delete "https://example.space/statuses/61208") + => delete-response) + (should (equal (mastodon-toot--delete-toot) + "Toot deleted!")))))) -- cgit v1.2.3 From 7d93e1f38332d03de0d935c7460bf3eb2821bf7d Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 22:31:11 +0100 Subject: docstring and move pin toot toggle --- lisp/mastodon-toot.el | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el index f49b35c..ec1ba49 100644 --- a/lisp/mastodon-toot.el +++ b/lisp/mastodon-toot.el @@ -188,7 +188,8 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (propertize marker 'face 'success))))))) (defun mastodon-toot--action (action callback) - "Take ACTION on toot at point, then execute CALLBACK." + "Take ACTION on toot at point, then execute CALLBACK. +Makes a POST request to the server." (let* ((id (mastodon-tl--property 'base-toot-id)) (url (mastodon-http--api (concat "statuses/" (mastodon-tl--as-string id) @@ -248,26 +249,6 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (message (format "%s #%s" action id)))) (message "Nothing to favorite here?!?")))) -(defun mastodon-toot--pin-toot-toggle () - "Pin or unpin user's toot at point." - (interactive) - (let* ((toot (mastodon-tl--property 'toot-json)) - (pinnable-p (and - (not (alist-get 'reblog toot)) - (equal (alist-get 'acct - (alist-get 'account toot)) - (mastodon-auth--user-acct)))) - (pinned-p (equal (alist-get 'pinned toot) t)) - (action (if pinned-p "unpin" "pin")) - (msg (if pinned-p "unpinned" "pinned")) - (msg-y-or-n (if pinned-p "Unpin" "Pin"))) - (if (not pinnable-p) - (message "You can only pin your own toots.") - (if (y-or-n-p (format "%s this toot? " msg-y-or-n)) - (mastodon-toot--action action - (lambda () - (message "Toot %s!" msg))))))) - (defun mastodon-toot--copy-toot-url () "Copy URL of toot at point." (interactive) @@ -284,6 +265,22 @@ Remove MARKER if REMOVE is non-nil, otherwise add it." (equal (alist-get 'acct (alist-get 'account toot)) (mastodon-auth--user-acct)))) +(defun mastodon-toot--pin-toot-toggle () + "Pin or unpin user's toot at point." + (interactive) + (let* ((toot (mastodon-tl--property 'toot-json)) + (pinnable-p (mastodon-toot--own-toot-p toot)) + (pinned-p (equal (alist-get 'pinned toot) t)) + (action (if pinned-p "unpin" "pin")) + (msg (if pinned-p "unpinned" "pinned")) + (msg-y-or-n (if pinned-p "Unpin" "Pin"))) + (if (not pinnable-p) + (message "You can only pin your own toots.") + (if (y-or-n-p (format "%s this toot? " msg-y-or-n)) + (mastodon-toot--action action + (lambda () + (message "Toot %s!" msg))))))) + (defun mastodon-toot--delete-toot () "Delete user's toot at point synchronously." (interactive) -- cgit v1.2.3 From 91e286e04b2a8a181955b40ab3934214076e33d2 Mon Sep 17 00:00:00 2001 From: mousebot Date: Mon, 20 Dec 2021 22:32:08 +0100 Subject: making a start on pinned toot tests --- test/mastodon-toot-tests.el | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/test/mastodon-toot-tests.el b/test/mastodon-toot-tests.el index ac56015..0c31029 100644 --- a/test/mastodon-toot-tests.el +++ b/test/mastodon-toot-tests.el @@ -98,6 +98,7 @@ mention string." (mock-verify))) (ert-deftest mastodon-toot--own-toot-p-fail () + "Should not return t if not own toot." (let ((toot mastodon-toot-test-base-toot)) (with-mock (mock (mastodon-auth--user-acct) => "joebogus@bogus.space") @@ -105,6 +106,7 @@ mention string." t)))))) (ert-deftest mastodon-toot--own-toot-p () + "Should return 't' if own toot." (let ((toot mastodon-toot-test-base-toot)) (with-mock (mock (mastodon-auth--user-acct) => "acct42@example.space") @@ -128,7 +130,7 @@ mention string." (let ((delete-response (current-buffer)) (toot mastodon-toot-test-base-toot)) (with-mock - (mock (mastodon-tl--property 'toot-json) => mastodon-toot-test-base-toot) + (mock (mastodon-tl--property 'toot-json) => toot) ;; (mock (mastodon-toot--own-toot-p toot) => t) (mock (mastodon-auth--user-acct) => "acct42@example.space") (mock (mastodon-http--api (format "statuses/61208")) @@ -138,3 +140,31 @@ mention string." => delete-response) (should (equal (mastodon-toot--delete-toot) "Toot deleted!")))))) + +(ert-deftest mastodon-toot-action-pin () + "Should return callback provided by `mastodon-toot--pin-toot-toggle'." + (with-temp-buffer + (insert mastodon-toot--200-html) + (let ((pin-response (current-buffer)) + (toot mastodon-toot-test-base-toot) + (id 61208)) + (with-mock + (mock (mastodon-tl--property 'base-toot-id) => id) + (mock (mastodon-http--api "statuses/61208/pin") + => "https://example.space/statuses/61208/pin") + (mock (mastodon-http--post "https://example.space/statuses/61208/pin" nil nil) + => pin-response) + (should (equal (mastodon-toot--action "pin" (lambda () + (message "Toot pinned!"))) + "Toot pinned!")))))) + +(ert-deftest mastodon-toot--pin-toot-fail () + (with-temp-buffer + (insert mastodon-toot--200-html) + (let ((pin-response (current-buffer)) + (toot mastodon-toot-test-base-toot)) + (with-mock + (mock (mastodon-tl--property 'toot-json) => toot) + (mock (mastodon-auth--user-acct) => "joebogus@example.space") + (should (equal (mastodon-toot--pin-toot-toggle) + "You can only pin your own toots.")))))) -- cgit v1.2.3 From 5f28753c3502997ac2e1638d76e5d26b09bc6c15 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 21 Dec 2021 09:41:56 +0100 Subject: override 'O' binding on links to my-profile --- lisp/mastodon-tl.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index 61b2885..004aa4a 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -128,6 +128,8 @@ etc.") ;; version that knows about more types of links. (define-key map [remap shr-next-link] 'mastodon-tl--next-tab-item) (define-key map [remap shr-previous-link] 'mastodon-tl--previous-tab-item) + ;; keep new my-profile binding; shr 'O' doesn't work here anyway + (define-key map (kbd "O") 'mastodon-profile--my-profile) (keymap-canonicalize map)) "The keymap to be set for shr.el generated links that are not images. -- cgit v1.2.3 From cbef7ab3c3b5cb452e9c5409f3fa12cbba0e7558 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 21 Dec 2021 19:23:44 +0100 Subject: remove all ^M from update profile note buffer --- lisp/mastodon-profile.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index ec9adaa..c7ef718 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -213,6 +213,7 @@ extra keybindings." (mastodon-profile-update-mode t) (insert note) (goto-char (point-min)) + (delete-trailing-whitespace) ; remove all ^M's (message "Edit your profile note. C-c C-c to send, C-c C-k to cancel."))) (defun mastodon-profile--user-profile-send-updated () -- cgit v1.2.3 From ac192b47f90bbea9682c4c47c0188d9678665cfc Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 21 Dec 2021 09:41:56 +0100 Subject: override 'O' binding on links to my-profile --- lisp/mastodon-tl.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index c2cfdb2..f1c66a4 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -128,6 +128,8 @@ etc.") ;; version that knows about more types of links. (define-key map [remap shr-next-link] 'mastodon-tl--next-tab-item) (define-key map [remap shr-previous-link] 'mastodon-tl--previous-tab-item) + ;; keep new my-profile binding; shr 'O' doesn't work here anyway + (define-key map (kbd "O") 'mastodon-profile--my-profile) (keymap-canonicalize map)) "The keymap to be set for shr.el generated links that are not images. -- cgit v1.2.3 From 907c8f7e86277d36eb1eac99ba8abe2b848eed57 Mon Sep 17 00:00:00 2001 From: mousebot Date: Tue, 21 Dec 2021 19:23:44 +0100 Subject: remove all ^M from update profile note buffer --- lisp/mastodon-profile.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index e8025ed..98e5090 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -218,6 +218,7 @@ extra keybindings." (mastodon-profile-update-mode t) (insert note) (goto-char (point-min)) + (delete-trailing-whitespace) ; remove all ^M's (message "Edit your profile note. C-c C-c to send, C-c C-k to cancel."))) (defun mastodon-profile--user-profile-send-updated () -- cgit v1.2.3 From a20b072589d6b00bce050978c5bb8d47af5a99fb Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Dec 2021 10:31:09 +0100 Subject: tiny cleanups after Ediff main / master --- lisp/mastodon-tl.el | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el index f1c66a4..7e9eb60 100644 --- a/lisp/mastodon-tl.el +++ b/lisp/mastodon-tl.el @@ -225,7 +225,7 @@ text, i.e. hidden spoiler text." "Prompts for tag and opens its timeline." (interactive) (let* ((word (or (word-at-point) "")) - (input (read-string (format "Load timeline for tag(%s): " word))) + (input (read-string (format "Load timeline for tag (%s): " word))) (tag (if (equal input "") word input))) (message "Loading timeline for #%s..." tag) (mastodon-tl--show-tag-timeline tag))) @@ -288,12 +288,10 @@ Optionally start from POS." (mastodon-media--get-avatar-rendering avatar-url)) (propertize name 'face 'mastodon-display-name-face - 'help-echo - (mastodon-tl--format-faves-count toot)) - ;; 'help-echo ;; echo faves count when point on post author name: ;; which is where --goto-next-toot puts point. - ;; (mastodon-tl--format-faves-count toot)) + 'help-echo + (mastodon-tl--format-faves-count toot)) " (" (propertize (concat "@" handle) 'face 'mastodon-handle-face @@ -654,7 +652,7 @@ Used for hitting on a given link." (error "Unknown link type %s" link-type))))) (defun mastodon-tl--do-link-action (event) - "Do the action of the link at. + "Do the action of the link at point. Used for a mouse-click EVENT on a link." (interactive "e") (mastodon-tl--do-link-action-at-point (posn-point (event-end event)))) @@ -724,18 +722,17 @@ message is a link which unhides/hides the main body." (defun mastodon-tl--content (toot) "Retrieve text content from TOOT. -If we are in thread view, the toot content is propertized with -faves/boosts/replies counts." +Runs `mastodon-tl--render-text' and fetches poll or media." (let* ((content (mastodon-tl--field 'content toot)) (reblog (alist-get 'reblog toot)) (poll-p (if reblog (alist-get 'poll reblog) (alist-get 'poll toot)))) (concat - (mastodon-tl--render-text content toot) - (when poll-p - (mastodon-tl--get-poll toot)) - (mastodon-tl--media toot)))) + (mastodon-tl--render-text content toot) + (when poll-p + (mastodon-tl--get-poll toot)) + (mastodon-tl--media toot)))) (defun mastodon-tl--insert-status (toot body author-byline action-byline) "Display the content and byline of timeline element TOOT. @@ -763,7 +760,7 @@ takes a single function. By default it is (mastodon-media--inline-images start-pos (point))))) (defun mastodon-tl--get-poll (toot) - "If post TOOT is a poll, return a formatted string of poll." + "If TOOT includes a poll, return it as a formatted string." (let* ((poll (mastodon-tl--field 'poll toot)) (options (mastodon-tl--field 'options poll)) (option-titles (mapcar (lambda (x) @@ -831,7 +828,6 @@ takes a single function. By default it is (url (mastodon-http--api (format "polls/%s/votes" poll-id))) ;; need to zero-index our option: (option-as-arg (number-to-string (1- (string-to-number (car option))))) - ;; (option-indexed (arg `(("choices[]" . ,option-as-arg))) (response (mastodon-http--post url arg nil))) (mastodon-http--triage response -- cgit v1.2.3 From 86d51fd563f3caaaf029cf0df06fffce3d75d8a7 Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Dec 2021 10:51:45 +0100 Subject: apply pleroma patch from #208 --- lisp/mastodon-http.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 33182ff..c0fa101 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -113,6 +113,8 @@ Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (append (unless unauthenticed-p `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token))))) + (unless (assoc "Content-Type" headers) + '(("Content-Type" . "application/x-www-form-urlencoded"))) headers))) (with-temp-buffer (mastodon-http--url-retrieve-synchronously url)))) -- cgit v1.2.3 From ab37e43c60edf5f0d591441e8cece61a27dd2a6d Mon Sep 17 00:00:00 2001 From: mousebot Date: Thu, 23 Dec 2021 13:30:22 +0100 Subject: tiny ediff clean up 2. --- lisp/mastodon-notifications.el | 3 +-- lisp/mastodon-profile.el | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el index 6d48681..bb05103 100644 --- a/lisp/mastodon-notifications.el +++ b/lisp/mastodon-notifications.el @@ -49,7 +49,6 @@ (autoload 'mastodon-tl--toot-id "mastodon-tl.el") (defvar mastodon-tl--display-media-p) - (defvar mastodon-notifications--types-alist '(("mention" . mastodon-notifications--mention) ("follow" . mastodon-notifications--follow) @@ -210,7 +209,7 @@ (defun mastodon-notifications--status (note) "Format for a `status' NOTE. Status notifications are given when -`mastodon-tl--notify-user-posts' has been set." +`mastodon-tl--enable-notify-user-posts' has been set." (let ((id (cdr (assoc 'id note))) (status (mastodon-tl--field 'status note))) (mastodon-notifications--insert-status diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el index c7ef718..05cacde 100644 --- a/lisp/mastodon-profile.el +++ b/lisp/mastodon-profile.el @@ -62,7 +62,6 @@ (defvar mastodon-tl--buffer-spec) (defvar mastodon-tl--update-point) - (defvar-local mastodon-profile--account nil "The data for the account being described in the current profile buffer.") @@ -475,8 +474,8 @@ If the handle does not match a search return then retun NIL." These include the author, author of reblogged entries and any user mentioned." (when status (let ((this-account (alist-get 'account status)) - (mentions (alist-get 'mentions status)) - (reblog (alist-get 'reblog status))) + (mentions (alist-get 'mentions status)) + (reblog (alist-get 'reblog status))) (seq-filter 'stringp (seq-uniq -- cgit v1.2.3