(provide 'murk)
+(require 'cl-lib)
+
;;; Customizations
(defcustom murk-networks
'(("debug" "localhost" 6667 :notls)
("libera" "irc.libera.chat" 6697)
- ("tilde" "tilde.chat" 6697))
+ ("tilde" "tilde.chat" 6697)
+ ("freenode" "chat.freenode.net" 6697))
"IRC networks."
:type '(alist :key-type string))
nil))))
-;;; Contexts and Servers
+;;; Contexts
;;
-;; A context is a list (server name ...) where name is a string
-;; representing either a channel name or nick, and server is a symbol
-;; identifying the server.
+;; A context is a list (server channel users) identifying the server
+;; and channel. The tail of the list contains the nicks of users
+;; present in the channel.
;;
-;; Each server has a special context (server nil) used for messages
+;; Each server has a special context (server) used for messages
;; to/from the server itself.
(defvar murk-contexts nil
The head of this list is always the current context.")
(defun murk-current-context ()
- "Returns the current context."
+ "Return the current context."
(if murk-contexts
(car murk-contexts)
nil))
(seq-take c2 2)))))
(defun murk-context-server (ctx) (elt ctx 0))
-(defun murk-context-name (ctx) (elt ctx 1))
-(defun murk-context-users (ctx) (seq-drop ctx 2))
+(defun murk-context-channel (ctx) (elt ctx 1))
+(defun murk-context-users (ctx) (elt ctx 2))
+(defun murk-set-context-users (ctx users)
+ (setcar (cddr ctx) users))
(defun murk-server-context-p (ctx) (not (cdr ctx)))
(defun murk-add-context (ctx)
(defun murk-context->string (ctx)
(if (murk-server-context-p ctx)
(concat "[" (murk-context-server ctx) "]")
- (concat (murk-context-name ctx) "@"
+ (concat (murk-context-channel ctx) "@"
(murk-context-server ctx))))
(defun murk-get-context (server &optional name)
(if name
- (assoc server murk-contexts)
- (let ((test-ctx (list server name)))
- (seq-find (lambda (ctx)
- (equal (seq-take ctx 2) test-ctx))
- murk-contexts))))
+ (let ((test-ctx (list server name)))
+ (seq-find (lambda (ctx)
+ (equal (seq-take ctx 2) test-ctx))
+ murk-contexts))
+ (assoc server murk-contexts)))
(defun murk-cycle-contexts (&optional reverse)
(setq murk-contexts
(seq-take murk-contexts nminus1)))
(append (cdr murk-contexts) (list (car murk-contexts))))))
+(defun murk-add-context-users (ctx users)
+ (murk-set-context-users
+ ctx
+ (cl-union users (murk-context-users ctx))))
+
;;; Buffer
;;
"Server"
(concat
"Channel: "
- (murk-context-name ctx)
+ (murk-context-channel ctx)
" ("
(number-to-string
(length (murk-context-users ctx)))
(murk-set-connection-nick server nick)
(murk-display-notice nil text)))
+ ("353" ; NAMEREPLY
+ (let* ((params (murk-msg-params msg))
+ (channel (elt params 2))
+ (names (split-string (elt params 3)))
+ (ctx (murk-get-context server channel)))
+ (if ctx
+ (murk-add-context-users ctx names)
+ (murk-display-notice nil "Users in " channel
+ ": " (string-join names " ")))))
+
+ ("366" ; ENDOFNAMES
+ (let* ((params (murk-msg-params msg))
+ (channel (elt params 1))
+ (ctx (murk-get-context server channel)))
+ (if ctx
+ (murk-display-notice
+ ctx
+ (murk--as-string (length (murk-context-users ctx)))
+ " users in " channel)
+ (murk-display-notice nil "End of " channel " names list."))))
+
+
((rx (= 3 (any digit)))
(murk-display-notice nil (mapconcat 'identity (cdr (murk-msg-params msg)) " ")))
(guard (equal (murk-connection-nick server)
(murk-msg-src msg))))
(let ((channel (car (murk-msg-params msg))))
- (murk-add-context (list server channel))
+ (murk-add-context (list server channel nil))
(murk-display-notice (murk-current-context)
"Joining channel " channel " on " server)
(murk-render-prompt)))
(let* ((server (murk-context-server (murk-current-context)))
(channel (if params
(car params)
- (murk-context-name (murk-current-context)))))
+ (murk-context-channel (murk-current-context)))))
(if channel
(murk-send-msg server (murk-msg nil nil "PART" channel))
(murk-display-error "No current channel to leave"))))
(_
(murk-display-error "Badly formed command")))
(unless (string-empty-p string)
- (if (murk-current-context)
- (let ((server (murk-context-server (murk-current-context))))
- (murk-send-msg server
- (murk-msg nil nil "PRIVMSG"
- (murk-context-name (murk-current-context))
- string))
- (murk-display-message server
- (murk-connection-nick server)
- (murk-context->string (murk-current-context))
- string))
- (murk-display-error "No current context")))))
+ (let ((ctx (murk-current-context)))
+ (if ctx
+ (if (not (murk-server-context-p ctx))
+ (let ((server (murk-context-server ctx))
+ (channel (murk-context-channel ctx)))
+ (murk-send-msg server
+ (murk-msg nil nil "PRIVMSG" channel string))
+ (murk-display-message server
+ (murk-connection-nick server)
+ channel string))
+ (murk-display-error "No current channel"))
+ (murk-display-error "No current context"))))))
;;; Command history
(interactive)
(murk-history-cycle +1))
+(defun murk-cycle-contexts-forward ()
+ (interactive)
+ (murk-cycle-contexts)
+ (murk-render-prompt))
+
+(defun murk-cycle-contexts-reverse ()
+ (interactive)
+ (murk-cycle-contexts t)
+ (murk-render-prompt))
+
(defun murk-complete-input ()
(interactive)
(let ((completion-ignore-case t))
(re-search-backward " " murk-input-marker t)))
(start (if space-idx (+ 1 space-idx) murk-input-marker)))
(unless (string-prefix-p "/" (buffer-substring start end))
- (let* ((users (murk-get-context-users (murk-current-context)))
+ (let* ((users (murk-context-users (murk-current-context)))
(users-no@ (mapcar
(lambda (u) (car (split-string u "@" t)))
users)))
(define-key map (kbd "<C-up>") 'murk-history-prev)
(define-key map (kbd "<C-down>") 'murk-history-next)
(define-key map (kbd "<C-tab>") 'murk-cycle-contexts-forward)
+ (define-key map (kbd "<C-S-iso-lefttab>") 'murk-cycle-contexts-reverse)
(define-key map (kbd "<C-S-tab>") 'murk-cycle-contexts-reverse)
(when (fboundp 'evil-define-key*)
(evil-define-key* 'motion map