+(defun lurk-contexts-equal (c1 c2)
+ (if (lurk-network-context-p c1)
+ (and (lurk-network-context-p c2)
+ (equal (lurk-context-network c1)
+ (lurk-context-network c2)))
+ (and (not (lurk-network-context-p c2))
+ (equal (seq-take c1 2)
+ (seq-take c2 2)))))
+
+(defun lurk-context-network (ctx)
+ (elt ctx 0))
+
+(defun lurk-context-channel (ctx)
+ (elt ctx 1))
+
+(defun lurk-network-context-p (ctx)
+ (not (cdr ctx)))
+
+(defun lurk-add-context (ctx)
+ (add-to-list 'lurk-contexts ctx))
+
+(defun lurk-remove-context (ctx)
+ (setq lurk-contexts
+ (seq-remove
+ (lambda (this-ctx)
+ (lurk-contexts-equal this-ctx ctx))
+ lurk-contexts)))
+
+(defun lurk-remove-network-contexts (network)
+ (setq lurk-contexts
+ (seq-remove (lambda (row) (equal (car row) network))
+ lurk-contexts)))
+
+(defun lurk-context->string (ctx)
+ (concat
+ (if (lurk-network-context-p ctx)
+ ""
+ (concat (lurk-context-channel ctx) "@"))
+ (lurk-context-network ctx)))
+
+(defun lurk-string->context (string)
+ (if (not (string-prefix-p "#" string))
+ (lurk-get-context string)
+ (let* ((parts (string-split string "@"))
+ (channel (elt parts 0))
+ (network (elt parts 1)))
+ (lurk-get-context network channel))))
+
+(defun lurk-get-context (network &optional channel)
+ (if (and channel (string-prefix-p "#" channel))
+ (let ((test-ctx (list network channel)))
+ (seq-find (lambda (ctx)
+ (equal (seq-take ctx 2) test-ctx))
+ lurk-contexts))
+ (car (member (list network) lurk-contexts))))
+
+(defun lurk-cycle-contexts (&optional reverse)
+ (setq lurk-contexts
+ (if reverse
+ (let ((nminus1 (- (length lurk-contexts) 1)))
+ (cons
+ (elt lurk-contexts nminus1)
+ (seq-take lurk-contexts nminus1)))
+ (append (cdr lurk-contexts) (list (car lurk-contexts))))))
+
+(defun lurk-switch-to-context (ctx)
+ (setq lurk-contexts
+ (let* ((new-head (memq ctx lurk-contexts))
+ (new-tail (take (- (length lurk-contexts)
+ (length new-head))
+ lurk-contexts)))
+ (append new-head new-tail))))
+
+
+;;; Context users
+;;
+
+(defvar lurk-context-users nil
+ "Association list between channel contexts and users.")
+
+(defun lurk-get-context-users (ctx)
+ (cdr (assoc ctx lurk-context-users)))
+
+(defun lurk-set-context-users (ctx users)
+ (setq lurk-context-users
+ (cons (cons ctx users) (assoc-delete-all ctx lurk-context-users))))
+
+(defun lurk-add-context-users (ctx users)
+ (lurk-set-context-users
+ ctx
+ (cl-union users (lurk-get-context-users ctx))))
+
+(defun lurk-del-context-user (ctx user)
+ (lurk-set-context-users
+ ctx
+ (delete user (lurk-get-context-users ctx))))