X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lirc.el;h=5301072df21caa841e62ab6c38f1be898dddd20b;hb=09d663a558f98effd144bfe74a8b44b52cbe0865;hp=cd746b57641a547d886605f51bf79d93efc90167;hpb=6d15ff371e4f3e62fbc46febd0cec79a3f594ce8;p=lurk.git diff --git a/lirc.el b/lirc.el index cd746b5..5301072 100644 --- a/lirc.el +++ b/lirc.el @@ -1,4 +1,4 @@ -;;; lirc.el --- Lambdalabs irc client -*- lexical-binding:t -*- +;;; lirc.el --- Lightweight irc client -*- lexical-binding:t -*- ;; Copyright (C) 2021 Tim Vaughan @@ -28,7 +28,7 @@ ;;; Code: -(provide 'lerc) +(provide 'lirc) ;;; Customizations ;; @@ -48,28 +48,29 @@ (defcustom lirc-port 6667 "Default port.") -(defcustom lirc-prompt-string "prompt> " +(defcustom lirc-prompt-string "> " "Prompt.") ;;; Faces ;; (defface lirc-prompt - '((t :inherit font-lock-string-face)) + '((t :inherit org-level-2)) "Face used for the prompt.") +(defface lirc-channel + '((t :inherit org-list-dt)) + "Face used for the channel name in the prompt.") + ;;; Global variables ;; -(defvar lirc-current-channel nil) -(defvar lirc-channel-list nil) - -(defvar lirc-response "") - ;;; Network process ;; +(defvar lirc-response "") + (defun lirc-filter (proc string) (dolist (line (split-string (concat lirc-response string) "\n")) (if (string-suffix-p "\r" line) @@ -117,11 +118,15 @@ (rx (opt (: "@" (group (* (not (or "\n" "\r" ";" " "))))) (* whitespace)) - (opt (: ":" (group (* (not (or "\n" "\r" " "))))) + (opt (: ":" (: (group (* (not (any space "!" "@")))) + (* (not (any space))))) (* whitespace)) (group (: (* (not whitespace)))) (* whitespace) - (opt (group (+ not-newline))))) + (opt (group (+ not-newline)))) + "Regex used to parse IRC messages. +Note that this regex is incomplete. Noteably, we discard the non-nick +portion of the source component of the message, as LIRC doesn't use this.") (defun lirc-string->msg (string) (if (string-match lirc-msg-regex string) @@ -159,6 +164,36 @@ nil)))) +;;; Channels +;; + +(defvar lirc-current-channel nil) +(defvar lirc-channel-list nil) + +(defun lirc-add-channel (channel-name) + (add-to-list 'lirc-channel-list + (list channel-name))) + +(defun lirc-del-channel (channel-name) + (setq lirc-channel-list + (assoc-delete-all channel-name lirc-channel-list))) + +(defun lirc-get-channel-users (channel-name) + (cdr (assoc channel-name lirc-channel-list))) + +(defun lirc-set-channel-users (channel-name users) + (setcdr (assoc channel-name lirc-channel-list) users)) + +(defun lirc-add-channel-users (channel-name &rest users) + (let ((current-users (lirc-get-channel-users channel-name))) + (lirc-set-channel-users channel-name (append users current-users)))) + +(defun lirc-del-channel-users (channel-name &rest users) + (let ((current-users (lirc-get-channel-users channel-name))) + (lirc-channel-set-users channel-name + (cl-set-difference current-users users :test #'equal)))) + + ;;; Buffer ;; @@ -181,16 +216,21 @@ (with-current-buffer "*lirc*" (set-marker-insertion-type lirc-prompt-marker nil) (set-marker-insertion-type lirc-input-marker t) - (let ((inhibit-read-only t)) - (delete-region lirc-prompt-marker lirc-input-marker)) (save-excursion - (goto-char lirc-prompt-marker) (let ((inhibit-read-only t)) - (insert (propertize lirc-prompt-string - 'face 'lirc-prompt - 'read-only t - 'rear-nonsticky t)))) - (set-marker-insertion-type lirc-input-marker nil))) + (delete-region lirc-prompt-marker lirc-input-marker) + (goto-char lirc-prompt-marker) + (insert + (propertize (if lirc-current-channel + lirc-current-channel + "[no channel]") + 'face 'lirc-channel + 'read-only t) + (propertize lirc-prompt-string + 'face 'lirc-prompt + 'read-only t + 'rear-nonsticky t))))) + (set-marker-insertion-type lirc-input-marker nil)) (defvar lirc-prompt-marker nil "Marker for prompt position in LIRC buffer.") @@ -214,33 +254,83 @@ ;; (defun lirc-eval-msg-string (string) + (lirc-display-string string) (let* ((msg (lirc-string->msg string))) - (cond - ((equal (lirc-msg-cmd msg) "PING") - (lirc-send-msg - (lirc-msg nil nil "PONG" (lirc-msg-params msg)))) - ((string-match (rx (= 3 digit)) (lirc-msg-cmd msg)) - (lirc-display-string (string-join (cdr (lirc-msg-params msg)) " "))) - (t - (lirc-display-string (lirc-msg->string msg)))))) + (pcase (lirc-msg-cmd msg) + ("PING" + (lirc-send-msg + (lirc-msg nil nil "PONG" (lirc-msg-params msg)))) + ;; ((rx (= 3 digit)) + ;; (lirc-display-string (string-join (cdr (lirc-msg-params msg)) " "))) + + ("353" ; NAMEREPLY + (let* ((params (lirc-msg-params msg)) + (channel (elt params 2)) + (names (split-string (elt params 3)))) + (apply #'lirc-add-channel-users (cons channel names)))) + + ((and "JOIN" + (guard (equal lirc-nick (lirc-msg-src msg)))) + (let ((channel (car (lirc-msg-params msg)))) + (setq lirc-current-channel channel) + (lirc-add-channel channel) + (lirc-render-prompt))) + + ("JOIN" + (let ((channel (car (lirc-msg-params msg))) + (nick (lirc-msg-src msg))) + (lirc-add-channel-users channel nick))) + + ((and "PART" + (guard (equal lirc-nick (lirc-msg-src msg)))) + (setq lirc-current-channel nil) + (lirc-del-channel (car (lirc-msg-params msg)))) + + ("PART" + (let ((channel (car (lirc-msg-params msg))) + (nick (lirc-msg-src msg))) + (lirc-del-channel-users channel nick))) + + ((and "NICK" + (guard (equal lirc-nick (lirc-msg-src msg)))) + (setq lirc-nick (car (lirc-msg-params msg))) + (lirc-display-string (concat "*** Set nick to " lirc-nick))) + + ("PRIVMSG" + (let ((nick (lirc-msg-src msg)) + (channel (car (lirc-msg-params msg))) + (text (cadr (lirc-msg-params msg)))) + (lirc-display-string (concat channel " <" nick "> " text)))) + (_ + (lirc-display-string (lirc-msg->string msg)))))) ;;; Command entering ;; (defun lirc-enter-string (string) - (cond ((string-prefix-p "/" string) - (let ((cmd-str (substring string 1))) - (lirc-send-msg (lirc-msg nil nil cmd-str)))) - (t - (error "Unknown command" string)))) + (if (string-prefix-p "/" string) + (pcase (substring string 1) + ((rx (: (let cmd-str (+ (not space)))) + (opt + (: (+ " ") + (let params-str (+ anything))))) + (lirc-send-msg (lirc-msg nil nil + cmd-str + (if params-str + (split-string params-str) + nil))))) + (lirc-send-msg (lirc-msg nil nil "PRIVMSG" lirc-current-channel string)))) (defun lirc-enter () "Enter current contents of line after prompt." (interactive) (with-current-buffer "*lirc*" (lirc-enter-string - (buffer-substring lirc-input-marker (point-max))))) + (buffer-substring lirc-input-marker (point-max))) + (let ((inhibit-read-only t)) + (delete-region lirc-input-marker (point-max))))) + ;;; Mode