emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/ement 6cce141042 2/2: Add: (ement-room-toggle-space)


From: ELPA Syncer
Subject: [elpa] externals/ement 6cce141042 2/2: Add: (ement-room-toggle-space)
Date: Tue, 14 Mar 2023 09:57:59 -0400 (EDT)

branch: externals/ement
commit 6cce141042dc96f1c2fad2d069e3fb0285761d95
Author: Adam Porter <adam@alphapapa.net>
Commit: Adam Porter <adam@alphapapa.net>

    Add: (ement-room-toggle-space)
    
    Including:
    
    * ement-lib.el:
    (ement--room-in-space-p): New function.
    (ement--room-spaces): New function.
    
    * ement-room-list.el:
    (ement-room-list-mode-map): New binding.
    
    * ement-room.el:
    (ement-room-mode-map): New binding.
    (ement-room-toggle-space): New command.
    (ement-room-transient): New prefix command.
---
 README.org         |  7 +++++++
 ement-lib.el       | 46 +++++++++++++++++++++++++++++++++++++++++
 ement-room-list.el |  3 +++
 ement-room.el      | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/README.org b/README.org
index 08911ec6b7..5aea5d83c8 100644
--- a/README.org
+++ b/README.org
@@ -132,6 +132,7 @@ Ement.el is intended to be installed with Emacs's package 
system, which will ens
       -  ~ement-room-override-name~ to override a room's display name.
       -  ~ement-ignore-user~ to ignore a user (or with interactive prefix, 
un-ignore).
       -  ~ement-room-set-message-format~ to set a room's message format 
buffer-locally.
+      -  ~ement-room-toggle-space~ to toggle a room's membership in a space (a 
way to group rooms in Matrix).
       -  ~ement-directory~ to view a room directory.
       -  ~ement-directory-search~ to search a room directory.
 4.  Use these special buffers to see events from multiple rooms (you can also 
reply to messages from these buffers!):
@@ -211,6 +212,7 @@ These bindings are common to all of the following buffer 
types:
 + Join room: ~R j~
 + Leave room: ~R l~
 + Forget room: ~R F~
++ Toggle room's spaces: ~R s~
 
 *Other*
 
@@ -222,6 +224,8 @@ These bindings are common to all of the following buffer 
types:
 +  Show buffer of next unread room: ~SPC~
 +  Move between room names: ~TAB~ / ~<backtab>~
 
++  Toggle room's spaces: ~s~
+
 *** Directory buffers
 
 + View/join a room: ~RET~ / ~mouse-1~
@@ -291,6 +295,9 @@ Note that, while ~matrix-client~ remains usable, and 
probably will for some time
 
 ** 0.8-pre
 
+*Additions*
++ Command ~ement-room-toggle-space~ toggles a room's membership in a space (a 
way to group rooms in Matrix).
+
 *Changes*
 
 + Room-related commands may be called interactively with a universal prefix to 
