2021-09-16 00:22:47 +00:00
;;; ement-taxy.el --- List Ement rooms with Taxy -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Adam Porter
;; Author: Adam Porter <adam@alphapapa.net>
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
2022-03-29 22:39:30 -05:00
( require 'button )
2021-09-16 17:01:35 +00:00
( require 'rx )
2022-04-14 16:08:21 -05:00
( require 'svg-lib )
2021-09-16 00:22:47 +00:00
( require 'taxy )
( require 'taxy-magit-section )
2021-09-16 17:01:35 +00:00
( require 'ement-room-list )
( defgroup ement-taxy nil
" Group Ement rooms with Taxy. "
:group 'ement )
;;;; Variables
( defvar ement-taxy-mode-map
( let ( ( map ( make-sparse-keymap ) ) )
( define-key map ( kbd " RET " ) #' ement-taxy-RET )
2022-03-29 03:04:15 -05:00
( define-key map ( kbd " SPC " ) #' ement-taxy-next-unread )
2021-09-16 17:01:35 +00:00
( define-key map [ mouse-1 ] #' ement-taxy-mouse-1 )
map ) )
2022-03-29 01:16:24 -05:00
;;;; Customization
( defcustom ement-taxy-auto-update t
" Automatically update the taxy-based room list buffer. "
:type 'boolean )
2022-03-29 10:51:03 -05:00
;;;;; Faces
2022-03-29 23:19:41 -05:00
( defface ement-room-list-space ' ( ( t ( :inherit ( font-lock-regexp-grouping-backslash ement-room-list-name ) ) ) )
2022-03-29 10:51:03 -05:00
" Space rooms. "
:group 'ement-room-list )
2021-09-16 00:22:47 +00:00
;;;; Keys
2021-09-16 17:01:35 +00:00
;; Since some of these keys need access to the session, and room
;; structs don't include the session, we use a two-element vector in
;; which the session is the second element.
2022-03-26 20:58:48 -05:00
( eval-and-compile
( taxy-define-key-definer ement-taxy-define-key
2022-04-11 06:14:32 -05:00
ement-taxy-keys " ement-taxy-key " " FIXME: Docstring. " ) )
2021-09-16 00:22:47 +00:00
2022-03-29 10:47:46 -05:00
( ement-taxy-define-key membership ( &key name status )
;; FIXME: Docstring: status should be a symbol of either `invite', `join', `leave'.
2022-03-26 01:50:46 -05:00
( cl-labels ( ( format-membership ( membership )
( pcase membership
( 'join " Joined " )
( 'invite " Invited " )
( 'leave " [Left] " ) ) ) )
2022-03-29 10:47:46 -05:00
( pcase-let ( ( ` [ , ( cl-struct ement-room ( status membership ) ) , _session ] item ) )
( if status
( when ( equal status membership )
2022-03-26 01:50:46 -05:00
( or name ( format-membership membership ) ) )
( format-membership membership ) ) ) ) )
2021-09-16 17:01:35 +00:00
( ement-taxy-define-key alias ( &key name regexp )
( pcase-let ( ( ` [ , ( cl-struct ement-room canonical-alias ) , _session ] item ) )
( when canonical-alias
( when ( string-match-p regexp canonical-alias )
name ) ) ) )
2021-09-16 00:22:47 +00:00
2022-04-13 11:00:45 -05:00
( ement-taxy-define-key buffer ( )
2021-09-16 17:01:35 +00:00
( pcase-let ( ( ` [ , ( cl-struct ement-room ( local ( map buffer ) ) ) , _session ] item ) )
( when buffer
" Buffer " ) ) )
2021-09-16 00:22:47 +00:00
2022-04-13 11:00:45 -05:00
( ement-taxy-define-key direct ( )
2021-09-16 17:01:35 +00:00
( pcase-let ( ( ` [ , room , session ] item ) )
2022-05-09 17:24:28 -05:00
( when ( ement--room-direct-p room session )
2021-09-16 17:01:35 +00:00
" Direct " ) ) )
2021-09-16 00:22:47 +00:00
2022-04-13 11:00:45 -05:00
( ement-taxy-define-key people ( )
2022-03-26 01:50:46 -05:00
( pcase-let ( ( ` [ , room , session ] item ) )
2022-05-09 17:24:28 -05:00
( when ( ement--room-direct-p room session )
2022-04-13 10:53:02 -05:00
( propertize " People " 'face 'ement-room-list-direct ) ) ) )
2022-03-26 01:50:46 -05:00
2022-03-29 10:51:03 -05:00
( ement-taxy-define-key space ( &key name id )
( pcase-let* ( ( ` [ , room , session ] item )
( ( cl-struct ement-session rooms ) session )
2022-03-30 02:09:22 -05:00
( ( cl-struct ement-room type ( local ( map parents ) ) ) room ) )
2022-03-29 10:51:03 -05:00
( cl-labels ( ( format-space
2022-03-29 11:28:49 -05:00
( id ) ( let* ( ( parent-room ( cl-find id rooms :key #' ement-room-id :test #' equal ) )
( space-name ( if parent-room
( ement-room-display-name parent-room )
id ) ) )
2022-04-13 10:53:02 -05:00
( concat " Space: " space-name ) ) ) )
2022-03-29 11:28:49 -05:00
( when-let ( ( key ( if id
;; ID specified.
( cond ( ( or ( member id parents )
( equal id ( ement-room-id room ) ) )
;; Room is in specified space.
( or name ( format-space id ) ) )
( ( and ( equal type " m.space " )
( equal id ( ement-room-id room ) ) )
;; Room is a specified space.
2022-04-13 10:53:02 -05:00
( or name ( concat " Space: " ( ement-room-display-name room ) ) )
2022-03-29 11:28:49 -05:00
) )
;; ID not specified.
( pcase ( length parents )
( 0 nil )
( 1
;; TODO: Make the rooms list a hash table to avoid this lookup.
( format-space ( car parents ) ) )
( _
;; TODO: How to handle this better? (though it should be very rare)
( string-join ( mapcar #' format-space parents ) " , " ) ) ) ) ) )
2022-03-29 10:51:03 -05:00
( propertize key 'face 'ement-room-list-space ) ) ) ) )
2022-04-28 15:59:02 -05:00
( ement-taxy-define-key space-p ( )
" Groups rooms that are themselves spaces. "
( pcase-let* ( ( ` [ , room , _session ] item )
( ( cl-struct ement-room type ) room ) )
( when ( equal " m.space " type )
" Spaces " ) ) )
2021-09-16 17:01:35 +00:00
( ement-taxy-define-key name ( &key name regexp )
( pcase-let* ( ( ` [ , room , _session ] item )
2022-05-09 17:24:28 -05:00
( display-name ( ement--room-display-name room ) ) )
2021-09-16 17:01:35 +00:00
( when display-name
( when ( string-match-p regexp display-name )
2022-03-29 10:46:46 -05:00
( or name regexp ) ) ) ) )
2021-09-16 00:22:47 +00:00
2022-04-13 11:00:45 -05:00
( ement-taxy-define-key latest ( &key name newer-than older-than )
( pcase-let* ( ( ` [ , room , _session ] item )
( ( cl-struct ement-room latest-ts ) room )
( age ) )
( when latest-ts
2022-06-23 02:06:37 -05:00
( setf age ( - ( time-convert nil 'integer ) ( / latest-ts 1000 ) ) )
2022-04-13 11:00:45 -05:00
( cond ( newer-than
( when ( <= age newer-than )
( or name ( format " Newer than %s seconds " newer-than ) ) ) )
( older-than
( when ( >= age older-than )
( or name ( format " Older than %s seconds " newer-than ) ) ) )
( t
;; Default to rooms with traffic in the last day.
( if ( <= age 86400 )
" Last 24 hours "
" Older than 24 hours " ) ) ) ) ) )
( ement-taxy-define-key freshness
( &key ( intervals ' ( ( 86400 . " Past 24h " )
( 604800 . " Past week " )
( 2419200 . " Past month " )
( 31536000 . " Past year " ) ) ) )
( pcase-let* ( ( ` [ , room , _session ] item )
( ( cl-struct ement-room latest-ts ) room )
( age ) )
( when latest-ts
2022-06-23 02:06:37 -05:00
( setf age ( - ( time-convert nil 'integer ) ( / latest-ts 1000 ) ) )
2022-04-13 11:00:45 -05:00
( or ( alist-get age intervals nil nil #' > )
" Older than a year " ) ) ) )
2021-09-16 17:01:35 +00:00
( ement-taxy-define-key session ( &optional user-id )
( pcase-let ( ( ` [ , _room , ( cl-struct ement-session
( user ( cl-struct ement-user id ) ) ) ]
item ) )
( pcase user-id
( ` nil id )
( _ ( when ( equal user-id id )
user-id ) ) ) ) )
2021-09-16 00:22:47 +00:00
2021-09-16 17:01:35 +00:00
( ement-taxy-define-key topic ( &key name regexp )
( pcase-let ( ( ` [ , ( cl-struct ement-room topic ) , _session ] item ) )
( when topic
( when ( string-match-p regexp topic )
name ) ) ) )
2022-04-13 11:00:45 -05:00
( ement-taxy-define-key unread ( )
( pcase-let ( ( ` [ , room , session ] item ) )
( when ( ement--room-unread-p room session )
2021-09-16 17:01:35 +00:00
" Unread " ) ) )
2022-04-09 14:02:06 -05:00
( ement-taxy-define-key favourite ( )
:then #' identity
( pcase-let ( ( ` [ , room , _session ] item ) )
( when ( ement--room-favourite-p room )
2022-04-13 10:53:02 -05:00
( propertize " Favourite " 'face 'ement-room-list-favourite ) ) ) )
2022-04-09 14:02:06 -05:00
( ement-taxy-define-key low-priority ( )
:then #' identity
( pcase-let ( ( ` [ , room , _session ] item ) )
( when ( ement--room-low-priority-p room )
" Low-priority " ) ) )
2021-09-16 17:01:35 +00:00
( defcustom ement-taxy-default-keys
2022-04-28 15:59:02 -05:00
' ( ( space-p space )
( ( membership :status 'invite ) )
2022-04-09 14:02:06 -05:00
( favourite )
2022-04-13 11:00:45 -05:00
( ( membership :status 'leave ) )
( low-priority )
( unread )
( ( latest :name " Last 24h " :newer-than 86400 ) )
( latest :name " Old " :older-than ( * 86400 90 ) )
( people )
freshness
2022-03-29 10:51:03 -05:00
( space ) )
2021-09-16 17:01:35 +00:00
" Default keys. "
:type 'sexp )
;;;; Columns
2022-03-29 00:57:16 -05:00
( defvar ement-taxy-room-avatar-cache ( make-hash-table )
" Hash table caching room avatars for the `ement-taxy' room list. " )
2022-03-29 07:38:26 -05:00
( eval-and-compile
( taxy-magit-section-define-column-definer " ement-taxy " ) )
2021-09-16 17:01:35 +00:00
2022-03-26 20:59:39 -05:00
( ement-taxy-define-column #( " 🐱 " 0 1 ( help-echo " Avatar " ) ) ( :align 'right )
2022-03-29 00:57:16 -05:00
( pcase-let* ( ( ` [ , room , _session ] item )
2022-04-14 16:08:21 -05:00
( ( cl-struct ement-room avatar display-name ) room ) )
( if ement-room-list-avatars
2022-03-29 00:57:16 -05:00
( or ( gethash room ement-taxy-room-avatar-cache )
2022-03-26 20:59:39 -05:00
( let ( ( new-avatar
2022-04-14 16:08:21 -05:00
( if avatar
;; NOTE: We resize every avatar to be suitable for this buffer, rather than using
;; the one cached in the room's struct. If the buffer's faces change height, this
;; will need refreshing, but it should be worth it to avoid resizing the images on
;; every update.
( propertize " " 'display
( ement--resize-image ( get-text-property 0 'display avatar )
nil ( frame-char-height ) ) )
;; Room has no avatar: make one.
2022-05-09 17:24:28 -05:00
( let* ( ( string ( or display-name ( ement--room-display-name room ) ) )
2022-05-30 04:01:12 -05:00
( ement-room-prism-minimum-contrast 1 )
2022-05-30 06:13:50 -05:00
( color ( ement--prism-color string :contrast-with " white " ) ) )
2022-05-30 04:01:12 -05:00
( when ( string-match ( rx bos ( or " # " " ! " " @ " ) ) string )
( setf string ( substring string 1 ) ) )
2022-04-14 16:08:21 -05:00
( propertize " " 'display ( svg-lib-tag ( substring string 0 1 ) nil
:background color :foreground " white "
:stroke 0 ) ) ) ) ) )
2022-03-29 00:57:16 -05:00
( puthash room new-avatar ement-taxy-room-avatar-cache ) ) )
2022-04-14 16:08:21 -05:00
;; Avatars disabled: use a two-space string.
2022-03-26 20:59:39 -05:00
" " ) ) )
2021-09-16 17:01:35 +00:00
( ement-taxy-define-column " Name " ( :max-width 25 )
( pcase-let* ( ( ` [ , room , session ] item )
2022-03-29 10:51:03 -05:00
( ( cl-struct ement-room type ) room )
2022-05-09 17:24:28 -05:00
( display-name ( ement--room-display-name room ) )
2021-09-16 17:01:35 +00:00
( face ) )
( or ( when display-name
2022-03-26 01:50:46 -05:00
;; TODO: Use code from ement-room-list and put in a dedicated function.
2021-09-16 17:01:35 +00:00
( setf face ( cl-copy-list ' ( :inherit ( ement-room-list-name ) ) ) )
2022-03-29 06:45:25 -05:00
;; In concert with the "Unread" column, this is roughly equivalent to the
;; "red/gray/bold/idle" states listed in <https://github.com/matrix-org/matrix-react-sdk/blob/b0af163002e8252d99b6d7075c83aadd91866735/docs/room-list-store.md#list-ordering-algorithm-importance>.
( when ( ement--room-unread-p room session )
2022-03-29 23:20:28 -05:00
;; For some reason, `push' doesn't work with `map-elt'...or does it?
( push 'ement-room-list-unread ( map-elt face :inherit ) ) )
2022-03-29 10:51:03 -05:00
( when ( equal " m.space " type )
2022-03-29 23:20:28 -05:00
( push 'ement-room-list-space ( map-elt face :inherit ) ) )
2022-05-09 17:24:28 -05:00
( when ( ement--room-direct-p room session )
2022-03-29 23:20:28 -05:00
( push 'ement-room-list-direct ( map-elt face :inherit ) ) )
2022-04-09 14:02:06 -05:00
( when ( ement--room-favourite-p room )
( push 'ement-room-list-favourite ( map-elt face :inherit ) ) )
( when ( ement--room-low-priority-p room )
( push 'ement-room-list-low-priority ( map-elt face :inherit ) ) )
2022-04-09 18:05:11 -05:00
( pcase ( ement-room-status room )
2021-09-16 17:01:35 +00:00
( 'invite
2022-04-09 18:05:11 -05:00
( push 'ement-room-list-invited ( map-elt face :inherit ) ) )
( 'leave
( push 'ement-room-list-left ( map-elt face :inherit ) ) ) )
2022-04-01 09:34:09 -05:00
( propertize ( ement--button-buttonize display-name #' ement-taxy-mouse-1 )
2022-03-29 03:02:00 -05:00
'face face
2022-03-29 03:38:45 -05:00
'mouse-face 'highlight ) )
2021-09-16 17:01:35 +00:00
" " ) ) )
2022-03-30 09:43:27 -05:00
( ement-taxy-define-column #( " Unread " 0 6 ( help-echo " Unread events (Notifications:Highlights) " ) ) ( :align 'right )
2022-03-29 07:43:52 -05:00
( pcase-let* ( ( ` [ , ( cl-struct ement-room unread-notifications ) , _session ] item )
( ( map notification_count highlight_count ) unread-notifications ) )
( if ( or ( not unread-notifications )
( and ( equal 0 notification_count )
( equal 0 highlight_count ) ) )
" "
( concat ( propertize ( number-to-string notification_count )
'face ( if ( zerop highlight_count )
'default
2022-06-29 22:42:55 -05:00
'ement-room-mention ) )
" : "
( propertize ( number-to-string highlight_count )
'face 'highlight ) ) ) ) )
2022-03-26 20:59:39 -05:00
2021-09-16 17:01:35 +00:00
( ement-taxy-define-column " Latest " ( )
( pcase-let ( ( ` [ , ( cl-struct ement-room latest-ts ) , _session ] item ) )
( if latest-ts
( let* ( ( difference-seconds ( - ( float-time ) ( / latest-ts 1000 ) ) )
( n ( cl-typecase difference-seconds
2022-04-20 13:00:23 -05:00
( ( number 0 3599 ) ;; <1 hour: 10-minute periods.
( truncate ( / difference-seconds 600 ) ) )
( ( number 3600 86400 ) ;; 1 hour to 1 day: 24 1-hour periods.
( + 6 ( truncate ( / difference-seconds 3600 ) ) ) )
2021-09-16 17:01:35 +00:00
( otherwise ;; Difference in weeks.
( min ( / ( length ement-room-list-timestamp-colors ) 2 )
( + 24 ( truncate ( / difference-seconds 86400 7 ) ) ) ) ) ) )
( face ( list :foreground ( elt ement-room-list-timestamp-colors n ) ) )
2022-06-23 02:06:37 -05:00
( formatted-ts ( ement--human-format-duration difference-seconds 'abbreviate ) ) )
2022-03-30 08:25:57 -05:00
( string-match ( rx ( 1+ digit ) ( repeat 1 alpha ) ) formatted-ts )
( propertize ( match-string 0 formatted-ts ) 'face face
'help-echo formatted-ts ) )
2021-09-16 17:01:35 +00:00
" " ) ) )
2022-03-29 07:43:52 -05:00
( ement-taxy-define-column " Topic " ( :max-width 35 )
2022-04-09 10:24:56 -05:00
( pcase-let ( ( ` [ , ( cl-struct ement-room topic status ) , _session ] item ) )
;; FIXME: Can the status and type unified, or is this inherent to the spec?
2022-04-10 08:09:03 -05:00
( when topic
( setf topic ( replace-regexp-in-string " \n " " " topic 'fixedcase 'literal ) ) )
2022-04-09 10:24:56 -05:00
( pcase status
( 'invite ( concat ( propertize " [invited] "
'face 'ement-room-list-invited )
" " topic ) )
( 'leave ( concat ( propertize " [left] "
'face 'ement-room-list-left )
" " topic ) )
( _ ( or topic " " ) ) ) ) )
2022-03-29 07:43:52 -05:00
( ement-taxy-define-column " Members " ( :align 'right )
( pcase-let ( ( ` [ , ( cl-struct ement-room
( summary ( map ( 'm.joined_member_count member-count ) ) ) )
, _session ]
item ) )
( if member-count
( number-to-string member-count )
" " ) ) )
2022-03-29 01:52:50 -05:00
2022-03-29 00:54:46 -05:00
( ement-taxy-define-column #( " B " 0 1 ( help-echo " Buffer exists for room " ) ) ( )
( pcase-let ( ( ` [ , ( cl-struct ement-room ( local ( map buffer ) ) ) , _session ] item ) )
2022-03-29 03:07:52 -05:00
( if buffer
#( " B " 0 1 ( help-echo " Buffer exists for room " ) )
" " ) ) )
2022-03-29 00:54:46 -05:00
2022-03-26 20:59:39 -05:00
( ement-taxy-define-column " Session " ( )
( pcase-let ( ( ` [ , _room , ( cl-struct ement-session ( user ( cl-struct ement-user id ) ) ) ] item ) )
id ) )
2021-09-16 17:01:35 +00:00
( unless ement-taxy-columns
;; TODO: Automate this or document it
( setq-default ement-taxy-columns
( get 'ement-taxy-columns 'standard-value ) ) )
2021-09-16 00:22:47 +00:00
2022-03-29 01:02:08 -05:00
;;;; Bookmark support
;; Especially useful with Burly: <https://github.com/alphapapa/burly.el>
( require 'bookmark )
( defun ement-taxy-bookmark-make-record ( )
" Return a bookmark record for the `ement-taxy' buffer. "
2022-07-01 06:34:58 -05:00
( list " *Ement Taxy* "
( cons 'handler #' ement-taxy-bookmark-handler ) ) )
2022-03-29 01:02:08 -05:00
( defun ement-taxy-bookmark-handler ( bookmark )
" Show `ement-taxy' room list buffer for BOOKMARK. "
2022-07-01 06:34:58 -05:00
( pcase-let* ( ( ` ( , _bookmark-name . , _ ) bookmark ) )
( unless ement-sessions
2022-03-29 01:02:08 -05:00
;; MAYBE: Automatically connect.
2022-07-01 06:34:58 -05:00
( user-error " No sessions connected: call `ement-connect' first " ) )
2022-03-29 03:02:51 -05:00
( ement-taxy-room-list ) ) )
2022-03-29 01:02:08 -05:00
2021-09-16 00:22:47 +00:00
;;;; Commands
2022-03-29 01:02:08 -05:00
;;;###autoload
2022-03-29 01:02:34 -05:00
( cl-defun ement-taxy-room-list ( &key ( buffer-name " *Ement Taxy* " )
( keys ement-taxy-default-keys )
2022-03-29 03:02:51 -05:00
( display-buffer-action ' ( display-buffer-same-window ) )
2022-03-29 07:41:47 -05:00
;; visibility-fn
)
2022-05-09 17:24:28 -05:00
" Show a buffer listing Ement rooms, grouped with Taxy KEYS.
The buffer is named BUFFER-NAME and is shown with
DISPLAY-BUFFER-ACTION. "
2021-09-16 17:01:35 +00:00
( interactive )
2022-07-01 06:34:58 -05:00
( let ( format-table column-sizes window-start )
2021-09-16 17:01:35 +00:00
( cl-labels ( ;; (heading-face
;; (depth) (list :inherit (list 'bufler-group (bufler-level-face depth))))
( format-item ( item ) ( gethash item format-table ) )
2022-04-13 11:00:45 -05:00
;; NOTE: Since these functions take an "item" (which is a [room session]
;; vector), they're prefixed "item-" rather than "room-".
( item-latest-ts
2022-04-09 10:24:23 -05:00
( item ) ( or ( ement-room-latest-ts ( elt item 0 ) )
;; Room has no latest timestamp. FIXME: This shouldn't
;; happen, but it can, maybe due to oversights elsewhere.
0 ) )
2022-04-13 11:00:45 -05:00
( item-unread-p
( item ) ( pcase-let ( ( ` [ , room , session ] item ) )
( ement--room-unread-p room session ) ) )
( item-left-p
2022-03-29 10:47:46 -05:00
( item ) ( pcase-let ( ( ` [ , ( cl-struct ement-room status ) , _session ] item ) )
( equal 'leave status ) ) )
2021-09-16 17:01:35 +00:00
( taxy-unread-p
2022-04-13 11:00:45 -05:00
( taxy ) ( or ( cl-some #' item-unread-p ( taxy-items taxy ) )
2021-09-16 17:01:35 +00:00
( cl-some #' taxy-unread-p ( taxy-taxys taxy ) ) ) )
2022-04-13 11:00:45 -05:00
( item-space-p
2022-03-29 10:51:03 -05:00
( item ) ( pcase-let ( ( ` [ , ( cl-struct ement-room type ) , _session ] item ) )
( equal " m.space " type ) ) )
2022-04-13 11:00:45 -05:00
( item-favourite-p
2022-04-09 14:02:06 -05:00
( item ) ( pcase-let ( ( ` [ , room , _session ] item ) )
( ement--room-favourite-p room ) ) )
2022-04-13 11:00:45 -05:00
( item-low-priority-p
2022-04-09 14:02:06 -05:00
( item ) ( pcase-let ( ( ` [ , room , _session ] item ) )
( ement--room-low-priority-p room ) ) )
2021-09-16 17:01:35 +00:00
( visible-p
;; This is very confusing and doesn't currently work.
( section ) ( let ( ( value ( oref section value ) ) )
( if ( cl-typecase value
2022-04-13 11:00:45 -05:00
( taxy-magit-section ( item-unread-p value ) )
2021-09-16 17:01:35 +00:00
( ement-room nil ) )
'show
'hide ) ) )
2022-04-13 11:00:45 -05:00
( item-invited-p
2022-04-09 10:24:45 -05:00
( item ) ( pcase-let ( ( ` [ , ( cl-struct ement-room status ) , _session ] item ) )
( equal 'invite status ) ) )
2021-09-16 17:01:35 +00:00
( t<nil ( a b ) ( and a ( not b ) ) )
2022-04-09 14:02:06 -05:00
( t>nil ( a b ) ( and ( not a ) b ) )
2021-09-16 17:01:35 +00:00
( make-fn ( &rest args )
( apply #' make-taxy-magit-section
:make #' make-fn
:format-fn #' format-item
2022-03-26 01:50:46 -05:00
:level-indent ement-taxy-level-indent
2021-09-16 17:01:35 +00:00
;; :visibility-fn #'visible-p
2022-03-26 01:50:46 -05:00
;; :heading-indent 2
2021-09-16 17:01:35 +00:00
:item-indent 2
;; :heading-face-fn #'heading-face
args ) ) )
;; (when (get-buffer buffer-name)
;; (kill-buffer buffer-name))
2022-03-29 03:04:04 -05:00
( unless ement-sessions
( error " Ement: Not connected. Use `ement-connect' to connect " ) )
2021-09-16 17:01:35 +00:00
( with-current-buffer ( get-buffer-create buffer-name )
( ement-taxy-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 ) ) ) )
2022-04-13 11:00:45 -05:00
( taxy ( cl-macrolet ( ( first-item
2022-04-11 06:13:37 -05:00
( pred ) ` ( lambda ( taxy )
2022-04-13 11:00:45 -05:00
( when ( taxy-items taxy )
( , pred ( car ( taxy-items taxy ) ) ) ) ) ) )
2022-04-11 06:13:37 -05:00
( thread-last
( make-fn
:name " Ement Rooms "
:take ( taxy-make-take-function keys ement-taxy-keys ) )
( taxy-fill room-session-vectors )
2022-04-13 11:00:45 -05:00
( taxy-sort #' > #' item-latest-ts )
( taxy-sort #' t<nil #' item-invited-p )
( taxy-sort #' t<nil #' item-favourite-p )
( taxy-sort #' t>nil #' item-low-priority-p )
( taxy-sort #' t<nil #' item-unread-p )
( taxy-sort #' t<nil #' item-space-p )
2022-04-14 03:04:03 -05:00
;; Within each taxy, left rooms should be sorted last so that one
;; can never be the first room in the taxy (unless it's the taxy
;; of left rooms), which would cause the taxy to be incorrectly
;; sorted last.
( taxy-sort #' t>nil #' item-left-p )
2022-04-11 06:13:37 -05:00
( taxy-sort* #' string< #' taxy-name )
2022-04-13 11:00:45 -05:00
( taxy-sort* #' > ( lambda ( taxy )
( if ( taxy-items taxy )
( item-latest-ts ( car ( taxy-items taxy ) ) )
most-negative-fixnum ) ) )
( taxy-sort* #' t<nil ( first-item item-unread-p ) )
( taxy-sort* #' t<nil ( first-item item-favourite-p ) )
2022-04-14 03:04:03 -05:00
( taxy-sort* #' t<nil ( first-item item-invited-p ) )
2022-04-13 11:00:45 -05:00
( taxy-sort* #' t>nil ( first-item item-low-priority-p ) )
( taxy-sort* #' t>nil ( first-item item-left-p ) ) ) ) )
2021-09-16 17:01:35 +00:00
( taxy-magit-section-insert-indent-items nil )
( inhibit-read-only t )
( format-cons ( taxy-magit-section-format-items
2022-03-29 03:03:51 -05:00
ement-taxy-columns ement-taxy-column-formatters taxy ) )
( pos ( point ) )
2022-04-11 06:12:46 -05:00
( section-ident ( when ( magit-current-section )
( magit-section-ident ( magit-current-section ) ) ) ) )
2021-09-16 17:01:35 +00:00
( setf format-table ( car format-cons )
column-sizes ( cdr format-cons )
header-line-format ( taxy-magit-section-format-header
2022-07-01 06:34:58 -05:00
column-sizes ement-taxy-column-formatters )
window-start ( if ( get-buffer-window buffer-name )
( window-start ( get-buffer-window buffer-name ) )
0 ) )
2021-09-16 17:01:35 +00:00
( delete-all-overlays )
( erase-buffer )
( save-excursion
2022-03-26 20:59:46 -05:00
( taxy-magit-section-insert taxy :items 'first
2021-09-16 17:01:35 +00:00
;; :blank-between-depth bufler-taxy-blank-between-depth
2022-03-29 03:03:51 -05:00
:initial-depth 0 ) )
( goto-char pos )
2022-04-11 06:12:46 -05:00
( when ( and section-ident ( magit-get-section section-ident ) )
2022-07-01 06:34:58 -05:00
( goto-char ( oref ( magit-get-section section-ident ) start ) ) ) ) )
( display-buffer buffer-name display-buffer-action )
( 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 ) ) ) )
2021-09-16 17:01:35 +00:00
2022-05-29 11:18:31 -05:00
( cl-defun ement-taxy-side-window ( &key ( side 'left ) )
" Show room list in side window on SIDE.
Interactively, with prefix, show on right side ; otherwise, on
left. "
( interactive ( when current-prefix-arg
( list :side 'right ) ) )
( let ( ( display-buffer-mark-dedicated t ) )
;; Not sure if binding `display-buffer-mark-dedicated' is still necessary.
( ement-taxy-room-list
:display-buffer-action ` ( display-buffer-in-side-window
( dedicated . t )
( side . , side )
( window-parameters
( no-delete-other-windows . t ) ) ) ) ) )
2021-09-16 17:01:35 +00:00
( defun ement-taxy-revert ( _ignore-auto _noconfirm )
" Revert current Ement-Taxy buffer. "
( interactive )
2022-03-29 03:02:51 -05:00
( ement-taxy-room-list :display-buffer-action ' ( display-buffer-no-window ( allow-no-window . t ) ) ) )
2021-09-16 17:01:35 +00:00
( defun ement-taxy-mouse-1 ( event )
2022-05-09 17:24:28 -05:00
" Call `ement-taxy-RET' at point. "
2021-09-16 17:01:35 +00:00
( interactive " e " )
( mouse-set-point event )
( call-interactively #' ement-taxy-RET ) )
( defun ement-taxy-RET ( )
2022-05-09 17:24:28 -05:00
" View room at point, or cycle section at point. "
2021-09-16 17:01:35 +00:00
( interactive )
( cl-etypecase ( oref ( magit-current-section ) value )
( vector ( pcase-let ( ( ` [ , room , session ] ( oref ( magit-current-section ) value ) ) )
( ement-view-room room session ) ) )
( taxy-magit-section ( call-interactively #' magit-section-cycle ) )
( null nil ) ) )
2022-03-29 03:04:15 -05:00
( defun ement-taxy-next-unread ( )
" Show next unread room. "
( interactive )
( unless ( button-at ( point ) )
( call-interactively #' forward-button ) )
2022-05-30 02:16:39 -05:00
( 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 )
do ( progn
( goto-char ( button-end ( button-at ( point ) ) ) )
( push-button ( 1- ( point ) ) )
( cl-return t ) )
else do ( call-interactively #' forward-button )
while ( > ( line-number-at-pos ) starting-line ) )
;; No more unread rooms.
( message " No more unread rooms " ) ) )
2022-03-29 03:04:15 -05:00
2021-09-16 17:01:35 +00:00
( define-derived-mode ement-taxy-mode magit-section-mode " Ement-Taxy "
:global nil
2022-03-29 01:50:40 -05:00
( setq-local bookmark-make-record-function #' ement-taxy-bookmark-make-record
2022-03-29 01:02:08 -05:00
revert-buffer-function #' ement-taxy-revert ) )
2021-09-16 17:01:35 +00:00
2022-03-29 01:16:24 -05:00
;;;; Functions
;;;###autoload
( defun ement-taxy-auto-update ( _session )
2022-03-29 01:50:52 -05:00
" Automatically update the Taxy room list buffer.
2022-03-29 01:16:24 -05:00
+Does so when variable ` ement-taxy-auto-update ' is non-nil.
+To be called in ` ement-sync-callback-hook '. "
( when ( and ement-taxy-auto-update
( buffer-live-p ( get-buffer " *Ement Taxy* " ) ) )
( with-current-buffer ( get-buffer " *Ement Taxy* " )
2022-05-09 17:24:28 -05:00
;; FIXME: This seems to redisplay the buffer even when it's buried. But it
;; shouldn't, because the revert function uses `display-buffer-no-window'.
2022-03-29 01:16:24 -05:00
( revert-buffer ) ) ) )
2021-09-16 17:01:35 +00:00
;;;; Footer
2021-09-16 00:22:47 +00:00
( provide 'ement-taxy )
;;; ement-taxy.el ends here