Skip to content

Commit 481f571

Browse files
committed
Change/Fix: Improve "Elemental" display format
This still isn't quite perfect, but it seems to be about 99% so, and a significant improvement.
1 parent aaba533 commit 481f571

File tree

1 file changed

+72
-94
lines changed

1 file changed

+72
-94
lines changed

ement-room.el

Lines changed: 72 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ option."
11011101
right-margin-width ement-room-right-margin-width)
11021102
(set-window-margins nil left-margin-width right-margin-width)
11031103
(if ement-room-sender-in-headers
1104-
(ement-room--insert-sender-headers)
1104+
(ement-room--insert-sender-headers ement-ewoc)
11051105
(ewoc-filter ement-ewoc (lambda (node-data)
11061106
;; Return non-nil for nodes that should stay.
11071107
(not (ement-user-p node-data)))))
@@ -1887,6 +1887,8 @@ the previously oldest event."
18871887
;; for a long time, as the time to do this in each buffer will increase with the
18881888
;; number of events. At least we only do it once per batch of events.)
18891889
(ement-room--insert-ts-headers nil (when retro orig-first-node))
1890+
(when ement-room-sender-in-headers
1891+
(ement-room--insert-sender-headers ement-ewoc))
18901892
(when buffer-window
18911893
(cond (retro (with-selected-window buffer-window
18921894
(set-window-start buffer-window (ewoc-location point-node))
@@ -2023,6 +2025,7 @@ data slot."
20232025
(ement-room--process-events (reverse (ement-room-state room)))
20242026
(ement-room--process-events (reverse (ement-room-timeline room)))
20252027
(ement-room--insert-ts-headers)
2028+
(ement-room--insert-sender-headers ement-ewoc)
20262029
(ement-room-move-read-markers room
20272030
:read-event (when-let ((event (alist-get "m.read" (ement-room-account-data room) nil nil #'equal)))
20282031
(map-nested-elt event '(content event_id)))
@@ -2669,55 +2672,71 @@ the first and last nodes in the buffer, respectively."
26692672
;; cause it to be marked modified, like moving the read markers).
26702673
(ewoc-enter-after ewoc node-a (list 'ts b-ts))))))))
26712674

2672-
(defun ement-room--insert-sender-headers (&optional start-node end-node)
2675+
(cl-defun ement-room--insert-sender-headers
2676+
(ewoc &optional (start-node (ewoc-nth ewoc 0)) (end-node (ewoc-nth ewoc -1)))
26732677
;; TODO: Use this in appropriate places.
26742678
"Insert sender headers into current buffer's `ement-ewoc'.
26752679
Inserts headers between START-NODE and END-NODE, which default to
26762680
the first and last nodes in the buffer, respectively."
2677-
(let* ((ewoc ement-ewoc)
2678-
(end-pos (ewoc-location (or end-node
2679-
(ewoc-nth ewoc -1))))
2680-
(node-b (or start-node (ewoc-nth ewoc 0)))
2681-
(type-predicate (lambda (node-data)
2682-
(pcase node-data
2683-
((pred ement-event-p) t)
2684-
(`(ts . ,_) t))))
2685-
node-a)
2686-
;; On the first loop iteration, node-a is set to the first matching
2687-
;; node after node-b; then it's set to the first node after node-a.
2688-
(while (and (setf node-a (ement-room--ewoc-next-matching ewoc (or node-a node-b) type-predicate)
2689-
node-b (when node-a
2690-
(ement-room--ewoc-next-matching ewoc node-a type-predicate)))
2691-
(not (or (> (ewoc-location node-a) end-pos)
2692-
(> (ewoc-location node-b) end-pos))))
2693-
;; This starts to get a little messy, accounting for the
2694-
;; different types of nodes. EIEIO would probably help here.
2695-
(let ((a-data (ewoc-data node-a))
2696-
(b-data (ewoc-data node-b)))
2697-
(cond ((and (ement-event-p b-data)
2698-
(equal "m.room.member" (ement-event-type b-data)))
2699-
;; B is a membership event: don't insert sender header.
2700-
nil)
2701-
((when-let ((node-after-a (ewoc-next ewoc node-a)))
2702-
(pcase (ewoc-data node-after-a)
2703-
((or (pred ement-user-p)
2704-
'ement-room-fully-read-marker
2705-
'ement-room-read-receipt-marker)
2706-
t)))
2707-
;; Node after A is a sender header: don't insert another.
2708-
nil)
2709-
((and (ement-event-p a-data)
2710-
(ement-event-p b-data)
2711-
(equal (ement-event-sender a-data)
2712-
(ement-event-sender b-data)))
2713-
;; Each node is an event and their senders are the same: don't insert another header.
2714-
nil)
2715-
((ement-event-p b-data)
2716-
;; Node B is an event with a different sender: insert header.
2717-
(ewoc-enter-before ewoc node-b (ement-event-sender b-data))))))))
2681+
(cl-labels ((read-marker-p
2682+
(data) (member data '(ement-room-fully-read-marker
2683+
ement-room-read-receipt-marker)))
2684+
(message-event-p
2685+
(data) (and (ement-event-p data)
2686+
(equal "m.room.message" (ement-event-type data))))
2687+
(insert-sender-before
2688+
(node) (ewoc-enter-before ewoc node (ement-event-sender (ewoc-data node)))))
2689+
(let* ((event-node (if (ement-event-p (ewoc-data start-node))
2690+
start-node
2691+
(ement-room--ewoc-next-matching ewoc start-node
2692+
#'ement-event-p)))
2693+
(prev-node (when event-node
2694+
;; Just in case...
2695+
(ewoc-prev ewoc event-node))))
2696+
(while (and event-node
2697+
;; I don't like looking up the location of these nodes on every loop
2698+
;; iteration, but it seems like the only reliable way to determine
2699+
;; whether we've reached the end node. However, when this function is
2700+
;; called for short batches of events (or even a single event, like when
2701+
;; called from `ement-room--insert-event'), the overhead should be
2702+
;; minimal.
2703+
(<= (ewoc-location event-node) (ewoc-location end-node)))
2704+
(when (message-event-p (ewoc-data event-node))
2705+
(if (not prev-node)
2706+
;; No previous node and event is a message: insert header.
2707+
(insert-sender-before event-node)
2708+
;; Previous node exists.
2709+
(when (read-marker-p prev-node)
2710+
;; Previous node is a read marker: we want to act as if they don't exist, so
2711+
;; we set `prev-node' to the non-marker node before it.
2712+
(setf prev-node (ement-room--ewoc-next-matching ewoc prev-node
2713+
(lambda (data)
2714+
(not (read-marker-p data))))))
2715+
(when prev-node
2716+
;; A previous node still exists: maybe we need to add a header.
2717+
(cl-typecase (ewoc-data prev-node)
2718+
(ement-event
2719+
;; Previous node is an event.
2720+
(when (and (message-event-p (ewoc-data prev-node))
2721+
(not (equal (ement-event-sender (ewoc-data prev-node))
2722+
(ement-event-sender (ewoc-data event-node)))))
2723+
;; Previous node is a message event with a different sender: insert
2724+
;; header.
2725+
(insert-sender-before event-node)))
2726+
((or ement-user ement-room-membership-events)
2727+
;; Previous node is a user or coalesced membership events: do not insert
2728+
;; header.
2729+
nil)
2730+
(t
2731+
;; Previous node is not an event and not a read marker: insert header.
2732+
(insert-sender-before event-node))))))
2733+
(setf event-node (ement-room--ewoc-next-matching ewoc event-node
2734+
#'ement-event-p)
2735+
prev-node (when event-node
2736+
(ewoc-prev ewoc event-node)))))))
27182737

27192738
(defun ement-room--coalesce-nodes (a b ewoc)
2720-
"Try to coalesce events in nodes A and B in EWOC, returning non-nil if done."
2739+
"Try to coalesce events in nodes A and B in EWOC, returning absorbing node if done."
27212740
(cl-labels ((coalescable-p
27222741
(node) (or (and (ement-event-p (ewoc-data node))
27232742
(member (ement-event-type (ewoc-data node)) '("m.room.member")))
@@ -2736,7 +2755,7 @@ the first and last nodes in the buffer, respectively."
27362755
(ement-room-membership-events--update (ewoc-data absorbing-node))
27372756
(ewoc-delete ewoc absorbed-node)
27382757
(ewoc-invalidate ewoc absorbing-node)
2739-
t))))
2758+
absorbing-node))))
27402759

27412760
(defun ement-room--insert-event (event)
27422761
"Insert EVENT into current buffer."
@@ -2813,55 +2832,14 @@ the first and last nodes in the buffer, respectively."
28132832
(ewoc-enter-after ewoc event-node-before event)))
28142833
(when ement-room-coalesce-events
28152834
;; Try to coalesce events.
2816-
(or (when event-node-before
2817-
(ement-room--coalesce-nodes event-node-before new-node ewoc))
2818-
(when (ewoc-next ewoc new-node)
2819-
(ement-room--coalesce-nodes new-node (ewoc-next ewoc new-node) ewoc))))
2820-
(when ement-room-sender-headers
2821-
;; Insert header for new event when necessary.
2822-
;; TODO: Make `ement-room--insert-sender-headers' work for this case and use it
2823-
;; instead, because this seems to duplicate functionality. (It almost works now.)
2824-
(cond ((not event-node-before)
2825-
(ement-debug "No event before: Add sender before new node.")
2826-
(ewoc-enter-before ewoc new-node (ement-event-sender event)))
2827-
;; There exists an event node before the new one: check the node immediately
2828-
;; before the new one (which may not be an event).
2829-
((let* ((ignored-node-data-preds
2830-
'((lambda (data)
2831-
(pcase data
2832-
((or 'ement-room-fully-read-marker
2833-
'ement-room-read-receipt-marker)
2834-
t)))
2835-
(lambda (data)
2836-
(pcase data
2837-
(`(ts . ,_)
2838-
t)))
2839-
(lambda (data)
2840-
(and (ement-event-p data)
2841-
(pcase (ement-event-type data)
2842-
((or "m.room.member" "m.room.invite")
2843-
t))))))
2844-
(event-node-before (cl-loop with start-node = new-node
2845-
for node = (ewoc-prev ewoc start-node)
2846-
while node
2847-
do (setf start-node node)
2848-
unless (cl-loop for pred in ignored-node-data-preds
2849-
thereis (funcall pred (ewoc-data node)))
2850-
when (ement-event-p (ewoc-data node))
2851-
return node)))
2852-
(when event-node-before
2853-
(ement-debug "Event node before new node: compare sender.")
2854-
(cond ((equal (ement-event-sender event)
2855-
(ement-event-sender (ewoc-data event-node-before)))
2856-
(ement-debug "Event node before new node has same sender: don't insert header."))
2857-
(t
2858-
(ement-debug "Event node before new node has different sender: insert header.")
2859-
(ewoc-enter-before ewoc new-node (ement-event-sender event))))))))
2860-
;; Insert header for event after new event when necessary.
2861-
(when-let ((next-event-node (find-node-if ewoc #'ement-event-p :start new-node :move #'ewoc-next)))
2862-
(unless (equal (ement-event-sender event) (ement-event-sender (ewoc-data next-event-node)))
2863-
(ement-debug "Event after from different sender: insert its sender before it.")
2864-
(ewoc-enter-before ewoc next-event-node (ement-event-sender (ewoc-data next-event-node))))))
2835+
;; TODO: Move this to a separate function and call it from where this function is called.
2836+
(setf new-node (or (when event-node-before
2837+
(ement-room--coalesce-nodes event-node-before new-node ewoc))
2838+
(when (ewoc-next ewoc new-node)
2839+
(ement-room--coalesce-nodes new-node (ewoc-next ewoc new-node) ewoc))
2840+
new-node)))
2841+
(when ement-room-sender-in-headers
2842+
(ement-room--insert-sender-headers ewoc new-node new-node))
28652843
;; Return new node.
28662844
new-node)))
28672845

0 commit comments

Comments
 (0)