diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4e6b95e..2d452d1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,6 +43,7 @@ jobs: emacs_version: - 26.3 - 27.1 + - 28.2 - snapshot steps: - uses: purcell/setup-emacs@master diff --git a/README.org b/README.org index 6e195684..8b24afc0 100644 --- a/README.org +++ b/README.org @@ -3,7 +3,7 @@ #+PROPERTY: LOGGING nil # Export options. -#+OPTIONS: broken-links:t *:t +#+OPTIONS: broken-links:t *:t num:1 toc:1 # Info export options. #+EXPORT_FILE_NAME: ement.texi @@ -184,7 +184,7 @@ These bindings are common to all of the following buffer types: + Send file: ~s f~ + Send image: ~s i~ + View event source: ~v~ -+ Complete members and rooms at point: ~C-M-i~ (standard ~completion-at-point~ command). ++ Complete members and rooms at point: ~C-M-i~ (standard ~completion-at-point~ command). (Type an ~@~ prefix for a member mention, a ~#~ prefix for a room alias, or a ~!~ prefix for a room ID.) *Images* @@ -254,6 +254,7 @@ These bindings are common to all of the following buffer types: + Starting in the room list buffer, by pressing ~SPC~ repeatedly, you can cycle through and read all rooms with unread buffers. (If a room doesn't have a buffer, it will not be included.) + Room buffers and the room-list buffer can be bookmarked in Emacs, i.e. using =C-x r m=. This is especially useful with [[https://github.com/alphapapa/burly.el][Burly]]: you can arrange an Emacs frame with several room buffers displayed at once, use =burly-bookmark-windows= to bookmark the layout, and then you can restore that layout and all of the room buffers by opening the bookmark, rather than having to manually arrange them every time you start Emacs or change the window configuration. + Images and other files can be uploaded to rooms using drag-and-drop. ++ Mention members by typing a ~@~ followed by their displayname or Matrix ID. (Members' names and rooms' aliases/IDs may be completed with ~completion-at-point~ commands.) + You can customize settings in the ~ement~ group. - *Note:* ~setq~ should not be used for certain options, because it will not call the associated setter function. Users who have an aversion to the customization system may experience problems. @@ -295,11 +296,37 @@ Note that, while ~matrix-client~ remains usable, and probably will for some time :TOC: :depth 0 :END: -** 0.9-pre +** 0.10-pre + +*Changes* + ++ Improve readme export settings. + +** 0.9.3 + +*Fixes* ++ Another attempt at restoring position in room list when refreshing. ++ Command ~ement-room-list-next-unread~. + +** 0.9.2 + +*Fixes* ++ Restore position in room list when refreshing. ++ Completion in minibuffer. + +** 0.9.1 + +*Fixes* ++ Error in ~ement-room-list~ command upon initial sync. + +** 0.9 *Additions* + Option ~ement-room-timestamp-header-align~ controls how timestamp headers are aligned in room buffers. ++ Option ~ement-room-view-hook~ runs functions when ~ement-room-view~ is called. (By default, it refreshes the room list buffer.) ++ In the room list, middle-clicking a room which has a buffer closes its buffer. ++ Basic support for video events. (Thanks to [[https://github.com/viiru-][Arto Jantunen]].) *Changes* @@ -308,6 +335,9 @@ Note that, while ~matrix-client~ remains usable, and probably will for some time *Fixes* + Recognition of certain MXID or displayname forms in outgoing messages when linkifying (aka "pilling") them. ++ Unreadable room avatar images no longer cause errors. (Fixes [[https://github.com/alphapapa/ement.el/issues/147][#147]]. Thanks to [[https://github.com/jgarte][@jgarte]] for reporting.) ++ Don't error in ~ement-room-list~ when no rooms are joined. (Fixes [[https://github.com/alphapapa/ement.el/issues/123][#123]]. Thanks to [[https://github.com/Kabouik][@Kabouik]] and [[https://github.com/oantolin][Omar Antolín Camarena]] for reporting.) ++ Enable member/room completion in compose buffers. (Fixes [[https://github.com/alphapapa/ement.el/issues/115][#115]]. Thanks to Thanks to [[https://github.com/piater][Justus Piater]] and [[https://github.com/chasecaleb][Caleb Chase]] for reporting.) ** 0.8.3 diff --git a/ement-lib.el b/ement-lib.el index 06c98ab6..c573d2a7 100644 --- a/ement-lib.el +++ b/ement-lib.el @@ -62,6 +62,30 @@ (defvar ement-room-prism-minimum-contrast) (defvar ement-room-unread-only-counts-notifications) +;;;; Function declarations + +;; Instead of using top-level `declare-function' forms (which can easily become obsolete +;; if not kept with the code that needs them), this allows the use of `(declare (function +;; ...))' forms in each function definition, so that if a function is moved or removed, +;; the `declare-function' goes with it. + +;; TODO: Propose this upstream. + +(eval-and-compile + (defun ement--byte-run--declare-function (_name _args &rest values) + "Return a `declare-function' form with VALUES. +Allows the use of a form like: + + (declare (function FN FILE ...)) + +inside of a function definition, effectively keeping its +`declare-function' form inside the function definition, ensuring +that stray such forms don't remain if the function is removed." + `(declare-function ,@values)) + + (cl-pushnew '(function ement--byte-run--declare-function) defun-declarations-alist :test #'equal) + (cl-pushnew '(function ement--byte-run--declare-function) macro-declarations-alist :test #'equal)) + ;;;; Compatibility ;; These workarounds should be removed when they aren't needed. diff --git a/ement-room-list.el b/ement-room-list.el index 39542c5d..6dad2354 100644 --- a/ement-room-list.el +++ b/ement-room-list.el @@ -39,6 +39,23 @@ "Group Ement rooms with Taxy." :group 'ement) +;;;; Mouse commands + +;; Since mouse-activated commands must handle mouse events, we define a simple macro to +;; wrap a command into a mouse-event-accepting one. + +(defmacro ement-room-list-define-mouse-command (command) + "Define a command that calls COMMAND interactively with point at mouse event. +COMMAND should be a form that evaluates to a function symbol; if +a symbol, it should be unquoted.." + (let ((docstring (format "Call command `%s' interactively with point at EVENT." command)) + (name (intern (format "ement-room-list-mouse-%s" command)))) + `(defun ,name (event) + ,docstring + (interactive "e") + (mouse-set-point event) + (call-interactively #',command)))) + ;;;; Variables (declare-function ement-room-toggle-space "ement-room") @@ -48,10 +65,23 @@ (define-key map (kbd "RET") #'ement-room-list-RET) (define-key map (kbd "SPC") #'ement-room-list-next-unread) (define-key map [tab] #'ement-room-list-section-toggle) - (define-key map [mouse-1] #'ement-room-list-mouse-1) + (define-key map [mouse-1] (ement-room-list-define-mouse-command ement-room-list-RET)) + (define-key map [mouse-2] (ement-room-list-define-mouse-command ement-room-list-kill-buffer)) (define-key map (kbd "k") #'ement-room-list-kill-buffer) (define-key map (kbd "s") #'ement-room-toggle-space) - map)) + map) + "Keymap for `ement-room-list' buffers. +See also `ement-room-list-button-map'.") + +(defvar ement-room-list-button-map + ;; This map is needed because some columns are propertized as buttons, which override + ;; the main keymap. + ;; TODO: Is it possible to adjust the button properties to obviate this map? + (let ((map (make-sparse-keymap))) + (define-key map [mouse-1] (ement-room-list-define-mouse-command ement-room-list-RET)) + (define-key map [mouse-2] (ement-room-list-define-mouse-command ement-room-list-kill-buffer)) + map) + "Keymap for buttonized text in `ement-room-list' buffers.") (defvar ement-room-list-timestamp-colors nil "List of colors used for timestamps. @@ -369,9 +399,10 @@ from recent to non-recent for rooms updated in the past hour.") (push 'ement-room-list-invited (map-elt face :inherit))) ('leave (push 'ement-room-list-left (map-elt face :inherit)))) - (propertize (ement--button-buttonize display-name #'ement-room-list-mouse-1) + (propertize display-name 'face face - 'mouse-face 'highlight)) + 'mouse-face 'highlight + 'keymap ement-room-list-button-map)) ""))) (ement-room-list-define-column #("Unread" 0 6 (help-echo "Unread events (Notifications:Highlights)")) (:align 'right) @@ -516,7 +547,8 @@ After showing it, its window is selected. The buffer is named BUFFER-NAME and is shown with DISPLAY-BUFFER-ACTION; or if DISPLAY-BUFFER-ACTION is nil, the buffer is not displayed." (interactive) - (let (format-table column-sizes window-start) + (let ((window-start 0) (window-point 0) + format-table column-sizes) (cl-labels (;; (heading-face ;; (depth) (list :inherit (list 'bufler-group (bufler-level-face depth)))) (format-item (item) (gethash item format-table)) @@ -584,77 +616,92 @@ DISPLAY-BUFFER-ACTION is nil, the buffer is not displayed." ;; (kill-buffer buffer-name)) (unless ement-sessions (error "Ement: Not connected. Use `ement-connect' to connect")) - (with-current-buffer (get-buffer-create buffer-name) - (ement-room-list-mode) - (let* ((room-session-vectors - (cl-loop for (_id . session) in ement-sessions - append (cl-loop for room in (ement-session-rooms session) - collect (vector room session)))) - (taxy (cl-macrolet ((first-item - (pred) `(lambda (taxy) - (when (taxy-items taxy) - (,pred (car (taxy-items taxy)))))) - (name= (name) `(lambda (taxy) - (equal ,name (taxy-name taxy))))) - (thread-last - (make-fn - :name "Ement Rooms" - :take (taxy-make-take-function keys ement-room-list-keys)) - (taxy-fill room-session-vectors) - (taxy-sort #'> #'item-latest-ts) - (taxy-sort #'tnil #'item-low-priority-p) - (taxy-sort #'tnil #'item-left-p) - (taxy-sort* #'string< #'taxy-name) - (taxy-sort* #'> #'taxy-latest-ts) - (taxy-sort* #'tnil (first-item item-space-p)) - (taxy-sort* #'t>nil (name= "Low-priority")) - (taxy-sort* #'t>nil (first-item item-left-p))))) - (taxy-magit-section-insert-indent-items nil) - (inhibit-read-only t) - (format-cons (taxy-magit-section-format-items - ement-room-list-columns ement-room-list-column-formatters taxy)) - (pos (point)) - (section-ident (when (magit-current-section) - (magit-section-ident (magit-current-section))))) - (setf format-table (car format-cons) - column-sizes (cdr format-cons) - header-line-format (taxy-magit-section-format-header - column-sizes ement-room-list-column-formatters) - window-start (if (get-buffer-window buffer-name) - (window-start (get-buffer-window buffer-name)) - 0)) - (when ement-room-list-visibility-cache - (setf magit-section-visibility-cache ement-room-list-visibility-cache)) - (add-hook 'kill-buffer-hook #'ement-room-list--cache-visibility nil 'local) - (delete-all-overlays) - (erase-buffer) - (save-excursion - (taxy-magit-section-insert taxy :items 'first - ;; :blank-between-depth bufler-taxy-blank-between-depth - :initial-depth 0)) - (goto-char pos) - (when (and section-ident (magit-get-section section-ident)) - (goto-char (oref (magit-get-section section-ident) start))))) - (when display-buffer-action - (when-let ((window (display-buffer buffer-name display-buffer-action))) - (select-window window))) - (when (get-buffer-window buffer-name) - (set-window-start (get-buffer-window buffer-name) window-start)) - ;; NOTE: In order for `bookmark--jump-via' to work properly, the restored buffer - ;; must be set as the current buffer, so we have to do this explicitly here. - (set-buffer buffer-name)))) + (if (not (cl-loop for (_id . session) in ement-sessions + thereis (ement-session-rooms session))) + (ement-message "No rooms have been joined") + (with-current-buffer (get-buffer-create buffer-name) + (ement-room-list-mode) + (let* ((room-session-vectors + (cl-loop for (_id . session) in ement-sessions + append (cl-loop for room in (ement-session-rooms session) + collect (vector room session)))) + (taxy (cl-macrolet ((first-item + (pred) `(lambda (taxy) + (when (taxy-items taxy) + (,pred (car (taxy-items taxy)))))) + (name= (name) `(lambda (taxy) + (equal ,name (taxy-name taxy))))) + (thread-last + (make-fn + :name "Ement Rooms" + :take (taxy-make-take-function keys ement-room-list-keys)) + (taxy-fill room-session-vectors) + (taxy-sort #'> #'item-latest-ts) + (taxy-sort #'tnil #'item-low-priority-p) + (taxy-sort #'tnil #'item-left-p) + (taxy-sort* #'string< #'taxy-name) + (taxy-sort* #'> #'taxy-latest-ts) + (taxy-sort* #'tnil (first-item item-space-p)) + (taxy-sort* #'t>nil (name= "Low-priority")) + (taxy-sort* #'t>nil (first-item item-left-p))))) + (taxy-magit-section-insert-indent-items nil) + (inhibit-read-only t) + (format-cons (taxy-magit-section-format-items + ement-room-list-columns ement-room-list-column-formatters taxy)) + (pos (point)) + (section-ident (when (magit-current-section) + (magit-section-ident (magit-current-section))))) + (setf format-table (car format-cons) + column-sizes (cdr format-cons) + header-line-format (taxy-magit-section-format-header + column-sizes ement-room-list-column-formatters)) + (when-let ((window (get-buffer-window (current-buffer)))) + (setf window-point (window-point window) + window-start (window-start window))) + (when ement-room-list-visibility-cache + (setf magit-section-visibility-cache ement-room-list-visibility-cache)) + (add-hook 'kill-buffer-hook #'ement-room-list--cache-visibility nil 'local) + ;; Before this point, no changes have been made to the buffer's contents. + (delete-all-overlays) + (erase-buffer) + (save-excursion + (taxy-magit-section-insert taxy :items 'first + ;; :blank-between-depth bufler-taxy-blank-between-depth + :initial-depth 0)) + (if-let* ((section-ident) + (section (magit-get-section section-ident))) + (goto-char (oref section start)) + (goto-char pos)))) + (when display-buffer-action + (when-let ((window (display-buffer buffer-name display-buffer-action))) + (select-window window))) + (when-let ((window (get-buffer-window buffer-name))) + (set-window-start window window-start) + (set-window-point window window-point)) + ;; FIXME: Despite all this code to save and restore point and window point and + ;; window start, when I send a message from the minibuffer, or when I abort + ;; sending a message from the minibuffer, point is moved to the beginning of the + ;; buffer. While the minibuffer is open (and the typing messages are being sent + ;; to the server, causing it to repeatedly sync), the point stays in the correct + ;; place. I can't find any reason why this happens. It makes no sense. And + ;; while trying to debug the problem, somehow Emacs got put into an unbreakable, + ;; infinite loop twice; even C-g and SIGUSR2 didn't stop it. + + ;; NOTE: In order for `bookmark--jump-via' to work properly, the restored buffer + ;; must be set as the current buffer, so we have to do this explicitly here. + (set-buffer buffer-name))))) (cl-defun ement-room-list-side-window (&key (side 'left)) "Show room list in side window on SIDE. @@ -692,12 +739,6 @@ left." (kill-buffer buffer) (ement-room-list-revert)))) -(defun ement-room-list-mouse-1 (event) - "Call `ement-room-list-RET' at EVENT." - (interactive "e") - (mouse-set-point event) - (call-interactively #'ement-room-list-RET)) - (declare-function ement-view-room "ement-room") (defun ement-room-list-RET () "View room at point, or cycle section at point." @@ -712,19 +753,17 @@ left." (defun ement-room-list-next-unread () "Show next unread room." (interactive) - (unless (button-at (point)) - (call-interactively #'forward-button)) + (when (eobp) + (goto-char (point-min))) (unless (cl-loop with starting-line = (line-number-at-pos) for value = (oref (magit-current-section) value) - for room = (elt value 0) - for session = (elt value 1) - if (ement--room-unread-p room session) + if (and (vectorp value) + (ement--room-unread-p (elt value 0) (elt value 1))) do (progn - (goto-char (button-end (button-at (point)))) - (push-button (1- (point))) + (ement-view-room (elt value 0) (elt value 1)) (ement-room-goto-fully-read-marker) (cl-return t)) - else do (call-interactively #'forward-button) + else do (forward-line 1) while (> (line-number-at-pos) starting-line)) ;; No more unread rooms. (message "No more unread rooms"))) diff --git a/ement-room.el b/ement-room.el index b37d3df3..f1883bc3 100644 --- a/ement-room.el +++ b/ement-room.el @@ -229,6 +229,12 @@ In that case, sender names are aligned to the margin edge.") (const :tag "Center" center) (const :tag "Right" right))) +(defcustom ement-room-view-hook + '(ement-room-view-hook-room-list-auto-update) + "Functions called when `ement-room-view' is called. +Called with two arguments, the room and the session." + :type 'hook) + ;;;;; Faces (defface ement-room-name @@ -1871,8 +1877,6 @@ reaction string, e.g. \"👍\"." ;;;; Functions -(declare-function magit-current-section "magit-section") - (defun ement-room-view (room session) "Switch to a buffer showing ROOM on SESSION. Uses action `ement-view-room-display-buffer-action', which see." @@ -1886,9 +1890,18 @@ Uses action `ement-view-room-display-buffer-action', which see." ;; FIXME: This doesn't seem to work as desired, e.g. when ;; `ement-view-room-display-buffer-action' is set to `display-buffer-no-window'; I ;; guess because `pop-to-buffer' selects a window. - (pop-to-buffer buffer ement-view-room-display-buffer-action))) + (pop-to-buffer buffer ement-view-room-display-buffer-action) + (run-hook-with-args 'ement-room-view-hook room session))) (defalias 'ement-view-room #'ement-room-view) +(defun ement-room-view-hook-room-list-auto-update (_room session) + "Call `ement-room-list-auto-update' with SESSION. +To be used in `ement-room-view-hook', which see." + ;; This function is necessary because the hook is called with the room argument, which + ;; `ement-room-list-auto-update' doesn't need. + (declare (function ement-room-list-auto-update "ement-room-list")) + (ement-room-list-auto-update session)) + (defun ement-room--buffer-name (room) "Return name for ROOM's buffer." (concat ement-room-buffer-name-prefix @@ -1906,8 +1919,6 @@ Uses action `ement-view-room-display-buffer-action', which see." (goto-char (ewoc-location node)) (error "Event not found in buffer: %S" (ement-event-id event)))) -(declare-function ement--make-event "ement.el") -(declare-function ement--put-event "ement.el") (cl-defun ement-room-retro-callback (room session data &key (set-prev-batch t)) "Push new DATA to ROOM on SESSION and add events to room buffer. @@ -1915,6 +1926,8 @@ If SET-PREV-BATCH is nil, don't set ROOM's prev-batch slot to the \"prev_batch\" token in response DATA (this should be set, e.g. when filling timeline gaps as opposed to retrieving messages before the earliest-seen message)." + (declare (function ement--make-event "ement.el") + (function ement--put-event "ement.el")) (pcase-let* (((cl-struct ement-room local) room) ((map _start end chunk state) data) ((map buffer) local) @@ -3378,6 +3391,7 @@ If FORMATTED-P, return the formatted body content, when available." ((or "m.text" "m.emote" "m.notice") nil) ("m.image" (ement-room--format-m.image event)) ("m.file" (ement-room--format-m.file event)) + ("m.video" (ement-room--format-m.video event)) (_ (if (or local-redacted-by unsigned-redacted-by) nil (format "[unsupported msgtype: %s]" msgtype)))))) @@ -3710,6 +3724,9 @@ a copy of the local keymap, and sets `header-line-format'." (setq-local ement-room room) (setq-local ement-session session) (setf ement-room-compose-buffer t) + (setq-local completion-at-point-functions + (append '(ement-room--complete-members-at-point ement-room--complete-rooms-at-point) + completion-at-point-functions)) ;; FIXME: Compose with local map? (use-local-map (if (current-local-map) (copy-keymap (current-local-map)) @@ -4187,6 +4204,31 @@ Then invalidate EVENT's node to show the image." (propertize " " 'display '(space :relative-height 1.5))))) +(defun ement-room--format-m.video (event) + "Return \"m.video\" EVENT formatted as a string." + ;; TODO: Insert thumbnail images when enabled. + (pcase-let* (((cl-struct ement-event + (content (map body + ('info (map mimetype size w h)) + ('url mxc-url)))) + event) + (url (when mxc-url + (ement--mxc-to-url mxc-url ement-session))) + (human-size (file-size-human-readable size)) + (string (format "[video: %s (%s) (%sx%s) (%s)]" body mimetype w h human-size))) + (concat (propertize string + 'action #'browse-url + 'button t + 'button-data url + 'category t + 'face 'button + 'follow-link t + 'help-echo url + 'keymap button-map + 'mouse-face 'highlight) + (propertize " " + 'display '(space :relative-height 1.5))))) + ;;;;; Org format sending ;; Some of these declarations may need updating as Org changes. @@ -4297,8 +4339,10 @@ Web-compatible HTML output, using HTML like: Uses members in the current buffer's room. For use in `completion-at-point-functions'." (let ((beg (save-excursion - (re-search-backward (rx (or bol bos blank))) - (1+ (point)))) + (when (re-search-backward (rx (or bol bos blank)) nil t) + (if (minibufferp) + (1+ (point)) + (point))))) (end (point)) (collection-fn (completion-table-dynamic ;; The manual seems to show the FUN ignoring any @@ -4306,14 +4350,17 @@ Uses members in the current buffer's room. For use in ;; seems to say that it should use the argument. (lambda (_ignore) (ement-room--member-names-and-ids))))) - (list beg end collection-fn :exclusive 'no))) + (when beg + (list beg end collection-fn :exclusive 'no)))) (defun ement-room--complete-rooms-at-point () "Complete room aliases and IDs at point. For use in `completion-at-point-functions'." (let ((beg (save-excursion - (re-search-backward (rx (or bol bos blank))) - (1+ (point)))) + (when (re-search-backward (rx (or bol bos blank) (or "!" "#")) nil t) + (if (minibufferp) + (1+ (point)) + (point))))) (end (point)) (collection-fn (completion-table-dynamic ;; The manual seems to show the FUN ignoring any @@ -4321,7 +4368,8 @@ For use in `completion-at-point-functions'." ;; seems to say that it should use the argument. (lambda (_ignore) (ement-room--room-aliases-and-ids))))) - (list beg end collection-fn :exclusive 'no))) + (when beg + (list beg end collection-fn :exclusive 'no)))) ;; TODO: Use `cl-pushnew' in these two functions instead of `delete-dups'. @@ -4341,10 +4389,6 @@ members list and return already-seen members instead. For use in (buffer-local-value 'ement-session (window-buffer (minibuffer-selected-window))) ement-session)) - (ewoc (if (minibufferp) - (buffer-local-value - 'ement-ewoc (window-buffer (minibuffer-selected-window))) - ement-ewoc)) ((cl-struct ement-room members) room) (members (if (alist-get 'fetched-members-p (ement-room-local room)) (hash-table-values members) @@ -4355,7 +4399,7 @@ members list and return already-seen members instead. For use in :then (lambda (_) (setf (alist-get 'getting-members-p (ement-room-local room)) nil)) :else (lambda (_) (setf (alist-get 'getting-members-p (ement-room-local room)) nil)))) (mapcar #'ement-event-sender - (ewoc-collect ewoc #'ement-event-p))))) + (ement-room-timeline ement-room))))) (delete-dups (cl-loop for member in members collect (ement-user-id member) diff --git a/ement.el b/ement.el index 0c5eded2..aed01dfd 100644 --- a/ement.el +++ b/ement.el @@ -5,7 +5,7 @@ ;; Author: Adam Porter ;; Maintainer: Adam Porter ;; URL: https://github.com/alphapapa/ement.el -;; Version: 0.9-pre +;; Version: 0.10-pre ;; Package-Requires: ((emacs "27.1") (map "2.1") (persist "0.5") (plz "0.2") (taxy "0.10") (taxy-magit-section "0.12.1") (svg-lib "0.2.5") (transient "0.3.7")) ;; Keywords: comm @@ -874,16 +874,22 @@ and `session' to the session. Adds function to :ascent 'center :max-width ement-room-avatar-max-width :max-height ement-room-avatar-max-height))) - (when (fboundp 'imagemagick-types) - ;; Only do this when ImageMagick is supported. - ;; FIXME: When requiring Emacs 27+, remove this (I guess?). - (setf (image-property image :type) 'imagemagick)) - ;; We set the room-avatar slot to a propertized string that - ;; displays as the image. This seems the most convenient thing to - ;; do. We also unset the cached room-list-avatar so it can be - ;; remade. - (setf (ement-room-avatar room) (propertize " " 'display image) - (alist-get 'room-list-avatar (ement-room-local room)) nil)))))) + (if (not image) + (progn + (display-warning 'ement (format "Room avatar seems unreadable: ROOM-ID:%S AVATAR-URL:%S" + (ement-room-id room) (ement--mxc-to-url url session))) + (setf (ement-room-avatar room) nil + (alist-get 'room-list-avatar (ement-room-local room)) nil)) + (when (fboundp 'imagemagick-types) + ;; Only do this when ImageMagick is supported. + ;; FIXME: When requiring Emacs 27+, remove this (I guess?). + (setf (image-property image :type) 'imagemagick)) + ;; We set the room-avatar slot to a propertized string that + ;; displays as the image. This seems the most convenient thing to + ;; do. We also unset the cached room-list-avatar so it can be + ;; remade. + (setf (ement-room-avatar room) (propertize " " 'display image) + (alist-get 'room-list-avatar (ement-room-local room)) nil))))))) ;; Unset avatar. (setf (ement-room-avatar room) nil (alist-get 'room-list-avatar (ement-room-local room)) nil)))) diff --git a/makem.sh b/makem.sh index 3985ff7d..82a2db0d 100755 --- a/makem.sh +++ b/makem.sh @@ -198,24 +198,36 @@ function elisp-byte-compile-file { cat >"$file" <