[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals-release/ement 4be346c563 12/12: Merge: v0.14
|
From: |
ELPA Syncer |
|
Subject: |
[elpa] externals-release/ement 4be346c563 12/12: Merge: v0.14 |
|
Date: |
Thu, 25 Jan 2024 21:58:01 -0500 (EST) |
branch: externals-release/ement
commit 4be346c5635ef4a732e94d7aad8bec0cc3063b3a
Merge: 3f5f792fef 0c725c6c73
Author: Adam Porter <adam@alphapapa.net>
Commit: Adam Porter <adam@alphapapa.net>
Merge: v0.14
---
.github/workflows/test.yml | 3 +-
README.org | 28 ++++-
ement-notifications.el | 57 +++++++---
ement-notify.el | 12 +-
ement-room-list.el | 37 ++++++-
ement-room.el | 266 ++++++++++++++++++++++++---------------------
ement.el | 9 +-
7 files changed, 254 insertions(+), 158 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b37fb71e41..d7a68c46a6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -41,8 +41,7 @@ jobs:
fail-fast: false
matrix:
emacs_version:
- - 26.3
- - 27.1
+ - 27.2
- 28.2
- 29.1
- snapshot
diff --git a/README.org b/README.org
index 6b1bb89ff5..1fe1bb0bec 100644
--- a/README.org
+++ b/README.org
@@ -18,7 +18,7 @@
# ELPA badge image.
[[https://elpa.gnu.org/packages/ement.html][https://elpa.gnu.org/packages/ement.svg]]
-Ement.el is a Matrix client for Emacs. It aims to be simple, fast,
featureful, and reliable.
+Ement.el is a [[http://www.matrix.org/][Matrix]] client for
[[https://www.gnu.org/software/emacs/][GNU Emacs]]. It aims to be simple,
fast, featureful, and reliable, while integrating naturally with Emacs.
Feel free to join us in the chat room:
[[https://matrix.to/#/#ement.el:matrix.org][https://img.shields.io/matrix/ement.el:matrix.org.svg?label=%23ement.el:matrix.org]]
@@ -41,7 +41,7 @@ Feel free to join us in the chat room:
[[https://matrix.to/#/#ement.el:matrix.or
:ID: d818f690-5f22-4eb0-83e1-4d8ce16c9e5b
:END:
-The default formatting style resembles IRC clients, with each message being
prefixed by the username (which enables powerful Emacs features, like using
Occur to show all messages from or mentioning a user). Alternative, built-in
styles include an Element-like one with usernames above groups of messages, as
well as a classic, no-margins IRC style. Messages may be optionally displayed
with unique colors for each user (with customizeable contrast), making it
easier to follow conversations [...]
+The default formatting style resembles IRC clients, with each message being
prefixed by the username (which enables powerful Emacs features, like using
Occur to show all messages from or mentioning a user). Alternative, built-in
styles include an Element-like one with usernames above groups of messages, as
well as a classic, no-margins IRC style. Messages may be optionally displayed
with unique colors for each user (with customizable contrast), making it easier
to follow conversations. [...]
[[images/ement-for-twim.png]]
@@ -122,8 +122,8 @@ Ement.el is intended to be installed with Emacs's package
system, which will ens
- [[#encrypted-room-support-through-pantalaimon][Encrypted room support
through Pantalaimon]]
:END:
-1. Call command ~ement-connect~ to connect. Multiple sessions are supported,
so you may call the command again to connect to another account.
-2. Wait for initial sync to complete (which can take a few moments--initial
sync JSON requests can be large).
+1. Call command ~ement-connect~ to connect. Multiple sessions are supported:
call the command again with a ~C-u~ universal prefix to connect to another
account.
+2. Wait for initial sync to complete (which can take a few moments--initial
sync JSON responses can be large).
3. Use these commands (room-related commands may be called with universal
prefix to prompt for the room):
- ~ement-list-rooms~ to view the list of joined rooms.
- ~ement-view-room~ to view a room's buffer, selected with completion.
@@ -293,6 +293,26 @@ Ement.el doesn't support encrypted rooms natively, but it
can be used transparen
:TOC: :depth 0
:END:
+** 0.14
+
+*Additions*
+
++ Audio events are rendered as a link to the audio file. (Thanks to
[[https://github.com/viiru-][Arto Jantunen]].)
++ Customization group ~ement-room-list~.
++ Option ~ement-room-list-space-prefix~ is applied to space names in the room
list (e.g. set to empty string for cleaner appearance).
++ Option ~ement-room-reaction-names-limit~ sets how many senders of a reaction
are shown in the buffer (more than that many are shown in the tooltip).
+
+*Changes*
+
++ Bind ~TAB~ / ~BACKTAB~ to move between links in room and like buffers.
([[https://github.com/alphapapa/ement.el/issues/113][#113]]. Thanks to
[[https://github.com/ericsfraga][Eric S. Fraga]] for suggesting.)
+
+*Fixes*
+
++ Insertion of sender headers (when using "Elemental" message format).
(Refactoring contributed by [[https://github.com/Stebalien][Steven Allen]].)
++ Some room event data was being unintentionally serialized to disk when
caching the room list visibility state.
([[https://github.com/alphapapa/ement.el/issues/256][#256]])
++ Notifications buffer restores properly when bookmarked.
++ Command ~ement-room-send-reaction~ checks for an event at point. (Thanks to
[[https://github.com/phil-s][Phil Sainty]].)
+
** 0.13
*Additions*
diff --git a/ement-notifications.el b/ement-notifications.el
index 40cf7e5bb2..4df7e96b26 100644
--- a/ement-notifications.el
+++ b/ement-notifications.el
@@ -62,15 +62,35 @@ is passed through `ement--make-event'."
(declare-function ement-room-list "ement-room-list")
(defvar ement-notifications-mode-map
(let ((map (make-sparse-keymap)))
+ (define-key map (kbd "<return>") #'ement-notifications-jump)
+ (define-key map [mouse-1] #'ement-notifications-jump-mouse)
+ (define-key map [mouse-2] #'ement-notifications-jump-mouse)
(define-key map (kbd "S-<return>") #'ement-notify-reply)
(define-key map (kbd "M-g M-l") #'ement-room-list)
(define-key map (kbd "M-g M-m") #'ement-notify-switch-to-mentions-buffer)
(define-key map (kbd "M-g M-n")
#'ement-notify-switch-to-notifications-buffer)
(define-key map [remap scroll-down-command]
#'ement-notifications-scroll-down-command)
(define-key map [remap mwheel-scroll] #'ement-notifications-mwheel-scroll)
- (make-composed-keymap (list map button-buffer-map) 'view-mode-map))
+ (make-composed-keymap (list map) 'view-mode-map))
"Map for Ement notification buffers.")
+(cl-defun ement-notifications-jump (&optional (pos (point)))
+ "Jump to Matrix event at POS."
+ (interactive)
+ (let ((session (get-text-property pos 'session))
+ (room (get-text-property pos 'room))
+ (event (get-text-property pos 'event)))
+ (ement-view-room room session)
+ (ement-room-goto-event event)))
+
+(defun ement-notifications-jump-mouse (event)
+ "Jump to Matrix event at EVENT."
+ (interactive "e")
+ (let ((pos (posn-point (event-start event))))
+ (if (button-at pos)
+ (push-button pos)
+ (ement-notifications-jump pos))))
+
(defvar ement-notifications-hook '(ement-notifications-log-to-buffer)
"Functions called for `ement-notifications' notifications.
Each function is called with two arguments, the session and the
@@ -197,19 +217,24 @@ to `ement-api', which see."
(inhibit-read-only t)
(start) (end))
(ewoc-goto-node ement-ewoc new-node)
- (setf start (point))
- (if-let (next-node (ewoc-next ement-ewoc new-node))
- (ewoc-goto-node ement-ewoc next-node)
- (goto-char (point-max)))
- (setf end (- (point) 2))
+ ;; Apply the button properties only to the room and sender names,
+ ;; allowing buttons in the rest of the message to remain separate.
+ (setf start (point)
+ end (save-excursion
+ (re-search-forward (rx "> "))))
+ (add-text-properties start end '( button (t)
+ category default-button
+ action
ement-notify-button-action))
+ ;; Apply the session, room, and event properties to the whole
event.
+ (setf end (save-excursion
+ (if-let ((next-node (ewoc-next ement-ewoc new-node)))
+ (ewoc-location next-node)
+ (point-max))))
(add-text-properties start end
- (list 'button '(t)
- 'category 'default-button
- 'action #'ement-notify-button-action
- 'session session
+ (list 'session session
'room ement-room
'event event))
- ;; Remove button face property.
+ ;; Remove button face property from the whole event.
(alter-text-property start end 'face
(lambda (face)
(pcase face
@@ -260,10 +285,14 @@ to `ement-api', which see."
(cons 'buffer-name (buffer-name))
(cons 'handler #'ement-notifications-bookmark-handler)))
-(defun ement-notifications-bookmark-handler (bookmark)
+(defun ement-notifications-bookmark-handler (_bookmark)
"Show `ement-notifications' buffer for BOOKMARK."
- (pcase-let ((`(,_bookmark-name . ,(map buffer-name)) bookmark))
- (switch-to-buffer (ement-notifications--log-buffer :name buffer-name))))
+ ;; FIXME: Handle multiple sessions.
+ ;; FIXME: This doesn't work quite correctly when the buffer isn't already
open, because
+ ;; the command is asynchronous in that case, so the buffer can be displayed
in the wrong
+ ;; window. Fixing this would be hacky and awkward, but a partial solution
is probably
+ ;; possible.
+ (ement-notifications (ement-complete-session)))
;;; Footer
diff --git a/ement-notify.el b/ement-notify.el
index c341678b40..7c52371f32 100644
--- a/ement-notify.el
+++ b/ement-notify.el
@@ -38,16 +38,6 @@
;;;; Variables
-(declare-function ement-room-list "ement-room-list")
-(defvar ement-notify-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "S-<return>") #'ement-notify-reply)
- (define-key map (kbd "M-g M-l") #'ement-room-list)
- (define-key map (kbd "M-g M-m") #'ement-notify-switch-to-mentions-buffer)
- (define-key map (kbd "M-g M-n")
#'ement-notify-switch-to-notifications-buffer)
- (make-composed-keymap (list map button-buffer-map) 'view-mode-map))
- "Map for Ement notification buffers.")
-
(defvar ement-notify-dbus-p
(and (featurep 'dbusbind)
(require 'dbus nil :no-error)
@@ -141,7 +131,7 @@ can help distinguish messages by room."
(defcustom ement-notify-room-avatars t
"Show room avatars in the notifications buffers.
This shows room avatars at the left of the window margin in
-notification buffers. It's not customizeable beyond that due to
+notification buffers. It's not customizable beyond that due to
limitations and complexities of displaying strings and images in
margins in Emacs. But it's useful, anyway."
:type 'boolean)
diff --git a/ement-room-list.el b/ement-room-list.el
index 232ef6d2c8..f0194db803 100644
--- a/ement-room-list.el
+++ b/ement-room-list.el
@@ -56,6 +56,29 @@ a symbol, it should be unquoted.."
(mouse-set-point event)
(call-interactively #',command))))
+;;;; Types
+
+(defclass ement-room-list-section (magit-section)
+ ;; We define this class so we can use it as the type of section we insert,
so we can
+ ;; define a method to return identifiers for our section type, so section
visibility can
+ ;; be cached concisely (i.e. without storing room event data in the values,
which can
+ ;; serialize to hundreds of megabytes after receiving many events).
+ nil)
+
+(cl-defmethod magit-section-ident-value ((section ement-room-list-section))
+ ;; FIXME: The name of each taxy could be ambiguous. Best would be to use the
+ ;; hierarchical path, but since the taxys aren't doubly linked, that isn't
easily done.
+ ;; Could probably be worked around by binding a special variable around the
creation of
+ ;; the taxy hierarchy that would allow the path to be saved into each taxy.
+ (pcase-exhaustive (oref section value)
+ ((and (cl-type taxy-magit-section) it)
+ (taxy-name it))
+ (`[,(and (cl-type ement-room) room)
+ ,(and (cl-type ement-session) session)]
+ (vector (ement-user-id (ement-session-user session))
+ (ement-room-id room)))
+ ((pred null) nil)))
+
;;;; Variables
(declare-function ement-room-toggle-space "ement-room")
@@ -99,6 +122,10 @@ Set automatically when `ement-room-list-mode' is
activated.")
;;;; Customization
+(defgroup ement-room-list nil
+ "Options for room list buffers."
+ :group 'ement)
+
(defcustom ement-room-list-auto-update t
"Automatically update the taxy-based room list buffer."
:type 'boolean)
@@ -107,6 +134,10 @@ Set automatically when `ement-room-list-mode' is
activated.")
"Show room avatars in the room list."
:type 'boolean)
+(defcustom ement-room-list-space-prefix "Space: "
+ "Prefix applied to space names."
+ :type 'string)
+
;;;;; Faces
(defface ement-room-list-direct
@@ -205,7 +236,7 @@ from recent to non-recent for rooms updated in the past
hour.")
(space-name (if parent-room
(ement-room-display-name parent-room)
id)))
- (concat "Space: " space-name))))
+ (concat ement-room-list-space-prefix space-name))))
(when-let ((key (if id
;; ID specified.
(cond ((or (member id parents)
@@ -215,7 +246,7 @@ from recent to non-recent for rooms updated in the past
hour.")
((and (equal type "m.space")
(equal id (ement-room-id room)))
;; Room is a specified space.
- (or name (concat "Space: "
(ement-room-display-name room)))))
+ (or name (concat ement-room-list-space-prefix
(ement-room-display-name room)))))
;; ID not specified.
(pcase (length parents)
(0 nil)
@@ -679,7 +710,7 @@ DISPLAY-BUFFER-ACTION is nil, the buffer is not displayed."
(save-excursion
(taxy-magit-section-insert taxy :items 'first
;; :blank-between-depth bufler-taxy-blank-between-depth
- :initial-depth 0))
+ :initial-depth 0 :section-class 'ement-room-list-section))
(if-let* ((section-ident)
(section (magit-get-section section-ident)))
(goto-char (oref section start))
diff --git a/ement-room.el b/ement-room.el
index 143c0dcf48..423551dd56 100644
--- a/ement-room.el
+++ b/ement-room.el
@@ -137,6 +137,8 @@ Used to, e.g. call `ement-room-compose-org'.")
(define-key map (kbd "m") #'ement-room-mark-read)
(define-key map [remap scroll-down-command]
#'ement-room-scroll-down-command)
(define-key map [remap mwheel-scroll] #'ement-room-mwheel-scroll)
+ (define-key map (kbd "<tab>") #'forward-button)
+ (define-key map (kbd "<backtab>") #'backward-button)
;; Switching
(define-key map (kbd "M-g M-l") #'ement-room-list)
@@ -250,6 +252,12 @@ Does not include filenames, emotes, etc.")
Called with two arguments, the room and the session."
:type 'hook)
+(defcustom ement-room-reaction-names-limit 3
+ "Up to this many users, show a reaction's senders' names.
+If more than this many users have sent a reaction, show the
+number of senders instead (and the names in a tooltip)."
+ :type 'natnum)
+
;;;;; Faces
(defface ement-room-name
@@ -708,27 +716,28 @@ number (to darken rather than lighten)."
"Highlight event at POSITION while evaluating BODY."
;; MAYBE: Accept a marker for POSITION.
(declare (indent 1))
- `(let* ((node (ewoc-locate ement-ewoc ,position))
- (event (ewoc-data node))
- ement-room-replying-to-overlay)
- (unless (and (ement-event-p event)
- (ement-event-id event))
- (error "No event at point"))
- (unwind-protect
- (progn
- (setf ement-room-replying-to-overlay
- (make-overlay (ewoc-location node)
- ;; NOTE: It doesn't seem possible to get the
end position of
- ;; a node, so if there is no next node, we use
point-max.
- ;; But this might break if we were to use an
EWOC footer.
- (if (ewoc-next ement-ewoc node)
- (ewoc-location (ewoc-next ement-ewoc node))
- (point-max))))
- (overlay-put ement-room-replying-to-overlay 'face 'highlight)
- ,@body)
- (when (overlayp ement-room-replying-to-overlay)
- (delete-overlay ement-room-replying-to-overlay))
- (setf ement-room-replying-to-overlay nil))))
+ (let ((node/g (gensym "node")) (event/g (gensym "event")))
+ `(let* ((,node/g (ewoc-locate ement-ewoc ,position))
+ (,event/g (ewoc-data ,node/g))
+ ement-room-replying-to-overlay)
+ (unless (and (ement-event-p ,event/g)
+ (ement-event-id ,event/g))
+ (error "No event at point"))
+ (unwind-protect
+ (progn
+ (setf ement-room-replying-to-overlay
+ (make-overlay (ewoc-location ,node/g)
+ ;; NOTE: It doesn't seem possible to get the
end position of
+ ;; a node, so if there is no next node, we
use point-max.
+ ;; But this might break if we were to use an
EWOC footer.
+ (if (ewoc-next ement-ewoc ,node/g)
+ (ewoc-location (ewoc-next ement-ewoc
,node/g))
+ (point-max))))
+ (overlay-put ement-room-replying-to-overlay 'face 'highlight)
+ ,@body)
+ (when (overlayp ement-room-replying-to-overlay)
+ (delete-overlay ement-room-replying-to-overlay))
+ (setf ement-room-replying-to-overlay nil)))))
(defmacro ement-room-with-typing (&rest body)
"Send typing notifications around BODY.
@@ -941,8 +950,8 @@ spec) without requiring all events to use the same margin
width."
(ement-room-define-event-formatter ?r
"Reactions."
- (ignore room session)
- (ement-room--format-reactions event))
+ (ignore session)
+ (ement-room--format-reactions event room))
(ement-room-define-event-formatter ?t
"Timestamp."
@@ -1774,17 +1783,22 @@ Interactively, to event at point."
(replying-to-event (ement--original-event-for event
ement-session)))
(ement-room-send-message room session :body body :replying-to-event
replying-to-event)))))
-(defun ement-room-send-reaction (key position)
+(defun ement-room-send-reaction (key position &optional event)
"Send reaction of KEY to event at POSITION.
Interactively, send reaction to event at point. KEY should be a
reaction string, e.g. \"👍\"."
(interactive
- (list (char-to-string (read-char-by-name "Reaction (prepend \"*\" for
substring search): "))
- (point)))
+ (let ((event (ewoc-data (ewoc-locate ement-ewoc))))
+ (unless (ement-event-p event)
+ (user-error "No event at point"))
+ (list (char-to-string (read-char-by-name "Reaction (prepend \"*\" for
substring search): "))
+ (point)
+ event)))
;; SPEC: MSC2677 <https://github.com/matrix-org/matrix-doc/pull/2677>
;; HACK: We could simplify this by storing the key in a text property...
(ement-room-with-highlighted-event-at position
- (pcase-let* ((event (or (ewoc-data (ewoc-locate ement-ewoc position))
+ (pcase-let* ((event (or event
+ (ewoc-data (ewoc-locate ement-ewoc position))
(user-error "No event at point")))
;; NOTE: Sadly, `face-at-point' doesn't work here because,
e.g. if
;; hl-line-mode is enabled, it only returns the hl-line face.
@@ -3006,63 +3020,40 @@ the first and last nodes in the buffer, respectively."
"Insert sender headers into EWOC.
Inserts headers between START-NODE and END-NODE, which default to
the first and last nodes in the buffer, respectively."
- (cl-labels ((read-marker-p (data)
- (member data '(ement-room-fully-read-marker
- ement-room-read-receipt-marker)))
- (message-event-p (data)
+ (cl-labels ((message-event-p (data)
(and (ement-event-p data)
- (equal "m.room.message" (ement-event-type data))))
- (insert-sender-before (node)
- (ewoc-enter-before ewoc node (ement-event-sender (ewoc-data
node)))))
- (let* ((event-node (if (ement-event-p (ewoc-data start-node))
- start-node
- (ement-room--ewoc-next-matching ewoc start-node
- #'ement-event-p)))
- (prev-node (when event-node
- ;; Just in case...
- (ewoc-prev ewoc event-node))))
- (while (and event-node
- ;; I don't like looking up the location of these nodes on
every loop
- ;; iteration, but it seems like the only reliable way to
determine
- ;; whether we've reached the end node. However, when this
function is
- ;; called for short batches of events (or even a single
event, like when
- ;; called from `ement-room--insert-event'), the overhead
should be
- ;; minimal.
- (<= (ewoc-location event-node) (ewoc-location end-node)))
- (when (message-event-p (ewoc-data event-node))
- (if (not prev-node)
- ;; No previous node and event is a message: insert header.
- (insert-sender-before event-node)
- ;; Previous node exists.
- (when (read-marker-p (ewoc-data prev-node))
- ;; Previous node is a read marker: we want to act as if they
don't exist, so
- ;; we set `prev-node' to the non-marker node before it.
- (setf prev-node (ement-room--ewoc-next-matching ewoc prev-node
- (lambda (data)
- (not (read-marker-p data)))
- #'ewoc-prev)))
- (when prev-node
- ;; A previous node still exists: maybe we need to add a header.
- (cl-typecase (ewoc-data prev-node)
- (ement-event
- ;; Previous node is an event.
- (when (and (message-event-p (ewoc-data prev-node))
- (not (equal (ement-event-sender (ewoc-data
prev-node))
- (ement-event-sender (ewoc-data
event-node)))))
- ;; Previous node is a message event with a different
sender: insert
- ;; header.
- (insert-sender-before event-node)))
- ((or ement-user ement-room-membership-events)
- ;; Previous node is a user or coalesced membership events: do
not insert
- ;; header.
- nil)
- (t
- ;; Previous node is not an event and not a read marker:
insert header.
- (insert-sender-before event-node))))))
- (setf event-node (ement-room--ewoc-next-matching ewoc event-node
- #'ement-event-p)
- prev-node (when event-node
- (ewoc-prev ewoc event-node)))))))
+ (equal "m.room.message" (ement-event-type data)))))
+ (when (and start-node (not (message-event-p (ewoc-data start-node))))
+ ;; Start node not a message event: forward to next message event (and if
none are
+ ;; found, there's nothing to do).
+ (setf start-node (ement-room--ewoc-next-matching ewoc start-node
#'message-event-p)))
+ (when end-node
+ ;; Set end node to first message event after it. (This simplifies the
loop by
+ ;; continuing until finding `end-node' or the last node, and ensures we
fix headers
+ ;; after any inserted messages.)
+ (setf end-node (ement-room--ewoc-next-matching ewoc end-node
#'message-event-p)))
+ (let ((event-node start-node) prev-node)
+ (while (and event-node (not (eq event-node end-node)))
+ (setf prev-node
+ ;; Find previous message or user header.
+ (ement-room--ewoc-next-matching ewoc event-node
+ (lambda (data)
+ (or (ement-user-p data) (message-event-p data)))
+ #'ewoc-prev))
+ (let ((sender (ement-event-sender (ewoc-data event-node))))
+ (cond ((not prev-node)
+ ;; No previous message/sender: insert sender.
+ (ewoc-enter-before ewoc event-node sender))
+ ((ement-user-p (ewoc-data prev-node))
+ ;; Previous node is a sender.
+ (unless (equal sender (ewoc-data prev-node))
+ ;; Previous node is the wrong sender: fix it.
+ (ewoc-set-data prev-node sender)))
+ ((and (message-event-p (ewoc-data prev-node))
+ (not (equal sender (ement-event-sender (ewoc-data
prev-node)))))
+ ;; Previous node is a message from a different sender: insert
header.
+ (ewoc-enter-before ewoc event-node sender))))
+ (setf event-node (ement-room--ewoc-next-matching ewoc event-node
#'message-event-p))))))
(defun ement-room--coalesce-nodes (a b ewoc)
"Try to coalesce events in nodes A and B in EWOC.
@@ -3110,6 +3101,9 @@ Search starts from node START and moves by NEXT."
((pred ement-event-p) t)
((pred ement-room-membership-events-p) t)
(`(ts . ,_) t)))
+ (read-marker-p
+ (data) (member data '(ement-room-fully-read-marker
+ ement-room-read-receipt-marker)))
(node-ts (data)
(pcase data
((pred ement-event-p) (ement-event-origin-server-ts data))
@@ -3129,7 +3123,7 @@ Search starts from node START and moves by NEXT."
;; HACK: Insert after any read markers.
(cl-loop for node-after-node-before = (ewoc-next ewoc event-node-before)
while node-after-node-before
- while (not (ement-event-p (ewoc-data node-after-node-before)))
+ while (read-marker-p (ewoc-data node-after-node-before))
do (setf event-node-before node-after-node-before))
(setf new-node (if (not event-node-before)
(progn
@@ -3347,50 +3341,54 @@ Formats according to `ement-room-message-format-spec',
which see."
(propertize " "
'display ement-room-event-separator-display-property)))
-(defun ement-room--format-reactions (event)
- "Return formatted reactions to EVENT."
+(defun ement-room--format-reactions (event room)
+ "Return formatted reactions to EVENT in ROOM."
;; 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)
- (key (propertize key 'face
'ement-room-reactions-key))
- (count (propertize (format " (%s)" (length
senders))
- 'face
'ement-room-reactions))
- (string
- (propertize (concat key count)
- 'button '(t)
- 'category 'default-button
- 'action
#'ement-room-reaction-button-action
- 'follow-link t
- 'help-echo (lambda (_window
buffer _pos)
- ;; NOTE: If the
reaction key string is a Unicode character composed
- ;; with, e.g.
"VARIATION SELECTOR-16", `string-to-char' ignores the
- ;; composed
modifier/variation-selector and just returns the first
- ;; character of the
string. This should be fine, since it's just
- ;; for the tooltip.
- (concat
-
(get-char-code-property (string-to-char key) 'name) ": "
- (senders-names
senders (buffer-local-value 'ement-room buffer))))))
- (local-user-p (cl-member (ement-user-id
(ement-session-user ement-session)) senders
- :key #'ement-user-id
:test #'equal)))
- (when local-user-p
- (add-face-text-property 0 (length string) '(:box
(:style pressed-button) :inverse-video t)
- nil string))
- (ement--remove-face-property string 'button)
- string))
- (senders-names (senders room)
- (cl-loop for sender in senders
- collect (ement--user-displayname-in room sender)
- into names
- finally return (string-join names ", "))))
+ (cl-labels
+ ((format-reaction (ks)
+ (pcase-let* ((`(,key . ,senders) ks)
+ (key (propertize key 'face 'ement-room-reactions-key))
+ (count (propertize (format " (%s)"
+ (if (length> senders
ement-room-reaction-names-limit)
+ (length senders)
+ (senders-names senders
room)))
+ 'face 'ement-room-reactions))
+ (string
+ (propertize (concat key count)
+ 'button '(t)
+ 'category 'default-button
+ 'action #'ement-room-reaction-button-action
+ 'follow-link t
+ 'help-echo (lambda (_window buffer _pos)
+ ;; NOTE: If the reaction key
string is a Unicode character composed
+ ;; with, e.g. "VARIATION
SELECTOR-16", `string-to-char' ignores the
+ ;; composed
modifier/variation-selector and just returns the first
+ ;; character of the string.
This should be fine, since it's just
+ ;; for the tooltip.
+ (concat
+ (get-char-code-property
(string-to-char key) 'name) ": "
+ (senders-names senders
(buffer-local-value 'ement-room buffer))))))
+ (local-user-p (cl-member (ement-user-id
(ement-session-user ement-session)) senders
+ :key #'ement-user-id :test
#'equal)))
+ (when local-user-p
+ (add-face-text-property 0 (length string) '(:box (:style
pressed-button) :inverse-video t)
+ nil string))
+ (ement--remove-face-property string 'button)
+ string))
+ (senders-names (senders room)
+ (cl-loop for sender in senders
+ collect (ement--user-displayname-in room sender)
+ into names
+ finally return (string-join names ", "))))
+ (if-let ((reactions (map-elt (ement-event-local event) 'reactions)))
(cl-loop with keys-senders
for reaction in reactions
for key = (map-nested-elt (ement-event-content reaction)
'(m.relates_to key))
for sender = (ement-event-sender reaction)
do (push sender (alist-get key keys-senders nil nil
#'string=))
finally do (setf keys-senders (cl-sort keys-senders #'> :key
(lambda (pair) (length (cdr pair)))))
- finally return (concat "\n " (mapconcat #'format-reaction
keys-senders " "))))
- ""))
+ finally return (concat "\n " (mapconcat #'format-reaction
keys-senders " ")))
+ "")))
(cl-defun ement-room--format-message (event room session &optional (format
ement-room-message-format-spec))
"Return EVENT in ROOM on SESSION formatted according to FORMAT.
@@ -3516,6 +3514,7 @@ If FORMATTED-P, return the formatted body content, when
available."
("m.image" (ement-room--format-m.image event))
("m.file" (ement-room--format-m.file event))
("m.video" (ement-room--format-m.video event))
+ ("m.audio" (ement-room--format-m.audio event))
(_ (if (or local-redacted-by unsigned-redacted-by)
nil
(format "[unsupported msgtype: %s]" msgtype
))))))
@@ -4315,6 +4314,31 @@ Then invalidate EVENT's node to show the image."
(propertize " "
'display '(space :relative-height 1.5)))))
+(defun ement-room--format-m.audio (event)
+ "Return \"m.audio\" EVENT formatted as a string."
+ (pcase-let* (((cl-struct ement-event
+ (content (map body
+ ('info (map mimetype duration size))
+ ('url mxc-url))))
+ event)
+ (url (when mxc-url
+ (ement--mxc-to-url mxc-url ement-session)))
+ (human-size (file-size-human-readable size))
+ (human-duration (format-seconds "%m:%s" (/ duration 1000)))
+ (string (format "[audio: %s (%s) (%s) (%s)]" body mimetype
human-duration 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.
diff --git a/ement.el b/ement.el
index 125c201f50..4523c23a81 100644
--- a/ement.el
+++ b/ement.el
@@ -5,8 +5,8 @@
;; Author: Adam Porter <adam@alphapapa.net>
;; Maintainer: Adam Porter <adam@alphapapa.net>
;; URL: https://github.com/alphapapa/ement.el
-;; Version: 0.13
-;; Package-Requires: ((emacs "27.1") (map "2.1") (persist "0.5") (plz "0.6")
(taxy "0.10") (taxy-magit-section "0.12.1") (svg-lib "0.2.5") (transient
"0.3.7"))
+;; Version: 0.14
+;; Package-Requires: ((emacs "27.1") (map "2.1") (persist "0.5") (plz "0.6")
(taxy "0.10") (taxy-magit-section "0.13") (svg-lib "0.2.5") (transient "0.3.7"))
;; Keywords: comm
;; This program is free software; you can redistribute it and/or modify
@@ -569,6 +569,7 @@ a filter ID). When unspecified, the value of
(defun ement--sync-callback (session data)
"Process sync DATA for SESSION.
Runs `ement-sync-callback-hook' with SESSION."
+ (ement-debug (ement-user-id (ement-session-user session)))
;; Remove the sync first. We already have the data from it, and the
;; process has exited, so it's safe to run another one.
(setf (map-elt ement-syncs session) nil)
@@ -685,7 +686,7 @@ Also used for left rooms, in which case STATUS should be
set to
(latest-timestamp))
(setf (ement-room-status room) status
(ement-room-unread-notifications room) unread-notifications)
- ;; NOTE: The idea is that, assuming that events in the sync reponse are in
+ ;; NOTE: The idea is that, assuming that events in the sync response are in
;; chronological order, we push them to the lists in the room slots in
that order,
;; leaving the head of each list as the most recent event of that type.
That means
;; that, e.g. the room state events may be searched in order to find, e.g.
the most
@@ -822,6 +823,8 @@ Adds sender to `ement-users' when necessary."
;;;;; Reading/writing sessions
+;; TODO: Use `persist' and/or `multisession'.
+
(defun ement--read-sessions ()
"Return saved sessions alist read from disk.
Returns nil if unable to read `ement-sessions-file'."
- [elpa] externals-release/ement d55751927f 01/12: Fix: (ement-notifications-bookmark-handler) Call command to restore, (continued)
- [elpa] externals-release/ement d55751927f 01/12: Fix: (ement-notifications-bookmark-handler) Call command to restore, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement b692c4a061 02/12: Add basic support for m.audio events, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 72a6399f18 06/12: Fix: (ement-room-with-highlighted-event-at) Use gensyms, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 2078ad4605 04/12: Merge: Support for m.audio events, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 71ce17d1fa 05/12: Tidy, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 27828a2362 08/12: Docs: Update changelog, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement a3cbeeade1 03/12: Docs: Update changelog, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement d3154cabb8 07/12: Fix: (ement-room-send-reaction) Bail out early when there's no event at point, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 08d5dadc82 09/12: Merge: (ement-room-send-reaction) Check for event at point, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 0c725c6c73 11/12: Release: v0.14, ELPA Syncer, 2024/01/25
- [elpa] externals-release/ement 4be346c563 12/12: Merge: v0.14,
ELPA Syncer <=
- [elpa] externals-release/ement a38eba1cc4 10/12: Comment: Add FIXME, ELPA Syncer, 2024/01/25