aboutsummaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authormarty hiatt <martianhiatus [a t] riseup [d o t] net>2023-04-05 13:03:59 +0200
committermarty hiatt <martianhiatus [a t] riseup [d o t] net>2023-04-05 13:03:59 +0200
commit81a6973878c16251bbc70ee0e98c153e5b30e720 (patch)
tree3ea0db7708f01b16d0eb8d0fef78ed448b8e62e8 /lisp
parentf53847ef151bf841a2cbdaad556b334f3bba2986 (diff)
parentc6acfe694d3c2e0468c98478775442f8710de7e1 (diff)
Merge branch 'develop'
Diffstat (limited to 'lisp')
-rw-r--r--lisp/mastodon-notifications.el4
-rw-r--r--lisp/mastodon-tl.el174
-rw-r--r--lisp/mastodon-toot.el42
-rw-r--r--lisp/mastodon-views.el45
-rw-r--r--lisp/mastodon.el11
5 files changed, 175 insertions, 101 deletions
diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el
index fd48a65..bed2d9a 100644
--- a/lisp/mastodon-notifications.el
+++ b/lisp/mastodon-notifications.el
@@ -76,7 +76,7 @@
("Posted a poll" . "that has now ended")
("Requested to follow" . "you")
("Posted" . "a post")
- ("Edited" . "a post"))
+ ("Edited" . "a post from"))
"Alist of subjects for notification types.")
(defvar mastodon-notifications--map
@@ -126,7 +126,7 @@ follow-requests view."
(lambda ()
(if f-reqs-view-p
(mastodon-views--view-follow-requests)
- (mastodon-notifications-get))
+ (mastodon-tl--reload-timeline-or-profile))
(message "Follow request of %s (@%s) %s!"
name handle (if reject
"rejected"
diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el
index 3c66176..794b198 100644
--- a/lisp/mastodon-tl.el
+++ b/lisp/mastodon-tl.el
@@ -39,6 +39,9 @@
(require 'mastodon-iso)
(require 'mpv nil :no-error)
+(autoload 'mastodon-mode "mastodon")
+(autoload 'mastodon-notifications-get "mastodon")
+(autoload 'mastodon-url-lookup "mastodon")
(autoload 'mastodon-auth--get-account-id "mastodon-auth")
(autoload 'mastodon-auth--get-account-name "mastodon-auth")
(autoload 'mastodon-http--api "mastodon-http")
@@ -55,10 +58,8 @@
(autoload 'mastodon-media--get-avatar-rendering "mastodon-media")
(autoload 'mastodon-media--get-media-link-rendering "mastodon-media")
(autoload 'mastodon-media--inline-images "mastodon-media")
-(autoload 'mastodon-mode "mastodon")
(autoload 'mastodon-notifications--filter-types-list "mastodon-notifications")
-(autoload 'mastodon-notifications-get "mastodon-notifications"
- "Display NOTIFICATIONS in buffer." t) ; interactive
+(autoload 'mastodon-notifications--get-mentions "mastodon-notifications")
(autoload 'mastodon-profile--account-field "mastodon-profile")
(autoload 'mastodon-profile--account-from-id "mastodon-profile")
(autoload 'mastodon-profile--extract-users-handles "mastodon-profile")
@@ -67,6 +68,7 @@
(autoload 'mastodon-profile--lookup-account-in-status "mastodon-profile")
(autoload 'mastodon-profile--make-author-buffer "mastodon-profile")
(autoload 'mastodon-profile--my-profile "mastodon-profile")
+(autoload 'mastodon-profile--open-statuses-no-reblogs "mastodon-profile")
(autoload 'mastodon-profile--profile-json "mastodon-profile")
(autoload 'mastodon-profile--search-account-by-handle "mastodon-profile")
(autoload 'mastodon-profile--toot-json "mastodon-profile")
@@ -82,7 +84,6 @@
(autoload 'mastodon-toot--schedule-toot "mastodon-toot")
(autoload 'mastodon-toot--set-toot-properties "mastodon-toot")
(autoload 'mastodon-toot--update-status-fields "mastodon-toot")
-(autoload 'mastodon-url-lookup "mastodon")
(defvar mastodon-toot--visibility)
(defvar mastodon-toot-mode)
@@ -347,50 +348,79 @@ Used on initializing a timeline or thread."
;;; TIMELINES
-(defun mastodon-tl--get-federated-timeline ()
- "Opens federated timeline."
- (interactive)
- (message "Loading federated timeline...")
- (mastodon-tl--init
- "federated" "timelines/public" 'mastodon-tl--timeline nil
- `(("limit" . ,mastodon-tl--timeline-posts-count))
- (when current-prefix-arg t)))
-
-(defun mastodon-tl--get-home-timeline ()
- "Opens home timeline."
- (interactive)
+(defun mastodon-tl--get-federated-timeline (&optional prefix local)
+ "Open federated timeline.
+If LOCAL, get only local timeline.
+With a single PREFIX arg, hide-replies.
+With a double PREFIX arg, only show posts with media."
+ (interactive "p")
+ (let ((params
+ `(("limit" . ,mastodon-tl--timeline-posts-count))))
+ ;; avoid adding 'nil' to our params alist:
+ (when (eq prefix 16)
+ (push '("only_media" . "true") params))
+ (when local
+ (push '("local" . "true") params))
+ (message "Loading federated timeline...")
+ (mastodon-tl--init
+ (if local "local" "federated")
+ "timelines/public" 'mastodon-tl--timeline nil
+ params
+ (when (eq prefix 4) t))))
+
+(defun mastodon-tl--get-home-timeline (&optional arg)
+ "Open home timeline.
+With a single prefix ARG, hide replies."
+ (interactive "p")
(message "Loading home timeline...")
(mastodon-tl--init
"home" "timelines/home" 'mastodon-tl--timeline nil
`(("limit" . ,mastodon-tl--timeline-posts-count))
- (when current-prefix-arg t)))
+ (when (eq arg 4) t)))
-(defun mastodon-tl--get-local-timeline ()
- "Opens local timeline."
- (interactive)
+(defun mastodon-tl--get-local-timeline (&optional prefix)
+ "Open local timeline.
+With a single PREFIX arg, hide-replies.
+With a double PREFIX arg, only show posts with media."
+ (interactive "p")
(message "Loading local timeline...")
- (mastodon-tl--init
- "local" "timelines/public" 'mastodon-tl--timeline
- nil `(("local" . "true")
- ("limit" . ,mastodon-tl--timeline-posts-count))
- (when current-prefix-arg t)))
+ (mastodon-tl--get-federated-timeline prefix :local))
-(defun mastodon-tl--get-tag-timeline (&optional tag)
+(defun mastodon-tl--get-tag-timeline (&optional prefix tag)
"Prompt for tag and opens its timeline.
-Optionally load TAG timeline directly."
- (interactive)
+Optionally load TAG timeline directly.
+With a single PREFIX arg, only show posts with media.
+With a double PREFIX arg, limit results to your own instance."
+ (interactive "p")
(let* ((word (or (word-at-point) ""))
(input (or tag (read-string (format "Load timeline for tag (%s): " word))))
(tag (or tag (if (string-empty-p input) word input))))
(message "Loading timeline for #%s..." tag)
- (mastodon-tl--show-tag-timeline tag)))
-
-(defun mastodon-tl--show-tag-timeline (tag)
- "Opens a new buffer showing the timeline of posts with hastag TAG."
- (mastodon-tl--init
- (concat "tag-" tag) (concat "timelines/tag/" tag)
- 'mastodon-tl--timeline nil
- `(("limit" . ,mastodon-tl--timeline-posts-count))))
+ (mastodon-tl--show-tag-timeline prefix tag)))
+
+(defun mastodon-tl--show-tag-timeline (&optional prefix tag)
+ "Opens a new buffer showing the timeline of posts with hastag TAG.
+If TAG is a list, show a timeline for all tags.
+With a single PREFIX arg, only show posts with media.
+With a double PREFIX arg, limit results to your own instance."
+ (let ((params
+ `(("limit" . ,mastodon-tl--timeline-posts-count))))
+ ;; avoid adding 'nil' to our params alist:
+ (when (eq prefix 4)
+ (push '("only_media" . "true") params))
+ (when (eq prefix 16)
+ (push '("local" . "true") params))
+ (when (listp tag)
+ (let ((list (mastodon-http--build-array-params-alist "any[]" (cdr tag))))
+ (while list
+ (push (pop list) params))))
+ (mastodon-tl--init (concat "tag-" (if (listp tag) "followed-tags" tag))
+ (concat "timelines/tag/" (if (listp tag)
+ ;; endpoint needs to be /tag/:sometag
+ (car tag) tag))
+ 'mastodon-tl--timeline
+ nil
+ params)))
;;; BYLINES, etc.
@@ -875,7 +905,7 @@ Used for hitting RET on a given link."
(cond ((eq link-type 'content-warning)
(mastodon-tl--toggle-spoiler-text position))
((eq link-type 'hashtag)
- (mastodon-tl--show-tag-timeline (get-text-property position 'mastodon-tag)))
+ (mastodon-tl--show-tag-timeline nil (get-text-property position 'mastodon-tag)))
;; 'account / 'account-id is not set for mentions, only bylines
((eq link-type 'user-handle)
(let ((account-json (get-text-property position 'account))
@@ -2044,15 +2074,25 @@ If TAG is provided, unfollow it."
(lambda ()
(message "tag #%s unfollowed!" tag)))))
-(defun mastodon-tl--list-followed-tags ()
- "List followed tags. View timeline of tag user choses."
- (interactive)
+(defun mastodon-tl--list-followed-tags (&optional prefix)
+ "List followed tags. View timeline of tag user choses.
+Prefix is sent to `mastodon-tl--get-tag-timeline', which see."
+ (interactive "p")
(let* ((followed-tags-json (mastodon-tl--followed-tags))
(tags (mastodon-tl--map-alist 'name followed-tags-json))
(tag (completing-read "Tag: " tags nil)))
(if (null tag)
(message "You have to follow some tags first.")
- (mastodon-tl--get-tag-timeline tag))))
+ (mastodon-tl--get-tag-timeline prefix tag))))
+
+(defun mastodon-tl--followed-tags-timeline (&optional prefix)
+ "Open a timeline of all your followed tags.
+Prefix is sent to `mastodon-tl--show-tag-timeline', which see."
+ (interactive "p")
+ (let* ((followed-tags-json (mastodon-tl--followed-tags))
+ (tags (mastodon-tl--map-alist 'name followed-tags-json)))
+ (mastodon-tl--show-tag-timeline prefix tags)))
+
;;; UPDATING, etc.
@@ -2083,25 +2123,37 @@ the current view."
(mastodon-http--get-json url args)))
;; TODO: add this to new posts in some cases, e.g. in thread view.
-(defun mastodon-tl--reload-timeline-or-profile ()
+(defun mastodon-tl--reload-timeline-or-profile (&optional pos)
"Reload the current timeline or profile page.
-For use after e.g. deleting a toot."
- (cond ((mastodon-tl--buffer-type-eq 'home)
- (mastodon-tl--get-home-timeline))
- ((mastodon-tl--buffer-type-eq 'federated)
- (mastodon-tl--get-federated-timeline))
- ((mastodon-tl--buffer-type-eq 'local)
- (mastodon-tl--get-local-timeline))
- ((mastodon-tl--buffer-type-eq 'notifications)
- (mastodon-notifications-get))
- ((mastodon-tl--buffer-type-eq 'own-profile)
- (mastodon-profile--my-profile))
- ((save-match-data
- (string-match
- "statuses/\\(?2:[[:digit:]]+\\)/context"
- (mastodon-tl--get-endpoint))
- (mastodon-tl--thread
- (match-string 2 (mastodon-tl--get-endpoint)))))))
+For use after e.g. deleting a toot.
+POS is a number, where point will be placed."
+ (let ((type (mastodon-tl--get-buffer-type)))
+ (cond ((eq type 'home)
+ (mastodon-tl--get-home-timeline))
+ ((eq type 'federated)
+ (mastodon-tl--get-federated-timeline))
+ ((eq type 'local)
+ (mastodon-tl--get-local-timeline))
+ ((eq type 'mentions)
+ (mastodon-notifications--get-mentions))
+ ((eq type 'notifications)
+ (mastodon-notifications-get nil nil :force))
+ ((eq type 'profile-statuses-no-boosts)
+ (mastodon-profile--open-statuses-no-reblogs))
+ ((eq type 'profile-statuses)
+ (mastodon-profile--my-profile))
+ ((eq type 'thread)
+ (save-match-data
+ (let ((endpoint (mastodon-tl--get-endpoint)))
+ (string-match
+ "statuses/\\(?2:[[:digit:]]+\\)/context"
+ endpoint)
+ (mastodon-tl--thread
+ (match-string 2 endpoint))))))
+ ;; TODO: sends point to POS, which was where point was in buffer before reload. This is very rough; we may have removed an item (deleted a toot, cleared a notif), so the buffer will be smaller, point will end up past where we were, etc.
+ (when pos
+ (goto-char pos)
+ (mastodon-tl--goto-prev-item))))
(defun mastodon-tl--build-link-header-url (str)
"Return a URL from STR, an http Link header."
@@ -2353,8 +2405,8 @@ This location is defined by a non-nil value of
(goto-char (or mastodon-tl--update-point (point-min)))
(funcall update-function json)
(when mastodon-tl--after-update-marker
- (goto-char mastodon-tl--after-update-marker))))
- (message "nothing to update")))))
+ (goto-char mastodon-tl--after-update-marker)))
+ (message "nothing to update"))))))
;;; LOADING TIMELINES
diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el
index 3cab565..c2c391d 100644
--- a/lisp/mastodon-toot.el
+++ b/lisp/mastodon-toot.el
@@ -568,7 +568,8 @@ NO-REDRAFT means delete toot only."
(url (mastodon-http--api (format "statuses/%s" id)))
(toot-cw (alist-get 'spoiler_text toot))
(toot-visibility (alist-get 'visibility toot))
- (reply-id (alist-get 'in_reply_to_id toot)))
+ (reply-id (alist-get 'in_reply_to_id toot))
+ (pos (point)))
(if (not (mastodon-toot--own-toot-p toot))
(message "You can only delete (and redraft) your own toots.")
(when (y-or-n-p (if no-redraft
@@ -581,7 +582,7 @@ NO-REDRAFT means delete toot only."
(if no-redraft
(progn
(when mastodon-tl--buffer-spec
- (mastodon-tl--reload-timeline-or-profile))
+ (mastodon-tl--reload-timeline-or-profile pos))
(message "Toot deleted!"))
(mastodon-toot--redraft response
reply-id
@@ -773,11 +774,12 @@ instance to edit a toot."
(let* ((toot (mastodon-toot--remove-docs))
(scheduled mastodon-toot--scheduled-for)
(scheduled-id mastodon-toot--scheduled-id)
+ (edit-id mastodon-toot--edit-toot-id)
(endpoint
- (if mastodon-toot--edit-toot-id
+ (if edit-id
;; we are sending an edit:
(mastodon-http--api (format "statuses/%s"
- mastodon-toot--edit-toot-id))
+ edit-id))
(mastodon-http--api "statuses")))
(spoiler (when (and (not (mastodon-toot--empty-p))
mastodon-toot--content-warning)
@@ -819,22 +821,25 @@ instance to edit a toot."
((mastodon-toot--empty-p)
(message "Empty toot. Cowardly refusing to post this."))
(t
- (let ((response (if mastodon-toot--edit-toot-id
+ (let ((response (if edit-id
;; we are sending an edit:
(mastodon-http--put endpoint args)
(mastodon-http--post endpoint args))))
- (mastodon-http--triage response
- (lambda ()
- (mastodon-toot--kill)
- (if scheduled
- (message "Toot scheduled!")
- (message "Toot toot!"))
- ;; cancel scheduled toot if we were editing it:
- (when scheduled-id
- (mastodon-views--cancel-scheduled-toot
- scheduled-id :no-confirm))
- (mastodon-toot--restore-previous-window-config
- prev-window-config))))))))
+ (mastodon-http--triage
+ response
+ (lambda ()
+ (mastodon-toot--kill)
+ (if scheduled
+ (message "Toot scheduled!")
+ (message "Toot toot!"))
+ ;; cancel scheduled toot if we were editing it:
+ (when scheduled-id
+ (mastodon-views--cancel-scheduled-toot
+ scheduled-id :no-confirm))
+ (mastodon-toot--restore-previous-window-config prev-window-config)
+ (when edit-id
+ (let ((pos (marker-position (cadr prev-window-config))))
+ (mastodon-tl--reload-timeline-or-profile pos))))))))))
;; EDITING TOOTS:
@@ -1609,7 +1614,8 @@ Added to `after-change-functions'."
(defun mastodon-toot--compose-buffer-p ()
"Return t if compose buffer is current."
- (mastodon-tl--buffer-type-eq 'new-toot))
+ (or (mastodon-tl--buffer-type-eq 'edit-toot)
+ (mastodon-tl--buffer-type-eq 'new-toot)))
;; NB: now that we have toot drafts, to ensure offline composing remains
;; possible, avoid any direct requests here:
diff --git a/lisp/mastodon-views.el b/lisp/mastodon-views.el
index 5576b14..38344b3 100644
--- a/lisp/mastodon-views.el
+++ b/lisp/mastodon-views.el
@@ -325,7 +325,10 @@ If ID is provided, use that list."
(endpoint (format "timelines/list/%s" id))
(name (mastodon-views--get-list-name id))
(buffer-name (format "list-%s" name)))
- (mastodon-tl--init buffer-name endpoint 'mastodon-tl--timeline)))
+ (mastodon-tl--init buffer-name endpoint
+ 'mastodon-tl--timeline
+ nil
+ `(("limit" . ,mastodon-tl--timeline-posts-count)))))
(defun mastodon-views--create-list ()
"Create a new list.
@@ -458,7 +461,7 @@ If ID is provided, use that list."
JSON is the data returned by the server."
(mastodon-views--minor-view
"follow requests"
- "a/r - accept/reject request at point\n n/p - go to next/prev request"
+ "a/j - accept/reject request at point\n n/p - go to next/prev request"
#'mastodon-views--insert-users-propertized-note
json))
@@ -717,6 +720,25 @@ BRIEF means show fewer details."
(interactive)
(mastodon-views--view-instance-description nil :brief))
+(defun mastodon-views--get-instance-url (url username &optional instance)
+ "Return an instance base url from a user account URL.
+USERNAME is the name to cull.
+If INSTANCE is given, use that."
+ (cond (instance
+ (concat "https://" instance))
+ ;; pleroma URL is https://instance.com/users/username
+ ((string-suffix-p "users/" (url-basepath url))
+ (string-remove-suffix "/users/"
+ (url-basepath url)))
+ ;; friendica is https://instance.com/profile/user
+ ((string-suffix-p "profile/" (url-basepath url))
+ (string-remove-suffix "/profile/"
+ (url-basepath url)))
+ ;; mastodon is https://instance.com/@user
+ (t
+ (string-remove-suffix (concat "/@" username)
+ url))))
+
(defun mastodon-views--view-instance-description (&optional user brief instance)
"View the details of the instance the current post's author is on.
USER means to show the instance details for the logged in user.
@@ -757,20 +779,7 @@ INSTANCE is an instance domain name."
(mastodon-tl--property 'profile-json))
(alist-get 'username toot) ;; profile
(alist-get 'username account)))
- (instance (cond (instance
- (concat "https://" instance))
- ;; pleroma URL is https://instance.com/users/username
- ((string-suffix-p "users/" (url-basepath url))
- (string-remove-suffix "/users/"
- (url-basepath url)))
- ;; friendica is https://instance.com/profile/user
- ((string-suffix-p "profile/" (url-basepath url))
- (string-remove-suffix "/profile/"
- (url-basepath url)))
- ;; mastodon:
- (t
- (string-remove-suffix (concat "/@" username)
- url))))
+ (instance (mastodon-views--get-instance-url url username instance))
(response (mastodon-http--get-json
(if user
(mastodon-http--api "instance")
@@ -806,7 +815,9 @@ INSTANCE is the instance were are working with."
(assoc 'rules response)
(assoc 'stats response))))
(mastodon-views--print-json-keys response)
- (mastodon-mode)
+ ;; (mastodon-mode) ; breaks our 'q' binding that avoids leaving
+ ;; split window
+ (setq mastodon-account--data account)
(mastodon-tl--set-buffer-spec (buffer-name buf)
"instance"
nil)
diff --git a/lisp/mastodon.el b/lisp/mastodon.el
index fa822a0..81a0092 100644
--- a/lisp/mastodon.el
+++ b/lisp/mastodon.el
@@ -64,6 +64,7 @@
(autoload 'mastodon-profile--view-favourites "mastodon-profile")
(autoload 'mastodon-tl--block-user "mastodon-tl")
(autoload 'mastodon-tl--follow-user "mastodon-tl")
+(autoload 'mastodon-tl--followed-tags-timeline "mastodon-tl")
(autoload 'mastodon-tl--get-buffer-type "mastodon-tl")
(autoload 'mastodon-tl--get-federated-timeline "mastodon-tl")
(autoload 'mastodon-tl--get-home-timeline "mastodon-tl")
@@ -152,6 +153,7 @@ Use. e.g. \"%c\" for your locale's date and time format."
;; navigation between timelines
(define-key map (kbd "#") #'mastodon-tl--get-tag-timeline)
(define-key map (kbd ":") #'mastodon-tl--list-followed-tags)
+ (define-key map (kbd "C-:") #'mastodon-tl--followed-tags-timeline)
(define-key map (kbd "A") #'mastodon-profile--get-toot-author)
(define-key map (kbd "F") #'mastodon-tl--get-federated-timeline)
(define-key map (kbd "H") #'mastodon-tl--get-home-timeline)
@@ -273,15 +275,18 @@ If REPLY-JSON is the json of the toot being replied to."
(mastodon-toot--compose-buffer user reply-to-id reply-json))
;;;###autoload
-(defun mastodon-notifications-get (&optional type buffer-name)
+(defun mastodon-notifications-get (&optional type buffer-name force)
"Display NOTIFICATIONS in buffer.
Optionally only print notifications of type TYPE, a string.
-BUFFER-NAME is added to \"*mastodon-\" to create the buffer name."
+BUFFER-NAME is added to \"*mastodon-\" to create the buffer name.
+FORCE means do not try to update an existing buffer, but fetch
+from the server and load anew."
(interactive)
(let ((buffer (if buffer-name
(concat "*mastodon-" buffer-name "*")
"*mastodon-notifications*")))
- (if (get-buffer buffer)
+ (if (and (not force)
+ (get-buffer buffer))
(progn (switch-to-buffer buffer)
(mastodon-tl--update))
(message "Loading your notifications...")