Network names now complete.
[lurk.git] / lurk.el
diff --git a/lurk.el b/lurk.el
index 9ef2fbb..7b46aae 100644 (file)
--- a/lurk.el
+++ b/lurk.el
   "Default quit message when none supplied.")
 
 (defcustom lurk-networks
-  '(("libera" "irc.libera.chat" 6697)
-    ("freenode" "chat.freenode.net" 6697)
-    ("tilde" "tilde.chat" 6697)
-    ("mbr" "mbrserver.com" 6667 :notls)
-    ("local" "localhost" 6697))
+  '(("libera" "irc.libera.chat" 6697))
   "IRC networks.")
 
 (defcustom lurk-allow-ipv6 nil
@@ -552,8 +548,8 @@ portion of the source component of the message, as LURK doesn't use this.")
        (opt (group (: ":" (+ digit))))
        (opt (group (: "/"
                       (opt
-                       (* (any alnum "-/.,#:%=&_?~@"))
-                       (any alnum "-/#:%=&_~@")))))))
+                       (* (any alnum "-/.,#:%=&_?~@+"))
+                       (any alnum "-/#:%=&_~@+")))))))
   "Imperfect regex used to find URLs in plain text.")
 
 (defun lurk-click-url (button)
@@ -611,6 +607,7 @@ portion of the source component of the message, as LURK doesn't use this.")
   (if lurk-debug
       (lurk-display-string nil nil string))
   (let* ((msg (lurk-string->msg string)))
+    (lurk-process-autoreplies msg)
     (pcase (lurk-msg-cmd msg)
       ("PING"
        (lurk-send-msg
@@ -763,14 +760,68 @@ portion of the source component of the message, as LURK doesn't use this.")
        (lurk-display-notice nil (lurk-msg->string msg))))))
 
 
+;;; User-defined responses
+
+
+(defvar lurk-autoreply-table nil
+  "Table of autoreply messages.
+
+Each autoreply is a list of two elements: (matcher reply)
+
+Here matcher is a list:
+
+(network src cmd params ...)
+
+and reply is another list:
+
+ (cmd params ...)
+
+Each entry in the matcher list is a regular expression tested against the
+corresponding values in the incomming message.  Entries can be nil,
+in which case they match anything.")
+
+(defun lurk--lists-equal (l1 l2)
+    (if (and l1 l2)
+        (if (or (not (and (car l1) (car l2)))
+                (string-match (car l1) (car l2)))
+            (lurk--lists-equal (cdr l1) (cdr l2))
+          nil)
+      t))
+
+(defun lurk-process-autoreply (msg autoreply)
+  (let ((matcher (car autoreply))
+        (reply (cadr autoreply)))
+    (let ((network (car matcher)))
+      (when (and (or (not network)
+                     (and (get-process "lurk")
+                          (equal (car (process-contact (get-process "lurk")))
+                                 (cadr (assoc network lurk-networks)))))
+                 (lurk--lists-equal (cdr matcher)
+                                    (append (list (lurk-msg-src msg)
+                                                  (lurk-msg-cmd msg))
+                                            (lurk-msg-params msg))))
+        (lurk-send-msg
+         (lurk-msg nil nil (car reply) (cdr reply)))))))
+
+(defun lurk-process-autoreplies (msg)
+  (mapc
+   (lambda (autoreply)
+     (lurk-process-autoreply msg autoreply))
+   lurk-autoreply-table))
+
 ;;; Command entering
 ;;
 
 (defun lurk-enter-string (string)
   (if (string-prefix-p "/" string)
       (pcase (substring string 1)
-        ((rx "DEBUG")
-         (setq lurk-debug (not lurk-debug))
+        ((rx (: "DEBUG" (opt (: " " (let setting (or "ON" "OFF"))))))
+         (setq lurk-debug
+               (if setting
+                   (if (equal (upcase setting) "ON")
+                       t
+                     nil)
+                 (not lurk-debug)))
          (lurk-display-notice nil "Debug mode now " (if lurk-debug "on" "off") "."))
 
         ((rx "HEADER")
@@ -906,16 +957,26 @@ portion of the source component of the message, as LURK doesn't use this.")
     (lurk-zoom-in lurk-current-context))
   (setq lurk-zoomed (not lurk-zoomed)))
 
-(defun lurk-complete-nick ()
+(defun lurk-complete-input ()
   (interactive)
-  (when (and (>= (point) lurk-input-marker) lurk-current-context)
-    (let* ((end (max lurk-input-marker (point)))
-           (space-idx (save-excursion
-                        (re-search-backward " " lurk-input-marker t)))
-           (start (if space-idx (+ 1 space-idx) lurk-input-marker))
-           (completion-ignore-case t))
-      (unless (string-prefix-p "/" (buffer-substring start end))
-        (completion-in-region start end (lurk-get-context-users lurk-current-context))))))
+  (when (and (>= (point) lurk-input-marker))
+    (pcase (buffer-substring lurk-input-marker (point))
+      ((rx (: "/connect" (+ " ")
+              (opt (let network (* (not whitespace))))
+              string-end))
+       (let ((space-idx (save-excursion
+                          (re-search-backward " " lurk-input-marker t))))
+         (completion-in-region (+ 1 space-idx)
+                               (point)
+                               (mapcar (lambda (row) (car row)) lurk-networks))))
+      (_
+       (let* ((end (max lurk-input-marker (point)))
+              (space-idx (save-excursion
+                           (re-search-backward " " lurk-input-marker t)))
+              (start (if space-idx (+ 1 space-idx) lurk-input-marker))
+              (completion-ignore-case t))
+         (unless (string-prefix-p "/" (buffer-substring start end))
+           (completion-in-region start end (lurk-get-context-users lurk-current-context))))))))
 
 
 ;;; Mode
@@ -924,7 +985,7 @@ portion of the source component of the message, as LURK doesn't use this.")
 (defvar lurk-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "RET") 'lurk-enter)
-    (define-key map (kbd "<tab>") 'lurk-complete-nick)
+    (define-key map (kbd "<tab>") 'lurk-complete-input)
     (define-key map (kbd "C-c C-z") 'lurk-toggle-zoom)
     (define-key map (kbd "<C-tab>") 'lurk-cycle-contexts-forward)
     (define-key map (kbd "<C-S-tab>") 'lurk-cycle-contexts-reverse)