From: Tim Vaughan Date: Mon, 28 Jun 2021 14:36:06 +0000 (+0200) Subject: Things are roughly working again after refactor. X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=lurk.git;a=commitdiff_plain;h=03b441c5ba7075419f91a84427b1afa1093f5d22 Things are roughly working again after refactor. --- diff --git a/lirc.el b/lirc.el index 9a5f681..e33f6cf 100644 --- a/lirc.el +++ b/lirc.el @@ -30,6 +30,7 @@ (provide 'lirc) + ;;; Customizations ;; @@ -50,9 +51,6 @@ ("local" "localhost" 6697)) "IRC networks.") -(defcustom lirc-prompt-string "> " - "Prompt.") - ;;; Faces ;; @@ -89,7 +87,7 @@ (defvar lirc-version "Lirc v0.1") -(defvar lirc-notice-prompt +(defvar lirc-notice-prefix (concat (propertize "-" 'face 'lirc-faded) @@ -98,9 +96,14 @@ (propertize "-" 'face 'lirc-faded))) -(defvar lirc-error-prompt +(defvar lirc-error-prefix (propertize "!!!" 'face 'lirc-error)) + +(defvar lirc-prompt-string + (propertize "> " 'face 'lirc-prompt)) + + ;;; Network process ;; @@ -130,11 +133,13 @@ (defun lirc-connect (network) - (setq lirc-channel-list nil) - (setq lirc-current-channel nil) - (lirc-start-process network) - (lirc-send-msg (lirc-msg nil nil "USER" lirc-user-name 0 "*" lirc-full-name)) - (lirc-send-msg (lirc-msg nil nil "NICK" lirc-nick))) + (if (get-process "lirc") + (lirc-display-error "Already connected. Disconnect first.") + (setq lirc-current-context nil) + (clrhash lirc-contexts) + (lirc-start-process network) + (lirc-send-msg (lirc-msg nil nil "USER" lirc-user-name 0 "*" lirc-full-name)) + (lirc-send-msg (lirc-msg nil nil "NICK" lirc-nick)))) (defun lirc-send-msg (msg) (let ((proc (get-process "lirc"))) @@ -143,19 +148,20 @@ (lirc-display-error "No server connection established.") (error "No server connection established")))) -;;; Messages + +;;; Server messages ;; -(defun lirc-as-string (obj) +(defun lirc--as-string (obj) (if obj (with-output-to-string (princ obj)) nil)) (defun lirc-msg (tags src cmd &rest params) - (list (lirc-as-string tags) - (lirc-as-string src) - (upcase (lirc-as-string cmd)) - (mapcar #'lirc-as-string + (list (lirc--as-string tags) + (lirc--as-string src) + (upcase (lirc--as-string cmd)) + (mapcar #'lirc--as-string (if (and params (listp (elt params 0))) (elt params 0) params)))) @@ -219,102 +225,65 @@ portion of the source component of the message, as LIRC doesn't use this.") nil)))) -;;; Channels and users +;;; Contexts and users ;; -(defvar lirc-current-channel nil) - -(defun lirc-channel (name next prev users) - (list name prev next users)) - -(defun lirc-get-channel-name (channel) - (elt channel 0)) -(defun lirc-get-channel-next (channel) - (elt channel 1)) -(defun lirc-get-channel-prev (channel) - (elt channel 2)) -(defun lirc-get-channel-users (channel) - (elt channel 3)) - -(defun lirc-set-channel-name (channel name) - (setf (elt channel 0) name)) -(defun lirc-set-channel-next (channel next) - (setf (elt channel 1) next)) -(defun lirc-set-channel-prev (channel prev) - (setf (elt channel 2) prev)) -(defun lirc-set-channel-users (channel users) - (setf (elt channel 3) users)) - -(defun lirc-add-channel (new-channel) - (if lirc-current-channel - (let* ((prev lirc-current-channel) - (next (lirc-get-channel-next lirc-current-channel))) - (lirc-set-channel-next new-channel prev) - (lirc-set-channel-prev new-channel next)) - (lirc-set-channel-next new-channel new-channel) - (lirc-set-channel-prev new-channel new-channel)) - (setq lirc-current-channel new-channel)) - -(defun lirc-del-channel (channel) - (let ((prev (lirc-get-channel-prev channel)) - (next (lirc-get-channel-next channel))) - (if (and prev next) - (if (eq prev next) - (progn - (lirc-set-channel-next prev nil) - (lirc-set-channel-prev prev nil) - (setq lirc-current-channel prev)) - (lirc-set-channel-next prev next) - (lirc-set-channel-prev next prev) - (if (eq channel lirc-current-channel) - (setq lirc-current-channel prev))) - (setq lirc-current-channel nil)))) - -(defun lirc-channel-do (proc) - (if lirc-current-channel - (let ((channel lirc-current-channel)) - (funcall proc lirc-current-channel) - (while (not (eq (lirc-get-channel-next channel) lirc-current-channel)) - (setq channel (lirc-get-channel-next channel)) - (funcall proc channel))))) - -(defun lirc-get-channel-with-name (channel-name) - (if lirc-current-channel - (let ((channel lirc-current-channel)) - (while (and (not (equal (lirc-get-channel-name channel) channel-name)) - (not (eq (lirc-get-channel-next channel) lirc-current-channel))) - (setq channel (lirc-get-channel-next channel))) - (if (equal (lirc-get-channel-name channel) channel-name) - channel - nil)) +(defvar lirc-context-table + '((channel lirc-display-channel-message) + (nick lirc-display-private-message) + (host lirc-diaplay-server-message))) + +(defvar lirc-current-context nil) +(defvar lirc-contexts (make-hash-table :test #'equal)) + +(defun lirc-add-context (name) + (puthash name nil lirc-contexts)) + +(defun lirc-del-context (name) + (remhash name lirc-contexts)) + +(defun lirc-get-context-users (name) + (gethash name lirc-contexts)) + +(defun lirc-add-context-users (context users) + (puthash context + (append users + (gethash context lirc-contexts)) + lirc-contexts)) + +(defun lirc-del-context-user (context user) + (puthash context + (remove user (gethash context lirc-contexts)) + lirc-contexts)) + +(defun lirc-del-user (user) + (dolist (context (lirc-get-context-list)) + (lirc-del-context-user context user))) + +(defun lirc-get-context-type (name) + (cond + ((string-prefix-p "#" name) 'channel) + ((string-match-p (rx (or "." "localhost")) name) 'host) + (t 'nick))) + +(defun lirc-get-context-list () + (let ((res nil)) + (maphash (lambda (key val) + (cl-pushnew key res)) + lirc-contexts) + res)) + +(defun lirc-get-next-context () + (if lirc-current-context + (let* ((context-list (lirc-get-context-list)) + (context-list* (member lirc-current-context context-list))) + (if (> (length context-list*) 1) + (cadr context-list*) + (car context-list))) nil)) + -(defun lirc-add-channel-with-name (channel-name) - (lirc-add-channel (lirc-channel channel-name nil nil nil))) - -(defun lirc-add-channel-users (channel &rest users) - (lirc-set-channel-users channel (append users (lirc-get-channel-users channel)))) - -(defun lirc-del-channel-users (channel &rest users) - (lirc-set-channel-users channel (cl-set-difference (lirc-get-channel-users channel) users))) - -(defun lirc-del-users (&rest users) - (lirc-channel-do - (lambda (channel) - (lirc-set-channel-users - channel - (cl-set-difference - (lirc-get-channel-users channel) - users - :test #'equal))))) - -(defun lirc-rename-user (old-nick new-nick) - (lirc-channel-do - (lambda (channel) - (lirc-set-channel-users - (cons new-nick (delete old-nick (lirc-get-channel-users channel))))))) - -(defun lirc-cycle-channels () +(defun lirc-cycle-contexts () (interactive) (if lirc-current-channel (progn @@ -322,6 +291,7 @@ portion of the source component of the message, as LIRC doesn't use this.") (lirc-render-prompt)) (lirc-display-error "No channels joined."))) + ;;; Buffer ;; @@ -342,23 +312,33 @@ portion of the source component of the message, as LIRC doesn't use this.") (defun lirc-render-prompt () (with-current-buffer "*lirc*" - (save-excursion - (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) - (goto-char lirc-prompt-marker) - (insert - (propertize (if lirc-current-channel - (lirc-get-channel-name 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)))) + (let ((update-point (= lirc-input-marker (point))) + (update-window-points (mapcar (lambda (w) + (list (= (window-point w) lirc-input-marker) + w)) + (get-buffer-window-list nil nil t)))) + (save-excursion + (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) + (goto-char lirc-prompt-marker) + (insert + (propertize (if lirc-current-context + lirc-current-context + "") + 'face 'lirc-context + 'read-only t) + (propertize lirc-prompt-string + 'face 'lirc-prompt + 'read-only t + 'rear-nonsticky t))) + (set-marker-insertion-type lirc-input-marker nil)) + (if update-point + (goto-char lirc-input-marker)) + (dolist (v update-window-points) + (if (car v) + (set-window-point (cadr v) lirc-input-marker)))))) (defvar lirc-prompt-marker nil "Marker for prompt position in LIRC buffer.") @@ -374,49 +354,46 @@ portion of the source component of the message, as LIRC doesn't use this.") (if (markerp lirc-input-marker) (set-marker lirc-input-marker (point-max)) (setq lirc-input-marker (point-max-marker))) - (lirc-render-prompt) (goto-char (point-max)) - (recenter -1))) + (lirc-render-prompt))) ;;; Output formatting ;; +(defun lirc-display-message (from to text) + (let* ((to-type (lirc-get-context-type to)) + (display-fun (cadr (assoc to-type lirc-context-table)))) + (funcall display-fun from to text))) + +(defun lirc-display-channel-message (from to text) + (lirc-display-string + (propertize (concat to + " <" from "> " + text) + 'face 'lirc-text))) + + (defun lirc-display-action (channel-name nick action) (lirc-display-string (concat channel-name " * " (propertize (concat nick " " action) 'face 'lirc-text)))) -(defun lirc-display-private-message (target nick message) +(defun lirc-display-private-message (from to text) (lirc-display-string (concat (propertize - (concat "[P]" - (if (equal target lirc-nick) - "<- " - "-> ")) - 'face 'lirc-bold) - (propertize (concat "<" nick "> " message) 'face 'lirc-text)))) + (concat "[" from " -> " to "] " + text) + 'face 'lirc-text)))) -(defun lirc-display-message (channel nick message) - (lirc-display-string - (concat - (propertize (concat (lirc-get-channel-name channel) " ") - 'face 'lirc-text) - (propertize (concat "<" nick "> ") - 'face - (if (equal nick lirc-nick) - 'lirc-your-nick - 'lirc-text)) - (propertize message 'face 'lirc-text)))) - (defun lirc-display-notice (&rest notices) - (lirc-display-string lirc-notice-prompt " " (apply #'concat notices))) + (lirc-display-string lirc-notice-prefix " " (apply #'concat notices))) (defun lirc-display-error (&rest messages) - (lirc-display-string lirc-error-prompt " " + (lirc-display-string lirc-error-prefix " " (propertize (apply #'concat messages) 'face 'lirc-error))) @@ -434,15 +411,14 @@ portion of the source component of the message, as LIRC doesn't use this.") ("353" ; NAMEREPLY (let* ((params (lirc-msg-params msg)) - (channel-name (elt params 2)) + (channel (elt params 2)) (names (split-string (elt params 3)))) - (apply #'lirc-add-channel-users - (cons (lirc-get-channel-with-name channel-name) names)))) + (lirc-add-context-users channel names))) ("366" ; ENDOFNAMES (lirc-display-notice - (lirc-as-string (length (lirc-get-channel-users lirc-current-channel))) - " users in " (lirc-get-channel-name lirc-current-channel))) + (lirc-as-string (length (lirc-get-context-users lirc-current-context))) + " users in " lirc-current-context)) ((rx (= 3 (any digit))) (lirc-display-notice (mapconcat 'identity (cdr (lirc-msg-params msg)) " "))) @@ -450,33 +426,36 @@ portion of the source component of the message, as LIRC doesn't use this.") ((and "JOIN" (guard (equal lirc-nick (lirc-msg-src msg)))) (let ((channel-name (car (lirc-msg-params msg)))) - (lirc-add-channel-with-name channel-name) + (lirc-add-context channel-name) + (setq lirc-current-context channel-name) (lirc-display-notice "Joining channel " channel-name) (lirc-render-prompt))) ("JOIN" (let ((channel-name (car (lirc-msg-params msg))) (nick (lirc-msg-src msg))) - (lirc-add-channel-users (lirc-get-channel-with-name channel-name) nick) + (lirc-add-context-users channel-name (list nick)) (lirc-display-notice nick " joined channel " channel-name))) ((and "PART" (guard (equal lirc-nick (lirc-msg-src msg)))) (let ((channel-name (car (lirc-msg-params msg)))) (lirc-display-notice "Left channel " channel-name) - (lirc-del-channel (lirc-get-channel-with-name channel-name)) + (lirc-del-context channel-name) + (if (equal channel-name lirc-current-context) + (setq lirc-current-context (lirc-get-next-context))) (lirc-render-prompt))) ("PART" (let ((channel-name (car (lirc-msg-params msg))) (nick (lirc-msg-src msg))) - (lirc-del-channel-users (lirc-get-channel channel-name) nick) + (lirc-del-context-user channel-name nick) (lirc-display-notice nick " left channel " channel-name))) ("QUIT" (let ((nick (lirc-msg-src msg)) (reason (mapconcat 'identity (lirc-msg-params msg) " "))) - (lirc-del-users nick) + (lirc-del-user nick) (lirc-display-notice nick " quit: " reason))) ((and "NICK" @@ -503,34 +482,28 @@ portion of the source component of the message, as LIRC doesn't use this.") (lirc-display-notice text))))) ("PRIVMSG" - (let ((nick (lirc-msg-src msg)) - (channel (lirc-get-channel-with-name (car (lirc-msg-params msg)))) - (text (cadr (lirc-msg-params msg)))) + (let* ((from (lirc-msg-src msg)) + (params (lirc-msg-params msg)) + (to (car params)) + (text (cadr params))) (pcase text - ((rx (: "\01ACTION " - (let action (* (not "\01"))) - "\01")) - (lirc-display-action channel nick action)) - ("\01VERSION\01" (let ((version-string (concat lirc-version " - running on GNU Emacs " emacs-version))) (lirc-send-msg (lirc-msg nil nil "NOTICE" - (list nick (concat "\01VERSION " + (list from (concat "\01VERSION " version-string "\01"))))) - (lirc-display-notice "CTCP version request received from " nick)) + (lirc-display-notice "CTCP version request received from " from)) ((rx (let ping (: "\01PING " (* (not "\01")) "\01"))) - (lirc-send-msg (lirc-msg nil nil "NOTICE" (list nick ping))) - (lirc-display-notice "CTCP ping received from " nick)) + (lirc-send-msg (lirc-msg nil nil "NOTICE" (list from ping))) + (lirc-display-notice "CTCP ping received from " from)) ("\01USERINFO\01" - (lirc-display-notice "CTCP userinfo request from " nick " (no response sent)")) + (lirc-display-notice "CTCP userinfo request from " from " (no response sent)")) (_ - (if channel - (lirc-display-message channel nick text) - (lirc-display-private-message (car (lirc-msg-params msg)) nick text)))))) + (lirc-display-message from to text))))) (_ (lirc-display-string (lirc-msg->string msg)))))) @@ -546,11 +519,11 @@ portion of the source component of the message, as LIRC doesn't use this.") (lirc-connect network)) ((rx (: "TOPIC " (let new-topic (* not-newline)))) - (lirc-send-msg (lirc-msg nil nil "TOPIC" lirc-current-channel new-topic))) + (lirc-send-msg (lirc-msg nil nil "TOPIC" lirc-current-context new-topic))) ((rx (: "ME " (let action (* not-newline)))) (lirc-send-msg (lirc-msg nil nil "PRIVMSG" - (list lirc-current-channel + (list lirc-current-context (concat "\01ACTION " action "\01")))) (lirc-display-action lirc-nick action)) @@ -560,18 +533,18 @@ portion of the source component of the message, as LIRC doesn't use this.") (lirc-display-notice "CTCP version request sent to " nick)) ((rx "PART" (opt (: " " (let channel (* not-newline))))) - (if (or lirc-current-channel channel) + (if (or lirc-current-context channel) (lirc-send-msg (lirc-msg nil nil "PART" (if channel channel - lirc-current-channel))) + lirc-current-context))) (lirc-display-error "No current channel to leave."))) ((rx "MSG " - (let target (* (not whitespace))) + (let to (* (not whitespace))) " " (let text (* not-newline))) (lirc-send-msg (lirc-msg nil nil "PRIVMSG" target text)) - (lirc-display-private-message target lirc-nick text)) + (lirc-display-message lirc-nick target text)) ((rx (: (let cmd-str (+ (not whitespace))) (opt (: " " (let params-str (* not-newline)))))) @@ -581,13 +554,13 @@ portion of the source component of the message, as LIRC doesn't use this.") nil))))) (unless (string-empty-p string) - (if lirc-current-channel + (if lirc-current-context (progn (lirc-send-msg (lirc-msg nil nil "PRIVMSG" - (lirc-get-channel-name lirc-current-channel) + lirc-current-context string)) - (lirc-display-message lirc-current-channel lirc-nick string)) - (lirc-display-error "No current channel."))))) + (lirc-display-message lirc-nick lirc-current-context string)) + (lirc-display-error "No current context."))))) (defun lirc-enter () "Enter current contents of line after prompt." @@ -599,14 +572,13 @@ portion of the source component of the message, as LIRC doesn't use this.") (delete-region lirc-input-marker (point-max))))) - ;;; Mode ;; (defvar lirc-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") 'lirc-enter) - (define-key map (kbd "") 'lirc-cycle-channels) + ;; (define-key map (kbd "") 'lirc-cycle-channels) map)) (define-derived-mode lirc-mode text-mode "lirc"