-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add: WIP support for URL previews #63
base: master
Are you sure you want to change the base?
Conversation
Thanks. I like the way you render the previews with the bar to the left, it looks nice. A few notes: As I mentioned in the chat room, before this could be accepted, I'd need you to do the FSF copyright assignment, because I plan to submit Ement to GNU ELPA. If you're uninterested or unable to do that, this could still be useful as a proof-of-concept. For the implementation: Generally, we should avoid adding new types in the EWOC nodes, because that would require changes in several places that check node types and easily lead to new bugs (like the one you noted about sender headers). So rather than inserting a new node for each preview, it would be simpler to handle it like reactions, by updating the message formatter to append any previews to the end of a message event. The preview-getting callback would add the preview data to the event's |
As I mentioned in the chat room, what's probably needed is for me to implement a queue system in Regarding the current code in this PR: it's not quite what I had in mind. It could be simpler and integrate more naturally into the existing code. But I can't ask you to put more work into this until you've done the FSF CA, otherwise your work could be in vain, and I'll end up having to do it myself anyway. So I don't think I should give more specific feedback until that's done. |
12c2abf
to
2e072ef
Compare
FYI, here's my WIP of using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your work on this. I made some comments on the code.
do (when-let ((inner-data (map-elt data (intern (concat "preview-" (number-to-string i)))))) | ||
(unless (looking-at-p "^\n") (insert "\n")) | ||
(insert (ement-room--format-url-preview inner-data))))) | ||
(dolist (preview previews) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking better. Now it probably should go into its own function, similar to ement-room--format-m.image
. And the code that calls it should probably go in ement-room--format-message-body
, treating it as a kind of "appendix" to the message body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've currently left it how it is, mainly due to the fact that there is already a function named ement-room--format-url-preview
. I think the most reasonable way to go about it is integrating the dolist into ement-room--format-url-preview
and calling it from ement-room--format-message-body
, but just wanted to confirm with you before I do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll also probably implement the message parsing in this combined function to insert the previews in the correct order rather than just iterating using dolist.
Sorry for not working on this in a while, was mainly waiting for the FSF CA to get done. Finally got it complete the other day. |
No problem. That's great news. I don't have time for another full review, but I'll make a few comments... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
@@ -2573,25 +2573,25 @@ Formats according to `ement-room-message-format-spec', which see." | |||
;; TODO: Like other events, pop to a buffer showing the raw reaction events when a key is pressed. | |||
(if-let ((reactions (map-elt (ement-event-local event) 'reactions))) | |||
(cl-labels ((format-reaction | |||
(ks) (pcase-let* ((`(,key . ,senders) ks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove any whitespace-only hunks from the patch.
|
||
(defun ement-room--preview-urls (event rendered) | ||
"Parse RENDERED body of EVENT for URLs and fetch previews for them." | ||
(if (and (not (alist-get 'url-previews (ement-event-local event))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what rendered
is here.
"Parse RENDERED body of EVENT for URLs and fetch previews for them." | ||
(if (and (not (alist-get 'url-previews (ement-event-local event))) | ||
rendered) | ||
(let ((room-buffer (alist-get 'buffer (ement-room-local ement-room)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can, please use pcase-let
to destructure when possible. I'm trying to use it consistently (although sometimes using alist-get
is still necessary).
(insert rendered) | ||
(goto-char (point-min)) | ||
(cl-loop with match = nil | ||
while (setf match (or (text-property-search-forward 'ement-url) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just do a regexp search for URLs on the message's plain-text body? It will probably be faster, because Emacs's regexp engine is very well optimized, and the code will be much simpler.
(defun ement-room--insert-preview (message related num data) | ||
"Insert link preview for DATA into MESSAGE from node RELATED if it isn't already present. | ||
NUM is the index for this link." | ||
(defun ement-room--insert-preview (message related key data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please write in terms of events rather than messages, because events are the logical unit we work in here.
NUM is the index for this link." | ||
(defun ement-room--insert-preview (message related key data) | ||
"Insert link preview for HTTP response DATA into MESSAGE from node RELATED, | ||
if it isn't already present. KEY will be the key used for inserting." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what "KEY will be the key used for inserting" means.
As well, "related" could be more clearly written as "related-event" or "related-node", etc.
NUM is the index for this link." | ||
(defun ement-room--insert-preview (message related key data) | ||
"Insert link preview for HTTP response DATA into MESSAGE from node RELATED, | ||
if it isn't already present. KEY will be the key used for inserting." | ||
(cond ((alist-get 'errcode data) (ement-debug "Rate limit in url preview")) | ||
(data (let ((related-node (ement-room--ewoc-node-before ement-ewoc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid one-symbol-per-line formatting style. This function has (declare (indent defun))
specified to avoid this. :)
(cl-pushnew (cons 'url-previews nil) (ement-event-local related))) | ||
(unless (alist-get key (map-elt (ement-event-local related) 'url-previews)) | ||
(cl-pushnew (cons key data) (map-elt (ement-event-local related) 'url-previews))) | ||
(event (ement-event-local related))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're binding the event's local
alist slot, the binding should be named local
, not event
--event
should be the event struct itself.
But since you need to push to that alist anyway, you probably shouldn't bind it. I may be mistaken, but I don't think setting the bound variable will also set the slot value; you need to set the place form's value (at least, that's been my experience).
(unless (alist-get key (map-elt (ement-event-local related) 'url-previews)) | ||
(cl-pushnew (cons key data) (map-elt (ement-event-local related) 'url-previews))) | ||
(event (ement-event-local related))) | ||
(unless (alist-get 'url-previews event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please be consistent: use either map-elt
or alist-get
. :) (If performance matters, using alist-get
will be faster, because map-elt
is generic. But see also map-nested-elt
, which can make for clearer code than nested alist-get
s, and it's fast enough--although I don't think setf
works with it, yet.)
(ewoc-invalidate ement-ewoc related-node))))) | ||
|
||
(defun ement-room--format-url-preview (data) | ||
"Return a pretty-printed preview for DATA." | ||
"Return a pretty-printed preview for DATA, an alist of parsed JSON from the homeserver." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: To keep the first line of the docstring short, the second clause (which is just supporting information) can go in a second sentence on a second line. (Checkdoc will complain, otherwise (although getting rid of all Checkdoc warnings is sometimes impractical)).
4a42004
to
481f571
Compare
a6ec9ad
to
fcbf1a5
Compare
9845fce
to
338b99b
Compare
7d2e0f2
to
c0b922b
Compare
a68abe0
to
9da7b8e
Compare
Implements basic support for asynchronous URL previews, currently almost everything is working. Getting the preview, inserting the preview to the proper place, inserting later messages to the proper places, etc.
It can be turned on by the variable
ement-room-url-previews
, set to nil by default because some homeservers don't support URL previews (probably be best to mention something in the readme about this if it gets merged).There are two things that currently don't work very well (probably more I haven't found yet though, haven't thoroughly tested this):
ement.el/ement-room.el
Line 2379 in 4692961
I'm not too sure why, all the macros make it hard to debug, though I suspect it is trivial. And everything appears to work fine except that it throws an error. The previews are inserted correctly, and even the headers are inserted correctly.
Feel free to edit, change, or delete anything you wish :)