prompt for the room/session (allowing to send events or change settings in 
rooms other than the current one).
diff --git a/ement-lib.el b/ement-lib.el
index b7ddcba80f..af743c6829 100644
--- a/ement-lib.el
+++ b/ement-lib.el
@@ -786,10 +786,56 @@ USER is an `ement-user' struct."
 ;; These functions aren't expected to be called by code in other packages (but 
if that
 ;; were necessary, they could be renamed accordingly).
 
+;; (defun ement--room-routing (room)
+;;   "Return a list of servers to route to ROOM through."
+;;   ;; See <https://spec.matrix.org/v1.2/appendices/#routing>.
+;;   ;; FIXME: Ensure highest power level user is at least level 50.
+;;   ;; FIXME: Ignore servers blocked due to server ACLs.
+;;   ;; FIXME: Ignore servers which are IP addresses.
+;;   (cl-labels ((most-powerful-user-in
+;;                (room))
+;;               (servers-by-population-in
+;;                (room))
+;;               (server-of (user)))
+;;     (let (first-server-by-power-level)
+;;       (delete-dups
+;;        (remq nil
+;;              (list
+;;               ;; 1.
+;;               (or (when-let ((user (most-powerful-user-in room)))
+;;                     (setf first-server-by-power-level t)
+;;                     (server-of user))
+;;                   (car (servers-by-population-in room)))
+;;               ;; 2.
+;;               (if first-server-by-power-level
+;;                   (car (servers-by-population-in room))
+;;                 (cl-second (servers-by-population-in room)))
+;;               ;; 3.
+;;               (cl-third (servers-by-population-in room))))))))
+
 (defun ement--room-space-p (room)
   "Return non-nil if ROOM is a space."
   (equal "m.space" (ement-room-type room)))
 
+(defun ement--room-in-space-p (room space)
+  "Return non-nil if ROOM is in SPACE on SESSION."
+  ;; We could use `ement---room-spaces', but since that returns rooms by 
looking them up
+  ;; by ID in the session's rooms list, this is more efficient.
+  (pcase-let* (((cl-struct ement-room (id parent-id) (local (map children))) 
space)
+               ((cl-struct ement-room (id child-id) (local (map parents))) 
room))
+    (or (member parent-id parents)
+        (member child-id children))))
+
+(defun ement--room-spaces (room session)
+  "Return list of ROOM's parent spaces on SESSION."
+  ;; NOTE: This only looks in the room's parents list; it doesn't look in 
every space's children
+  ;; list.  This should be good enough, assuming we add to the lists correctly 
elsewhere.
+  (pcase-let* (((cl-struct ement-session rooms) session)
+               ((cl-struct ement-room (local (map parents))) room))
+    (cl-remove-if-not (lambda (session-room-id)
+                        (member session-room-id parents))
+                      rooms :key #'ement-room-id)))
+
 (cl-defun ement--prism-color (string &key (contrast-with (face-background 
'default nil 'default)))
   "Return a computed color for STRING.
 The color is adjusted to have sufficient contrast with the color
diff --git a/ement-room-list.el b/ement-room-list.el
index 3c734f7e0f..7d2e3f0dc8 100644
--- a/ement-room-list.el
+++ b/ement-room-list.el
@@ -40,12 +40,15 @@
 
 ;;;; Variables
 
+(declare-function ement-room-toggle-space "ement-room")
+
 (defvar ement-room-list-mode-map
   (let ((map (make-sparse-keymap)))
     (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 (kbd "s") #'ement-room-toggle-space)
     map))
 
 (defvar ement-room-list-timestamp-colors nil
diff --git a/ement-room.el b/ement-room.el
index 0ec32d569f..17a8efeea4 100644
--- a/ement-room.el
+++ b/ement-room.el
@@ -166,6 +166,7 @@ Used to, e.g. call `ement-room-compose-org'.")
     (define-key map (kbd "R l") #'ement-leave-room)
     (define-key map (kbd "R F") #'ement-forget-room)
     (define-key map (kbd "R n") #'ement-room-set-display-name)
+    (define-key map (kbd "R s") #'ement-room-toggle-space)
 
     ;; Other
     (define-key map (kbd "g") #'ement-room-sync)
@@ -1812,6 +1813,52 @@ reaction string, e.g. \"👍\"."
     (goto-char (button-start button))
     (call-interactively #'ement-room-toggle-reaction)))
 
+(defun ement-room-toggle-space (room space session)
+  ;; Naming things is hard, but this seems the best balance between concision, 
ambiguity,
+  ;; and consistency.  The docstring is always there.  (Or there's the sci-fi 
angle:
+  ;; "spacing" a room...)
+  "Toggle ROOM's membership in SPACE on SESSION."
+  (interactive
+   (ement-with-room-and-session
+     :room-form (ement-complete-room :session ement-session
+                  :predicate (lambda (room) (not (ement--room-space-p room))) )
+     (pcase-let* ((prompt (format "Toggle room %S's membership in space: "
+                                  (ement--format-room ement-room)))
+                  ;; TODO: Use different face for spaces the room is already 
in.
+                  (`(,space ,_session) (ement-complete-room :session 
ement-session :prompt prompt :suggest nil
+                                         :predicate #'ement--room-space-p)))
+       (list ement-room space ement-session))))
+  (pcase-let* (((cl-struct ement-room (id child-id)) room)
+               (routing-server (progn
+                                 (string-match (rx (1+ (not (any ":"))) ":" 
(group (1+ anything))) child-id)
+                                 (match-string 1 child-id)))
+               (action (if (ement--room-in-space-p room space)
+                           'remove 'add))
+               (data (pcase action
+                       ('add (ement-alist "via" (vector
+                                                 ;; FIXME: Finish and use the 
routing function.
+                                                 ;; (ement--room-routing room)
+                                                 routing-server)))
+                       ('remove (make-hash-table)))))
+    (ement-put-state space "m.space.child" child-id data session
+      :then (lambda (response-data)
+              ;; It appears that the server doesn't send the new event in the 
next sync (at
+              ;; least, not to the client that put the state), so we must 
simulate receiving it.
+              (pcase-let* (((map event_id) response-data)
+                           ((cl-struct ement-session user) session)
+                           ((cl-struct ement-room (id child-id)) room)
+                           (fake-event (make-ement-event :id event_id :type 
"m.space.child"
+                                                         :sender user 
:state-key child-id
+                                                         :content 
(json-read-from-string (json-encode data)))))
+                (push fake-event (ement-room-timeline space))
+                (run-hook-with-args 'ement-event-hook fake-event space 
session))
+              (ement-message "Room %S %s space %S"
+                             (ement--format-room room)
+                             (pcase action
+                               ('add "added to")
+                               ('remove "removed from"))
+                             (ement--format-room space))))))
+
 ;;;; Functions
 
 (defun ement-room-view (room session)
@@ -4340,7 +4387,18 @@ For use in `completion-at-point-functions'."
                                       (propertize (ement--user-displayname-in
                                                    ement-room (gethash 
(ement-user-id (ement-session-user ement-session))
                                                                        
ement-users))
-                                                  'face 'transient-value))))]]
+                                                  'face 'transient-value))))
+              ("R s" "Toggle spaces" ement-room-toggle-space
+               :description (lambda ()
+                              (format "Toggle spaces (%s)"
+                                      (if-let ((spaces (ement--room-spaces 
ement-room ement-session)))
+                                          (string-join
+                                           (mapcar (lambda (space)
+                                                     (propertize 
(ement-room-display-name space)
+                                                                 'face 
'transient-value))
+                                                   spaces)
+                                           ", ")
+                                        (propertize "none" 'face 
'transient-inactive-value)))))]]
   ["Other"
    ("v" "View event" ement-room-view-event)
    ("g" "Sync new messages" ement-room-sync



reply via email to

[Prev in Thread] Current Thread [Next in Thread]